163 lines
4.7 KiB
TypeScript
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>
|
|
)
|
|
}
|
|
|