import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";
import { useEffect } from "react";
import { useCommandPaletteStore } from "../commandPaletteStore";
import { useHandleNewThread } from "../hooks/useHandleNewThread";
import {
startNewLocalThreadFromContext,
startNewThreadFromContext,
} from "../lib/chatThreadActions";
import { isTerminalFocused } from "../lib/terminalFocus";
import { resolveShortcutCommand } from "../keybindings";
import { selectThreadTerminalUiState, useTerminalUiStateStore } from "../terminalUiStateStore";
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 = useTerminalUiStateStore((state) =>
routeThreadRef
? selectThreadTerminalUiState(state.terminalUiStateByThreadKey, routeThreadRef).terminalOpen
: false,
);
const appSettings = useSettings();
useEffect(() => {
const onWindowKeyDown = (event: KeyboardEvent) => {
if (event.defaultPrevented) return;
const command = resolveShortcutCommand(event, keybindings, {
context: {
terminalFocus: isTerminalFocused(),
terminalOpen,
},
});
if (useCommandPaletteStore.getState().open) {
return;
}
if (event.key === "Escape" && selectedThreadKeysSize > 0) {
event.preventDefault();
clearSelection();
return;
}
if (command === "chat.newLocal") {
event.preventDefault();
event.stopPropagation();
void startNewLocalThreadFromContext({
activeDraftThread,
activeThread,
defaultProjectRef,
defaultThreadEnvMode: resolveSidebarNewThreadEnvMode({
defaultEnvMode: appSettings.defaultThreadEnvMode,
}),
handleNewThread,
});
return;
}
if (command === "chat.new") {
event.preventDefault();
event.stopPropagation();
void startNewThreadFromContext({
activeDraftThread,
activeThread,
defaultProjectRef,
defaultThreadEnvMode: resolveSidebarNewThreadEnvMode({
defaultEnvMode: appSettings.defaultThreadEnvMode,
}),
handleNewThread,
});
}
};
window.addEventListener("keydown", onWindowKeyDown);
return () => {
window.removeEventListener("keydown", onWindowKeyDown);
};
}, [
activeDraftThread,
activeThread,
clearSelection,
handleNewThread,
keybindings,
defaultProjectRef,
selectedThreadKeysSize,
terminalOpen,
appSettings.defaultThreadEnvMode,
]);
return null;
}
function ChatRouteLayout() {
return (
<>
>
);
}
export const Route = createFileRoute("/_chat")({
beforeLoad: async ({ context }) => {
if (
context.authGateState.status !== "authenticated" &&
context.authGateState.status !== "hosted-static"
) {
throw redirect({ to: "/pair", replace: true });
}
},
component: ChatRouteLayout,
});