Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import {
|
|
createFileRoute,
|
|
Outlet,
|
|
redirect,
|
|
useRouterState,
|
|
} from "@tanstack/react-router"
|
|
|
|
import { ControlTrigger } from "@/components/Chat/ChatPanel"
|
|
import { ConnectionNotice } from "@/components/Common/ConnectionNotice"
|
|
import ErrorComponent from "@/components/Common/ErrorComponent"
|
|
import { Footer } from "@/components/Common/Footer"
|
|
import { useFlowSocket } from "@/components/Flow/useFlowSocket"
|
|
import AppSidebar from "@/components/Sidebar/AppSidebar"
|
|
import {
|
|
SidebarInset,
|
|
SidebarProvider,
|
|
SidebarTrigger,
|
|
} from "@/components/ui/sidebar"
|
|
import { isLoggedIn } from "@/hooks/useAuth"
|
|
|
|
export const Route = createFileRoute("/_layout")({
|
|
component: Layout,
|
|
// Inside the shell rather than at the root, so a screen that throws leaves
|
|
// the sidebar standing and somebody can navigate away from it. The root's
|
|
// own boundary replaces the whole app, navigation included.
|
|
errorComponent: () => <ErrorComponent />,
|
|
beforeLoad: async () => {
|
|
if (!isLoggedIn()) {
|
|
throw redirect({
|
|
to: "/login",
|
|
})
|
|
}
|
|
},
|
|
})
|
|
|
|
function Layout() {
|
|
// Dashboards live in this shell and read live values, so the socket belongs
|
|
// here rather than only inside the editor.
|
|
useFlowSocket()
|
|
const home = useRouterState({ select: (s) => s.location.pathname === "/" })
|
|
|
|
return (
|
|
<SidebarProvider className="bg-card">
|
|
<AppSidebar />
|
|
<SidebarInset className="bg-card">
|
|
{/* Draws nothing itself, and nothing at all unless this page is
|
|
served through a portal: it raises the offline notification. */}
|
|
<ConnectionNotice />
|
|
{/* The sidebar carries its own collapse control; a phone has no
|
|
sidebar on screen to carry it. Home's chat sits opposite, where
|
|
the brain view has it on a wider screen. */}
|
|
<header className="sticky top-0 z-10 flex h-16 shrink-0 items-center gap-2 px-4 md:hidden">
|
|
<SidebarTrigger className="-ml-1 text-muted-foreground" />
|
|
{home ? <ControlTrigger className="-mr-1 ml-auto" /> : null}
|
|
</header>
|
|
<main className="flex-1 p-4 sm:p-6 md:p-8">
|
|
<div className="mx-auto max-w-7xl">
|
|
<Outlet />
|
|
</div>
|
|
</main>
|
|
<Footer />
|
|
</SidebarInset>
|
|
</SidebarProvider>
|
|
)
|
|
}
|
|
|
|
export default Layout
|