119 lines · 3.8 KB · TypeScript
RawDownload
import { scopeProjectRef } from "@t3tools/client-runtime";import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";import { useEffect } from "react"; import {  ensurePrimaryEnvironmentReady,  resolveInitialServerAuthGateState,} from "../environments/primary";import { useHandleNewThread } from "../hooks/useHandleNewThread";import { isTerminalFocused } from "../lib/terminalFocus";import { resolveShortcutCommand } from "../keybindings";import { selectThreadTerminalState, useTerminalStateStore } from "../terminalStateStore";import { useThreadSelectionStore } from "../threadSelectionStore";import { resolveSidebarNewThreadEnvMode } from "~/components/Sidebar.logic";import { useSettings } from "~/hooks/useSettings";import { useServerKeybindings } from "~/rpc/serverState"; function ChatRouteGlobalShortcuts() {  const clearSelection = useThreadSelectionStore((state) => state.clearSelection);  const selectedThreadKeysSize = useThreadSelectionStore((state) => state.selectedThreadKeys.size);  const { activeDraftThread, activeThread, defaultProjectRef, handleNewThread, routeThreadRef } =    useHandleNewThread();  const keybindings = useServerKeybindings();  const terminalOpen = useTerminalStateStore((state) =>    routeThreadRef      ? selectThreadTerminalState(state.terminalStateByThreadKey, routeThreadRef).terminalOpen      : false,  );  const appSettings = useSettings();   useEffect(() => {    const onWindowKeyDown = (event: KeyboardEvent) => {      if (event.defaultPrevented) return;       if (event.key === "Escape" && selectedThreadKeysSize > 0) {        event.preventDefault();        clearSelection();        return;      }       const projectRef = activeThread        ? scopeProjectRef(activeThread.environmentId, activeThread.projectId)        : activeDraftThread && routeThreadRef          ? scopeProjectRef(routeThreadRef.environmentId, activeDraftThread.projectId)          : defaultProjectRef;      if (!projectRef) return;       const command = resolveShortcutCommand(event, keybindings, {        context: {          terminalFocus: isTerminalFocused(),          terminalOpen,        },      });       if (command === "chat.newLocal") {        event.preventDefault();        event.stopPropagation();        void handleNewThread(projectRef, {          envMode: resolveSidebarNewThreadEnvMode({            defaultEnvMode: appSettings.defaultThreadEnvMode,          }),        });        return;      }       if (command === "chat.new") {        event.preventDefault();        event.stopPropagation();        void handleNewThread(projectRef, {          branch: activeThread?.branch ?? activeDraftThread?.branch ?? null,          worktreePath: activeThread?.worktreePath ?? activeDraftThread?.worktreePath ?? null,          envMode:            activeDraftThread?.envMode ?? (activeThread?.worktreePath ? "worktree" : "local"),        });        return;      }    };     window.addEventListener("keydown", onWindowKeyDown);    return () => {      window.removeEventListener("keydown", onWindowKeyDown);    };  }, [    activeDraftThread,    activeThread,    clearSelection,    handleNewThread,    keybindings,    defaultProjectRef,    routeThreadRef,    selectedThreadKeysSize,    terminalOpen,    appSettings.defaultThreadEnvMode,  ]);   return null;} function ChatRouteLayout() {  return (    <>      <ChatRouteGlobalShortcuts />      <Outlet />    </>  );} export const Route = createFileRoute("/_chat")({  beforeLoad: async () => {    const [, authGateState] = await Promise.all([      ensurePrimaryEnvironmentReady(),      resolveInitialServerAuthGateState(),    ]);    if (authGateState.status !== "authenticated") {      throw redirect({ to: "/pair", replace: true });    }  },  component: ChatRouteLayout,});