diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx index face19f291c743484177b4fd83a34e942aaf7788..6510cea7ee3ca999660b8447c360dde862b7f352 100644 --- a/apps/web/src/components/DiffPanel.tsx +++ b/apps/web/src/components/DiffPanel.tsx @@ -3,12 +3,11 @@ import { FileDiff, type FileDiffMetadata, Virtualizer, - WorkerPoolContextProvider, } from "@pierre/diffs/react"; import { useQuery } from "@tanstack/react-query"; import { useNavigate, useParams, useSearch } from "@tanstack/react-router"; import { Columns2Icon, Rows3Icon } from "lucide-react"; -import { type ReactNode, useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { checkpointDiffQueryOptions } from "~/lib/providerReactQuery"; import { cn } from "~/lib/utils"; import { parseDiffRouteSearch } from "../diffRouteSearch"; @@ -77,28 +76,7 @@ interface DiffPanelProps { mode?: "inline" | "sheet"; } -export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { - const workerPoolSize = useMemo(() => { - const cores = typeof navigator === "undefined" ? 4 : Math.max(1, navigator.hardwareConcurrency || 4); - return Math.max(2, Math.min(6, Math.floor(cores / 2))); - }, []); - - return ( - - new Worker(new URL("../workers/diffs.worker.ts", import.meta.url), { type: "module" }), - poolSize: workerPoolSize, - totalASTLRUCacheSize: 240, - }} - highlighterOptions={{ - tokenizeMaxLineLength: 1_000, - }} - > - {children} - - ); -} +export { DiffWorkerPoolProvider } from "./DiffWorkerPoolProvider"; export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { const api = useNativeApi(); diff --git a/apps/web/src/components/DiffWorkerPoolProvider.tsx b/apps/web/src/components/DiffWorkerPoolProvider.tsx new file mode 100644 index 0000000000000000000000000000000000000000..53939cf81cfefa1371776945a059c4e6df247ba8 --- /dev/null +++ b/apps/web/src/components/DiffWorkerPoolProvider.tsx @@ -0,0 +1,26 @@ +import { WorkerPoolContextProvider } from "@pierre/diffs/react"; +import { useMemo, type ReactNode } from "react"; + +export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { + const workerPoolSize = useMemo(() => { + const cores = typeof navigator === "undefined" ? 4 : Math.max(1, navigator.hardwareConcurrency || 4); + return Math.max(2, Math.min(6, Math.floor(cores / 2))); + }, []); + + return ( + + new Worker(new URL("../workers/diffs.worker.ts", import.meta.url), { type: "module" }), + poolSize: workerPoolSize, + totalASTLRUCacheSize: 240, + }} + highlighterOptions={{ + tokenizeMaxLineLength: 1_000, + }} + > + {children} + + ); +} + diff --git a/apps/web/src/routes/_chat.$threadId.tsx b/apps/web/src/routes/_chat.$threadId.tsx index 8cca8c2e69d0dde8c85474d0589215cf00883b80..ecf1e2bd53bf39931d872c404a5440387d4a2c38 100644 --- a/apps/web/src/routes/_chat.$threadId.tsx +++ b/apps/web/src/routes/_chat.$threadId.tsx @@ -1,15 +1,73 @@ import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { useEffect } from "react"; +import { Activity, Suspense, lazy, type ReactNode, useCallback, useEffect } from "react"; import ChatView from "../components/ChatView"; import { parseDiffRouteSearch } from "../diffRouteSearch"; +import { useMediaQuery } from "../hooks/useMediaQuery"; import { useStore } from "../store"; +import { Sheet, SheetPopup } from "../components/ui/sheet"; + +const DiffPanel = lazy(() => import("../components/DiffPanel")); +const DIFF_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 1180px)"; + +const DiffPanelWrapper = (props: { + children: ReactNode; + sheet: boolean; + diffOpen: boolean; + onCloseDiff: () => void; +}) => { + if (props.sheet) { + return ( + { + if (!open) { + props.onCloseDiff(); + } + }} + > + + {props.children} + + + ); + } + + return ( + + ); +}; function ChatThreadRouteView() { const { state } = useStore(); const navigate = useNavigate(); const { threadId } = Route.useParams(); + const search = Route.useSearch(); const threadExists = threadId ? state.threads.some((thread) => thread.id === threadId) : false; + const diffOpen = search.diff === "1"; + const shouldUseDiffSheet = useMediaQuery(DIFF_INLINE_LAYOUT_MEDIA_QUERY); + const closeDiff = useCallback(() => { + void navigate({ + to: "/$threadId", + params: { threadId }, + search: (previous) => { + const { + diff: _diff, + diffTurnId: _diffTurnId, + diffFilePath: _diffFilePath, + ...rest + } = previous; + return rest; + }, + }); + }, [navigate, threadId]); useEffect(() => { if (!threadId) { @@ -31,10 +89,33 @@ function ChatThreadRouteView() { return null; } - return ; + const diffLoadingFallback = + !diffOpen || shouldUseDiffSheet ? ( +
+ Loading diff viewer... +
+ ) : ( + + ); + + return ( + <> + + + + + + + + + + ); } export const Route = createFileRoute("/_chat/$threadId")({ validateSearch: (search) => parseDiffRouteSearch(search), component: ChatThreadRouteView, }); + diff --git a/apps/web/src/routes/_chat.tsx b/apps/web/src/routes/_chat.tsx index d225a4e33f353b6fb10d756f4788a35a06301a6d..6f766e44f1db3a5f4d90a09e7f61586c89ebf339 100644 --- a/apps/web/src/routes/_chat.tsx +++ b/apps/web/src/routes/_chat.tsx @@ -1,112 +1,15 @@ -import { - Outlet, - createFileRoute, - useNavigate, - useParams, - useSearch, -} from "@tanstack/react-router"; -import { Activity, Suspense, lazy, type ReactNode, useCallback, useMemo } from "react"; +import { Outlet, createFileRoute } from "@tanstack/react-router"; +import { DiffWorkerPoolProvider } from "../components/DiffWorkerPoolProvider"; import Sidebar from "../components/Sidebar"; -import { parseDiffRouteSearch } from "../diffRouteSearch"; -import { useMediaQuery } from "../hooks/useMediaQuery"; -import { Sheet, SheetPopup } from "../components/ui/sheet"; - -const DiffPanel = lazy(() => import("../components/DiffPanel")); -const DiffWorkerPoolProvider = lazy(() => - import("../components/DiffPanel").then((module) => ({ - default: module.DiffWorkerPoolProvider, - })), -); -const DIFF_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 1180px)"; - -const DiffPanelWrapper = (props: { - children: ReactNode; - sheet: boolean; - diffOpen: boolean; - onCloseDiff: () => void; -}) => { - if (props.sheet) { - return ( - { - if (!open) { - props.onCloseDiff(); - } - }} - > - - {props.children} - - - ); - } - - return ( - - ); -}; function ChatRouteLayout() { - const navigate = useNavigate(); - const params = useParams({ strict: false }); - const routeThreadId = typeof params.threadId === "string" ? params.threadId : null; - const rawSearch = useSearch({ strict: false }); - const diffSearch = useMemo( - () => parseDiffRouteSearch(rawSearch as Record), - [rawSearch], - ); - const diffOpen = routeThreadId !== null && diffSearch.diff === "1"; - const shouldUseDiffSheet = useMediaQuery(DIFF_INLINE_LAYOUT_MEDIA_QUERY); - const closeDiff = useCallback(() => { - if (!routeThreadId) return; - void navigate({ - to: "/$threadId", - params: { threadId: routeThreadId }, - search: (previous) => { - const { - diff: _diff, - diffTurnId: _diffTurnId, - diffFilePath: _diffFilePath, - ...rest - } = previous; - return rest; - }, - }); - }, [navigate, routeThreadId]); - - const diffLoadingFallback = - !diffOpen || shouldUseDiffSheet ? ( -
- Loading diff viewer... -
- ) : ( - - ); - return (
- - - - - - - - - - + + +
); } @@ -114,3 +17,4 @@ function ChatRouteLayout() { export const Route = createFileRoute("/_chat")({ component: ChatRouteLayout, }); +