webui: accordion sidebar and general-purpose status badges

Replace flat nav-section-header labels with collapsible <details>/<summary>
accordion groups (Network, Wireless, VPN, Services, System). Groups default
open; user state persists via localStorage. Tablet icon-only mode always
shows all items regardless of open/closed state.

Add badge-up/down/warning/info/neutral utility classes with full dark mode
support, complementing the existing firewall-specific badge variants.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-06-14 22:07:23 +02:00
parent bc535099ec
commit 6271e40ce0
3 changed files with 236 additions and 135 deletions
+65 -6
View File
@@ -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;