14 files in docs/wireframes/v2/ addressing 13 UX gaps from v1: - Theme spec with indigo brand, status tokens, terminal/diff tokens, dark mode, Geist typography, 6px radius, layered shadows - Wireframes for all pages with loading/error/empty states - Shared component specs (SaveIndicator, EmptyState, ErrorState, CommandPalette, ThemeToggle)
12 KiB
Shared Components (v2)
NEW — no v1 equivalent
Reusable component specifications used across multiple pages. Each component includes: description, props/API, ASCII mockups of all states, usage locations, and proposed source file path.
1. <SaveIndicator>
Inline status indicator for auto-save operations. Shows current save state with icon + label, auto-hides on success.
Props
interface SaveIndicatorProps {
status: 'idle' | 'saving' | 'saved' | 'error';
onRetry?: () => void;
}
States
Idle: (hidden — renders nothing)
Saving: [spinner] Saving...
Saved: [v] Saved <- fades out after 2s, transitions to idle
Error: [!] Failed to save [retry]
Detailed ASCII
Saving
+---------------------------+
| [spinner] Saving... |
+---------------------------+
text-muted-foreground text-sm- Spinner is a 14px animated SVG
Saved
+---------------------------+
| [v] Saved |
+---------------------------+
text-green-600 text-sm- Checkmark icon, 14px
- Fades to
opacity-0over 300ms after 2s delay, then sets status toidle
Error
+--------------------------------------+
| [!] Failed to save [retry] |
+--------------------------------------+
text-destructive text-sm- Alert icon, 14px
[retry]is a text button:text-destructive underline cursor-pointer- Does not auto-hide — persists until retry succeeds or user navigates away
Usage
| Page | Location |
|---|---|
| Content tab | Top-right of Tiptap editor toolbar (see content-tab.md) |
| Plan tab | Top-right of phase description editor (see plan-tab.md) |
Source
packages/web/src/components/SaveIndicator.tsx(proposed)
2. <EmptyState>
Centered placeholder shown when a list or section has no items. Configurable icon, messaging, and optional CTA button.
Props
interface EmptyStateProps {
icon: React.ReactNode; // e.g., <Inbox />, <ListTodo />, <Users />
title: string; // e.g., "No initiatives yet"
description?: string; // e.g., "Create an initiative to get started."
action?: {
label: string; // e.g., "New Initiative"
onClick: () => void;
};
}
Default (with action)
+-------------------------------------------+
| |
| [icon] |
| No phases yet |
| Add a phase to start planning. |
| |
| [ Add Phase ] |
| |
+-------------------------------------------+
Without action
+-------------------------------------------+
| |
| [icon] |
| No conversations yet |
| Questions from agents appear here. |
| |
+-------------------------------------------+
Without description
+-------------------------------------------+
| |
| [icon] |
| No agents running |
| |
+-------------------------------------------+
Styling
- Container:
flex flex-col items-center justify-center py-16 text-center - Icon:
h-12 w-12 text-muted-foreground mb-4 - Title:
text-lg font-medium text-foreground mb-1 - Description:
text-sm text-muted-foreground mb-6 - Action button: default shadcn
<Button>variant
Usage
| Page | Title | Has Action? |
|---|---|---|
| Initiatives list (no data) | "No initiatives yet" | Yes — "New Initiative" |
| Initiatives list (no match) | "No matching initiatives" | No — text link instead |
| Plan tab (no phases) | "No phases yet" | Yes — "Add Phase" |
| Execution tab (no tasks) | "No tasks to execute" | No |
| Agents page (no agents) | "No agents running" | No |
| Inbox page (no conversations) | "No conversations yet" | No |
| Settings > Accounts (none) | "No accounts registered" | Yes — "Add Account" |
Source
packages/web/src/components/EmptyState.tsx(proposed)
3. <ErrorState>
Centered error display with optional retry action. Used when a data fetch fails or a section encounters an unrecoverable error.
Props
interface ErrorStateProps {
message: string; // e.g., "Failed to load initiatives"
onRetry?: () => void; // If provided, shows Retry button
}
With retry
+-------------------------------------------+
| |
| [AlertCircle] |
| Failed to load initiatives |
| |
| [ Retry ] |
| |
+-------------------------------------------+
Without retry (navigation fallback)
+-------------------------------------------+
| |
| [AlertCircle] |
| Error loading initiative |
| Could not fetch initiative data. |
| |
| [ Back to Initiatives ] |
| |
+-------------------------------------------+
Note: The "without retry" variant is not a prop configuration of <ErrorState>
itself. Pages that need navigation instead of retry render <ErrorState>
without onRetry and add their own navigation button below it.
Styling
- Container:
flex flex-col items-center justify-center py-16 text-center - Icon:
h-12 w-12 text-destructive mb-4(AlertCircle from lucide-react) - Message:
text-lg font-medium text-foreground mb-4 - Retry button:
<Button variant="outline">Retry</Button>
Usage
| Page | Message | Has Retry? |
|---|---|---|
| Initiatives list | "Failed to load initiatives" | Yes |
| Initiative detail | "Error loading initiative" | No (nav button) |
| Review tab | "Failed to load proposals" | Yes |
| Agents page | "Failed to load agents" | Yes |
| Settings page | "Failed to load settings" | Yes |
Source
packages/web/src/components/ErrorState.tsx(proposed)
4. <CommandPalette>
Global search overlay triggered by keyboard shortcut. Provides quick navigation to initiatives, agents, tasks, and settings pages.
Trigger
Cmd+K(Mac) /Ctrl+K(Windows)- Header button
[cmd-k](see app-layout.md)
Props
interface CommandPaletteProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
Internally fetches data via tRPC queries (initiatives, agents, tasks).
Default State (open, empty query)
+----------------------------------------------------------+
| [search] Search everything... [Esc] |
| --------------------------------------------------------|
| Recent |
| -> Auth System Overhaul |
| -> Agents |
| -> Settings |
+----------------------------------------------------------+
Shows recent navigation history when search is empty.
With Search Results
+----------------------------------------------------------+
| [search] auth___ [Esc] |
| --------------------------------------------------------|
| Initiatives |
| Auth System Overhaul [ACTIVE] |
| --------------------------------------------------------|
| Tasks |
| Implement auth middleware [execute] 3/7 |
| Review auth token flow [verify] done |
| --------------------------------------------------------|
| Agents |
| blue-fox-7 (auth middleware) [RUNNING] |
+----------------------------------------------------------+
No Results
+----------------------------------------------------------+
| [search] xyznonexistent___ [Esc] |
| --------------------------------------------------------|
| |
| No results for "xyznonexistent" |
| |
+----------------------------------------------------------+
Keyboard Navigation
[search] auth___ [Esc]
---------------------------------------------------------
Initiatives
> Auth System Overhaul [ACTIVE] <- highlighted
---------------------------------------------------------
Tasks
Implement auth middleware [execute] 3/7
>indicates the currently highlighted itemArrow Up/Arrow Down— move highlightEnter— navigate to highlighted item, close paletteEsc— close palette- Type to filter — results update as you type (debounced 100ms)
Result Groups
| Group | Source | Display |
|---|---|---|
| Initiatives | listInitiatives query |
Name + status badge |
| Tasks | listTasks query (across initiatives) |
Name + category + status |
| Agents | listAgents query |
Name + task description + status badge |
| Pages | Go to Initiatives, Go to Agents, etc. |
Static navigation items |
Groups are hidden when they have 0 matches. Max 5 items per group.
Overlay Behavior
- Renders as a centered modal with backdrop (
bg-black/50) - Width:
max-w-lg(512px) - Position:
top-[20%]of viewport - Backdrop click closes the palette
- Focus is trapped inside the modal while open
- Search input auto-focuses on open
Source
packages/web/src/components/CommandPalette.tsx(proposed)
5. <ThemeToggle>
3-state segmented control for switching between light, system, and dark
color schemes. Persists selection to localStorage.
Props
// No props — reads/writes theme from ThemeProvider context
// ThemeProvider wraps the app root
type Theme = 'light' | 'system' | 'dark';
States
Light active: [*sun*] [monitor] [moon]
System active: [sun] [*monitor*] [moon]
Dark active: [sun] [monitor] [*moon*]
Detailed ASCII
Light mode selected
+-----+----------+---------+
| sun | monitor | moon |
+-----+----------+---------+
^^^
filled bg, active text
System mode selected (default)
+-----+----------+---------+
| sun | monitor | moon |
+-----+----------+---------+
^^^^^^^^
filled bg, active text
Dark mode selected
+-----+----------+---------+
| sun | monitor | moon |
+-----+----------+---------+
^^^^^^
filled bg, active text
Styling
- Container:
inline-flex rounded-lg bg-muted p-0.5 gap-0.5 - Segment (inactive):
px-2 py-1 rounded-md text-muted-foreground hover:text-foreground - Segment (active):
px-2 py-1 rounded-md bg-background text-foreground shadow-sm - Icons: 16px lucide-react icons (
Sun,Monitor,Moon) - No text labels — icons only in the header (compact)
Tooltip on hover
[sun] -> "Light"
[monitor] -> "System"
[moon] -> "Dark"
Persistence
- Stored in
localStoragekeycw-theme - Default:
system - On load: reads
localStorage, appliesclass="dark"to<html>if theme isdarkor if theme issystemandprefers-color-scheme: dark
Usage
| Page | Location |
|---|---|
| App layout (header) | Right cluster, between Cmd+K button and health dot |
See app-layout.md for header placement.
Source
packages/web/src/components/ThemeToggle.tsx(proposed)packages/web/src/providers/ThemeProvider.tsx(proposed)
Cross-Reference Index
Quick lookup of which shared components are used on each page.
| Component | app-layout | initiatives-list | initiative-detail | content-tab | plan-tab | execution-tab | review-tab | agents | inbox | settings |
|---|---|---|---|---|---|---|---|---|---|---|
| SaveIndicator | x | x | ||||||||
| EmptyState | x | x | x | x | x | x | ||||
| ErrorState | x | x | x | x | x | |||||
| CommandPalette | x | |||||||||
| ThemeToggle | x |