From fe33801008bfbdfbbb04d84ae915e30758416196 Mon Sep 17 00:00:00 2001 From: MT-Mint <798521692@qq.com> Date: Tue, 21 Apr 2026 09:41:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(Tour):=20=E5=90=8C=E4=B8=80=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E4=B8=8D=E5=90=8C=E5=B8=90=E5=8F=B7=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E6=BC=AB=E6=B8=B8=E4=BD=BF=E7=94=A8=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/workspace/input-box.tsx | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/workspace/input-box.tsx b/frontend/src/components/workspace/input-box.tsx index e58d12fb..0271d3c2 100644 --- a/frontend/src/components/workspace/input-box.tsx +++ b/frontend/src/components/workspace/input-box.tsx @@ -103,6 +103,42 @@ import { Tooltip } from "./tooltip"; const MAX_REFERENCES_PER_MESSAGE = 10; const INPUT_TOOLS_TOUR_SEEN_KEY = "workspace.input_tools_tour_seen.v1"; +type InputToolsTourSeenState = { + seen: boolean; + threadIds?: string[]; +}; + +function parseInputToolsTourSeenState( + value: string | null, +): InputToolsTourSeenState | null { + if (!value) return null; + if (value === "1") { + return { seen: true }; + } + try { + const parsed = JSON.parse(value) as InputToolsTourSeenState & { + threadId?: string; + }; + if (typeof parsed?.seen !== "boolean") { + return null; + } + if ( + parsed.threadIds != null && + (!Array.isArray(parsed.threadIds) || + parsed.threadIds.some((id) => typeof id !== "string")) + ) { + return null; + } + return { + seen: parsed.seen, + threadIds: + parsed.threadIds ?? + (typeof parsed.threadId === "string" ? [parsed.threadId] : undefined), + }; + } catch { + return null; + } +} type WorkspaceToolButtonProps = ComponentProps; @@ -296,17 +332,32 @@ export function InputBox({ setIsInputToolsTourOpen(false); return; } - const hasSeenTour = window.localStorage.getItem(INPUT_TOOLS_TOUR_SEEN_KEY); - if (!hasSeenTour) { + const seenState = parseInputToolsTourSeenState( + window.localStorage.getItem(INPUT_TOOLS_TOUR_SEEN_KEY), + ); + const hasSeenTourForCurrentThread = + seenState?.seen === true && Boolean(seenState.threadIds?.includes(threadId)); + if (!hasSeenTourForCurrentThread) { setIsInputToolsTourOpen(true); } - }, [showWelcomeStyle, hasSubmitted, isInputToolsTourReady]); + }, [showWelcomeStyle, hasSubmitted, isInputToolsTourReady, threadId]); const finishInputToolsTour = useCallback(() => { - window.localStorage.setItem(INPUT_TOOLS_TOUR_SEEN_KEY, "1"); + const seenState = parseInputToolsTourSeenState( + window.localStorage.getItem(INPUT_TOOLS_TOUR_SEEN_KEY), + ); + const seenThreadIds = new Set(seenState?.threadIds ?? []); + seenThreadIds.add(threadId); + window.localStorage.setItem( + INPUT_TOOLS_TOUR_SEEN_KEY, + JSON.stringify({ + seen: true, + threadIds: Array.from(seenThreadIds), + } satisfies InputToolsTourSeenState), + ); setIsInputToolsTourOpen(false); - }, []); - const closeInputToolsTour = useCallback(() => { + }, [threadId]); + const closeInputToolsTour = useCallback(() => { setIsInputToolsTourOpen(false); }, []);