/* =================================================================== KabelFlux v5 — Command palette (⌘K) Adds a power-user navigation surface so users don't hunt across 11 tabs. =================================================================== */ const Palette = ({ open, onClose, onNav, project, projects = [], isAdmin = false, isSuper = false }) => { const [q, setQ] = useState(''); const [sel, setSel] = useState(0); const ref = useRef(); useEffect(() => { if (open) { setTimeout(() => { ref.current && ref.current.focus(); }, 30); setQ(''); setSel(0); } }, [open]); const items = useMemo(() => { const all = [ { group: 'Navigate', icon: 'layout', label: 'Go to Layout', hint: 'Canvas · diagram + formboard', kbd: 'G 1', kind: 'goto:layout' }, { group: 'Navigate', icon: 'wires', label: 'Go to Wires', hint: 'Inline-editable wire table', kbd: 'G 2', kind: 'goto:wires' }, { group: 'Navigate', icon: 'connector', label: 'Go to Connectors', hint: 'Connector inventory + pinouts', kbd: 'G 3', kind: 'goto:connectors' }, { group: 'Navigate', icon: 'bom', label: 'Go to BOM', hint: 'Bill of materials + charts', kbd: 'G 4', kind: 'goto:bom' }, { group: 'Navigate', icon: 'nodes', label: 'Go to Nodes', hint: 'Splices, fuses, grounds', kbd: 'G 5', kind: 'goto:nodes' }, { group: 'Navigate', icon: 'notes', label: 'Go to Notes & Revisions', kbd: 'G 6', kind: 'goto:notes' }, { group: 'Navigate', icon: 'title', label: 'Go to Title Block', kbd: 'G 7', kind: 'goto:title' }, { group: 'Navigate', icon: 'library', label: 'Go to Symbol Library', kbd: 'G 8', kind: 'goto:library' }, { group: 'Navigate', icon: 'settings', label: 'Go to Settings', kbd: 'G 9', kind: 'goto:settings' }, { group: 'Actions', icon: 'plus', label: 'New wire', hint: 'Add a wire to the harness', kbd: 'N', kind: 'action:new-wire' }, { group: 'Actions', icon: 'bolt', label: 'Toggle Wire mode', hint: 'Click-pin-A then click-pin-B', kbd: 'W', kind: 'action:wire-mode' }, { group: 'Actions', icon: 'connector', label: 'New connector', hint: 'Pick from symbol library', kind: 'action:new-conn' }, { group: 'Actions', icon: 'nodes', label: 'New splice / fuse / ground node', kind: 'action:new-node' }, { group: 'Actions', icon: 'import_', label: 'Import CSV / Komax',hint: 'Wire list into current project', kind: 'action:import' }, { group: 'Export', icon: 'download', label: 'Production Drawing (PDF)', hint: 'Combined formboard + wire table + breakout', kbd: '⌘⇧E', kind: 'export:prod' }, { group: 'Export', icon: 'flask', label: 'Continuity Test Plan', hint: 'QA-ready PDF · sign-off block', kind: 'export:cont' }, { group: 'Export', icon: 'bom', label: 'BOM (XLSX)', kind: 'export:bom-xlsx' }, { group: 'Export', icon: 'ruler', label: 'Formboard DXF', hint: 'AutoCAD / Fusion 360 layers', kind: 'export:dxf' }, { group: 'Export', icon: 'file', label: 'Komax / Schleuniger CSV', hint: 'For wire-prep machines', kind: 'export:komax' }, { group: 'Export', icon: 'ok', label: 'AS50881 compliance audit', kind: 'export:as50881' }, // OPERATIONS (admin + super-admin) ...(isAdmin ? [ { group: 'Admin', icon: 'folder', label: 'Workspace settings', hint: 'Company · branding · defaults', kind: 'admin:workspace' }, { group: 'Admin', icon: 'user', label: 'Manage users', hint: 'Add / remove · roles', kind: 'admin:users' }, { group: 'Admin', icon: 'share', label: 'Share links', hint: 'Read-only links · expiry · revoke', kind: 'admin:share' }, ] : []), // SYSTEM (super-admin only — Companies, Database backups, System health) ...(isSuper ? [ { group: 'Admin', icon: 'folder', label: 'Companies', hint: 'All tenants · status · approve · edit', kind: 'admin:companies' }, { group: 'Admin', icon: 'backup', label: 'Database backups', hint: 'Manual snapshot · pause switch · restore', kind: 'admin:backups' }, { group: 'Admin', icon: 'info', label: 'System health', hint: 'API version · last backup', kind: 'admin:health' }, ] : []), ...projects.map(p => ({ group: 'Projects', icon: 'folder', label: p.code + ' — ' + p.name, hint: `Rev ${p.revision} · ${p.wires} wires · ${p.modified}`, kind: 'project:' + p.id })), ]; if (!q.trim()) return all; const lq = q.toLowerCase(); return all.filter(it => (it.label + ' ' + (it.hint || '') + ' ' + it.group).toLowerCase().includes(lq)); }, [q, projects, isAdmin, isSuper]); const grouped = useMemo(() => { const out = {}; items.forEach(it => { if (!out[it.group]) out[it.group] = []; out[it.group].push(it); }); return out; }, [items]); useEffect(() => { const fn = e => { if (!open) return; if (e.key === 'Escape') onClose(); if (e.key === 'ArrowDown') { e.preventDefault(); setSel(s => Math.min(items.length - 1, s + 1)); } if (e.key === 'ArrowUp') { e.preventDefault(); setSel(s => Math.max(0, s - 1)); } if (e.key === 'Enter') { e.preventDefault(); const it = items[sel]; if (it) handle(it); } }; document.addEventListener('keydown', fn); return () => document.removeEventListener('keydown', fn); }, [open, items, sel]); const handle = (it) => { onNav(it.kind); onClose(); }; if (!open) return null; return (