// Aegis Drone Command — Shared Shell const PAGES = [ { label: 'Live Feed', href: '/' }, { label: 'Video Analysis', href: '/static/video.html' }, { label: 'Alerts', href: '/static/alerts.html' }, { label: 'Query Frames', href: '/static/query.html' }, { label: 'Daily Summary', href: '/static/summary.html' }, ]; const SIDEBAR_LINKS = [ { icon: 'precision_manufacturing', label: 'Systems', id: 'systems' }, { icon: 'airplanemode_active', label: 'Drones', id: 'drones' }, { icon: 'settings_input_component', label: 'Telemetry', id: 'telemetry', active: true }, { icon: 'view_in_ar', label: 'Payload', id: 'payload' }, { icon: 'admin_panel_settings', label: 'Security', id: 'security' }, ]; // Panel content for each sidebar item const PANEL_DATA = { systems: { title: 'SYSTEM STATUS', icon: 'precision_manufacturing', rows: [ { label: 'Core Engine', val: 'ONLINE', color: 'secondary-fixed-dim' }, { label: 'GPU Cluster', val: 'ACTIVE', color: 'secondary-fixed-dim' }, { label: 'Neural Net v4.2', val: 'LOADED', color: 'secondary-fixed-dim' }, { label: 'Memory Usage', val: '67%', color: 'primary' }, { label: 'CPU Load', val: '42%', color: 'primary' }, { label: 'Uptime', val: '14d 07h 33m', color: 'on-surface' }, { label: 'Last Reboot', val: '2026-04-28', color: 'outline' }, { label: 'Firmware', val: 'v8.1.4-mil', color: 'outline' }, ] }, drones: { title: 'DRONE FLEET', icon: 'airplanemode_active', rows: [ { label: 'Unit-01 (Alpha)', val: 'PATROL', color: 'secondary-fixed-dim' }, { label: 'Unit-02 (Alpha)', val: 'PATROL', color: 'secondary-fixed-dim' }, { label: 'Unit-03 (Bravo)', val: 'STANDBY', color: 'primary' }, { label: 'Unit-04 (Delta)', val: 'ENGAGED', color: 'error' }, { label: 'Unit-07 (Delta)', val: 'ACTIVE', color: 'secondary-fixed-dim' }, { label: 'Unit-09 (Charlie)', val: 'CHARGING', color: 'tertiary' }, { label: 'Unit-12 (Bravo)', val: 'MAINTENANCE', color: 'tertiary' }, { label: 'Unit-15 (Alpha)', val: 'PATROL', color: 'secondary-fixed-dim' }, ] }, telemetry: { title: 'TELEMETRY FEED', icon: 'settings_input_component', rows: [ { label: 'Altitude', val: '120m AGL', color: 'secondary-fixed-dim' }, { label: 'Ground Speed', val: '14.2 m/s', color: 'on-surface' }, { label: 'Heading', val: '247° WSW', color: 'on-surface' }, { label: 'Battery', val: '78%', color: 'secondary-fixed-dim' }, { label: 'Signal Strength', val: '-42 dBm', color: 'secondary-fixed-dim' }, { label: 'GPS Satellites', val: '14 locked', color: 'on-surface' }, { label: 'Wind Speed', val: '8.3 kts NE', color: 'primary' }, { label: 'Temperature', val: '22.4°C', color: 'outline' }, ] }, payload: { title: 'PAYLOAD STATUS', icon: 'view_in_ar', rows: [ { label: 'Camera (RGB)', val: 'ACTIVE', color: 'secondary-fixed-dim' }, { label: 'Camera (IR)', val: 'STANDBY', color: 'primary' }, { label: 'LIDAR Module', val: 'SCANNING', color: 'secondary-fixed-dim' }, { label: 'Spotlight', val: 'OFF', color: 'outline' }, { label: 'Speaker Array', val: 'ARMED', color: 'tertiary' }, { label: 'Gas Sensor', val: 'NOMINAL', color: 'secondary-fixed-dim' }, { label: 'Storage Used', val: '34.2 GB', color: 'on-surface' }, { label: 'Transmission', val: 'ENCRYPTED', color: 'secondary-fixed-dim' }, ] }, security: { title: 'SECURITY CONFIG', icon: 'admin_panel_settings', rows: [ { label: 'Auth Level', val: 'LEVEL 4', color: 'secondary-fixed-dim' }, { label: 'Encryption', val: 'AES-256', color: 'secondary-fixed-dim' }, { label: 'Firewall', val: 'ACTIVE', color: 'secondary-fixed-dim' }, { label: 'IDS Status', val: 'MONITORING', color: 'secondary-fixed-dim' }, { label: 'Last Breach', val: 'NONE', color: 'outline' }, { label: 'Perimeter', val: 'SECURED', color: 'secondary-fixed-dim' }, { label: 'Access Tokens', val: '3 active', color: 'on-surface' }, { label: 'Audit Log', val: '1,247 entries', color: 'outline' }, ] }, logs: { title: 'SYSTEM LOGS', icon: 'list_alt', rows: [ { label: '20:14:22', val: 'SYS_BOOT complete', color: 'secondary-fixed-dim' }, { label: '20:14:25', val: 'Network link established', color: 'secondary-fixed-dim' }, { label: '20:15:01', val: 'Auth token refreshed', color: 'on-surface' }, { label: '20:15:44', val: 'Drone fleet sync OK', color: 'secondary-fixed-dim' }, { label: '20:16:12', val: 'Patrol route loaded', color: 'on-surface' }, { label: '20:18:03', val: 'Sensor calibration done', color: 'on-surface' }, { label: '20:19:30', val: 'Operator login: Unit 07', color: 'primary' }, { label: '20:20:00', val: 'System nominal', color: 'secondary-fixed-dim' }, ] }, terminal: { title: 'TERMINAL', icon: 'terminal', rows: [ { label: '$', val: 'aegis status --all', color: 'secondary-fixed-dim' }, { label: '>', val: 'All subsystems operational', color: 'on-surface' }, { label: '$', val: 'drone list --active', color: 'secondary-fixed-dim' }, { label: '>', val: '7 units online, 1 maintenance', color: 'on-surface' }, { label: '$', val: 'alert count --today', color: 'secondary-fixed-dim' }, { label: '>', val: '3 alerts (0 critical)', color: 'on-surface' }, { label: '$', val: 'uptime', color: 'secondary-fixed-dim' }, { label: '>', val: '14 days, 7 hours, 33 minutes', color: 'on-surface' }, ] }, settings: { title: 'SETTINGS', icon: 'settings', rows: [ { label: 'Theme', val: 'DARK MODE', color: 'on-surface' }, { label: 'Language', val: 'ENGLISH', color: 'on-surface' }, { label: 'Notifications', val: 'ENABLED', color: 'secondary-fixed-dim' }, { label: 'Sound Alerts', val: 'ON', color: 'secondary-fixed-dim' }, { label: 'Auto-Refresh', val: '5 SEC', color: 'on-surface' }, { label: 'Map Overlay', val: 'TACTICAL', color: 'on-surface' }, { label: 'Data Retention', val: '90 DAYS', color: 'outline' }, { label: 'API Version', val: 'v2.4.1', color: 'outline' }, ] }, }; let activePanelId = null; function isActive(href) { const p = window.location.pathname; if (href === '/') return p === '/' || p === '/static/index.html'; return p === href; } function openPanel(id) { const wasOpen = activePanelId === id; closePanel(); if (wasOpen) return; activePanelId = id; updateSidebarHighlight(id); const data = PANEL_DATA[id]; if (!data) return; const overlay = document.createElement('div'); overlay.id = 'aegis-panel-overlay'; overlay.className = 'fixed inset-0 bg-black/40 z-[55]'; overlay.onclick = () => closePanel(); document.body.appendChild(overlay); const panel = document.createElement('div'); panel.id = 'aegis-panel'; panel.className = 'fixed top-16 left-60 w-80 bg-surface-container-high border-2 border-surface-dim shadow-[0_10px_40px_rgba(0,0,0,0.9)] z-[60] flex flex-col overflow-hidden'; panel.style.maxHeight = 'calc(100vh - 5rem)'; panel.style.animation = 'panelSlide .2s ease-out'; let rowsHtml = data.rows.map(r => `
${r.label} ${r.val}
` ).join(''); panel.innerHTML = `
${data.icon} ${data.title}
${rowsHtml}
LIVE DATA
${new Date().toLocaleTimeString('en-US',{hour12:false})} UTC
`; document.body.appendChild(panel); } function closePanel() { const p = document.getElementById('aegis-panel'); const o = document.getElementById('aegis-panel-overlay'); if (p) p.remove(); if (o) o.remove(); activePanelId = null; updateSidebarHighlight(null); } function updateSidebarHighlight(activeId) { const links = document.querySelectorAll('#aegis-sidebar nav a[data-panel]'); links.forEach(a => { const id = a.getAttribute('data-panel'); if (id === activeId) { a.className = 'flex items-center gap-3 px-3 py-2.5 rounded font-label-caps text-[12px] bg-surface-container-highest text-secondary-fixed shadow-[inset_0_2px_4px_rgba(0,0,0,0.8)] border-l-4 border-secondary-fixed uppercase'; a.querySelector('.material-symbols-outlined').style.fontVariationSettings = "'FILL' 1"; } else { a.className = 'flex items-center gap-3 px-3 py-2.5 rounded font-label-caps text-[12px] text-outline hover:text-on-surface-variant hover:bg-surface-container-high transition-all active:scale-95 uppercase'; a.querySelector('.material-symbols-outlined').style.fontVariationSettings = "'FILL' 0"; } }); } function emergencyStop(el) { const btn = el ? el.closest('button') : (window.event ? window.event.target.closest('button') : null); if (!btn || btn.dataset.stopping) return; btn.dataset.stopping = '1'; btn.classList.add('translate-y-[3px]'); btn.innerHTML = `syncHALTING...`; // Call the backend halt endpoint fetch('/api/halt', { method: 'POST' }) .then(r => r.json()) .then(data => { // Also reset simulation state return fetch('/api/reset', { method: 'POST' }); }) .then(r => r.json()) .then(() => { btn.innerHTML = `check_circleALL HALTED`; btn.classList.remove('bg-error'); btn.classList.add('bg-secondary-fixed-dim','text-black'); // Dispatch a global halt event so pages can clean up their EventSource / state window.dispatchEvent(new CustomEvent('aegis-halt')); setTimeout(() => { btn.classList.remove('translate-y-[3px]','bg-secondary-fixed-dim','text-black'); btn.classList.add('bg-error'); btn.innerHTML = `warningEMERGENCY STOP`; delete btn.dataset.stopping; }, 2500); }) .catch(err => { btn.innerHTML = `errorHALT FAILED`; setTimeout(() => { btn.classList.remove('translate-y-[3px]'); btn.innerHTML = `warningEMERGENCY STOP`; delete btn.dataset.stopping; }, 2000); }); } function buildTopNav() { const nav = document.createElement('header'); nav.id = 'aegis-topnav'; nav.className = 'bg-surface-container-highest fixed w-full top-0 border-b-4 border-surface-dim shadow-[0_4px_10px_rgba(0,0,0,0.8)] flex justify-between items-center px-6 h-16 z-50'; const brand = document.createElement('div'); brand.className = 'flex items-center gap-3 shrink-0'; brand.innerHTML = `security Aegis Drone Command`; const tabs = document.createElement('nav'); tabs.className = 'hidden md:flex items-center h-full gap-1 ml-8'; PAGES.forEach(p => { const a = document.createElement('a'); a.href = p.href; a.textContent = p.label; a.className = isActive(p.href) ? 'h-full flex items-center px-4 text-secondary-fixed-dim border-b-2 border-secondary-fixed-dim font-bold shadow-[0_0_12px_rgba(0,230,57,0.3)] bg-surface-container/50 font-label-caps text-[13px] uppercase tracking-wider' : 'h-full flex items-center px-4 text-on-surface-variant hover:bg-surface-bright hover:text-on-surface transition-colors font-label-caps text-[13px] uppercase tracking-wider'; tabs.appendChild(a); }); const right = document.createElement('div'); right.className = 'flex items-center gap-2 shrink-0'; right.innerHTML = ` `; nav.appendChild(brand); nav.appendChild(tabs); nav.appendChild(right); return nav; } function buildSidebar() { const aside = document.createElement('aside'); aside.id = 'aegis-sidebar'; aside.className = 'bg-surface-container-low fixed left-0 h-full w-60 border-r-4 border-surface-dim shadow-[10px_0_20px_rgba(0,0,0,0.5)] flex flex-col pt-16 pb-4 z-40'; const profile = document.createElement('div'); profile.className = 'px-5 py-5 border-b border-surface-variant flex items-center gap-3'; profile.innerHTML = `
person
Unit 07
Sector Delta
`; aside.appendChild(profile); const navCont = document.createElement('nav'); navCont.className = 'flex-1 py-4 flex flex-col gap-1 px-3 overflow-y-auto'; SIDEBAR_LINKS.forEach(l => { const a = document.createElement('a'); a.href = '#'; a.setAttribute('data-panel', l.id); a.onclick = (e) => { e.preventDefault(); openPanel(l.id); }; a.className = 'flex items-center gap-3 px-3 py-2.5 rounded font-label-caps text-[12px] text-outline hover:text-on-surface-variant hover:bg-surface-container-high transition-all active:scale-95 uppercase'; a.innerHTML = `${l.icon}${l.label}`; navCont.appendChild(a); }); aside.appendChild(navCont); const footer = document.createElement('div'); footer.className = 'mt-auto px-3 flex flex-col gap-2'; footer.innerHTML = `
list_altLogs terminalTerminal
`; aside.appendChild(footer); return aside; } // CSS animation function injectStyles() { if (document.getElementById('aegis-shell-styles')) return; const s = document.createElement('style'); s.id = 'aegis-shell-styles'; s.textContent = `@keyframes panelSlide{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}`; document.head.appendChild(s); } function injectShell() { document.querySelectorAll('#aegis-topnav, #aegis-sidebar, #aegis-panel, #aegis-panel-overlay').forEach(e => e.remove()); injectStyles(); document.body.prepend(buildSidebar()); document.body.prepend(buildTopNav()); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', injectShell); else injectShell();