Files
eventify-server-monitor/client/src/components/layout/Sidebar.tsx

134 lines
3.7 KiB
TypeScript
Raw Normal View History

import {
LayoutDashboard,
Container,
MemoryStick,
HardDrive,
Wifi,
Settings,
HelpCircle,
Server,
LogOut,
} from "lucide-react"
import { cn } from "@/lib/utils"
import { Separator } from "@/components/ui/separator"
interface NavItem {
id: string
label: string
icon: React.ElementType
}
const mainNav: NavItem[] = [
{ id: "dashboard", label: "Dashboard", icon: LayoutDashboard },
{ id: "containers", label: "Containers", icon: Container },
{ id: "memory", label: "Memory", icon: MemoryStick },
{ id: "storage", label: "Storage", icon: HardDrive },
{ id: "network", label: "Network", icon: Wifi },
]
const bottomNav: NavItem[] = [
{ id: "settings", label: "Settings", icon: Settings },
{ id: "help", label: "Help & Support", icon: HelpCircle },
]
interface SidebarProps {
activePage: string
onNavigate: (page: string) => void
onLogout?: () => void
}
function NavButton({
item,
active,
onClick,
}: {
item: NavItem
active: boolean
onClick: () => void
}) {
const Icon = item.icon
return (
<button
onClick={onClick}
className={cn(
"flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
active
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:bg-muted hover:text-foreground"
)}
>
<Icon className="size-5 shrink-0" />
<span>{item.label}</span>
</button>
)
}
export function Sidebar({ activePage, onNavigate, onLogout }: SidebarProps) {
return (
<aside className="flex h-screen w-60 shrink-0 flex-col border-r bg-sidebar-background">
{/* Brand */}
<div className="flex items-center gap-3 px-5 py-6">
<div className="flex size-9 items-center justify-center rounded-lg bg-primary">
<Server className="size-5 text-primary-foreground" />
</div>
<span className="text-lg font-bold tracking-tight text-foreground">
Eventify
</span>
</div>
{/* Main nav */}
<nav className="flex flex-1 flex-col gap-1 px-3">
{mainNav.map((item) => (
<NavButton
key={item.id}
item={item}
active={activePage === item.id}
onClick={() => onNavigate(item.id)}
/>
))}
<Separator className="my-4" />
{bottomNav.map((item) => (
<NavButton
key={item.id}
item={item}
active={activePage === item.id}
onClick={() => onNavigate(item.id)}
/>
))}
{/* Spacer */}
<div className="flex-1" />
{/* Status card */}
<div className="mb-4 rounded-xl border bg-muted/40 p-4">
<div className="flex items-center gap-2">
<span className="relative flex size-2.5">
<span className="absolute inline-flex size-full animate-ping rounded-full bg-green-400 opacity-75" />
<span className="relative inline-flex size-2.5 rounded-full bg-green-500" />
</span>
<span className="text-xs font-semibold text-foreground">
Server Status
</span>
</div>
<p className="mt-2 text-xs text-muted-foreground">
All Systems Operational
</p>
</div>
{/* Logout */}
{onLogout && (
<button
onClick={onLogout}
className="mb-4 flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-red-50 hover:text-red-600 cursor-pointer"
>
<LogOut className="size-5 shrink-0" />
<span>Sign Out</span>
</button>
)}
</nav>
</aside>
)
}