Phase 2 of Organizr Migration - Front Hall restructure: - Add FrontHallState provider with three modes (dashboard, iframe, settings) - Create QuickLinksPanel widget with categorized links and overflow menus - Add IframeView with platform-aware implementation (web iframe, mobile fallback) - Extract DashboardContent from FrontHallPage - Add QuickLinkSettingsContent placeholder for Phase 4 link editor - Implement QuickLink entity and data layer with Core API datasource - Add default quick links fallback when API unavailable - Update UI_LAYOUT.md with Front Hall panel configurations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
665 lines
38 KiB
Markdown
665 lines
38 KiB
Markdown
# 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 │ │ <iframe src="jellyfin.url"> │ │ │
|
|
│ │ │ │ │ │
|
|
│ ▌AMP │ │ │ │ │
|
|
│ AMP Home │ │ │ │ │
|
|
│ │ │ │ │ │
|
|
│ ▌INFRA │ │ │ │ │
|
|
│ Netdata │ │ │ │ │
|
|
│ │ └─────────────────────────────────────────────┘ │ │
|
|
│ [⚙ Settings] │ │ │
|
|
└──────────────┴─────────────────────────────────────────────────┴────────────┘
|
|
```
|
|
|
|
#### Settings Mode
|
|
```
|
|
┌──────────────┬─────────────────────────────────────────────────┬────────────┐
|
|
│ [←] Links │ ┌─────────────────────────────────────────────┐ │ CHAT DOCK │
|
|
│ │ │ ← Back Edit Quick Link [Save] │ │ (collapsed)│
|
|
│ [+ Add New] │ ├─────────────────────────────────────────────┤ │ │
|
|
├──────────────┤ │ │ │ │
|
|
│ ▌HOME │ │ Name: [Jellyfin_________________] │ │ │
|
|
│ ▸Jellyfin ⋮ │ │ │ │ │
|
|
│ WebUI ⋮ │ │ URL: [https://jellyfin.schweitz...] │ │ │
|
|
│ │ │ │ │ │
|
|
│ ▌AMP │ │ Category: [Home ▼] │ │ │
|
|
│ AMP Home ⋮ │ │ │ │ │
|
|
│ │ │ Type: ◉ Iframe ○ New Tab │ │ │
|
|
│ ▌INFRA │ │ │ │ │
|
|
│ Netdata ⋮ │ │ Icon: [🎬 Pick...] │ │ │
|
|
│ Portainer⋮ │ │ │ │ │
|
|
│ │ │ Active: [✓] │ │ │
|
|
└──────────────┴─────────────────────────────────────────────────┴────────────┘
|
|
```
|
|
|
|
**Settings mode panel behavior:**
|
|
- Back button in header (exits settings mode → dashboard)
|
|
- "+ Add New Link" button at top
|
|
- Each item has overflow menu (Edit, Delete, Move Up/Down)
|
|
- Clicking item selects it for editing in content area
|
|
- Uses EntityPageScaffold pattern (no modals)
|
|
|
|
### 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)
|
|
|
|
Nav panel with grouped section navigation. Chat collapsed.
|
|
|
|
**Current state** (single grouper - headers hidden):
|
|
```
|
|
┌───────────────┬───────────────────────────────────────────────────────┬──────┐
|
|
│ │ │ │
|
|
│ SECTIONS │ CONTAINERS [Search] [+ New] │ 💬 │
|
|
│ │ ─────────────────────────────────────────────────── │ │
|
|
│ ▸ Containers │ ☑ NAME STATUS CPU MEM IMAGE ⋮ │ │
|
|
│ 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 │ ─────────────────────────────────────────────────── │ │
|
|
│ Images │ Showing 3 of 40 < 1 2 3 4 5 > │ │
|
|
│ │ │ │
|
|
│ ▌NPM │ │ │
|
|
│ Proxy Hosts│ │ │
|
|
│ Redirects │ │ │
|
|
│ │ │ │
|
|
│ ▌AUTHENTIK │ │ │
|
|
│ Users │ │ │
|
|
│ Groups │ │ │
|
|
│ │ │ │
|
|
└───────────────┴───────────────────────────────────────────────────────┴──────┘
|
|
```
|
|
|
|
**Components:**
|
|
- 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)
|
|
|
|
---
|
|
|
|
### 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
|
|
|
|
```css
|
|
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
|
|
|
|
```css
|
|
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
|
|
|
|
```dart
|
|
/// 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
|
|
|
|
```dart
|
|
abstract class Breakpoints {
|
|
static const double mobile = 600;
|
|
static const double compact = 800;
|
|
static const double medium = 1200;
|
|
}
|
|
```
|
|
|
|
### Panel Width Constants
|
|
|
|
```dart
|
|
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
|
|
|
|
```dart
|
|
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](../PHILOSOPHY.md) - "Rooms of the Estate" metaphor
|
|
- [ARCHITECTURE.md](./ARCHITECTURE.md) - Clean Architecture patterns
|
|
- [THEMING.md](./THEMING.md) - Material3 color scheme
|
|
- [DATAGRID.md](./DATAGRID.md) - DataGrid component API
|