deerflow-code/docs/superpowers/plans/2026-06-01-iframe-chat-page.md
2026-09-07 18:24:55 +08:00

5.7 KiB

Iframe Chat Page Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add a standalone /page/workspace/chats_iframe/* chat page that reuses the existing thread system and history, while showing only 你好 and no input box before the first user message.

Architecture: Keep the existing workspace shell and chat runtime intact, then add a new route pair and a copied page component dedicated to the iframe path. The new page keeps the original chat behavior once a thread already has messages, but it owns its empty-state rendering and URL transition to /page/workspace/chats_iframe/:thread_id.

Tech Stack: React, TypeScript, React Router, Next navigation shim, existing LangGraph thread hooks


Task 1: Add the iframe chat routes

Files:

  • Modify: frontend-web/src/pages/WorkspaceRoutes.tsx

  • Step 1: Add chats_iframe/new and chats_iframe/:thread_id routes that render the new page inside the existing workspace layout and chat runtime

      <Route
        path="chats_iframe/new"
        element={
          <WorkspaceLayout {...layoutProps}>
            <ChatRuntime>
              <IframeChatPage />
            </ChatRuntime>
          </WorkspaceLayout>
        }
      />
      <Route
        path="chats_iframe/:thread_id"
        element={
          <WorkspaceLayout {...layoutProps}>
            <ChatRuntime>
              <IframeChatPage />
            </ChatRuntime>
          </WorkspaceLayout>
        }
      />
  • Step 2: Ensure the new route imports compile cleanly

Run: rg -n "IframeChatPage|chats_iframe" frontend-web/src/pages/WorkspaceRoutes.tsx Expected: WorkspaceRoutes.tsx contains one import for IframeChatPage and both chats_iframe route entries.

Task 2: Add a standalone iframe chat page

Files:

  • Create: frontend-web/src/pages/IframeChatPage.tsx

  • Reference: frontend-web/src/pages/ChatPage.tsx

  • Step 1: Copy the current ChatPage implementation into IframeChatPage and preserve the existing chat runtime integration

export default function IframeChatPage() {
  const routeBase = useRouteBase();
  const router = useRouter();
  const [showFollowups, setShowFollowups] = useState(false);
  const [hasStartedConversation, setHasStartedConversation] = useState(false);
  const { threadId, setThreadId, isNewThread, setIsNewThread, isMock } =
    useThreadChat();
  // keep the rest of the existing chat hooks and handlers aligned with ChatPage
}
  • Step 2: Change the thread creation URL replacement to stay on the iframe route family
    onStart: (createdThreadId) => {
      setThreadId(createdThreadId);
      setIsNewThread(false);
      history.replaceState(
        null,
        "",
        `${window.location.pathname}${window.location.search}#${routeBase}/chats_iframe/${createdThreadId}`,
      );
    },
  • Step 3: Replace the default landing state with a simple 你好 view and do not render the input box while the iframe page is still a brand-new untouched chat
                {isLandingState && mounted ? (
                  <div className="flex min-h-[240px] items-center justify-center">
                    <div className="text-2xl font-medium">你好</div>
                  </div>
                ) : null}
                {!isLandingState &&
                  (mounted ? (
                    <div className="w-full -translate-y-4">
                      <InputBox
                        className="w-full"
                        isNewThread={false}
                        threadId={threadId}
                        autoFocus={false}
                        status={thread.error ? "error" : thread.isLoading ? "streaming" : "ready"}
                        context={settings.context}
                        disabled={env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" || isUploading}
                        onContextChange={(context) => setSettings("context", context)}
                        promptPrefix={promptPrefixProp}
                        onFollowupsVisibilityChange={setShowFollowups}
                        onSubmit={handleSubmit}
                        onStop={handleStop}
                      />
                    </div>
                  ) : (
                    <div aria-hidden="true" className="bg-background/5 h-32 w-full -translate-y-4 rounded-3xl border" />
                  ))}
  • Step 4: Keep message rendering, thread title, export, token usage, todos, artifact triggers, and all post-first-message behavior identical to the original page

Run: rg -n "MessageList|ThreadTitle|ArtifactTrigger|TokenUsageIndicator|TodoList" frontend-web/src/pages/IframeChatPage.tsx Expected: The new page still renders the same core chat primitives used by ChatPage.

Task 3: Verify the new page compiles

Files:

  • Test: frontend-web/src/pages/IframeChatPage.tsx

  • Test: frontend-web/src/pages/WorkspaceRoutes.tsx

  • Step 1: Run the frontend build

Run: cmd /c npm run build Expected: Build succeeds without TypeScript or bundling errors related to IframeChatPage or chats_iframe.

  • Step 2: Spot-check the changed routes in the built source

Run: rg -n "chats_iframe" frontend-web/src/pages Expected: Matches appear in WorkspaceRoutes.tsx and IframeChatPage.tsx.

  • Step 3: Commit after verification
git add docs/superpowers/plans/2026-06-01-iframe-chat-page.md frontend-web/src/pages/WorkspaceRoutes.tsx frontend-web/src/pages/IframeChatPage.tsx
git commit -m "feat: add iframe chat page routes"