import { useId, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { Link, Outlet, useNavigate } from "@tanstack/react-router"; import * as stylex from "@stylexjs/stylex"; import { useAuth } from "@/auth/store"; import InlineError from "@/lib/InlineError"; import { healthQuery, versionQuery } from "@/lib/queries"; import PauseControl from "@/features/pause/PauseControl"; import { diagnosticsBadge } from "./diagnosticsBadge"; import ConfigStatusNotices from "./ConfigStatusNotices"; import AuthorityLine from "@/features/configuration/AuthorityLine"; import { styles as shared } from "@/ui/styles"; import { colors } from "@/ui/tokens.stylex"; /** The one breakpoint the shell has: below it the sidebar becomes a drawer. */ const WIDE = "@media (min-width: 768px)"; const DARK = "@media (prefers-color-scheme: dark)"; /** * The four operational surfaces, then the configuration group. Configuration * is a labelled group rather than a collapsible tree: three items do not earn * a disclosure, and a tree would hide the authority line under it. */ const NAV_ITEMS = [ { to: "/overview", label: "Overview" }, { to: "/activity", label: "Activity" }, { to: "/clients", label: "Clients" }, { to: "/diagnostics", label: "Diagnostics" }, ] as const; const CONFIGURATION_ITEMS = [ { to: "/configuration/protection", label: "Protection" }, { to: "/configuration/resolution", label: "Resolution" }, { to: "/configuration/system", label: "System" }, ] as const; const styles = stylex.create({ navList: { display: "flex", flexDirection: "column", gap: "0.25rem", }, navLink: { display: "flex", alignItems: "center", gap: "0.5rem", borderRadius: "0.25rem", paddingInline: "0.75rem", paddingBlock: "0.375rem", textDecorationLine: "none", }, navLabel: { flex: 1, }, navGroup: { marginTop: "1rem", }, navGroupLabel: { paddingInline: "0.75rem", paddingBlock: "0.25rem", fontSize: "0.75rem", lineHeight: "1rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", color: colors.textMuted, }, /** * Neutral chrome: the mark is the message, and a coloured pill here would be * the page's loudest element on every route. Text and shape carry it. */ badge: { minWidth: "1.25rem", borderRadius: "0.625rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, backgroundColor: colors.surfaceHover, paddingInline: "0.375rem", fontSize: "0.75rem", lineHeight: "1.125rem", fontWeight: 500, textAlign: "center", color: colors.textSecondary, }, /** The control sits with the footer, not in the scrolling nav list above it. */ sidebarFooter: { paddingInline: "1rem", paddingTop: "0.75rem", }, /** The current page reads as a filled chip, heavier than the hover fill. */ navActive: { backgroundColor: { default: "oklch(92% 0.004 286.32)", [DARK]: "oklch(27.4% 0.006 286.033)" }, color: colors.text, fontWeight: 500, }, navIdle: { backgroundColor: { default: "transparent", ":hover": colors.surfaceHover }, color: { default: colors.textSecondary, ":hover": colors.text }, }, versionFooter: { paddingInline: "1rem", paddingBlock: "0.75rem", fontSize: "0.75rem", lineHeight: "1rem", color: colors.textMuted, }, logoutRow: { display: "flex", alignItems: "center", gap: "0.5rem", }, shell: { minHeight: "100dvh", height: { default: null, [WIDE]: "100dvh" }, overflow: { default: null, [WIDE]: "hidden" }, backgroundColor: colors.surface, color: colors.text, display: { default: "block", [WIDE]: "grid" }, gridTemplateColumns: { default: null, [WIDE]: "14rem 1fr" }, }, sidebar: { display: { default: "none", [WIDE]: "flex" }, flexDirection: { default: null, [WIDE]: "column" }, minHeight: { default: null, [WIDE]: 0 }, overflow: { default: null, [WIDE]: "hidden" }, borderRightWidth: 1, borderRightStyle: "solid", borderRightColor: colors.border, }, brand: { paddingInline: "1rem", paddingBlock: "1rem", fontSize: "1.125rem", lineHeight: "1.75rem", fontWeight: 600, }, sidebarNav: { flex: 1, minHeight: { default: null, [WIDE]: 0 }, overflowY: { default: null, [WIDE]: "auto" }, paddingInline: "0.5rem", }, column: { display: "flex", minHeight: { default: "100dvh", [WIDE]: 0 }, minWidth: { default: null, [WIDE]: 0 }, flexDirection: "column", }, header: { display: "flex", alignItems: "center", gap: "0.75rem", borderBottomWidth: 1, borderBottomStyle: "solid", borderBottomColor: colors.border, paddingInline: "1rem", paddingBlock: "0.5rem", }, narrowOnly: { display: { default: null, [WIDE]: "none" }, }, narrowBrand: { fontSize: "1.125rem", lineHeight: "1.75rem", fontWeight: 600, display: { default: null, [WIDE]: "none" }, }, headerRight: { marginLeft: "auto", display: "flex", alignItems: "center", gap: "0.75rem", }, drawer: { borderBottomWidth: 1, borderBottomStyle: "solid", borderBottomColor: colors.border, display: { default: null, [WIDE]: "none" }, }, drawerNav: { paddingInline: "0.5rem", paddingBlock: "0.5rem", }, main: { flex: 1, minHeight: { default: null, [WIDE]: 0 }, minWidth: { default: null, [WIDE]: 0 }, overflowY: { default: null, [WIDE]: "auto" }, padding: "1rem", }, }); function NavItem({ to, label, onNavigate, badge, }: { to: string; label: string; onNavigate?: () => void; badge?: { text: string; label: string } | null; }) { return (