Files
KLALB-dashboard/src/components/layout/app-sidebar.tsx
T
2026-08-23 17:36:27 +08:00

163 lines
4.7 KiB
TypeScript

import {
LayoutDashboard,
Network,
GitFork,
Share2,
Cpu,
Settings,
Activity,
Layers,
} from 'lucide-react'
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarRail,
} from '@/components/ui/sidebar'
import { Badge } from '@/components/ui/badge'
export type NavTab = 'dashboard' | 'links' | 'routes' | 'topology' | 'interfaces' | 'settings'
interface AppSidebarProps {
currentTab: NavTab
onSelectTab: (tab: NavTab) => void
onlineDevices?: number
linksCount?: number
isConnected?: boolean
}
export function AppSidebar({
currentTab,
onSelectTab,
onlineDevices = 0,
linksCount = 0,
isConnected = false,
}: AppSidebarProps) {
const navItems = [
{
id: 'dashboard' as NavTab,
title: '仪表盘总览',
icon: LayoutDashboard,
badge: isConnected ? 'Live' : undefined,
},
{
id: 'links' as NavTab,
title: '线路与链路',
icon: Network,
badge: linksCount > 0 ? `${linksCount}` : undefined,
},
{
id: 'routes' as NavTab,
title: 'SRv6 路由表',
icon: GitFork,
},
{
id: 'topology' as NavTab,
title: '网络拓扑',
icon: Share2,
badge: onlineDevices > 0 ? `${onlineDevices}` : undefined,
},
{
id: 'interfaces' as NavTab,
title: '网卡接口',
icon: Cpu,
},
{
id: 'settings' as NavTab,
title: '系统配置',
icon: Settings,
},
]
return (
<Sidebar collapsible="icon">
<SidebarHeader className="border-b border-sidebar-border p-2">
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
size="lg"
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
>
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-primary text-primary-foreground">
<Layers className="size-4" />
</div>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">KLALB SRv6</span>
<span className="truncate text-xs text-muted-foreground">WAN汇聚网络</span>
</div>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>网络监控与管理</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{navItems.map((item) => {
const Icon = item.icon
const isActive = currentTab === item.id
return (
<SidebarMenuItem key={item.id}>
<SidebarMenuButton
isActive={isActive}
tooltip={item.title}
onClick={() => onSelectTab(item.id)}
>
<Icon data-icon="inline-start" />
<span>{item.title}</span>
</SidebarMenuButton>
{item.badge && (
<SidebarMenuBadge>
<Badge
variant={isActive ? 'default' : 'secondary'}
className="px-1.5 py-0 text-[10px]"
>
{item.badge}
</Badge>
</SidebarMenuBadge>
)}
</SidebarMenuItem>
)
})}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter className="border-t border-sidebar-border p-2">
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
size="sm"
tooltip={isConnected ? 'SSE 实时同步正常' : 'SSE 连接断开'}
className="justify-start"
>
<span
className={`inline-block size-2 rounded-full shrink-0 ${
isConnected ? 'bg-emerald-500 animate-pulse' : 'bg-rose-500'
}`}
/>
<span className="flex-1 truncate text-xs text-muted-foreground">
{isConnected ? 'SSE 实时流已连接' : '实时连接断开'}
</span>
<Activity className="size-3.5 text-muted-foreground shrink-0 group-data-[collapsible=icon]:hidden" />
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
<SidebarRail />
</Sidebar>
)
}