'use client' import * as React from 'react' import Link from 'next/link' import { usePathname, useRouter } from 'next/navigation' import { Package, ChevronRight } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { Sidebar, SidebarContent, SidebarGroup, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarRail, useSidebar, } from '@/components/ui/sidebar' import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' import type { MenuItem } from '@/constants/menu' import { getMenuIcon } from '@/constants/menu-icons' import { SITE_NAME, SITE_VERSION } from '@/constants/site' interface AppSidebarProps extends React.ComponentProps { menuItems: MenuItem[] } export function AppSidebar({ menuItems, ...props }: AppSidebarProps) { const pathname = usePathname() const router = useRouter() const { isMobile, setOpenMobile } = useSidebar() // 移动端点击菜单项后关闭侧边栏,延迟导航避免闪动 const handleMenuItemClick = React.useCallback((e: React.MouseEvent, href: string) => { if (isMobile) { e.preventDefault() // 阻止默认跳转 setOpenMobile(false) // 先关闭侧边栏 // 等待侧边栏关闭动画完成后再导航 setTimeout(() => { router.push(href) }, 350) } }, [isMobile, setOpenMobile, router]) return (
{SITE_NAME} {SITE_VERSION}
{menuItems.map((item) => { const Icon = getMenuIcon(item.icon) const isActive = pathname === item.href || pathname.startsWith(item.href + "/") const hasActiveChild = item.children?.some( (child) => pathname === child.href || pathname.startsWith(item.href + "/") ) // 如果有子菜单,使用 Collapsible if (item.children?.length) { return ( {Icon && } {item.title} {item.badge && ( {item.badge} )} {item.children.map((child) => { const ChildIcon = getMenuIcon(child.icon) const childIsActive = pathname === child.href || pathname.startsWith(child.href + "/") return ( handleMenuItemClick(e, child.href || '#')}> {ChildIcon && } {child.title} {child.badge && ( {child.badge} )} ) })} ) } // 没有子菜单的普通菜单项 return ( handleMenuItemClick(e, item.href || '#')}> {Icon && } {item.title} {item.badge && ( {item.badge} )} ) })}
) }