Refactor nav: horizontal top bar → sidebar layout

- Replace cramped horizontal nav with grouped sidebar navigation
- Sections: Monitor, Respond, Analyze with logical grouping
- Collapsible sidebar with localStorage persistence
- Tooltips on hover when collapsed (icon-only mode)
- Slim top bar: search, alerts bell, help, theme toggle, user menu
- Org switcher + settings pinned to sidebar bottom
- Mobile: grouped slide-out panel matches sidebar sections
- Smooth CSS transitions on collapse/expand
This commit is contained in:
Graham McIntire 2026-03-13 13:28:19 -05:00
parent d23dac1513
commit 5a8e3885a9
4 changed files with 576 additions and 529 deletions

View file

@ -1 +1 @@
/nix/store/zx636v118rzzqzwafgrw2aybh7l0szrl-pre-commit-config.json
/nix/store/4xlkmdd947h5qlhj2rmbyavq08grkz27-pre-commit-config.json

View file

@ -105,6 +105,56 @@
/* Hide 1Password live region */
[id="1p-live-region"] { display: none !important; }
/* Sidebar layout */
#app-sidebar {
@apply w-56 transition-all duration-200;
}
.sidebar-collapsed #app-sidebar {
@apply w-16;
}
.sidebar-collapsed [data-sidebar-text] {
display: none;
}
.sidebar-collapsed [data-sidebar-section] {
display: none;
}
.sidebar-collapsed .sidebar-collapse-icon {
transform: rotate(180deg);
}
.sidebar-collapse-icon {
transition: transform 0.2s ease;
}
.sidebar-collapsed [data-sidebar-tooltip] {
position: relative;
}
.sidebar-collapsed [data-sidebar-tooltip]:hover::after {
content: attr(data-sidebar-tooltip);
position: absolute;
left: 100%;
top: 50%;
transform: translateY(-50%);
margin-left: 0.5rem;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
white-space: nowrap;
z-index: 50;
background-color: #1f2937;
color: #fff;
pointer-events: none;
}
#main-wrapper {
@apply transition-all duration-200;
}
@media (min-width: 1024px) {
#main-wrapper {
margin-left: 14rem; /* w-56 = 224px */
}
.sidebar-collapsed #main-wrapper {
margin-left: 4rem; /* w-16 = 64px */
}
}
/* This file is for your main application CSS */
/* Page transitions */

View file

@ -1375,6 +1375,22 @@ const StatusTitle = {
}
}
// Sidebar collapse - restore state from localStorage and persist toggle
const SidebarCollapse = {
mounted(this: any) {
if (localStorage.getItem('sidebarCollapsed') === 'true') {
this.el.classList.add('sidebar-collapsed')
}
this.el.querySelector('[data-sidebar-toggle]')?.addEventListener('click', () => {
// The JS.toggle_class will fire, so we check after a tick
requestAnimationFrame(() => {
const collapsed = this.el.classList.contains('sidebar-collapsed')
localStorage.setItem('sidebarCollapsed', String(collapsed))
})
})
}
}
const ThemeSelector = {
mounted() {
this.updateActive()
@ -1398,7 +1414,7 @@ const ThemeSelector = {
const liveSocket = new LiveSocket("/live", Socket, {
longPollFallbackMs: 5000,
params: { _csrf_token: csrfToken, timezone: userTimezone },
hooks: { ...colocatedHooks, SensorChart, CopyToClipboard, ScrollToTop, AutoDismissFlash, BetaBannerDismiss, NetworkMap, SitesMap, LeafletMap, DeviceListReorder, MikrotikPortSync, GlobalSearch, GlobalSearchTrigger, DynamicFavicon, StatusTitle, ThemeSelector },
hooks: { ...colocatedHooks, SensorChart, CopyToClipboard, ScrollToTop, AutoDismissFlash, BetaBannerDismiss, NetworkMap, SitesMap, LeafletMap, DeviceListReorder, MikrotikPortSync, GlobalSearch, GlobalSearchTrigger, DynamicFavicon, StatusTitle, ThemeSelector, SidebarCollapse },
})
// Show progress bar on live navigation and form submits

File diff suppressed because it is too large Load diff