import { useState } from 'react'; import { Link, useRouterState } from '@tanstack/react-router'; import { House, ChartGantt, ClipboardCheck, FolderKanban, PanelLeft, ChevronUp, } from 'lucide-react'; import { trpc } from '@/lib/trpc'; import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, useSidebar, } from '@/components/ui/sidebar'; const NAV_ITEMS = [ { to: '/', icon: House, label: 'Home' }, { to: '/timeline', icon: ChartGantt, label: 'Timeline' }, { to: '/tasks', icon: ClipboardCheck, label: 'Tasks' }, { to: '/projects', icon: FolderKanban, label: 'Projects' }, ] as const; interface AppShellProps { children: React.ReactNode; } export function AppShell({ children }: AppShellProps) { const collapsedQuery = trpc.settings.getSidebarCollapsed.useQuery(undefined, { staleTime: Infinity, }); const setSidebarCollapsedMutation = trpc.settings.setSidebarCollapsed.useMutation(); const routerState = useRouterState(); const currentPath = routerState.location.pathname; // Controlled open state (spec: "Controlled Sidebar" pattern) const [open, setOpen] = useState(() => collapsedQuery.data === undefined ? true : !collapsedQuery.data ); const handleOpenChange = (value: boolean) => { setOpen(value); setSidebarCollapsedMutation.mutate({ collapsed: !value }); }; return ( {children} {/* Right-edge vertical 'keep scrolling for AI' affordance (non-interactive) */}
keep scrolling up for AI
); } function AppSidebar({ currentPath }: { currentPath: string }) { const { toggleSidebar } = useSidebar(); return ( {/* Logo */}
Adiuva
{/* Nav */} {NAV_ITEMS.map(({ to, icon: Icon, label }) => { const isActive = to === '/' ? currentPath === '/' : currentPath.startsWith(to); return ( {label} ); })} {/* Collapse toggle — spec: useSidebar() + custom trigger */} Collapse
); }