diff --git a/docs/UI_LAYOUT.md b/docs/UI_LAYOUT.md index 93aa0b5..5a5ff16 100644 --- a/docs/UI_LAYOUT.md +++ b/docs/UI_LAYOUT.md @@ -75,6 +75,117 @@ All left-side panels (Nav Panel, Filter Panel) dock their header content to the Right-side panels (Detail Panel, Chat Dock) use standard vertically-centered headers since the logo bulge doesn't reach them. +### Nav Panel Sections + +Nav items can be organized into **sections**. Section headers are **conditionally visible** - they only appear when multiple sections exist. + +#### Single Section (headers hidden) + +When all items belong to one section, no headers are shown: + +``` +┌─────────────────────────┐ +│ [≡] Sections [···] │ ← Panel header +├─────────────────────────┤ +│ ▸ Containers │ +│ Networks │ +│ Volumes │ +│ Images │ +│ │ +└─────────────────────────┘ +``` + +#### Multiple Sections (headers visible) + +When items span multiple sections, section headers appear: + +``` +┌─────────────────────────┐ +│ [≡] Sections [···] │ ← Panel header +├─────────────────────────┤ +│ ▌Portainer │ ← Section header (subtle bg, left accent) +│ ▸ Containers │ +│ Networks │ +│ Volumes │ +│ Images │ +│ │ +│ ▌NPM │ ← Section header +│ Proxy Hosts │ +│ Redirections │ +│ Streams │ +│ │ +│ ▌Authentik │ ← Section header +│ Users │ +│ Groups │ +│ Applications │ +│ │ +└─────────────────────────┘ +``` + +#### Section Header Styling + +``` +┌─────────────────────────┐ +│▌SECTION NAME │ ← Left accent bar (2px, primary color) +└─────────────────────────┘ ← Background: surfaceContainerHigh + ← Text: labelSmall, onSurfaceVariant + ← Padding: 8px horizontal, 6px vertical + ← All caps, letter-spacing: 0.5 +``` + +#### Data Model + +```dart +/// NavItem model (in nav_panel.dart) +class NavItem { + final String id; + final String label; + final IconData icon; + final String? section; // null = ungrouped +} + +// Section headers auto-generate from unique section values +// Visibility: items.map((i) => i.section).toSet().length > 1 +``` + +#### Route Configuration Driven + +Sections are defined in the feature's route configuration, not the widget: + +```dart +/// In lib/features/control_room/router.dart + +enum ControlRoomNav { + // Portainer section + containers('containers', 'Containers', Icons.dns, 'Portainer'), + networks('networks', 'Networks', Icons.hub, 'Portainer'), + volumes('volumes', 'Volumes', Icons.storage, 'Portainer'), + images('images', 'Images', Icons.photo_library, 'Portainer'), + // NPM section (future) + proxyHosts('proxy-hosts', 'Proxy Hosts', Icons.public, 'NPM'), + redirections('redirections', 'Redirections', Icons.alt_route, 'NPM'), + // Authentik section (future) + users('users', 'Users', Icons.people, 'Authentik'), + groups('groups', 'Groups', Icons.group_work, 'Authentik'); + + const ControlRoomNav(this.id, this.label, this.icon, this.section); + + final String id; + final String label; + final IconData icon; + final String section; + + NavItem toNavItem() => NavItem( + id: id, + label: label, + icon: icon, + section: section, + ); +} +``` + +The NavPanel widget receives items and auto-generates section headers based on unique section values in the list. No section logic lives in the widget - it just renders what the route config provides. + --- ## Panel Configurations by Room @@ -260,29 +371,51 @@ Primary landing page. Chat dock expanded by default. ### Control Room (Infrastructure) -Context sidebar with section navigation. Chat collapsed. +Nav panel with grouped section navigation. Chat collapsed. +**Current state** (single grouper - headers hidden): ``` ┌───────────────┬───────────────────────────────────────────────────────┬──────┐ │ │ │ │ │ SECTIONS │ CONTAINERS [Search] [+ New] │ 💬 │ │ │ ─────────────────────────────────────────────────── │ │ │ ▸ Containers │ ☑ NAME STATUS CPU MEM IMAGE ⋮ │ │ -│ Stacks │ ☐ jellyfin ● Run 2.3% 1.2GB latest ⋮ │ │ +│ Networks │ ☐ jellyfin ● Run 2.3% 1.2GB latest ⋮ │ │ +│ Volumes │ ☐ ollama ● Run 45% 8.0GB 0.1.32 ⋮ │ │ +│ Images │ ☐ postgres ● Run 1.1% 512MB 16-alp ⋮ │ │ +│ │ ☐ redis ● Run 0.2% 128MB 7-alp ⋮ │ │ +│ │ ─────────────────────────────────────────────────── │ │ +│ │ Showing 5 of 40 < 1 2 3 4 5 > │ │ +│ │ │ │ +└───────────────┴───────────────────────────────────────────────────────┴──────┘ +``` + +**Future state** (multiple groupers - headers visible): +``` +┌───────────────┬───────────────────────────────────────────────────────┬──────┐ +│ │ │ │ +│ SECTIONS │ CONTAINERS [Search] [+ New] │ 💬 │ +│ │ ─────────────────────────────────────────────────── │ │ +│ ▌PORTAINER │ ☑ NAME STATUS CPU MEM IMAGE ⋮ │ │ +│ ▸ Containers │ ☐ jellyfin ● Run 2.3% 1.2GB latest ⋮ │ │ │ Networks │ ☐ ollama ● Run 45% 8.0GB 0.1.32 ⋮ │ │ -│ Volumes │ ☐ postgres ● Run 1.1% 512MB 16-alp ⋮ │ │ -│ Images │ ☐ redis ● Run 0.2% 128MB 7-alp ⋮ │ │ -│ │ ☐ authentik ○ Stop - - 2024.2 ⋮ │ │ -│ ──────────── │ ─────────────────────────────────────────────────── │ │ -│ Netdata ↗ │ Showing 5 of 40 < 1 2 3 4 5 > │ │ -│ Portainer↗ │ │ │ -│ NPM ↗ │ │ │ +│ Volumes │ ─────────────────────────────────────────────────── │ │ +│ Images │ Showing 3 of 40 < 1 2 3 4 5 > │ │ +│ │ │ │ +│ ▌NPM │ │ │ +│ Proxy Hosts│ │ │ +│ Redirects │ │ │ +│ │ │ │ +│ ▌AUTHENTIK │ │ │ +│ Users │ │ │ +│ Groups │ │ │ │ │ │ │ └───────────────┴───────────────────────────────────────────────────────┴──────┘ ``` **Components:** -- Context Sidebar: Section nav + external links +- Nav Panel: Grouped section navigation (grouper headers conditional) +- Filter Panel: Stack/item filtering within section - DataGrid: Container list with bulk actions - Detail Panel: Opens on row selection (replaces grid or slides in)