- Update UI_LAYOUT.md with comprehensive panel taxonomy - Document Nav Panel, Filter Panel, Detail Panel, Chat Dock specs - Add panel header behavior (bottom-docked for left panels) - Add responsive breakpoints with panel folding summary - Create PanelHeader widget with dockToBottom option - Create FilterPanel widget for data filtering sidebars - Refactor Control Room to use FilterPanel - Remove external links from sidebar (cleanup) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
26 KiB
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.
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.
Panel Configurations by Room
Front Hall
┌────────────────────────────────────────────────────────────────┬────────────┐
│ PRIMARY CONTENT (no nav panel) │ CHAT DOCK │
│ Dashboard cards, activity feed │ (expanded) │
└────────────────────────────────────────────────────────────────┴────────────┘
Control Room
┌───────────┬──────────────────────────────────────────────────────┬──────────┐
│ NAV PANEL │ PRIMARY CONTENT │ CHAT │
│ │ ┌────────────┬────────────────────────────────────┐ │ DOCK │
│ Sections: │ │ FILTER │ DATA GRID │ │ │
│ • Contai. │ │ PANEL │ Container/Stack list │ │ (collap- │
│ • Stacks │ │ │ │ │ sed) │
│ • Network │ │ Stack list │ │ │ │
│ • Volumes │ │ + search │ │ │ │
└───────────┴──┴────────────┴────────────────────────────────────┴─┴──────────┘
Parlor
┌───────────┬────────────────────────────────────────────────────┬────────────┐
│ NAV PANEL │ PRIMARY CONTENT │ CHAT DOCK │
│ │ Device controls, scenes │ (collapsed)│
│ Areas: │ │ │
│ • Living │ │ │
│ • Bedroom │ │ │
│ • Kitchen │ │ │
└───────────┴────────────────────────────────────────────────────┴────────────┘
Component Roles
| Component | Flex | Description |
|---|---|---|
| Header Bar | intrinsic (56px) | Logo bulge, room icons, profile menu |
| Nav Panel | flex: 0, 280px |
Room-level section navigation |
| Filter Panel | flex: 0, 280px |
Data filtering within a section |
| Primary Content | flex: 1 |
Main working area |
| Detail Panel | flex: 0, 320-400px |
Selected item details (optional) |
| Chat Dock | flex: 0, intrinsic |
Tatlock assistant, collapsible |
Responsive Breakpoints
Wide (>= 1200px)
┌───────────┬─────────────────────────────────────────────┬────────────────────┐
│ NAV PANEL │ [Filter Panel] [═══ Data Grid ═══] │ CHAT DOCK │
│ (280px) │ (280px) (flex: 1) │ (expanded, 320px) │
└───────────┴─────────────────────────────────────────────┴────────────────────┘
- All panels visible
- Chat dock expanded by default on Front Hall
- Nav panel visible with full labels
- Filter panel visible (where applicable)
- Full data grid columns
Medium (>= 800px, < 1200px)
┌───────────┬───────────────────────────────────────────────────────────┬────┐
│ NAV PANEL │ [Filter Panel] [═══════════ Data Grid ═══════════] │ 💬 │
│ (280px) │ (280px) (flex: 1) │48px│
└───────────┴───────────────────────────────────────────────────────────┴────┘
- Chat dock collapsed to icon rail (48px)
- Click chat icon to expand as overlay
- Nav panel still visible
- Filter panel still visible
- Data grid may hide some columns
Compact (>= 600px, < 800px)
┌────┬───────────────────────────────────────────────────────────────────┬────┐
│ ≡ │ [═══════════════════════ Content ═══════════════════════] │ 💬 │
│48px│ Filter panel becomes top bar or collapsible │48px│
└────┴───────────────────────────────────────────────────────────────────┴────┘
- Nav panel collapses to icon rail (48px), expands as drawer on tap
- Filter panel moves to top of content or becomes collapsible
- Chat dock remains collapsed (48px)
- Data grid shows essential columns only
Mobile (< 600px)
┌────────────────────────────────────────────────────────────────────────┐
│ HEADER: [≡] [Room Icons scroll] ─────────────────────────────── [💬] │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ [═══════════════════════ Content ══════════════════════] │
│ Filter as expandable section at top │
│ │
└────────────────────────────────────────────────────────────────────────┘
- Single column layout
- Nav panel opens as full-screen drawer (hamburger menu)
- Filter panel becomes expandable section at top of content
- Chat opens as bottom sheet (60vh max)
- Data grid becomes card list or single-column table
Panel Folding Summary
| Panel | Wide (≥1200) | Medium (≥800) | Compact (≥600) | Mobile (<600) |
|---|---|---|---|---|
| Nav Panel | 280px visible | 280px visible | 48px rail → drawer | Hidden → drawer |
| Filter Panel | 280px visible | 280px visible | Collapsed/top bar | Expandable section |
| Chat Dock | 320px expanded | 48px rail → overlay | 48px rail → overlay | Icon → bottom sheet |
| Detail Panel | 320-400px slide-in | 320px slide-in | Full-width overlay | Full-screen |
Component Constraints
| Component | Min Width | Max Width | Collapse Behavior |
|---|---|---|---|
| Chat Dock (expanded) | 280px | 33vw | Collapses to icon rail |
| Chat Dock (collapsed) | 48px | 48px | - |
| Context Sidebar | 200px | - | Collapses to 56px icon rail, then drawer |
| Stat Card | 180px | 1fr | Grid reflows |
| Service Card | 120px | 1fr | Grid reflows |
| Data Grid | 400px | - | Horizontal scroll if needed |
Room Wireframes
Front Hall (Dashboard)
Primary landing page. Chat dock expanded by default.
┌─────────────────────────────────────────────────────────────┬─────────────────┐
│ │ │
│ STAT CARDS (auto-fit grid, min 180px) │ TATLOCK CHAT │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────┐ │ │
│ │ CPU │ │ Memory │ │ Disk │ │Containe│ │ [conversation] │
│ │ 45% │ │ 62% │ │ 78% │ │ 34/40 │ │ │
│ │ ████████░░░ │ │ ██████████░ │ │ ███████████ │ │ ██████ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └────────┘ │ │
│ │ │
│ QUICK ACCESS (auto-fill grid, min 120px) │ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ 🎬 │ │ 🔍 │ │ 📚 │ │ 🎮 │ │ 🌐 │ │ │
│ │Jellyfin│ │SearXNG │ │ Wiki │ │ AMP │ │Requests│ │ │
│ │● Online│ │● Online│ │● Online│ │● Online│ │● Online│ │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ │ │
│ RECENT ACTIVITY │ [input field] │
│ ┌────────────────────────────────────────────────────────┐ │ │
│ │ 📦 Container 'ollama' restarted 15 min ago │ │ │
│ │ 🏠 Living room set to evening mode 1 hr ago │ │ │
│ │ 🔄 System backup completed 2 hrs ago │ │ │
│ └────────────────────────────────────────────────────────┘ │ │
│ │ │
└─────────────────────────────────────────────────────────────┴─────────────────┘
Components:
- Stat Cards: CPU, Memory, Disk, Containers
- Quick Access: Service cards grid (external links)
- Recent Activity: Timeline of system events
Control Room (Infrastructure)
Context sidebar with section navigation. Chat collapsed.
┌───────────────┬───────────────────────────────────────────────────────┬──────┐
│ │ │ │
│ SECTIONS │ CONTAINERS [Search] [+ New] │ 💬 │
│ │ ─────────────────────────────────────────────────── │ │
│ ▸ Containers │ ☑ NAME STATUS CPU MEM IMAGE ⋮ │ │
│ Stacks │ ☐ 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 ↗ │ │ │
│ │ │ │
└───────────────┴───────────────────────────────────────────────────────┴──────┘
Components:
- Context Sidebar: Section nav + external links
- DataGrid: Container list with bulk actions
- Detail Panel: Opens on row selection (replaces grid or slides in)
Parlor (Housekeeping)
Context sidebar with areas and scenes. Chat collapsed.
┌───────────────┬───────────────────────────────────────────────────────┬──────┐
│ │ │ │
│ AREAS │ LIVING ROOM │ 💬 │
│ │ ─────────────────────────────────────────────────── │ │
│ ▸ Living Rm │ │ │
│ Bedroom │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ Kitchen │ │ 💡 │ │ 📺 │ │ 🌡️ │ │ 🔌 │ │ │
│ Office │ │ Ceiling │ │ Samsung │ │ Thermo │ │ Outlet 1 │ │ │
│ Garage │ │ 75% │ │ OFF │ │ 72°F │ │ ON │ │ │
│ │ │ ○─────● │ │ [ ] │ │ [-] [+] │ │ [ ] │ │ │
│ ──────────── │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ SCENES │ │ │
│ 🌅 Morning │ SCENES │ │
│ ☀️ Day │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ 🌆 Evening │ │ 🌅 │ │ ☀️ │ │ 🌆 │ │ 🌙 │ │ 🎬 │ │ │
│ 🌙 Night │ │ Morn │ │ Day │ │ Eve │ │Night │ │Movie │ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │ │
└───────────────┴───────────────────────────────────────────────────────┴──────┘
Components:
- Context Sidebar: Area list + scene shortcuts
- Device Grid: Control tiles for current area
- Scene Bar: Quick activation buttons
Grid Specifications
Stat Cards
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
| Viewport Width | Cards per Row |
|---|---|
| >= 900px | 4 |
| >= 720px | 3 |
| >= 540px | 2 |
| < 540px | 1 |
Service Cards
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 0.75rem;
Reflows naturally based on available width.
Chat Dock Behavior
The Tatlock chat assistant is omnipresent - accessible from any room.
| State | Width | Trigger |
|---|---|---|
| Expanded | intrinsic (min 280px, max 33vw) | Default on Front Hall, click icon elsewhere |
| Collapsed | 48px (icon rail) | Default on other rooms, viewport < 1200px |
| Overlay | 90vw or 400px max | Expanded on medium viewports |
| Bottom Sheet | 100vw, 60vh max | Mobile viewports |
| Fullscreen | 100vw, 100vh | User-triggered overlay (future) |
Persistence: Conversation state persists across room navigation.
Future: Fullscreen mode provides an immersive chat experience as a modal overlay, independent of the current room.
Flutter Implementation Notes
Panel Widget Library
All panels are built from shared components in lib/shared/layouts/widgets/:
| Widget | File | Purpose |
|---|---|---|
PanelContainer |
panel_container.dart |
Base container for all panels |
PanelHeader |
panel_header.dart |
Configurable header (bottom-docked or centered) |
NavPanel |
nav_panel.dart |
Left-side room navigation |
FilterPanel |
filter_panel.dart |
Left-side data filtering |
DetailPanel |
detail_panel.dart |
Right-side item details |
ChatDock |
chat_dock.dart |
Right-side AI assistant |
PanelHeader Configuration
/// Panel header with configurable content alignment.
class PanelHeader extends StatelessWidget {
const PanelHeader({
required this.title,
required this.icon,
this.actions,
this.dockToBottom = false, // true for left-side panels
});
}
Left-side panels (Nav, Filter) use dockToBottom: true to accommodate the logo bulge:
- Header height: 56px (matches app header)
- Content aligned to bottom with 8px margin
- Empty space at top allows logo bulge overlay
Right-side panels (Detail, Chat) use dockToBottom: false:
- Standard vertically-centered content
- No accommodation needed for logo bulge
Recommended Widgets
| Concept | Flutter Widget |
|---|---|
| Breakpoint detection | LayoutBuilder, MediaQuery |
| Main layout | Row with Expanded and SizedBox |
| Collapsible dock | AnimatedContainer or AnimatedSize |
| Grid layouts | GridView.builder with SliverGridDelegateWithMaxCrossAxisExtent |
| Drawer fallback | Scaffold.drawer or custom Drawer |
| Bottom sheet chat | showModalBottomSheet or DraggableScrollableSheet |
Breakpoint Constants
abstract class Breakpoints {
static const double mobile = 600;
static const double compact = 800;
static const double medium = 1200;
}
Panel Width Constants
abstract class PanelWidths {
static const double navPanel = 280;
static const double filterPanel = 280;
static const double detailPanel = 360;
static const double chatDockExpanded = 320;
static const double chatDockCollapsed = 48;
static const double railWidth = 48;
}
Layout Builder Pattern
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= Breakpoints.medium) {
return WideLayout(...);
} else if (constraints.maxWidth >= Breakpoints.compact) {
return MediumLayout(...);
} else {
return CompactLayout(...);
}
},
)
Related Documents
- PHILOSOPHY.md - "Rooms of the Estate" metaphor
- ARCHITECTURE.md - Clean Architecture patterns
- THEMING.md - Material3 color scheme
- DATAGRID.md - DataGrid component API