diff --git a/web/src/app/_components/messages-block.tsx b/web/src/app/_components/messages-block.tsx index 5dc5845..90cfb9b 100644 --- a/web/src/app/_components/messages-block.tsx +++ b/web/src/app/_components/messages-block.tsx @@ -1,7 +1,8 @@ // Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT -import { FastForward } from "lucide-react"; +import { motion } from "framer-motion"; +import { FastForward, Play } from "lucide-react"; import { useCallback, useRef, useState } from "react"; import { Button } from "~/components/ui/button"; @@ -21,11 +22,13 @@ import { ConversationStarter } from "./conversation-starter"; import { InputBox } from "./input-box"; import { MessageListView } from "./message-list-view"; import { RainbowText } from "./rainbow-text"; +import { Welcome } from "./welcome"; export function MessagesBlock({ className }: { className?: string }) { const messageCount = useStore((state) => state.messageIds.length); const responding = useStore((state) => state.responding); const { isReplay } = useReplay(); + const [replayStarted, setReplayStarted] = useState(false); const abortControllerRef = useRef(null); const [feedback, setFeedback] = useState<{ option: Option } | null>(null); const handleSend = useCallback( @@ -61,6 +64,10 @@ export function MessagesBlock({ className }: { className?: string }) { const handleRemoveFeedback = useCallback(() => { setFeedback(null); }, [setFeedback]); + const handleStartReplay = useCallback(() => { + setReplayStarted(true); + void sendMessage(); + }, [setReplayStarted]); const [fastForwarding, setFastForwarding] = useState(false); const handleFastForwardReplay = useCallback(() => { setFastForwarding(!fastForwarding); @@ -91,36 +98,68 @@ export function MessagesBlock({ className }: { className?: string }) { /> ) : ( -
- -
-
- - - Replay Mode - - - - DeerFlow is now replaying the conversation... - - - + <> +
+ +
+ + +
+
+ + + + Replay Mode + + + + + {responding + ? "DeerFlow is now replaying the conversation..." + : replayStarted + ? "The replay has been stopped." + : `You're now in DeerFlow's replay mode. Click the start button on the right to replay.`} + + + +
+
+ {responding && ( + + )} + {!replayStarted && ( + + )} +
-
- {responding && ( - - )} -
-
- -
+
+ + )}
); diff --git a/web/src/app/app.tsx b/web/src/app/app.tsx new file mode 100644 index 0000000..36edc31 --- /dev/null +++ b/web/src/app/app.tsx @@ -0,0 +1,73 @@ +// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates +// SPDX-License-Identifier: MIT + +"use client"; + +import { GithubOutlined } from "@ant-design/icons"; +import Link from "next/link"; +import { useMemo } from "react"; + +import { Button } from "~/components/ui/button"; +import { useReplay } from "~/core/replay"; +import { useStore } from "~/core/store"; +import { cn } from "~/lib/utils"; + +import { Logo } from "./_components/logo"; +import { MessagesBlock } from "./_components/messages-block"; +import { ResearchBlock } from "./_components/research-block"; +import { ThemeToggle } from "./_components/theme-toggle"; +import { Tooltip } from "./_components/tooltip"; +import { SettingsDialog } from "./_settings/dialogs/settings-dialog"; + +export default function App() { + const { isReplay } = useReplay(); + const openResearchId = useStore((state) => state.openResearchId); + const doubleColumnMode = useMemo( + () => openResearchId !== null, + [openResearchId], + ); + return ( +
+
+ +
+ + + + + {!isReplay && } +
+
+
+ + +
+
+ ); +} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 0a1108c..cc4fb26 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -3,76 +3,15 @@ "use client"; -import { GithubOutlined } from "@ant-design/icons"; -import Link from "next/link"; -import { useEffect, useMemo } from "react"; +import dynamic from "next/dynamic"; +import { Suspense } from "react"; -import { Button } from "~/components/ui/button"; -import { useReplay } from "~/core/replay"; -import { sendMessage, useStore } from "~/core/store"; -import { cn } from "~/lib/utils"; - -import { Logo } from "./_components/logo"; -import { MessagesBlock } from "./_components/messages-block"; -import { ResearchBlock } from "./_components/research-block"; -import { ThemeToggle } from "./_components/theme-toggle"; -import { Tooltip } from "./_components/tooltip"; -import { SettingsDialog } from "./_settings/dialogs/settings-dialog"; +const App = dynamic(() => import("./app"), { ssr: false }); export default function HomePage() { - const { isReplay } = useReplay(); - const openResearchId = useStore((state) => state.openResearchId); - const doubleColumnMode = useMemo( - () => openResearchId !== null, - [openResearchId], - ); - useEffect(() => { - if (isReplay) { - void sendMessage(); - } - }, [isReplay]); return ( -
-
- -
- - - - - {!isReplay && } -
-
-
- - -
-
+ Loading DeerFlow...}> + + ); }