'use client'; import { ReactNode, useState } from 'react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { cn } from '../../lib/utils'; import { ChevronLeft, ChevronRight } from 'lucide-react'; import { Button } from '../ui/button'; export interface SidebarLink { href: string; label: string; icon?: ReactNode; } export interface SidebarSection { title?: string; links: SidebarLink[]; } export interface SidebarProps { /** * Application name/logo */ appName: string; /** * Navigation sections */ sections: SidebarSection[]; /** * User dropdown content (rendered at bottom of sidebar) */ userDropdown?: ReactNode; /** * Additional className for sidebar */ className?: string; /** * Whether sidebar is collapsible */ collapsible?: boolean; /** * Default collapsed state (uncontrolled) */ defaultCollapsed?: boolean; /** * Controlled collapsed state. Pass with onCollapsedChange when the surrounding * layout also needs to know (see AppShell — the content spacer must shrink with * the rail, otherwise "Collapse" only narrows the rail and leaves a dead gap). */ collapsed?: boolean; /** Fires whenever the collapse toggle is used. */ onCollapsedChange?: (collapsed: boolean) => void; } export function Sidebar({ appName, sections, userDropdown, className, collapsible = true, defaultCollapsed = false, collapsed: controlledCollapsed, onCollapsedChange, }: SidebarProps) { const pathname = usePathname(); const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed); const collapsed = controlledCollapsed ?? internalCollapsed; const setCollapsed = (next: boolean) => { if (controlledCollapsed === undefined) setInternalCollapsed(next); onCollapsedChange?.(next); }; const isActivePath = (href: string) => { if (href === '/') { return pathname === '/'; } return pathname.startsWith(href); }; return (
{/* Logo */}
{collapsed ? appName.substring(0, 2).toUpperCase() : appName}
{/* Navigation */} {/* User Dropdown */} {userDropdown && (
{userDropdown}
)} {/* Collapse Toggle */} {collapsible && (
)}
); } /** * Layout wrapper that adds proper spacing for sidebar */ export interface SidebarLayoutProps { children: ReactNode; collapsed?: boolean; } export function SidebarLayout({ children, collapsed = false }: SidebarLayoutProps) { return (
{/* Spacer for fixed sidebar */}
{/* Main content area */}
{children}
); }