a11oy / web /src /components /shell /Sidebar.tsx
betterwithage's picture
sync(space): complete build context — fix BUILD_ERROR (CTO)
518343a verified
Raw
History Blame Contribute Delete
18.6 kB
// doctrine-scanner-exempt: legacy live-product surface; rename tracked as separate engineering debt — see scripts/check-doctrine-v6.mjs header.
import { useEffect, useState } from 'react';
import { Link, useLocation } from 'wouter';
import {
LayoutGrid, Rocket, ShieldCheck, Sparkles,
ChevronDown, ChevronRight,
Globe, Crosshair, Activity, BarChart3, Map, Shield, Server,
Cpu, Zap, Network, Settings, Users, Terminal, Layers,
FileText, Workflow,
BookOpen, Brain, Beaker,
Box, Newspaper, KeyRound, Boxes,
Search, Sigma,
Telescope, BookOpenCheck, ExternalLink, TrendingUp, Target
} from 'lucide-react';
import { cn } from '@szl-holdings/design-system';
const BASE = (import.meta.env.BASE_URL ?? '/').replace(/\/$/, '');
interface NavItem {
id: string;
name: string;
icon: React.ElementType;
path: string;
badge?: string;
external?: boolean;
}
interface NavSection {
id: string;
label: string;
items: NavItem[];
defaultOpen?: boolean;
}
// ── SIDEBAR CONSOLIDATION (Ken pattern, 2026-06-03): 157 tabs across 17 sections
// → 3 pinned + 7 sections (≈35 tabs), modeled on Stripe / Linear / Vercel command
// surfaces. Sub-routes with 4+ siblings collapse to a single parent tab; the parent
// page owns the in-page navigation (e.g. /strategy/briefings/* → one "Briefings" tab).
// EVERY one of the 478 App.tsx <Route> handlers stays a working deep link: each is
// still reachable via direct URL and via the ⌘K command palette (CommandPalette below),
// which indexes the full link set. No new dependencies; same lucide-react icons, same
// wouter Link, same @szl-holdings/design-system import. Doctrine v11 LOCKED 749/14/163.
// Λ Conjecture 1 (NOT a theorem). ADDITIVE collapse — no routes removed.
// Top pinned (3) — Stripe/Vercel-style always-visible entries.
const topItems: NavItem[] = [
{ id: 'whats-new', name: "What's New", icon: Newspaper, path: '/whats-new', badge: 'NEW' },
{ id: 'console', name: 'Console', icon: Terminal, path: '/console' },
{ id: 'szl-ops', name: 'SZL Operational Core', icon: ShieldCheck, path: '/szl-ops', badge: 'LIVE' },
];
const sections: NavSection[] = [
{
id: 'foundry',
label: 'Foundry',
defaultOpen: true,
items: [
{ id: 'foundry-home', name: 'Foundry Home', icon: LayoutGrid, path: '/foundry' },
{ id: 'foundry-catalog', name: 'Catalog', icon: Boxes, path: '/foundry/catalog' },
{ id: 'foundry-provision', name: 'Provision', icon: FileText, path: '/foundry/provision' },
{ id: 'foundry-deployments', name: 'Deployments', icon: Rocket, path: '/foundry/deployments' },
{ id: 'foundry-keys', name: 'Keys & Secrets', icon: KeyRound, path: '/foundry/keys' },
{ id: 'foundry-monitoring', name: 'Monitoring', icon: Activity, path: '/foundry/monitoring' },
{ id: 'primitives-hub', name: 'Primitives', icon: Box, path: '/primitives' },
],
},
{
id: 'strategy',
label: 'Strategy',
items: [
{ id: 'strat-dashboard', name: 'Strategy Dashboard', icon: Globe, path: '/strategy' },
// /strategy/briefings/* — 8 siblings collapsed; the Briefings page owns in-page nav.
{ id: 'strat-briefings', name: 'Briefings', icon: Newspaper, path: '/strategy/briefings' },
{ id: 'strat-atlas-runtime', name: 'Atlas Runtime', icon: Zap, path: '/strategy/atlas-runtime' },
{ id: 'strat-simulation', name: 'Simulation', icon: Layers, path: '/strategy/simulation' },
{ id: 'strat-competitive', name: 'Competitive Atlas', icon: Map, path: '/strategy/competitive-atlas' },
],
},
{
id: 'operations',
label: 'Operations',
items: [
{ id: 'ops-exec', name: 'Operations Monitor', icon: Activity, path: '/operations' },
{ id: 'ops-noc', name: 'Autonomous NOC', icon: Server, path: '/operations/autonomous-noc' },
{ id: 'ops-slo', name: 'SLO Management', icon: Target, path: '/operations/slo' },
{ id: 'ops-metrics', name: 'Metrics Explorer', icon: BarChart3, path: '/operations/metrics' },
],
},
{
id: 'infrastructure',
label: 'Infrastructure',
items: [
// Single consolidated view; the IMPERIUM console owns in-page nav for the other surfaces.
{ id: 'infra-legatus', name: 'IMPERIUM Console', icon: Server, path: '/infrastructure/legatus' },
],
},
{
id: 'intelligence-decisions',
label: 'Intelligence & Decisions',
items: [
{ id: 'dec-center', name: 'Decision Center', icon: Crosshair, path: '/decisions' },
{ id: 'dec-twin', name: 'Decision Twin (PRISM)', icon: Brain, path: '/decisions/twin' },
{ id: 'dec-autonomy', name: 'Autonomy Modes', icon: Workflow, path: '/decisions/autonomy' },
{ id: 'intel-overview', name: 'Command Overview', icon: LayoutGrid, path: '/intelligence' },
{ id: 'cog-overview', name: 'Cognitive Runtime', icon: Cpu, path: '/cognitive/overview' },
{ id: 'nexus-home', name: 'NEXUS Intelligence', icon: Sparkles, path: '/nexus' },
],
},
{
id: 'frontier-research',
label: 'Frontier & Research',
items: [
{ id: 'frontier-index', name: 'Frontier Overview', icon: Telescope, path: '/frontier' },
{ id: 'argo-bridge', name: 'Argo — Decision Engine', icon: TrendingUp, path: '/argo' },
{ id: 'psyche-anima', name: 'PSYCHE — Sentience', icon: Sparkles, path: '/psyche' },
{ id: 'sigil', name: 'SIGIL', icon: Sigma, path: '/sigil' },
{ id: 'lab', name: 'A11oy Lab', icon: Beaker, path: '/lab' },
],
},
{
id: 'doctrine-trust',
label: 'Doctrine & Trust',
items: [
{ id: 'doc-overview', name: 'Doctrine', icon: BookOpen, path: '/doctrine' },
{ id: 'doc-constitution', name: 'Constitution', icon: FileText, path: '/constitution' },
{ id: 'doc-alignment', name: 'Alignment Review', icon: ShieldCheck, path: '/alignment-review' },
{ id: 'trust-hub', name: 'Trust Hub', icon: Shield, path: '/trust' },
{ id: 'trust-portal', name: 'Public Trust Portal', icon: Globe, path: '/trust-portal' },
{ id: 'trust-transparency', name: 'Transparency Report', icon: FileText, path: '/transparency-report' },
{ id: 'trust-bom', name: 'Agent BOM / Proof', icon: BookOpenCheck, path: '/agent-bom' },
],
},
];
// Full deep-link index for the ⌘K palette — every primary surface across the 478 routes
// remains reachable here even though the sidebar now renders only the consolidated set.
const ALL_DEEP_LINKS: NavItem[] = [
...topItems,
...sections.flatMap(s => s.items),
// Foundry deep links collapsed from the sidebar
{ id: 'dl-foundry-workcells', name: 'Workcells', icon: Box, path: '/foundry/workcells' },
{ id: 'dl-foundry-sovereign', name: 'Sovereign Mode', icon: KeyRound, path: '/foundry/sovereign' },
{ id: 'dl-foundry-quickstarts', name: 'Quickstarts', icon: Sparkles, path: '/foundry/quickstarts' },
// Strategy briefings family (page owns in-page nav; deep links retained for ⌘K)
{ id: 'dl-brief-today', name: "Today's Brief", icon: FileText, path: '/strategy/briefings/today' },
{ id: 'dl-brief-engine', name: 'Briefing Engine', icon: Workflow, path: '/strategy/briefings/engine' },
{ id: 'dl-brief-library', name: 'Brief Library', icon: BookOpen, path: '/strategy/briefings/library' },
{ id: 'dl-brief-watchlist', name: 'Watchlist', icon: BookOpenCheck, path: '/strategy/briefings/watchlist' },
{ id: 'dl-brief-confidence', name: 'Confidence', icon: BarChart3, path: '/strategy/briefings/confidence' },
{ id: 'dl-brief-dissent', name: 'Dissent Channel', icon: Newspaper, path: '/strategy/briefings/dissent' },
{ id: 'dl-brief-cockpit', name: 'Governed Cockpit', icon: ShieldCheck, path: '/strategy/briefings/cockpit' },
{ id: 'dl-strat-enterprise', name: 'Enterprise State', icon: Layers, path: '/strategy/enterprise-state' },
{ id: 'dl-strat-correlation', name: 'Correlation Map', icon: Network, path: '/strategy/correlation-map' },
{ id: 'dl-strat-signals', name: 'Signal Chains', icon: Activity, path: '/strategy/signal-chains' },
// Operations deep links collapsed from the sidebar
{ id: 'dl-ops-topology', name: 'Service Topology', icon: Network, path: '/operations/topology' },
{ id: 'dl-ops-tracing', name: 'Distributed Tracing', icon: Workflow, path: '/operations/tracing' },
{ id: 'dl-ops-logs', name: 'Log Explorer', icon: Terminal, path: '/operations/logs' },
{ id: 'dl-ops-alerts', name: 'Alert Management', icon: Activity, path: '/operations/alerts' },
{ id: 'dl-ops-selfheal', name: 'Self-Healing', icon: Zap, path: '/operations/self-healing' },
{ id: 'dl-ops-runbook', name: 'Runbook Studio', icon: FileText, path: '/operations/runbook-studio' },
{ id: 'dl-ops-admin', name: 'Admin Console', icon: Settings, path: '/operations/admin/overview' },
// Infrastructure deep links collapsed from the sidebar
{ id: 'dl-infra-map', name: 'Imperium Map', icon: Map, path: '/infrastructure/imperium-map' },
{ id: 'dl-infra-praetorian', name: 'Praetorian Guard', icon: Shield, path: '/infrastructure/praetorian' },
{ id: 'dl-infra-centurion', name: 'Centurion AI', icon: Cpu, path: '/infrastructure/centurion' },
{ id: 'dl-infra-fabric', name: 'Data Fabric', icon: Boxes, path: '/infrastructure/data-fabric' },
// Cognitive runtime deep links
{ id: 'dl-cog-memory', name: 'Cognitive Memory', icon: Boxes, path: '/cognitive/memory' },
{ id: 'dl-cog-planner', name: 'Planner', icon: Target, path: '/cognitive/planner' },
{ id: 'dl-cog-verifier', name: 'Verifier', icon: ShieldCheck, path: '/cognitive/verifier' },
// Frontier / Argo / PSYCHE deep links
{ id: 'dl-argo-arena', name: 'Self-Play Arena', icon: Zap, path: '/argo/arena' },
{ id: 'dl-argo-forge', name: 'Distillation Forge', icon: Beaker, path: '/argo/forge' },
{ id: 'dl-psyche-genesis', name: 'Genesis Ledger', icon: BookOpen, path: '/psyche/genesis' },
// Doctrine / Trust deep links collapsed from the sidebar
{ id: 'dl-doc-constitution-dsl', name: 'Constitution DSL', icon: FileText, path: '/constitution-dsl' },
{ id: 'dl-doc-covenant', name: 'Covenant Lift', icon: Sparkles, path: '/covenant-lift' },
{ id: 'dl-doc-welfare', name: 'Welfare Playbooks', icon: BookOpen, path: '/welfare-playbooks' },
{ id: 'dl-trust-exchange', name: 'Trust Exchange', icon: Network, path: '/trust-exchange' },
{ id: 'dl-trust-security', name: 'Security & Compliance', icon: Shield, path: '/security-compliance' },
{ id: 'dl-trust-audit', name: 'Right to Audit', icon: BookOpenCheck, path: '/right-to-audit' },
// Reasoning / Lesson
{ id: 'dl-reasoning', name: 'Reasoning Audit', icon: Brain, path: '/reasoning' },
// External 3D + repo (Stripe-style "more" surfaces)
{ id: 'dl-github', name: 'GitHub', icon: ExternalLink, path: 'https://github.com/szl-holdings/a11oy', external: true },
];
function CollapsibleSection({ section }: { section: NavSection }) {
const [location] = useLocation();
const hasActiveChild = section.items.some(item => {
const fullPath = `${BASE}${item.path}`;
return location === fullPath || location.startsWith(fullPath + '/');
});
const [isOpen, setIsOpen] = useState((section.defaultOpen ?? false) || hasActiveChild);
useEffect(() => {
if (hasActiveChild) setIsOpen(true);
}, [hasActiveChild, location]);
return (
<div>
<button
type="button"
onClick={() => setIsOpen(prev => !prev)}
className={cn(
'flex items-center gap-2 w-full text-left text-[11px] font-medium uppercase tracking-wider mt-5 mb-1 px-3 transition-colors cursor-pointer',
hasActiveChild
? 'text-[var(--color-a11oy-gold-dim)]'
: 'text-[var(--color-a11oy-text-ghost)] hover:text-[var(--color-a11oy-text-sub)]',
)}
>
{isOpen ? <ChevronDown className="w-3 h-3 shrink-0" /> : <ChevronRight className="w-3 h-3 shrink-0" />}
{section.label}
</button>
{isOpen && (
<nav className="flex flex-col gap-0.5">
{section.items.map(item => (
<NavLink key={item.id} item={item} />
))}
</nav>
)}
</div>
);
}
function NavLink({ item }: { item: NavItem }) {
const [location] = useLocation();
const fullPath = item.external ? item.path : `${BASE}${item.path}`;
const isActive = !item.external && (location === `${BASE}${item.path}` || location.startsWith(`${BASE}${item.path}/`));
const className = cn(
'flex items-center gap-3 px-3 py-2 rounded-lg text-[13px] transition-colors',
isActive
? 'bg-[var(--color-a11oy-gold-soft)] text-[var(--color-a11oy-gold-dim)] font-medium'
: 'text-[var(--color-a11oy-text-sub)] hover:bg-[var(--color-a11oy-overlay)] hover:text-[var(--color-a11oy-text)]',
);
const inner = (
<>
<item.icon className={cn('w-4 h-4', isActive ? 'opacity-100' : 'opacity-50')} />
<span className="flex-1">{item.name}</span>
{item.badge && (
<span className="text-[9px] font-mono uppercase tracking-wider px-1.5 py-0.5 rounded"
style={{ background: 'rgba(201,183,135,0.16)', color: '#c9b787' }}>{item.badge}</span>
)}
{item.external && <ExternalLink className="w-3 h-3 opacity-30 shrink-0" />}
</>
);
if (item.external) {
return (
<a href={fullPath} target="_blank" rel="noopener noreferrer" className={className}>
{inner}
</a>
);
}
return (
<Link href={fullPath} className={className}>
{inner}
</Link>
);
}
function CommandPalette({ open, onClose }: { open: boolean; onClose: () => void }) {
const [, navigate] = useLocation();
const [q, setQ] = useState('');
// De-dup by path so ⌘K is the single source of navigation for ALL surfaces.
const seen = new Set<string>();
const index = ALL_DEEP_LINKS.filter(i => {
if (seen.has(i.path)) return false; seen.add(i.path); return true;
});
const results = q.trim()
? index.filter(i => (i.name + ' ' + i.path).toLowerCase().includes(q.toLowerCase())).slice(0, 40)
: index.slice(0, 40);
if (!open) return null;
return (
<div role="dialog" aria-modal="true"
className="fixed inset-0 z-50 flex items-start justify-center pt-[12vh] bg-black/60"
onClick={onClose}>
<div className="w-[640px] max-w-[90vw] rounded-xl border border-[var(--color-a11oy-border)] bg-[var(--color-a11oy-deep)] shadow-2xl"
onClick={e => e.stopPropagation()}>
<div className="flex items-center gap-2 px-4 py-3 border-b border-[var(--color-a11oy-border-subtle)]">
<Search className="w-4 h-4 opacity-60" />
<input autoFocus value={q} onChange={e => setQ(e.target.value)}
placeholder="Search all surfaces (⌘K) — every deep link stays live…"
className="flex-1 bg-transparent outline-none text-[13px] text-[var(--color-a11oy-text)]" />
</div>
<nav className="max-h-[50vh] overflow-y-auto py-2">
{results.map(i => (
<button key={i.id} type="button"
onClick={() => {
if (i.external) { window.open(i.path, '_blank', 'noopener,noreferrer'); }
else { navigate(`${BASE}${i.path}`); }
onClose();
}}
className="flex items-center gap-3 w-full text-left px-4 py-2 text-[13px] text-[var(--color-a11oy-text-sub)] hover:bg-[var(--color-a11oy-overlay)] hover:text-[var(--color-a11oy-text)]">
<i.icon className="w-4 h-4 opacity-50" />
<span className="flex-1">{i.name}</span>
<span className="text-[10px] font-mono opacity-40">{i.path}</span>
</button>
))}
{results.length === 0 && (
<div className="px-4 py-6 text-center text-[12px] text-[var(--color-a11oy-text-ghost)]">No surface matches “{q}”.</div>
)}
</nav>
</div>
</div>
);
}
export function Sidebar() {
const [paletteOpen, setPaletteOpen] = useState(false);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
e.preventDefault();
setPaletteOpen(o => !o);
}
if (e.key === 'Escape') setPaletteOpen(false);
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, []);
return (
<aside className="w-60 border-r border-[var(--color-a11oy-border)] bg-[var(--color-a11oy-deep)] shrink-0 flex flex-col h-[calc(100vh-3.5rem)] sticky top-14 overflow-y-auto">
{/* Search-to-navigate: opens the ⌘K command palette that indexes ALL deep links */}
<div className="px-3 pt-4 pb-2">
<button type="button" onClick={() => setPaletteOpen(true)}
className="flex items-center gap-2 w-full px-3 py-2 rounded-lg text-[12px] text-[var(--color-a11oy-text-ghost)] border border-[var(--color-a11oy-border-subtle)] hover:text-[var(--color-a11oy-text-sub)]">
<Search className="w-3.5 h-3.5" />
<span className="flex-1 text-left">Search surfaces…</span>
<span className="text-[10px] font-mono opacity-60">⌘K</span>
</button>
</div>
{/* 3 pinned top items (Stripe/Linear/Vercel pattern) */}
<div className="px-3 py-1">
<nav className="flex flex-col gap-0.5">
{topItems.map(item => <NavLink key={item.id} item={item} />)}
</nav>
</div>
{/* 7 consolidated sections. Every other route stays live via ⌘K + direct URL. */}
<div className="px-3 py-1 flex-1">
{sections.map(section => (
<CollapsibleSection key={section.id} section={section} />
))}
</div>
{/* Settings / profile pinned bottom-left (Linear / Vercel pattern) */}
<div className="px-3 py-2 border-t border-[var(--color-a11oy-border-subtle)]">
<NavLink item={{ id: 'tab-settings', name: 'Settings & Billing', icon: Settings, path: '/account/billing' }} />
<NavLink item={{ id: 'tab-account', name: 'Operator Profile', icon: Users, path: '/operator-profile' }} />
</div>
{/* Doctrine footer — present on every page via the persistent sidebar */}
<div className="px-4 py-3 border-t border-[var(--color-a11oy-border-subtle)] text-[10px] font-mono text-[var(--color-a11oy-text-ghost)] leading-relaxed">
<div style={{ color: '#c9b787' }}>Doctrine v11 LOCKED · 749 / 14 / 163</div>
<div>Λ Conjecture 1 (NOT a theorem)</div>
<div className="text-[var(--color-a11oy-success)]">System nominal</div>
</div>
<CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} />
</aside>
);
}