Files
LINUX-AETHERFORGE/web/src/components/layout/Sidebar.tsx
drjones 3678b199d0
Some checks failed
Test / test (push) Has been cancelled
Initial commit: AetherForge Linux (forge-mesh) v0.1.0-dev
2026-07-04 09:31:23 +00:00

105 lines
3.2 KiB
TypeScript

import { NavLink } from "react-router-dom";
import {
Activity,
Anvil,
Eye,
Gauge,
Hammer,
LogOut,
Terminal,
Wifi,
WifiOff,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { clearStoredAuth } from "@/lib/auth";
import { useNavigate } from "react-router-dom";
import type { WsConnectionState } from "@/hooks/useFleetWebSocket";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
const navItems = [
{ to: "/dashboard", label: "Dashboard", icon: Gauge },
{ to: "/forge", label: "Forge", icon: Hammer },
{ to: "/calibrate", label: "Calibrate", icon: Activity },
{ to: "/crucible", label: "Crucible", icon: Terminal },
{ to: "/seer", label: "Seer", icon: Eye },
];
interface SidebarProps {
wsState?: WsConnectionState;
}
export function Sidebar({ wsState = "disconnected" }: SidebarProps) {
const navigate = useNavigate();
const handleLogout = () => {
clearStoredAuth();
navigate("/login");
};
const wsBadge =
wsState === "connected"
? { variant: "online" as const, label: "WS LIVE", icon: Wifi }
: wsState === "connecting"
? { variant: "probing" as const, label: "WS CONNECTING", icon: Wifi }
: { variant: "offline" as const, label: "WS OFFLINE", icon: WifiOff };
const WsIcon = wsBadge.icon;
return (
<aside className="flex h-full w-56 flex-col border-r border-deck-border bg-deck-surface/80 backdrop-blur-sm">
<div className="border-b border-deck-border p-4">
<div className="flex items-center gap-2">
<div className="flex h-8 w-8 items-center justify-center rounded-md border border-deck-accent/40 bg-deck-accent/10">
<Anvil className="h-4 w-4 text-deck-accent" />
</div>
<div>
<p className="text-sm font-semibold tracking-wide text-deck-text">
AetherForge
</p>
<p className="font-mono text-[10px] uppercase text-deck-muted">
Command Deck
</p>
</div>
</div>
</div>
<nav className="flex-1 space-y-1 p-3">
{navItems.map(({ to, label, icon: Icon }) => (
<NavLink
key={to}
to={to}
className={({ isActive }) =>
cn(
"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
isActive
? "bg-deck-accent/10 text-deck-accent border border-deck-accent/30"
: "text-deck-muted hover:bg-deck-panel hover:text-deck-text",
)
}
>
<Icon className="h-4 w-4" />
{label}
</NavLink>
))}
</nav>
<div className="space-y-3 border-t border-deck-border p-4">
<Badge variant={wsBadge.variant} className="w-full justify-center gap-1.5">
<WsIcon className="h-3 w-3" />
{wsBadge.label}
</Badge>
<Button
variant="ghost"
size="sm"
className="w-full justify-start text-deck-muted"
onClick={handleLogout}
>
<LogOut className="h-4 w-4" />
Sign out
</Button>
</div>
</aside>
);
}