From 546da471f82f332a12e8b8b09825bf28e6e46e3c Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Wed, 11 Feb 2026 12:03:33 +0100 Subject: [PATCH] feat(ui): Add C3BOX sidebar navigation to KISS theme - Add shared navigation config in kiss-theme.js - Add renderSidebar() method for reusable sidebar - Add wrap() helper for full page with sidebar - Update InterceptoR to use sidebar layout - Responsive: collapses on mobile, icons-only on tablet Other views can use: KissTheme.wrap([content], 'active/path') Co-Authored-By: Claude Opus 4.5 --- .../resources/view/interceptor/overview.js | 138 +++++++++++++++--- .../resources/secubox/kiss-theme.js | 111 ++++++++++++++ 2 files changed, 229 insertions(+), 20 deletions(-) diff --git a/package/secubox/luci-app-interceptor/htdocs/luci-static/resources/view/interceptor/overview.js b/package/secubox/luci-app-interceptor/htdocs/luci-static/resources/view/interceptor/overview.js index 8b76c7f7..7d1c3eee 100644 --- a/package/secubox/luci-app-interceptor/htdocs/luci-static/resources/view/interceptor/overview.js +++ b/package/secubox/luci-app-interceptor/htdocs/luci-static/resources/view/interceptor/overview.js @@ -24,6 +24,27 @@ var QUICK_LINKS = [ { name: 'CrowdSec', path: 'admin/secubox/security/crowdsec/overview', icon: '🛡️' } ]; +var C3_NAV = [ + { cat: 'Main', items: [ + { icon: '🏠', name: 'Home', path: 'admin/secubox-home' }, + { icon: '📊', name: 'System Hub', path: 'admin/secubox/system/system-hub' } + ]}, + { cat: 'Security', items: [ + { icon: '🧙', name: 'InterceptoR', path: 'admin/secubox/interceptor/overview', active: true }, + { icon: '🛡️', name: 'CrowdSec', path: 'admin/secubox/security/crowdsec/overview' }, + { icon: '🔍', name: 'mitmproxy', path: 'admin/secubox/security/mitmproxy/status' }, + { icon: '🌐', name: 'DNS Guard', path: 'admin/secubox/security/dnsguard' } + ]}, + { cat: 'Services', items: [ + { icon: '📡', name: 'IoT Guard', path: 'admin/secubox/services/iot-guard' }, + { icon: '💾', name: 'CDN Cache', path: 'admin/services/cdn-cache' }, + { icon: '🔗', name: 'HAProxy', path: 'admin/services/haproxy' } + ]}, + { cat: 'Navigate', items: [ + { icon: '🌳', name: 'LuCI Tree', path: 'admin/secubox/luci-tree' } + ]} +]; + return view.extend({ load: function() { return callGetStatus().catch(function() { @@ -50,12 +71,17 @@ return view.extend({ var score = summary.health_score || 0; var pillarsActive = summary.pillars_active || 0; - return E('div', { 'class': 'kiss-root' }, [ - // Header - E('div', { 'style': 'margin-bottom: 24px;' }, [ - E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '🧙 InterceptoR'), - E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'The Gandalf Proxy — Transparent traffic interception') - ]), + return E('div', { 'class': 'kiss-root kiss-with-sidebar' }, [ + // Sidebar + this.renderSidebar(), + + // Main content + E('div', { 'class': 'kiss-main' }, [ + // Header + E('div', { 'style': 'margin-bottom: 24px;' }, [ + E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '🧙 InterceptoR'), + E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'The Gandalf Proxy — Transparent traffic interception') + ]), // Health Score Card E('div', { 'class': 'kiss-card', 'style': 'text-align: center; padding: 30px; margin-bottom: 20px;' }, [ @@ -72,22 +98,56 @@ return view.extend({ }) ), - // Quick Links - E('div', { 'class': 'kiss-card' }, [ - E('div', { 'class': 'kiss-card-title' }, '🔗 Quick Links'), - E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 10px;' }, - QUICK_LINKS.map(function(link) { - return E('a', { - 'href': '/cgi-bin/luci/' + link.path, - 'class': 'kiss-btn', - 'style': 'text-decoration: none;' - }, link.icon + ' ' + link.name); - }) - ) + // Quick Links + E('div', { 'class': 'kiss-card' }, [ + E('div', { 'class': 'kiss-card-title' }, '🔗 Quick Links'), + E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 10px;' }, + QUICK_LINKS.map(function(link) { + return E('a', { + 'href': '/cgi-bin/luci/' + link.path, + 'class': 'kiss-btn', + 'style': 'text-decoration: none;' + }, link.icon + ' ' + link.name); + }) + ) + ]) ]) ]); }, + renderSidebar: function() { + var navItems = []; + + C3_NAV.forEach(function(cat) { + navItems.push(E('div', { 'class': 'kiss-nav-section' }, cat.cat)); + cat.items.forEach(function(item) { + navItems.push(E('a', { + 'href': '/cgi-bin/luci/' + item.path, + 'class': 'kiss-nav-item' + (item.active ? ' active' : '') + }, [ + E('span', { 'class': 'kiss-nav-icon' }, item.icon), + item.name + ])); + }); + }); + + return E('nav', { 'class': 'kiss-sidebar' }, [ + // Logo + E('div', { 'class': 'kiss-sidebar-logo' }, [ + E('div', { 'class': 'kiss-logo-text' }, [ + E('span', { 'style': 'color: var(--kiss-green);' }, 'C'), + E('span', { 'style': 'color: var(--kiss-red); font-size: 14px; vertical-align: super;' }, '3'), + E('span', { 'style': 'color: var(--kiss-blue);' }, 'B'), + E('span', { 'style': 'color: #37474F;' }, 'O'), + E('span', { 'style': 'color: var(--kiss-green);' }, 'X') + ]), + E('div', { 'class': 'kiss-logo-sub' }, 'SECUBOX') + ]), + // Nav + E('div', { 'class': 'kiss-nav' }, navItems) + ]); + }, + renderPillar: function(pillar, data) { var enabled = data.enabled || false; var running = data.running !== undefined ? data.running : enabled; @@ -148,8 +208,34 @@ return view.extend({ } .kiss-root { background: var(--kiss-bg); color: var(--kiss-text); - font-family: 'Segoe UI', sans-serif; min-height: 100vh; padding: 20px; + font-family: 'Segoe UI', sans-serif; min-height: 100vh; } +.kiss-with-sidebar { display: flex; } +.kiss-sidebar { + position: fixed; left: 0; top: 0; bottom: 0; width: 200px; + background: linear-gradient(180deg, #0d1321 0%, var(--kiss-bg) 100%); + border-right: 1px solid var(--kiss-line); z-index: 100; + display: flex; flex-direction: column; overflow-y: auto; +} +.kiss-sidebar-logo { + padding: 16px; border-bottom: 1px solid var(--kiss-line); text-align: center; +} +.kiss-logo-text { font-weight: 900; font-size: 24px; letter-spacing: -1px; } +.kiss-logo-sub { font-size: 9px; color: var(--kiss-muted); letter-spacing: 2px; margin-top: 4px; } +.kiss-nav { flex: 1; padding: 8px 0; } +.kiss-nav-section { + padding: 8px 12px 4px; font-size: 9px; letter-spacing: 2px; + text-transform: uppercase; color: var(--kiss-muted); +} +.kiss-nav-item { + display: flex; align-items: center; gap: 10px; padding: 8px 16px; + text-decoration: none; font-size: 13px; color: var(--kiss-muted); + transition: all 0.2s; border-left: 2px solid transparent; +} +.kiss-nav-item:hover { background: rgba(255,255,255,0.03); color: var(--kiss-text); } +.kiss-nav-item.active { color: var(--kiss-green); background: rgba(0,200,83,0.05); border-left-color: var(--kiss-green); } +.kiss-nav-icon { font-size: 16px; width: 20px; text-align: center; } +.kiss-main { margin-left: 200px; padding: 20px; flex: 1; min-height: 100vh; } .kiss-card { background: var(--kiss-card); border: 1px solid var(--kiss-line); border-radius: 12px; padding: 20px; margin-bottom: 16px; @@ -171,7 +257,19 @@ return view.extend({ display: flex; align-items: center; justify-content: center; } #kiss-toggle:hover { opacity: 1; transform: scale(1.1); } -@media (max-width: 600px) { .kiss-grid-auto { grid-template-columns: 1fr 1fr; } } +@media (max-width: 768px) { + .kiss-sidebar { width: 60px; } + .kiss-sidebar-logo, .kiss-nav-section { display: none; } + .kiss-nav-item { padding: 12px; justify-content: center; } + .kiss-nav-item span:last-child { display: none; } + .kiss-main { margin-left: 60px; } + .kiss-grid-auto { grid-template-columns: 1fr 1fr; } +} +@media (max-width: 480px) { + .kiss-sidebar { display: none; } + .kiss-main { margin-left: 0; } + .kiss-grid-auto { grid-template-columns: 1fr; } +} `; var style = document.createElement('style'); style.id = 'kiss-interceptor-css'; diff --git a/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox/kiss-theme.js b/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox/kiss-theme.js index 4bf3aff8..d8223e2e 100644 --- a/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox/kiss-theme.js +++ b/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox/kiss-theme.js @@ -14,6 +14,29 @@ */ window.KissTheme = window.KissTheme || { + // Navigation config - shared across all views + nav: [ + { cat: 'Main', items: [ + { icon: '🏠', name: 'Home', path: 'admin/secubox-home' }, + { icon: '📊', name: 'System Hub', path: 'admin/secubox/system/system-hub' } + ]}, + { cat: 'Security', items: [ + { icon: '🧙', name: 'InterceptoR', path: 'admin/secubox/interceptor/overview' }, + { icon: '🛡️', name: 'CrowdSec', path: 'admin/secubox/security/crowdsec/overview' }, + { icon: '🔍', name: 'mitmproxy', path: 'admin/secubox/security/mitmproxy/status' }, + { icon: '🌐', name: 'DNS Guard', path: 'admin/secubox/security/dnsguard' } + ]}, + { cat: 'Services', items: [ + { icon: '📡', name: 'IoT Guard', path: 'admin/secubox/services/iot-guard' }, + { icon: '💾', name: 'CDN Cache', path: 'admin/services/cdn-cache' }, + { icon: '🔗', name: 'HAProxy', path: 'admin/services/haproxy' }, + { icon: '🔒', name: 'WireGuard', path: 'admin/services/wireguard' } + ]}, + { cat: 'Navigate', items: [ + { icon: '🌳', name: 'LuCI Tree', path: 'admin/secubox/luci-tree' } + ]} + ], + // Core palette colors: { bg: '#0a0e17', @@ -120,9 +143,53 @@ window.KissTheme = window.KissTheme || { .kiss-panel-red { border-left: 3px solid var(--kiss-red); } .kiss-panel-blue { border-left: 3px solid var(--kiss-blue); } .kiss-panel-orange { border-left: 3px solid var(--kiss-orange); } +/* Sidebar layout */ +.kiss-with-sidebar { display: flex; } +.kiss-sidebar { + position: fixed; left: 0; top: 0; bottom: 0; width: 200px; + background: linear-gradient(180deg, #0d1321 0%, var(--kiss-bg) 100%); + border-right: 1px solid var(--kiss-line); z-index: 100; + display: flex; flex-direction: column; overflow-y: auto; +} +.kiss-sidebar-logo { + padding: 16px; border-bottom: 1px solid var(--kiss-line); text-align: center; +} +.kiss-logo-text { font-weight: 900; font-size: 24px; letter-spacing: -1px; } +.kiss-logo-sub { font-size: 9px; color: var(--kiss-muted); letter-spacing: 2px; margin-top: 4px; } +.kiss-nav { flex: 1; padding: 8px 0; } +.kiss-nav-section { + padding: 8px 12px 4px; font-size: 9px; letter-spacing: 2px; + text-transform: uppercase; color: var(--kiss-muted); +} +.kiss-nav-item { + display: flex; align-items: center; gap: 10px; padding: 8px 16px; + text-decoration: none; font-size: 13px; color: var(--kiss-muted); + transition: all 0.2s; border-left: 2px solid transparent; +} +.kiss-nav-item:hover { background: rgba(255,255,255,0.03); color: var(--kiss-text); } +.kiss-nav-item.active { color: var(--kiss-green); background: rgba(0,200,83,0.05); border-left-color: var(--kiss-green); } +.kiss-nav-icon { font-size: 16px; width: 20px; text-align: center; } +.kiss-main { margin-left: 200px; padding: 20px; flex: 1; min-height: 100vh; } +/* Toggle */ +#kiss-toggle { + position: fixed; top: 10px; right: 10px; z-index: 99999; + font-size: 32px; cursor: pointer; opacity: 0.7; transition: all 0.3s; + background: rgba(0,0,0,0.5); border-radius: 50%; width: 50px; height: 50px; + display: flex; align-items: center; justify-content: center; +} +#kiss-toggle:hover { opacity: 1; transform: scale(1.1); } /* Responsive */ @media (max-width: 768px) { .kiss-grid-2, .kiss-grid-3, .kiss-grid-4 { grid-template-columns: 1fr; } + .kiss-sidebar { width: 60px; } + .kiss-sidebar-logo, .kiss-nav-section { display: none; } + .kiss-nav-item { padding: 12px; justify-content: center; } + .kiss-nav-item span:last-child { display: none; } + .kiss-main { margin-left: 60px; } +} +@media (max-width: 480px) { + .kiss-sidebar { display: none; } + .kiss-main { margin-left: 0; } } `; }, @@ -283,6 +350,50 @@ window.KissTheme = window.KissTheme || { 'class': 'kiss-btn' + (type ? ' kiss-btn-' + type : ''), 'onClick': onClick }, label); + }, + + // Render sidebar navigation + renderSidebar: function(activePath) { + var self = this; + var currentPath = activePath || window.location.pathname.replace('/cgi-bin/luci/', ''); + var navItems = []; + + this.nav.forEach(function(cat) { + navItems.push(self.E('div', { 'class': 'kiss-nav-section' }, cat.cat)); + cat.items.forEach(function(item) { + var isActive = currentPath.indexOf(item.path) !== -1; + navItems.push(self.E('a', { + 'href': '/cgi-bin/luci/' + item.path, + 'class': 'kiss-nav-item' + (isActive ? ' active' : '') + }, [ + self.E('span', { 'class': 'kiss-nav-icon' }, item.icon), + self.E('span', {}, item.name) + ])); + }); + }); + + return this.E('nav', { 'class': 'kiss-sidebar' }, [ + this.E('div', { 'class': 'kiss-sidebar-logo' }, [ + this.E('div', { 'class': 'kiss-logo-text' }, [ + this.E('span', { 'style': 'color: var(--kiss-green);' }, 'C'), + this.E('span', { 'style': 'color: var(--kiss-red); font-size: 14px; vertical-align: super;' }, '3'), + this.E('span', { 'style': 'color: var(--kiss-blue);' }, 'B'), + this.E('span', { 'style': 'color: #37474F;' }, 'O'), + this.E('span', { 'style': 'color: var(--kiss-green);' }, 'X') + ]), + this.E('div', { 'class': 'kiss-logo-sub' }, 'SECUBOX') + ]), + this.E('div', { 'class': 'kiss-nav' }, navItems) + ]); + }, + + // Create full page with sidebar + wrap: function(content, activePath) { + this.apply(); + return this.E('div', { 'class': 'kiss-root kiss-with-sidebar' }, [ + this.renderSidebar(activePath), + this.E('div', { 'class': 'kiss-main' }, Array.isArray(content) ? content : [content]) + ]); } };