# UI Layout Specification This document defines the layout structure, responsive behavior, and component constraints for Tatlock UI. It implements the "Rooms of the Estate" metaphor from [PHILOSOPHY.md](../PHILOSOPHY.md). ## Navigation Structure The UI uses a **tabbed room navigation** in the header rather than a traditional sidebar. Each "room" represents a distinct usage context, reducing cognitive clutter. | Room | Purpose | Chat Dock Default | |------|---------|-------------------| | **Front Hall** | Dashboard - estate overview, quick access, activity | Expanded | | **Control Room** | Infrastructure - containers, stacks, monitoring | Collapsed | | **Parlor** | Housekeeping - home automation, devices, scenes | Collapsed | | **Library** | Knowledge - docs, notes, bookmarks (future) | Collapsed | **Hidden for now:** - **Study** - Secretarial tasks (email, calendaring) - future implementation --- ## Layout Structure ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ HEADER BAR (56px, with logo bulge overlay) │ │ [◯Logo◯] [Room Icons] ─────────────────────────────────── [Profile Menu] │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────────────────────────┐ ┌───────────────────┐ │ │ │ NAV PANEL │ │ PRIMARY CONTENT │ │ CHAT DOCK │ │ │ │ │ │ │ │ │ │ │ │ Room-level │ │ ┌──────────┐ ┌──────────────┐ │ │ Tatlock AI │ │ │ │ navigation │ │ │ FILTER │ │ DATA GRID │ │ │ assistant │ │ │ │ (sections) │ │ │ PANEL │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Persistent │ │ │ │ 280px fixed │ │ │ Optional │ │ flex: 1 │ │ │ across rooms │ │ │ │ │ │ │ 280px │ │ │ │ │ │ │ │ └─────────────┘ │ └──────────┘ └──────────────┘ │ │ 280px-33vw │ │ │ │ │ │ │ │ │ │ flex: 1 │ │ flex: 0 │ │ │ └─────────────────────────────────┘ └───────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Panel Taxonomy All panels share common styling patterns but serve different purposes. ### Panel Types | Panel | Position | Purpose | Width | Content Alignment | |-------|----------|---------|-------|-------------------| | **Header Bar** | Top | Room nav, profile | 56px height | Logo in bulge, rest at bottom | | **Nav Panel** | Left | Room-level section nav | 280px fixed | Header docked to bottom | | **Filter Panel** | Left (inside content) | Data filtering/search | 280px fixed | Header docked to bottom | | **Detail Panel** | Right (inside content) | Selected item details | 320-400px | Standard header | | **Chat Dock** | Right | AI assistant | 280px-33vw | Standard header | ### Panel Header Behavior All left-side panels (Nav Panel, Filter Panel) dock their header content to the **bottom** of the header area. This accommodates the logo bulge that overlays into their space. ``` ┌─────────────────────────┐ │ │ ← Logo bulge overlays this space │ (empty) │ │ │ │ [Icon] Title [Action]│ ← Content docked to bottom (8px margin) ├─────────────────────────┤ │ Panel content... │ ``` 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 ### Front Hall Front Hall uses a **three-mode content system** with a persistent QuickLinks panel: | Mode | QuickLinks Panel | Content Area | |------|------------------|--------------| | **Dashboard** | Normal navigation | Dashboard widgets (stats, weather) | | **Iframe** | Normal navigation | Embedded iframe content | | **Settings** | Edit mode (back button, add new, overflow menus) | QuickLinkPage (EntityPageScaffold) | #### Dashboard Mode (default) ``` ┌──────────────┬─────────────────────────────────────────────────┬────────────┐ │ QUICK LINKS │ PRIMARY CONTENT │ CHAT DOCK │ │ │ │ (expanded) │ │ ▌HOME │ SYSTEM STATS │ │ │ Jellyfin │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │ WebUI │ │ CPU │ │ MEM │ │ DISK │ │ NET │ │ │ │ │ └──────┘ └──────┘ └──────┘ └──────┘ │ │ │ ▌AMP │ │ │ │ AMP Home │ WEATHER AIR QUALITY │ │ │ │ ┌────────────────┐ ┌────────────────┐ │ │ │ ▌INFRA │ │ 72°F Sunny │ │ AQI: 42 Good │ │ │ │ Netdata │ └────────────────┘ └────────────────┘ │ │ │ │ │ │ │ [⚙ Settings] │ │ │ └──────────────┴─────────────────────────────────────────────────┴────────────┘ ``` #### Iframe Mode ``` ┌──────────────┬─────────────────────────────────────────────────┬────────────┐ │ QUICK LINKS │ ┌─────────────────────────────────────────────┐ │ CHAT DOCK │ │ │ │ Jellyfin [↗] [⟳] [✕] │ │ (collapsed)│ │ ▌HOME │ ├─────────────────────────────────────────────┤ │ │ │ ▸Jellyfin │ │ │ │ │ │ WebUI │ │