"use client" import Link from "next/link" import { usePathname } from "next/navigation" import { ChevronRight, Circle } from "lucide-react" import type { NavGroup, NavItem } from "@/base/types/navigation" import { cn } from "@/shared/lib/utils" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/shared/components/ui/collapsible" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarRail, useSidebar, } from "@/shared/components/ui/sidebar" type AppSidebarProps = React.ComponentProps & { navGroups: NavGroup[] logo?: React.ReactNode } export function AppSidebar({ navGroups, logo, ...props }: AppSidebarProps) { const { state, isMobile } = useSidebar() const isCollapsed = state === "collapsed" && !isMobile return ( {logo && ( {logo} )} {navGroups.map((group, groupIndex) => ( {group.label && ( {group.label} )} {group.items.map((item) => item.items && item.items.length > 0 ? ( ) : ( ) )} ))} ) } function SimpleNavItem({ item, isCollapsed }: { item: NavItem; isCollapsed: boolean }) { const pathname = usePathname() const isActive = item.isActive ?? pathname === item.href return ( {item.icon} { !isCollapsed && {item.title} } ) } function CollapsibleNavItem({ item, isCollapsed }: { item: NavItem; isCollapsed: boolean }) { const pathname = usePathname() const isChildActive = item.items?.some((sub) => pathname === sub.href) const isActive = item.isActive ?? (pathname === item.href || isChildActive === true) // Collapsed sidebar → flyout dropdown with sub-items if (isCollapsed) { return ( {item.icon} { !isCollapsed && {item.title} } {item.title} {item.items?.map((sub) => { const isSubActive = sub.isActive ?? pathname === sub.href return ( {sub.icon ? ( svg]:size-4", isSubActive ? "text-primary" : "text-muted-foreground/70")}> {sub.icon} ) : ( )} {sub.title} ) })} ) } // Expanded sidebar → collapsible/accordion sub-menu return ( {item.icon} {item.title} {item.items?.map((sub) => { const isSubActive = sub.isActive ?? pathname === sub.href return ( {sub.icon ? ( svg]:size-4", isSubActive ? "text-primary" : "text-muted-foreground/70 group-hover/menu-sub-item:text-primary")}> {sub.icon} ) : ( )} {sub.title} ) })} ) }