diff --git a/src/webui/static/css/style.css b/src/webui/static/css/style.css index 2a6c6980..9f69573d 100644 --- a/src/webui/static/css/style.css +++ b/src/webui/static/css/style.css @@ -182,20 +182,50 @@ a:hover { } .sidebar-nav { - list-style: none; flex: 1; - padding: 1rem 0; + padding: 0.5rem 0; + overflow-y: auto; } -.nav-section-header { +/* Accordion Nav Groups */ +details.nav-group { + border-top: 1px solid var(--sidebar-border); +} +details.nav-group:first-child { + border-top: none; +} + +details.nav-group > summary.nav-group-summary { + list-style: none; + cursor: pointer; font-size: 0.65rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--sidebar-fg); opacity: 0.5; - padding: 1rem 1rem 0.25rem; - pointer-events: none; + padding: 0.875rem 1rem 0.375rem; + display: flex; + justify-content: space-between; + align-items: center; + user-select: none; + transition: opacity 0.15s; +} +details.nav-group > summary.nav-group-summary:hover { opacity: 0.8; } +details.nav-group > summary.nav-group-summary::-webkit-details-marker { display: none; } +details.nav-group > summary.nav-group-summary::marker { display: none; } + +details.nav-group > summary.nav-group-summary::after { + content: '▸'; + font-size: 0.7rem; +} +details[open].nav-group > summary.nav-group-summary::after { + content: '▾'; +} + +.nav-group-items { + list-style: none; + padding-bottom: 0.5rem; } .nav-icon { @@ -796,6 +826,31 @@ a:hover { .dark .badge-drop { background: var(--slate-800); color: var(--slate-400); } .dark .badge-continue { background: rgba(59, 130, 246, 0.2); color: #93c5fd; } +/* General-purpose status badges */ +.badge-up { background: #dcfce7; color: #166534; } +.badge-down { background: #fef2f2; color: #991b1b; } +.badge-warning { background: #fef9c3; color: #854d0e; } +.badge-info { background: #dbeafe; color: #1e40af; } +.badge-neutral { background: var(--slate-100); color: var(--slate-600); } + +@media (prefers-color-scheme: dark) { + .badge-up { background: rgba(22, 163, 74, 0.2); color: #86efac; } + .badge-down { background: rgba(220, 38, 38, 0.2); color: #fca5a5; } + .badge-warning { background: rgba(245, 158, 11, 0.2); color: #fcd34d; } + .badge-info { background: rgba(59, 130, 246, 0.2); color: #93c5fd; } + .badge-neutral { background: var(--slate-800); color: var(--slate-400); } +} +.dark .badge-up { background: rgba(22, 163, 74, 0.2); color: #86efac; } +.dark .badge-down { background: rgba(220, 38, 38, 0.2); color: #fca5a5; } +.dark .badge-warning { background: rgba(245, 158, 11, 0.2); color: #fcd34d; } +.dark .badge-info { background: rgba(59, 130, 246, 0.2); color: #93c5fd; } +.dark .badge-neutral { background: var(--slate-800); color: var(--slate-400); } +.light .badge-up { background: #dcfce7; color: #166534; } +.light .badge-down { background: #fef2f2; color: #991b1b; } +.light .badge-warning { background: #fef9c3; color: #854d0e; } +.light .badge-info { background: #dbeafe; color: #1e40af; } +.light .badge-neutral { background: var(--slate-100); color: var(--slate-600); } + /* Interfaces */ .iface-name { white-space: nowrap; font-weight: 500; } .iface-name a { color: var(--primary); text-decoration: none; } @@ -1047,9 +1102,13 @@ a:hover { display: none; } - .nav-section-header { + /* Accordion in icon-only mode: always show items, hide section headers */ + details.nav-group > summary.nav-group-summary { display: none; } + details.nav-group:not([open]) > .nav-group-items { + display: block !important; + } .nav-link { justify-content: center; diff --git a/src/webui/static/js/app.js b/src/webui/static/js/app.js index 565e0755..81119d08 100644 --- a/src/webui/static/js/app.js +++ b/src/webui/static/js/app.js @@ -185,6 +185,26 @@ }); })(); +// Accordion nav group persistence +(function() { + document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('details.nav-group').forEach(function(d) { + var label = d.querySelector('summary'); + if (!label) return; + var key = 'nav-group:' + label.textContent.trim(); + var saved = localStorage.getItem(key); + if (saved === 'closed') { + d.removeAttribute('open'); + } else if (saved === 'open') { + d.setAttribute('open', ''); + } + d.addEventListener('toggle', function() { + localStorage.setItem(key, d.open ? 'open' : 'closed'); + }); + }); + }); +})(); + // Sidebar toggle (mobile) (function() { document.addEventListener('DOMContentLoaded', function() { diff --git a/src/webui/templates/layouts/sidebar.html b/src/webui/templates/layouts/sidebar.html index 6d9318b5..1947ca17 100644 --- a/src/webui/templates/layouts/sidebar.html +++ b/src/webui/templates/layouts/sidebar.html @@ -3,141 +3,163 @@ - + + +