import { RotateCcwIcon } from "lucide-react";import { Outlet, createFileRoute, redirect, useCanGoBack, useLocation, useNavigate,} from "@tanstack/react-router";import { useCallback, useEffect, useState } from "react"; import { useSettingsRestore } from "../components/settings/SettingsPanels";import { SettingsBreadcrumb } from "../components/settings/SettingsBreadcrumb";import { Button } from "../components/ui/button";import { SidebarInset } from "../components/ui/sidebar";import { isElectron } from "../env";import { cn } from "~/lib/utils";import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "~/workspaceTitlebar"; function RestoreDefaultsButton({ onRestored }: { onRestored: () => void }) { const { changedSettingLabels, restoreDefaults } = useSettingsRestore(onRestored); return ( <Button size="xs" variant="ghost" disabled={changedSettingLabels.length === 0} onClick={() => void restoreDefaults()} > <RotateCcwIcon className="mx-1 size-3.5" /> Restore defaults </Button> );} function SettingsContentLayout() { const location = useLocation(); const navigate = useNavigate(); const canGoBack = useCanGoBack(); const [restoreSignal, setRestoreSignal] = useState(0); const showRestoreDefaults = location.pathname === "/settings/general"; const handleRestored = () => setRestoreSignal((value) => value + 1); const navigateBackWithinApp = useCallback(() => { if (canGoBack) { window.history.back(); return; } void navigate({ to: "/" }); }, [canGoBack, navigate]); useEffect(() => { const onKeyDown = (event: KeyboardEvent) => { if (event.defaultPrevented) return; if (event.key === "Escape") { event.preventDefault(); const activeElement = document.activeElement; if (activeElement instanceof HTMLElement) { activeElement.blur(); } navigateBackWithinApp(); } }; window.addEventListener("keydown", onKeyDown); return () => { window.removeEventListener("keydown", onKeyDown); }; }, [navigateBackWithinApp]); return ( <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground isolate"> <div className="flex min-h-0 min-w-0 flex-1 flex-col bg-background text-foreground"> {!isElectron && ( <header className={cn( "flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center px-3 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none sm:px-5", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > <div className="flex w-full items-center gap-2"> <SettingsBreadcrumb pathname={location.pathname} /> {showRestoreDefaults ? ( <div className="ms-auto flex items-center gap-2"> <RestoreDefaultsButton onRestored={handleRestored} /> </div> ) : null} </div> </header> )} {isElectron && ( <div className={cn( "drag-region flex h-[52px] shrink-0 items-center px-5 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > <div className="flex w-full items-center gap-2"> <SettingsBreadcrumb pathname={location.pathname} /> {showRestoreDefaults ? ( <div className="ms-auto flex items-center gap-2"> <RestoreDefaultsButton onRestored={handleRestored} /> </div> ) : null} </div> </div> )} <div key={restoreSignal} className="min-h-0 flex flex-1 flex-col"> <Outlet /> </div> </div> </SidebarInset> );} function SettingsRouteLayout() { return <SettingsContentLayout />;} export const Route = createFileRoute("/settings")({ beforeLoad: async ({ context, location }) => { if ( context.authGateState.status !== "authenticated" && context.authGateState.status !== "hosted-static" ) { throw redirect({ to: "/pair", replace: true }); } if (location.pathname === "/settings") { throw redirect({ to: "/settings/general", replace: true }); } }, component: SettingsRouteLayout,});
import { RotateCcwIcon } from "lucide-react";
import {
Outlet,
createFileRoute,
redirect,
useCanGoBack,
useLocation,
useNavigate,
} from "@tanstack/react-router";
import { useCallback, useEffect, useState } from "react";
import { useSettingsRestore } from "../components/settings/SettingsPanels";
import { SettingsBreadcrumb } from "../components/settings/SettingsBreadcrumb";
import { Button } from "../components/ui/button";
import { SidebarInset } from "../components/ui/sidebar";
import { isElectron } from "../env";
import { cn } from "~/lib/utils";
import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "~/workspaceTitlebar";
function RestoreDefaultsButton({ onRestored }: { onRestored: () => void }) {
const { changedSettingLabels, restoreDefaults } = useSettingsRestore(onRestored);
return (
<Button
size="xs"
variant="ghost"
disabled={changedSettingLabels.length === 0}
onClick={() => void restoreDefaults()}
>
<RotateCcwIcon className="mx-1 size-3.5" />
Restore defaults
</Button>
);
}
function SettingsContentLayout() {
const location = useLocation();
const navigate = useNavigate();
const canGoBack = useCanGoBack();
const [restoreSignal, setRestoreSignal] = useState(0);
const showRestoreDefaults = location.pathname === "/settings/general";
const handleRestored = () => setRestoreSignal((value) => value + 1);
const navigateBackWithinApp = useCallback(() => {
if (canGoBack) {
window.history.back();
return;
}
void navigate({ to: "/" });
}, [canGoBack, navigate]);
useEffect(() => {
const onKeyDown = (event: KeyboardEvent) => {
if (event.defaultPrevented) return;
if (event.key === "Escape") {
event.preventDefault();
const activeElement = document.activeElement;
if (activeElement instanceof HTMLElement) {
activeElement.blur();
}
navigateBackWithinApp();
}
};
window.addEventListener("keydown", onKeyDown);
return () => {
window.removeEventListener("keydown", onKeyDown);
};
}, [navigateBackWithinApp]);
return (
<SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground isolate">
<div className="flex min-h-0 min-w-0 flex-1 flex-col bg-background text-foreground">
{!isElectron && (
<header
className={cn(
"flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center px-3 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none sm:px-5",
COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,
)}
>
<div className="flex w-full items-center gap-2">
<SettingsBreadcrumb pathname={location.pathname} />
{showRestoreDefaults ? (
<div className="ms-auto flex items-center gap-2">
<RestoreDefaultsButton onRestored={handleRestored} />
</div>
) : null}
</div>
</header>
)}
{isElectron && (
<div
className={cn(
"drag-region flex h-[52px] shrink-0 items-center px-5 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]",
COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,
)}
>
<div className="flex w-full items-center gap-2">
<SettingsBreadcrumb pathname={location.pathname} />
{showRestoreDefaults ? (
<div className="ms-auto flex items-center gap-2">
<RestoreDefaultsButton onRestored={handleRestored} />
</div>
) : null}
</div>
</div>
)}
<div key={restoreSignal} className="min-h-0 flex flex-1 flex-col">
<Outlet />
</div>
</div>
</SidebarInset>
);
}
function SettingsRouteLayout() {
return <SettingsContentLayout />;
}
export const Route = createFileRoute("/settings")({
beforeLoad: async ({ context, location }) => {
if (
context.authGateState.status !== "authenticated" &&
context.authGateState.status !== "hosted-static"
) {
throw redirect({ to: "/pair", replace: true });
}
if (location.pathname === "/settings") {
throw redirect({ to: "/settings/general", replace: true });
}
},
component: SettingsRouteLayout,
});