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 <noreply@anthropic.com>
This commit is contained in:
parent
03e90bb4af
commit
546da471f8
@ -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';
|
||||
|
||||
@ -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])
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user