diff --git a/app/layout.tsx b/app/layout.tsx index dd454b67..3f97ee89 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -16,6 +16,7 @@ import { CalendarToggleProvider } from '@/components/calendar-toggle-context' import { MapLoadingProvider } from '@/components/map-loading-context'; import ConditionalLottie from '@/components/conditional-lottie'; import { MapProvider } from '@/components/map/map-context' +import { StreamingProvider } from '@/components/streaming-context' const fontSans = FontSans({ subsets: ['latin'], @@ -60,8 +61,9 @@ export default function RootLayout({ - + - - - + + + + diff --git a/components/header.tsx b/components/header.tsx index 5b5c564a..3809a78b 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -2,6 +2,7 @@ import React from 'react' import Image from 'next/image' import { useCalendarToggle } from './calendar-toggle-context' +import { useStreaming } from './streaming-context' import { ModeToggle } from './mode-toggle' import { cn } from '@/lib/utils' import HistoryContainer from './history-container' @@ -18,6 +19,7 @@ import { ProfileToggle } from './profile-toggle' export const Header = () => { const { toggleCalendar } = useCalendarToggle() + const { isStreaming } = useStreaming() return (
@@ -28,7 +30,16 @@ export const Header = () => {
diff --git a/components/message.tsx b/components/message.tsx index 264aa1f6..127e5fb1 100644 --- a/components/message.tsx +++ b/components/message.tsx @@ -7,9 +7,16 @@ import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' import rehypeKatex from 'rehype-katex' import 'katex/dist/katex.min.css' +import { useStreaming } from './streaming-context' +import { useEffect } from 'react' export function BotMessage({ content }: { content: StreamableValue }) { const [data, error, pending] = useStreamableValue(content) + const { setIsStreaming } = useStreaming() + + useEffect(() => { + setIsStreaming(pending) + }, [pending, setIsStreaming]) // Currently, sometimes error occurs after finishing the stream. if (error) return
Error
diff --git a/components/streaming-context.tsx b/components/streaming-context.tsx new file mode 100644 index 00000000..4d900505 --- /dev/null +++ b/components/streaming-context.tsx @@ -0,0 +1,29 @@ +'use client' + +import { createContext, useContext, useState, ReactNode } from 'react' + +interface StreamingContextType { + isStreaming: boolean + setIsStreaming: (streaming: boolean) => void +} + +const StreamingContext = createContext(undefined) + +export const useStreaming = () => { + const context = useContext(StreamingContext) + if (!context) { + // Return default values if used outside provider (e.g., during SSR) + return { isStreaming: false, setIsStreaming: () => {} } + } + return context +} + +export const StreamingProvider = ({ children }: { children: ReactNode }) => { + const [isStreaming, setIsStreaming] = useState(false) + + return ( + + {children} + + ) +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 68c971ee..8b2af9e8 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -68,10 +68,15 @@ const config = { from: { height: "var(--radix-accordion-content-height)" }, to: { height: "0" }, }, + "spin-ccw": { + from: { transform: "rotate(0deg)" }, + to: { transform: "rotate(-360deg)" }, + }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", + "spin-ccw": "spin-ccw 2s linear infinite", }, fontFamily: { sans: ["var(--font-sans)", ...fontFamily.sans],