SidebarStatusStrip.tsx
1 import { Link } from "react-router-dom"; 2 import type { StatusResponse } from "@/lib/api"; 3 import { useSidebarStatus } from "@/hooks/useSidebarStatus"; 4 import { cn } from "@/lib/utils"; 5 import { useI18n } from "@/i18n"; 6 7 /** Gateway + session summary for the System sidebar block (no separate strip chrome). */ 8 export function SidebarStatusStrip() { 9 const status = useSidebarStatus(); 10 const { t } = useI18n(); 11 12 if (status === null) { 13 return ( 14 <div className="px-5 py-1.5" aria-hidden> 15 <div className="h-2 w-[80%] max-w-full animate-pulse rounded-sm bg-midground/10" /> 16 </div> 17 ); 18 } 19 20 const gw = gatewayLine(status, t); 21 const { activeSessionsLabel, gatewayStatusLabel } = t.app; 22 23 return ( 24 <Link 25 to="/sessions" 26 title={t.app.statusOverview} 27 className={cn( 28 "block text-left", 29 "px-5 pb-2 pt-0.5", 30 "text-muted-foreground/70", 31 "transition-colors hover:text-muted-foreground/90", 32 "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-midground/40", 33 "focus-visible:ring-inset", 34 )} 35 > 36 <div className="flex flex-col gap-1 font-mondwest text-[0.55rem] leading-snug tracking-[0.12em]"> 37 <p className="break-words"> 38 <span className="text-muted-foreground/50">{gatewayStatusLabel}</span>{" "} 39 <span className={cn("font-medium", gw.tone)}>{gw.label}</span> 40 </p> 41 42 <p className="break-words"> 43 <span className="text-muted-foreground/50">{activeSessionsLabel}</span>{" "} 44 <span className="tabular-nums text-muted-foreground/70"> 45 {status.active_sessions} 46 </span> 47 </p> 48 </div> 49 </Link> 50 ); 51 } 52 53 function gatewayLine( 54 status: StatusResponse, 55 t: ReturnType<typeof useI18n>["t"], 56 ): { label: string; tone: string } { 57 const g = t.app.gatewayStrip; 58 const byState: Record<string, { label: string; tone: string }> = { 59 running: { label: g.running, tone: "text-success" }, 60 starting: { label: g.starting, tone: "text-warning" }, 61 startup_failed: { label: g.failed, tone: "text-destructive" }, 62 stopped: { label: g.stopped, tone: "text-muted-foreground" }, 63 }; 64 if (status.gateway_state && byState[status.gateway_state]) { 65 return byState[status.gateway_state]; 66 } 67 return status.gateway_running 68 ? { label: g.running, tone: "text-success" } 69 : { label: g.off, tone: "text-muted-foreground" }; 70 }