import Link from "next/link"; import { LayoutGrid, FolderKanban, Settings, Users, CalendarRange } from "lucide-react"; import { cn } from "@/lib/cn"; import { KanbanNav } from "@/components/shell/kanban-nav"; import type { SidebarProjectGroup } from "@/lib/data/board"; import type { Role } from "@/lib/pb/types"; interface NavItem { href: string; label: string; icon: React.ComponentType<{ size?: number; strokeWidth?: number }>; ownerOnly?: boolean; } const NAV: NavItem[] = [ { href: "/", label: "Projects", icon: LayoutGrid }, { href: "/plan", label: "Plan", icon: CalendarRange }, { href: "/admin/clients", label: "Clients", icon: Users, ownerOnly: true }, { href: "/admin/projects", label: "Manage", icon: FolderKanban, ownerOnly: true }, { href: "/admin/settings", label: "Settings", icon: Settings, ownerOnly: true }, ]; function NavLink({ item, active }: { item: NavItem; active: boolean }) { const Icon = item.icon; return ( {item.label} ); } /** * The icon rail from the reference: an icon over a small label, not an icon * alone. Icon-only rails force everyone to learn a private vocabulary, and a * client manager visits this maybe twice a month. * * Owner-only links are filtered out here for tidiness. That is presentation, * not security — the pages themselves re-check the role. * * "Kanban" is not in NAV: it is not a destination, it is a picker (see * KanbanNav), so it renders separately between Projects and the rest. */ export function Sidebar({ role, currentPath, kanbanGroups, }: { role: Role; currentPath: string; kanbanGroups: SidebarProjectGroup[]; }) { const items = NAV.filter((item) => !item.ownerOnly || role === "owner"); const isActive = (item: NavItem) => item.href === "/" ? currentPath === "/" : currentPath.startsWith(item.href); return ( ); }