diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 0a9c0371a1..38ddb15e05 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -1027,7 +1027,9 @@ export default function ChatView({ threadId }: ChatViewProps) { replace: true, search: (previous) => { const rest = stripDiffSearchParams(previous); - return diffOpen ? { ...rest, diff: undefined } : { ...rest, diff: "1" }; + return diffOpen + ? { ...rest, clearDiff: "1" as const } + : { ...rest, diff: "1" }; }, }); }, [diffOpen, navigate, threadId]); diff --git a/apps/web/src/routes/_chat.$threadId.tsx b/apps/web/src/routes/_chat.$threadId.tsx index 5e05b51fbd..8d4dcf8351 100644 --- a/apps/web/src/routes/_chat.$threadId.tsx +++ b/apps/web/src/routes/_chat.$threadId.tsx @@ -1,5 +1,5 @@ import { ThreadId } from "@t3tools/contracts"; -import { createFileRoute, retainSearchParams, useNavigate } from "@tanstack/react-router"; +import { createFileRoute, stripSearchParams, useNavigate } from "@tanstack/react-router"; import { Suspense, lazy, type ReactNode, useCallback, useEffect } from "react"; import ChatView from "../components/ChatView"; @@ -20,6 +20,36 @@ const DIFF_INLINE_SIDEBAR_WIDTH_STORAGE_KEY = "chat_diff_sidebar_width"; const DIFF_INLINE_DEFAULT_WIDTH = "clamp(28rem,48vw,44rem)"; const DIFF_INLINE_SIDEBAR_MIN_WIDTH = 26 * 16; const COMPOSER_COMPACT_MIN_LEFT_CONTROLS_WIDTH_PX = 208; +const CLEAR_DIFF_SEARCH_VALUE = "1"; + +type ChatThreadRouteSearch = DiffRouteSearch & { + clearDiff?: typeof CLEAR_DIFF_SEARCH_VALUE; +}; + +function shouldClearDiff(value: unknown): boolean { + return value === CLEAR_DIFF_SEARCH_VALUE || value === 1 || value === true; +} + +function parseChatThreadRouteSearch(search: Record): ChatThreadRouteSearch { + const parsed = parseDiffRouteSearch(search); + return shouldClearDiff(search.clearDiff) + ? { ...parsed, clearDiff: CLEAR_DIFF_SEARCH_VALUE } + : parsed; +} + +function retainDiffUnlessCleared({ + search, + next, +}: { + search: ChatThreadRouteSearch; + next: (newSearch: ChatThreadRouteSearch) => ChatThreadRouteSearch; +}): ChatThreadRouteSearch { + const result = next(search); + if (result.clearDiff === CLEAR_DIFF_SEARCH_VALUE || "diff" in result) { + return result; + } + return search.diff ? { ...result, diff: search.diff } : result; +} const DiffPanelSheet = (props: { children: ReactNode; @@ -170,7 +200,12 @@ function ChatThreadRouteView() { void navigate({ to: "/$threadId", params: { threadId }, - search: { diff: undefined }, + search: (previous) => { + return { + ...stripDiffSearchParams(previous), + clearDiff: CLEAR_DIFF_SEARCH_VALUE, + }; + }, }); }, [navigate, threadId]); const openDiff = useCallback(() => { @@ -225,9 +260,12 @@ function ChatThreadRouteView() { } export const Route = createFileRoute("/_chat/$threadId")({ - validateSearch: (search) => parseDiffRouteSearch(search), + validateSearch: (search) => parseChatThreadRouteSearch(search), search: { - middlewares: [retainSearchParams(["diff"])], + middlewares: [ + retainDiffUnlessCleared, + stripSearchParams(["clearDiff"]), + ], }, component: ChatThreadRouteView, });