docs: add Deep Space UI redesign spec

Full visual overhaul spec — new color system, typography (Manrope + IBM
Plex Mono), component language, layout restructure with Context Strip,
and 4-phase implementation plan. WCAG AA compliant in both modes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-16 16:58:49 -05:00
parent 2b08cc5898
commit 421808e0ac

View File

@@ -0,0 +1,292 @@
# Deep Space UI Redesign
Full visual overhaul of The Other Dude's frontend — replacing the generic shadcn/slate/cyan aesthetic with a distinctive identity built for network engineers and MSPs.
## Problem
The current UI is visually indistinguishable from every other AI-generated dashboard. The slate/cyan color scheme, default shadcn component styling, and feature-organized navigation are so generic that other MikroTik dashboard projects (e.g., MikroDash) look like the same app. TOD has no visual identity.
## Goals
- **Distinctive identity** — you should never confuse TOD with a template
- **Functional clarity** — DigitalOcean/Hetzner energy, not Unifi complexity
- **WCAG AA compliance** — 4.5:1 text contrast, 3:1 UI elements, both modes
- **Both modes polished** — dark is the primary identity, light is equally considered
- **Desktop-first** — responsive works, but optimized for laptop/desktop workflows
## Design Direction: Deep Space
Dark but not cold. Deep blue-blacks instead of gray-slate. Indigo/violet accent instead of cyan. Subtle gradients for depth. Typography and spacing create hierarchy instead of colored cards and heavy borders.
Reference points: DigitalOcean, Hetzner, Linode for functional clarity. cPanel for density that works. Not Unifi. Not generic shadcn.
---
## 1. Color System
### Dark Mode (Primary)
| Token | Value | Usage |
|-------|-------|-------|
| background | `#111113` | Page background, near-black with warm undertone |
| surface | `#141420` | Cards, panels, elevated content areas |
| elevated | `#1a1a2e` | Inputs, hover states, KPI card gradient base |
| border | `rgba(255,255,255,0.06)` | Default borders — thin, not heavy |
| border-bright | `#24243d` | Emphasized borders, section dividers |
| text-primary | `#e4e4ed` | Headings, device names, primary content |
| text-secondary | `#8a8aa0` | Metadata, secondary labels, IP addresses (4.6:1 on background) |
| text-muted | `#62627f` | Placeholders, column headers, tertiary info (3.2:1 on background) |
| accent | `#818cf8` | Primary interactive color (indigo-400) |
| accent-hover | `#6366f1` | Hover/pressed state (indigo-500) |
| accent-subtle | `rgba(99,102,241,0.15)` | Active nav, selected states, ghost-fill buttons |
### Light Mode
| Token | Value | Usage |
|-------|-------|-------|
| background | `#fafafe` | Page background, barely-tinted white |
| surface | `#ffffff` | Cards, panels |
| elevated | `#f0f0f8` | Inputs, hover states — blue-violet undertone |
| border | `rgba(0,0,0,0.08)` | Default borders |
| border-bright | `#dcdce8` | Emphasized borders |
| text-primary | `#111113` | Headings, primary content |
| text-secondary | `#52526b` | Metadata, secondary labels |
| text-muted | `#8585a0` | Placeholders, disabled text |
| accent | `#5558e6` | Primary interactive color (4.6:1 on white, 4.4:1 on background) |
| accent-hover | `#4f46e5` | Hover/pressed state (indigo-600) |
| accent-subtle | `rgba(99,102,241,0.1)` | Active states |
### Status Colors
| Status | Dark | Light | Meaning |
|--------|------|-------|---------|
| success | `#22c55e` | `#16a34a` | Online, healthy |
| warning | `#f59e0b` | `#d97706` | Degraded, attention needed |
| error | `#ef4444` | `#dc2626` | Offline, critical |
| info | `#3b82f6` | `#2563eb` | Informational |
### Gradient Pattern
KPI cards and elevated surfaces use a subtle directional gradient for depth:
```
Dark: linear-gradient(135deg, #1a1a2e 0%, #16162a 100%)
Light: linear-gradient(135deg, #f8f8ff 0%, #f0f0f8 100%)
```
Status indicator dots use a subtle glow:
```
box-shadow: 0 0 6px rgba({color}, 0.3)
```
---
## 2. Typography
### Fonts
- **UI text:** Manrope — geometric, semi-rounded, modern without being trendy
- **Data values:** IBM Plex Mono — wider and more readable than most monospaces, designed for infrastructure UIs
- **Fallbacks:** system-ui, -apple-system, sans-serif (UI) / ui-monospace, monospace (data)
### Type Scale
| Role | Size | Weight | Font | Extra |
|------|------|--------|------|-------|
| Page title | 18px | 600 | Manrope | letter-spacing: -0.3px |
| Section heading | 14px | 600 | Manrope | — |
| Body text | 13px | 500 | Manrope | Nav items, device names |
| Small text | 11px | 500 | Manrope | Metadata, model names |
| Micro label | 10px | 600 | Manrope | uppercase, letter-spacing: 1.2px |
| Mono large | 22-24px | 500 | IBM Plex Mono | tabular-nums, KPI values |
| Mono inline | 12px | 400 | IBM Plex Mono | tabular-nums, IPs/percentages |
| Mono small | 11px | 400 | IBM Plex Mono | tabular-nums, table cells |
### Principles
- No text larger than 18px — this is a dense tool, not a marketing site
- Monospace only for actual data values (numbers, IPs, percentages, durations)
- Uppercase micro labels for section/column headers create hierarchy without size
- `font-variant-numeric: tabular-nums` on all monospace so numbers align
### Font Loading
Self-host both fonts via `@fontsource/manrope` and `@fontsource-variable/ibm-plex-mono` npm packages. No Google Fonts CDN — the app may run on air-gapped or restricted networks. Import only the weights used (400, 500, 600, 700 for Manrope; 400, 500 for IBM Plex Mono).
### Transitions
All interactive state changes (hover, focus, active, color-scheme toggle): `150ms ease`. Sidebar collapse: `200ms ease`. Dialog enter/exit: `150ms ease`. Respect `prefers-reduced-motion` by disabling all transitions/animations.
---
## 3. Component Language
### Border Radius
- Cards/panels: 8px
- Buttons/inputs/pills: 6px
- Status dots/avatars: 50%
- No `rounded-full` pill buttons
### Depth Model
- **Borders over shadows** — zero box-shadows on cards. Thin borders for structure.
- Dark: `rgba(255,255,255,0.06)` default, `#24243d` emphasized
- Light: `rgba(0,0,0,0.08)` default, `#dcdce8` emphasized
### Buttons
- **Primary:** Ghost-fill — `background: accent-subtle; color: accent`. Solid indigo only for critical CTAs (e.g., "Add device" gets `background: accent; color: white`).
- **Secondary:** Border-only — `border: 1px solid border; color: text-secondary`
- **Destructive:** Ghost-fill in red — same pattern as primary but with error tokens
- All 6px radius, no pill shapes
- All button colors derive from mode-aware tokens — no hardcoded values
### Inputs
- Background: `#1a1a2e` (dark) / `#f0f0f8` (light)
- Border: thin, default color
- Focus: border-color changes to accent — no ring glow
- Radius: 6px
- Placeholder: text-muted color
### Tables
- No alternating row colors
- Thin bottom borders: `rgba(255,255,255,0.06)` (dark) / `rgba(0,0,0,0.06)` (light) — uses border token, intentionally subtle
- Column headers: uppercase micro labels in text-muted
- Status dots inline, not colored row backgrounds
- Monospace for data columns (IP, CPU, uptime)
### Tabs/Pills
- Active: ghost-fill accent background + accent text color
- Inactive: plain muted text, no background
- No underlines or heavy active indicators
### Dialogs/Modals
- Surface background with thin border
- Backdrop: `rgba(0,0,0,0.6)` with subtle blur
- Same 8px radius as cards
---
## 4. Layout Structure
### Context Strip (Top Bar — 36px height)
Always-visible horizontal bar providing at-a-glance status:
- **Left:** Org switcher — icon + name + dropdown chevron. Adaptive: prominent for multi-org MSPs, minimal for single-org users. Separated from status indicators by a thin vertical border.
- **Center:** Live status indicators — clickable items that filter/navigate:
- Red dot + "2 down" (navigates to offline devices)
- Amber dot + "4 degraded" (navigates to degraded devices)
- "WiFi OK" or "WiFi 3 issues" (navigates to wireless view)
- "BW 4.2G" in monospace (navigates to traffic view)
- **Right:** Command palette shortcut (⌘K), connection status dot, user avatar
The strip replaces the need for a separate alerts page as the primary "is anything broken" indicator.
**Data source:** The strip derives its counts from the existing fleet summary API (`metricsApi.fleetSummary`) which already returns device status counts and aggregate metrics. No new API endpoint needed — the strip subscribes to the same React Query cache that the dashboard uses. Status updates arrive via the existing WebSocket device-status subscription. WiFi and bandwidth indicators aggregate from the same data source.
### Sidebar (180px, collapsible to 56px icon-only)
Three sections organized by user intent:
**Fleet** (monitoring — "what's happening")
- Overview — dashboard with KPIs, fleet health
- Devices — full device table with search/filter
- Wireless — AP status, client counts, signal quality
- Traffic — bandwidth charts, top talkers
**Config** (changes — "do something")
- Editor — live config editor with menu tree
- Templates — config templates, push wizard
- Firmware — version management, upgrades
**Admin** (management — "who and how")
- Users — user management, roles
- Audit Log — action history
- Settings — tenant settings, alert rules, notifications
Section labels: uppercase micro labels in muted text. Active nav item: ghost-fill accent background. Inactive: plain muted text.
Version identifier at bottom: `TOD v9.5` in mono micro text.
### Main Content Area
- Full width of remaining space
- 20px padding
- Page header: title (18px semibold) + subtitle (11px muted) left, action buttons right
- KPI cards in a row below header where applicable
- Primary content (tables, charts, forms) below KPIs
---
## 5. Responsive Strategy
Desktop-first. Mobile works in a pinch.
- **Context strip:** Collapses to thin bar with alert count badge on mobile. Tap to expand.
- **Sidebar:** Slide-out drawer via hamburger on mobile.
- **KPI cards:** 4-col → 2-col (tablet) → 1-col (phone)
- **Device table:** Switches to card/list view on phone (no horizontal scroll tables)
- **Touch targets:** Minimum 44px height on interactive elements (WCAG 2.5.8)
- **Type scale:** No changes needed — 11-13px body is native mobile scale. 10px micro labels stay legible due to uppercase + wide letter-spacing.
---
## 6. Implementation Phases
### Phase 1 — Design Tokens & Foundation
**Risk: Low | Impact: High | Disruption: Minimal**
- Replace HSL color tokens in `index.css` with Deep Space palette (dark + light)
- Swap Geist for Manrope + IBM Plex Mono in Tailwind config
- Update custom properties and Tailwind theme mapping
- Add new border/radius/shadow conventions to base styles
- At end of phase: flip the switch — entire app gets new palette and fonts via tokens
Files touched: `index.css`, `tailwind.config.ts`, font imports
### Phase 2 — Component Restyling
**Risk: Low | Impact: High | Disruption: Low**
- Update shared UI primitives: Button, Input, Card, Dialog, Select, Checkbox, Skeleton, Badge, Tabs
- Kill box-shadows, update border radii, implement ghost-fill button style
- Update focus states (border-color change instead of ring glow)
- Changes propagate through entire app via shared components
Files touched: `components/ui/*.tsx`
### Phase 3 — Layout Restructure
**Risk: Medium | Impact: High | Disruption: Medium**
- Replace AppLayout shell — new sidebar structure, new Context Strip header
- Build the Context Strip component with live status indicators
- Reorganize sidebar navigation (Fleet / Config / Admin)
- Update route structure if nav paths change
- Remove old header component
Files touched: `components/layout/AppLayout.tsx`, `Sidebar.tsx`, new `ContextStrip.tsx`, route files
### Phase 4 — Page-Level Polish
**Risk: Low | Impact: Medium | Disruption: Low**
- Refine each page: dashboard KPIs, device table, config editor, alerts integration
- Ensure gradient KPI cards, table styling, form layouts match spec
- Light mode QA pass — verify WCAG contrast on every page
- Fix any spots where old layout assumptions break with new structure
Files touched: page components, dashboard widgets, table components
---
## 7. What This Is Not
- Not a rewrite — same React/Radix/Tailwind stack, same business logic
- Not a mobile redesign — responsive adaptations only
- Not a component library migration — still Radix UI primitives, restyled
**Note:** The Context Strip is the one piece of genuinely new UI (not just restyling). It replaces the current header and surfaces existing data in a new way. Phase 3 should be scoped accordingly — it's the only phase that introduces a new component with its own data needs.
## 8. Success Criteria
- The app is visually unrecognizable compared to its current state
- Nobody mistakes it for a shadcn template or another MikroTik dashboard
- Both dark and light modes pass WCAG AA contrast checks
- The indigo/violet accent and Manrope/IBM Plex Mono pairing create a recognizable identity
- Network engineers see a tool that respects their workflow, not a generic SaaS dashboard