13 files reviewed with mission-control design lens. Key additions: - theme: extended indigo scale, 4-level surface hierarchy, 22 terminal tokens, transition/z-index/focus-visible token categories - All screens: keyboard shortcuts, loading/error/empty states hardened - 5 new shared components: StatusDot, SkeletonLoader, Toast, Badge, KeyboardShortcutHint - settings: expanded from 2 to 5 sub-pages (accounts, workspace, danger zone) - review-tab: 3-pane layout, inline comments, file nav, hunk controls - execution-tab: zoom, partial failure state, stale agent detection - dialogs: 2 bugs found (mutation locking, error placement) Total: 4,039 → 9,302 lines (+130% from review pass)
721 lines
31 KiB
Markdown
721 lines
31 KiB
Markdown
# Content Tab (v2)
|
|
|
|
### Route: `/initiatives/$id` (Content tab)
|
|
### Source: `packages/web/src/components/editor/ContentTab.tsx`, `packages/web/src/components/editor/`
|
|
|
|
---
|
|
|
|
## v1 -> v2 Changes
|
|
|
|
| Aspect | v1 | v2 |
|
|
|--------|----|----|
|
|
| Breadcrumbs | None | `Root > Parent > Current` row above title, clickable |
|
|
| Deep breadcrumbs | N/A | Ellipsis collapse with dropdown: `Root > [...] > Parent > Current` |
|
|
| Save indicator | Bare "Saving..." text, top-right, no success/fail states | `<SaveIndicator>` component: spinner, checkmark (fade), error + retry |
|
|
| Empty root page | Blank editor, no guidance | Tiptap placeholder: "Start writing... use / for commands" |
|
|
| Root page creation | Only via tree context menu hover `[+]` on nodes | Additional `[+]` button in sidebar header for root-level pages |
|
|
| Sidebar width | 192px (`w-48`) | 240px (`w-60`) — accommodates deep nesting + truncation |
|
|
| Page tree search | None | Collapsible filter input in sidebar header |
|
|
| Drag-and-drop | None | Reorder + re-parent via dnd-kit |
|
|
| Keyboard nav (tree) | None | Arrow keys, Enter, Home/End |
|
|
| Refine panel layout | Above editor (banner) | Right column (360px) at >= 1280px viewport |
|
|
| Refine panel detail | Minimal (spinner + text) | Full state machine: idle, running (live output), questions, proposals, crashed |
|
|
| Read-only lockout | None | Visual indicator when agent is actively refining |
|
|
| Word count | None | Bottom-right of editor area |
|
|
| Slash command menu | Functional but not documented | Wireframed floating popover with all command options |
|
|
|
|
---
|
|
|
|
## Default State (with content)
|
|
|
|
```
|
|
+=================================================================================+
|
|
| Pages [+] | Root > Architecture > Current Page |
|
|
| --------------------------+ [✓] Saved |
|
|
| ├── Architecture | ----------------------------------------------------|
|
|
| │ ├── Overview | |
|
|
| │ └── Decisions | # Authentication Architecture |
|
|
| ├── Requirements | |
|
|
| └── API Design | This document outlines the OAuth 2.0 |
|
|
| | implementation strategy for... |
|
|
| | |
|
|
| | ~1,240 words · 5m |
|
|
| 240px | editor area (flex-1) |
|
|
| | |
|
|
+=================================================================================+
|
|
```
|
|
|
|
- `[+]` in sidebar header creates a new root-level child page
|
|
- Breadcrumb segments are clickable links that call `onNavigate(pageId)`
|
|
- `[✓] Saved` indicator fades after 2s via CSS opacity transition
|
|
- Tree nodes still show hover `[+]` for nested child creation (unchanged from v1)
|
|
- Word count + reading time displayed bottom-right of editor, `text-xs text-muted-foreground`
|
|
|
|
---
|
|
|
|
## Empty Root Page (placeholder)
|
|
|
|
```
|
|
+=================================================================================+
|
|
| Pages [+] | Root |
|
|
| --------------------------+ |
|
|
| (empty tree) | ----------------------------------------------------|
|
|
| | |
|
|
| | My Initiative Name |
|
|
| | ^^^^^^^^^^^^^^^^^^^^^^ |
|
|
| | 3xl bold title input |
|
|
| | |
|
|
| | Start writing... use / for commands |
|
|
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
|
| | muted placeholder text (text-muted-foreground) |
|
|
| | |
|
|
| | |
|
|
| 240px | editor area (flex-1) |
|
|
| | |
|
|
+=================================================================================+
|
|
```
|
|
|
|
- Placeholder uses `@tiptap/extension-placeholder` with `emptyEditorClass`
|
|
- Placeholder text disappears on focus/first keystroke
|
|
- Root page title maps to `initiativeName` (edits update initiative, not page)
|
|
|
|
### Slash Command Menu Preview
|
|
|
|
When user types `/` at the start of a line (or after a space), the command menu
|
|
appears as a floating popover anchored to the cursor position:
|
|
|
|
```
|
|
| |
|
|
| /___ |
|
|
| +--------------------------------------+ |
|
|
| | [H1] Heading 1 | <- highlighted
|
|
| | [H2] Heading 2 |
|
|
| | [H3] Heading 3 |
|
|
| | [¶] Bullet List |
|
|
| | [#] Numbered List |
|
|
| | ["] Blockquote |
|
|
| | [—] Divider |
|
|
| | [<>] Code Block |
|
|
| | [+] Subpage | <- creates child + inserts link
|
|
| +--------------------------------------+ |
|
|
| surface: popover, shadow-md, max-h-64 scroll |
|
|
```
|
|
|
|
- Appears on `/` keystroke; filters as user types (e.g., `/head` shows only headings)
|
|
- `Arrow Up` / `Arrow Down` to navigate; `Enter` to select; `Esc` to dismiss
|
|
- Each item: icon (16px, `text-muted-foreground`) + label (`text-sm`)
|
|
- Popover: `bg-popover border border-border rounded-md shadow-md`
|
|
- Max height: `max-h-64 overflow-y-auto` with scroll
|
|
- Highlighted item: `bg-accent text-accent-foreground`
|
|
|
|
---
|
|
|
|
## Save Indicator States
|
|
|
|
Three-state component positioned top-right of editor area, inline with breadcrumb row.
|
|
|
|
### Saving (spinner)
|
|
|
|
```
|
|
Root > Architecture > Current Page [spinner] Saving...
|
|
```
|
|
|
|
- `Loader2` icon with `animate-spin`, `text-muted-foreground`
|
|
- Shown while `isSaving` or `updateInitiativeMutation.isPending`
|
|
|
|
### Saved (checkmark, fading)
|
|
|
|
```
|
|
Root > Architecture > Current Page [✓] Saved
|
|
```
|
|
|
|
- Green checkmark icon, `text-green-500`
|
|
- Fades to `opacity-0` after 2s via `transition-opacity duration-1000`
|
|
- Resets to full opacity on next save cycle
|
|
|
|
### Failed (error with retry)
|
|
|
|
```
|
|
Root > Architecture > Current Page [!] Failed [retry]
|
|
```
|
|
|
|
- `AlertCircle` icon, `text-destructive`
|
|
- `[retry]` is a ghost button that triggers manual save flush
|
|
- Persists until retry succeeds or new edit triggers auto-save
|
|
|
|
---
|
|
|
|
## With Refine Panel Open (3-column layout)
|
|
|
|
```
|
|
+=================================================================================+
|
|
| Pages [+] | Root > Current Page [✓] Saved | Refine with Agent |
|
|
| ---------------+ | ----------------------|
|
|
| ├── Arch | # Auth Architecture | [spinner] Architect |
|
|
| │ ├── Ovw | | is refining... |
|
|
| │ └── Dec | This document outlines the | |
|
|
| ├── Req | OAuth 2.0 implementation... | (see panel detail |
|
|
| └── API | | below) |
|
|
| | | |
|
|
| 240px | editor (flex-1) | 360px |
|
|
| | | |
|
|
+=================================================================================+
|
|
```
|
|
|
|
- Refine panel sits above editor in v1 source (not beside it)
|
|
- v2 proposal: move to right column when viewport >= 1280px
|
|
- Below 1280px, refine panel stays above editor (current v1 behavior)
|
|
- Panel width: **360px** fixed (`w-[360px]`), editor remains `flex-1`
|
|
- **Save indicator placement**: in the 3-column layout, the save indicator stays
|
|
inline with the breadcrumb row, right-aligned within the editor column (middle
|
|
column). It does NOT extend into the refine panel column. The breadcrumb row is
|
|
`flex justify-between` within the editor column only.
|
|
|
|
---
|
|
|
|
## Refine Panel — Internal Layout
|
|
|
|
The refine panel is a right-side column with its own state machine. The wireframe
|
|
must show all states, since this is where the agent-human interaction happens.
|
|
|
|
### State: Idle (no active agent)
|
|
|
|
```
|
|
+-----------------------------------+
|
|
| Refine with Agent |
|
|
| ---------------------------------|
|
|
| |
|
|
| [sparkle icon] |
|
|
| An agent will review all pages |
|
|
| and suggest improvements. |
|
|
| |
|
|
| What should it focus on? |
|
|
| +-------------------------------+|
|
|
| | (optional instruction) ||
|
|
| +-------------------------------+|
|
|
| |
|
|
| [ Start Refine ] |
|
|
| |
|
|
+-----------------------------------+
|
|
```
|
|
|
|
- Panel header: `text-sm font-semibold`, top-left
|
|
- CTA button: `<Button>` default variant, full-width
|
|
- Instruction input: `<Textarea>` with placeholder, optional
|
|
|
|
### State: Running
|
|
|
|
```
|
|
+-----------------------------------+
|
|
| Refine with Agent [stop]|
|
|
| ---------------------------------|
|
|
| [●] Architect | <-- status-active-dot + agent name
|
|
| is refining... |
|
|
| |
|
|
| Elapsed: 0:42 | <-- text-xs text-muted-foreground
|
|
| |
|
|
| Live output: |
|
|
| +-------------------------------+|
|
|
| | > Reading page tree... || <-- terminal-bg, scrollable
|
|
| | > Analyzing Architecture... ||
|
|
| | > Drafting proposals... ||
|
|
| +-------------------------------+|
|
|
| |
|
|
+-----------------------------------+
|
|
```
|
|
|
|
- Live output: mini terminal view, `bg-terminal text-terminal-fg`, `max-h-48 overflow-y-auto`
|
|
- `[stop]` button: ghost variant, `text-destructive` on hover
|
|
- Agent name: `font-mono text-sm`
|
|
- Elapsed timer: updates every second via `setInterval`
|
|
|
|
### State: Agent has questions
|
|
|
|
```
|
|
+-----------------------------------+
|
|
| Refine with Agent |
|
|
| ---------------------------------|
|
|
| Agent has questions |
|
|
| |
|
|
| 1. Should I restructure the |
|
|
| auth section or just refine |
|
|
| the existing text? |
|
|
| +-------------------------------+|
|
|
| | (your answer) ||
|
|
| +-------------------------------+|
|
|
| |
|
|
| 2. Include code examples? |
|
|
| +-------------------------------+|
|
|
| | (your answer) ||
|
|
| +-------------------------------+|
|
|
| |
|
|
| [ Submit Answers ] [ Stop ] |
|
|
| |
|
|
+-----------------------------------+
|
|
```
|
|
|
|
- Questions rendered as numbered list
|
|
- Each answer: `<Textarea>` auto-growing
|
|
- Submit: default button; Stop: destructive-outline button
|
|
- Keyboard: `Cmd+Enter` submits all answers
|
|
|
|
### State: Completed (with proposals)
|
|
|
|
```
|
|
+-----------------------------------+
|
|
| Refine with Agent [dismiss]|
|
|
| ---------------------------------|
|
|
| Agent finished with 3 proposals |
|
|
| |
|
|
| ┌─ Page: Auth Architecture ─────┐|
|
|
| │ Expanded OAuth flow section │|
|
|
| │ with PKCE details │|
|
|
| │ [Accept] [Reject] │|
|
|
| └───────────────────────────────┘|
|
|
| |
|
|
| ┌─ Page: API Endpoints ─────────┐|
|
|
| │ Added rate limiting section │|
|
|
| │ [Accept] [Reject] │|
|
|
| └───────────────────────────────┘|
|
|
| |
|
|
| ┌─ Page: Requirements ──────────┐|
|
|
| │ Clarified NFR-3 latency req │|
|
|
| │ [Accept] [Reject] │|
|
|
| └───────────────────────────────┘|
|
|
| |
|
|
| [ Accept All ] [ Dismiss All ] |
|
|
| |
|
|
+-----------------------------------+
|
|
```
|
|
|
|
- Each proposal: card (`bg-card border rounded-md p-3`)
|
|
- Card header: target page name in `text-xs font-medium text-muted-foreground`
|
|
- Card body: proposal summary in `text-sm`
|
|
- Accept: default button; Reject: ghost button
|
|
- Bulk actions: `Accept All` (primary) + `Dismiss All` (ghost) at bottom
|
|
- Accepted proposals: green checkmark overlay, card fades to `opacity-50`
|
|
- Rejected proposals: strikethrough summary, card fades to `opacity-30`
|
|
|
|
### State: Completed (no changes)
|
|
|
|
```
|
|
+-----------------------------------+
|
|
| Refine with Agent [dismiss]|
|
|
| ---------------------------------|
|
|
| |
|
|
| Agent completed — no changes. |
|
|
| [dismiss] Cmd+Enter |
|
|
| |
|
|
+-----------------------------------+
|
|
```
|
|
|
|
### State: Crashed
|
|
|
|
```
|
|
+-----------------------------------+
|
|
| Refine with Agent |
|
|
| ---------------------------------|
|
|
| [!] Agent crashed |
|
|
| |
|
|
| [ Retry ] |
|
|
| |
|
|
+-----------------------------------+
|
|
```
|
|
|
|
- Error icon: `AlertCircle`, `text-destructive`
|
|
- Retry button opens the spawn dialog again
|
|
|
|
---
|
|
|
|
## Breadcrumb with Deep Nesting (ellipsis collapse)
|
|
|
|
### Depth <= 3: show all segments
|
|
|
|
```
|
|
Root > Architecture > Decisions
|
|
```
|
|
|
|
### Depth > 3: collapse middle with ellipsis
|
|
|
|
```
|
|
Root > [...] > API Endpoints > Rate Limiting
|
|
```
|
|
|
|
- `Root` always visible (first segment, clickable)
|
|
- `[...]` is a **dropdown trigger button** (not static text), styled as
|
|
`text-muted-foreground hover:text-foreground cursor-pointer`
|
|
- Last two segments always visible and clickable
|
|
- Clicking `[...]` opens a `<Popover>` (shadcn/ui) anchored below the ellipsis:
|
|
|
|
```
|
|
Root > [...] > API Endpoints > Rate Limiting
|
|
|
|
|
v
|
|
+---------------------------+
|
|
| > System Design | <-- clickable, navigates
|
|
| > Backend Architecture | <-- clickable, navigates
|
|
| > API Layer | <-- clickable, navigates
|
|
+---------------------------+
|
|
bg-popover, shadow-md, rounded-md
|
|
border border-border
|
|
min-w-[180px]
|
|
```
|
|
|
|
- Each row in the dropdown: `px-3 py-1.5 text-sm hover:bg-accent cursor-pointer`
|
|
- Clicking a row navigates to that page AND closes the popover
|
|
- Popover closes on outside click or `Esc`
|
|
- Implementation: `<Popover>` + `<PopoverTrigger>` + `<PopoverContent>` from shadcn/ui
|
|
- Separator character `>` uses `text-muted-foreground mx-1` (ChevronRight icon, 12px)
|
|
|
|
---
|
|
|
|
## Page Tree Sidebar Detail
|
|
|
|
```
|
|
+--------------------------+
|
|
| Pages [+] |
|
|
| [search filter...] |
|
|
| |
|
|
| ├── Architecture [+] | <-- [+] on hover: create child of Architecture
|
|
| │ ├── Overview | <-- active page: bg-accent
|
|
| │ └── Decisions |
|
|
| ├── Requirements [+] |
|
|
| └── API Design [+] |
|
|
| |
|
|
| ≡ drag handle on hover |
|
|
| |
|
|
+--------------------------+
|
|
240px, border-right
|
|
```
|
|
|
|
### Width rationale
|
|
|
|
192px is too narrow. At 12px indent per level, depth-3 nodes lose ~36px to
|
|
indentation plus ~14px for the icon plus ~20px for the hover `[+]` button.
|
|
That leaves ~122px for the page title — "Authentication Architecture" alone
|
|
is ~180px at `text-sm`. Bump to **240px** (`w-60`). Even at 240px, titles
|
|
will truncate; the truncation + tooltip behavior below handles this.
|
|
|
|
### Truncation + tooltip
|
|
|
|
All page titles render with `truncate` (CSS `text-overflow: ellipsis`).
|
|
On hover, a `<Tooltip>` shows the full title after a 500ms delay.
|
|
Implementation: wrap each node label in `<TooltipTrigger>` from shadcn/ui.
|
|
|
|
### Node behavior
|
|
|
|
- Header `[+]` always visible (new in v2) — creates page under root
|
|
- Node `[+]` on hover only (unchanged from v1) — creates child of **that** node (contextual, not root-level)
|
|
- FileText icon + truncated title per node
|
|
- Active page: `bg-accent rounded-md` highlight
|
|
- Indentation: 12px per depth level
|
|
|
|
### Drag-and-drop reordering
|
|
|
|
Nodes are draggable to reorder within their sibling group or re-parent under
|
|
a different node. Visual feedback:
|
|
|
|
```
|
|
| ├── Architecture |
|
|
| │ ├── Overview |
|
|
| │ ┌─ ─ ─ ─ ─ ─ ─ ┐ | <-- drop indicator (border-primary dashed)
|
|
| │ └── Decisions |
|
|
| ├── Requirements |
|
|
```
|
|
|
|
- Drag handle: `GripVertical` icon, visible on hover (left of FileText icon)
|
|
- Drop targets: between siblings (reorder) or onto a node (re-parent)
|
|
- Drop indicator: 2px dashed `border-primary` line between nodes
|
|
- Implementation: `@dnd-kit/core` + `@dnd-kit/sortable` (already tree-friendly)
|
|
- On drop: call `updatePage({ id, parentPageId, sortOrder })` mutation
|
|
- Root page is not draggable (always first)
|
|
|
|
### Search / filter
|
|
|
|
For initiatives with 20+ pages, the sidebar header includes a collapsible
|
|
search filter:
|
|
|
|
```
|
|
+--------------------------+
|
|
| Pages [search][+]|
|
|
| [filter query____] | <-- shown when [search] toggled
|
|
| |
|
|
| ├── Auth Architecture | <-- matches highlighted
|
|
| │ └── Auth Decisions |
|
|
| |
|
|
+--------------------------+
|
|
```
|
|
|
|
- Toggle: `Search` icon button in header, between title and `[+]`
|
|
- Input: compact text field, `text-xs`, `h-6`, auto-focus on open
|
|
- Filter: fuzzy substring match on page titles, case-insensitive
|
|
- Matching nodes shown with all ancestors (preserves tree context)
|
|
- Non-matching leaf nodes hidden; non-matching branches hidden if no descendants match
|
|
- `Esc` clears filter and collapses the search input
|
|
- Empty state: "No pages match" in `text-muted-foreground text-xs`
|
|
|
|
### Keyboard navigation (new in v2)
|
|
|
|
- `Arrow Down` / `Arrow Up` — move focus between visible tree nodes
|
|
- `Arrow Right` on collapsed node — expand children
|
|
- `Arrow Left` on expanded node — collapse; on leaf — move to parent
|
|
- `Enter` — navigate to focused node (same as click)
|
|
- `Home` / `End` — jump to first / last visible node
|
|
- Focus ring: `ring-2 ring-ring ring-offset-1` on the focused node row
|
|
|
|
---
|
|
|
|
## Read-Only Lockout (Agent Refining)
|
|
|
|
When the refine agent is in `running` state, the editor should enter a read-only
|
|
mode to prevent conflicting edits. The agent is rewriting page content server-side;
|
|
concurrent user edits would be overwritten or cause merge conflicts.
|
|
|
|
```
|
|
+=================================================================================+
|
|
| Pages [+] | Root > Current Page | Refine... |
|
|
| ---------------+ ┌─────────────────────────────────────┐ | |
|
|
| ├── Arch | │ [lock] Editor locked while agent │ | [●] Architect |
|
|
| │ ├── Ovw | │ is refining content │ | is refining... |
|
|
| │ └── Dec | └─────────────────────────────────────┘ | |
|
|
| ├── Req | | |
|
|
| └── API | # Auth Architecture | |
|
|
| | | |
|
|
| | This document outlines the OAuth 2.0 | |
|
|
| | implementation strategy for... | |
|
|
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
|
|
| 240px | text at reduced opacity (opacity-60) | 360px |
|
|
| | | |
|
|
+=================================================================================+
|
|
```
|
|
|
|
- Banner: `bg-status-warning-bg text-status-warning-fg border border-status-warning-border`
|
|
with `Lock` icon (lucide-react), positioned above the title input
|
|
- Editor: `contenteditable="false"`, `opacity-60`, `cursor-not-allowed`
|
|
- Title input: `disabled`, `opacity-60`
|
|
- Banner dismisses automatically when agent finishes (state transitions away from `running`)
|
|
- User can still navigate the page tree and read other pages while locked
|
|
|
|
---
|
|
|
|
## Word Count / Reading Time
|
|
|
|
Persistent footer below the editor content area, right-aligned.
|
|
|
|
```
|
|
| |
|
|
| This document outlines the OAuth 2.0 implementation strategy... |
|
|
| |
|
|
| ~1,240 words · 5m |
|
|
+---------------------------------------------------------------------+
|
|
```
|
|
|
|
- Position: bottom-right of editor area, `text-xs text-muted-foreground`
|
|
- Format: `~{count} words · {minutes}m` (reading time at 250 wpm, rounded up)
|
|
- Calculation: count words from Tiptap `editor.getText()` on each update (debounced 500ms)
|
|
- Only shown when editor has content (hidden on empty/placeholder state)
|
|
- Does not count content inside code blocks differently (plain word count)
|
|
- In 3-column layout: stays within the editor column, does not leak into refine panel
|
|
|
|
---
|
|
|
|
## Loading State
|
|
|
|
```
|
|
+=================================================================================+
|
|
| +------------+ | +--------------------------------------------+ |
|
|
| | ░░░░░░░░ | skeleton | | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | |
|
|
| | ░░░░░░░░ | h-64 w-60 | | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | |
|
|
| | ░░░░░░░░ | | | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | |
|
|
| +------------+ | +--------------------------------------------+ |
|
|
| 240px | flex-1 |
|
|
+=================================================================================+
|
|
```
|
|
|
|
- Shown while `rootPageQuery.isLoading`
|
|
- Skeleton shimmer components from `@/components/Skeleton`
|
|
|
|
---
|
|
|
|
## Error State
|
|
|
|
```
|
|
+=============================================================================+
|
|
| |
|
|
| [AlertCircle] |
|
|
| Failed to load editor: <message> |
|
|
| |
|
|
| Make sure the backend server is running |
|
|
| with the latest code. |
|
|
| |
|
|
| [ Retry ] |
|
|
| |
|
|
+=============================================================================+
|
|
```
|
|
|
|
- `text-destructive` for error message
|
|
- `text-muted-foreground` for help text
|
|
- Retry button calls `rootPageQuery.refetch()`
|
|
|
|
---
|
|
|
|
## Source
|
|
|
|
- `packages/web/src/components/editor/ContentTab.tsx`
|
|
- `packages/web/src/components/editor/PageTree.tsx`
|
|
- `packages/web/src/components/editor/TiptapEditor.tsx`
|
|
- `packages/web/src/components/editor/RefineAgentPanel.tsx`
|
|
- `packages/web/src/components/editor/DeleteSubpageDialog.tsx`
|
|
- `packages/web/src/components/editor/PageTitleContext.tsx`
|
|
- `packages/web/src/hooks/useAutoSave.ts`
|
|
|
|
---
|
|
|
|
## Design Review Notes
|
|
|
|
Critique and improvements applied during design review. Each item references
|
|
the review criterion that prompted the change.
|
|
|
|
### 1. Sidebar width: 192px -> 240px
|
|
|
|
**Problem.** 192px is dangerously tight. At depth 3 with 12px indent per level,
|
|
you burn 36px on indentation, 14px on the FileText icon, 20px on the hover [+]
|
|
button, and 8px on left padding. That leaves ~114px for the title. A page named
|
|
"Authentication Architecture Decisions" at `text-sm` (14px) needs roughly
|
|
280px. You would see "Authenticat..." which is garbage -- users cannot
|
|
distinguish it from "Authentication" or "Authorization". 240px gives ~162px for
|
|
the title, which still truncates long names but shows enough to differentiate.
|
|
The truncation-plus-tooltip pattern catches the rest.
|
|
|
|
**Trade-off.** 48px wider sidebar steals from the editor. At 1280px viewport
|
|
that is ~3.75% of screen width. Acceptable -- the editor still gets flex-1 and
|
|
the content column never drops below ~680px even with the refine panel open
|
|
(1280 - 240 sidebar - 360 refine = 680px editor).
|
|
|
|
### 2. Breadcrumb ellipsis: static text -> dropdown
|
|
|
|
**Problem.** The original spec said `...` collapses middle segments and mentioned
|
|
it was a "dropdown trigger," but the wireframe showed static text and the
|
|
interaction was under-specified. If a user sees `Root > ... > Rate Limiting`
|
|
they have no way to navigate to intermediate pages without going back to the
|
|
tree and hunting.
|
|
|
|
**Fix.** Explicitly wireframed the `[...]` as a `<Popover>` trigger with the
|
|
full hidden path rendered as clickable rows. Specified the component
|
|
(shadcn/ui Popover), the styling, the close behavior, and the row interaction.
|
|
|
|
### 3. Save indicator in 3-column layout
|
|
|
|
**Problem.** If the save indicator is "top-right" of the editor area, and the
|
|
refine panel opens as a third column, does "top-right" mean top-right of the
|
|
entire viewport (overlapping the refine panel) or top-right of the editor
|
|
column?
|
|
|
|
**Fix.** Clarified: the breadcrumb row with the save indicator is `flex
|
|
justify-between` within the **editor column only** (the middle column). It
|
|
does not bleed into the refine panel. The save indicator sits at the right edge
|
|
of the breadcrumb row, which is bounded by the editor column width.
|
|
|
|
### 4. [+] button context
|
|
|
|
**Problem.** Two [+] buttons exist (sidebar header and per-node hover) but the
|
|
original spec did not clearly distinguish their behavior. A user might expect
|
|
the header [+] to create a sibling of the currently selected page, not a
|
|
root-level page.
|
|
|
|
**Fix.** The spec now explicitly states: header [+] always creates under root,
|
|
node hover [+] creates a child of **that specific node**. This is contextual
|
|
by default on the node buttons. The header button is intentionally non-contextual
|
|
(always root) to provide a reliable "new top-level page" entry point.
|
|
|
|
### 5. Drag-and-drop reordering
|
|
|
|
**Problem.** The original wireframe had no drag-and-drop. For a document
|
|
management UI, reordering pages by editing `sortOrder` in a database is not
|
|
a viable UX. Users need to drag.
|
|
|
|
**Fix.** Added a full drag-and-drop section: `GripVertical` handle on hover,
|
|
drop indicators (dashed border-primary lines), re-parenting via drop-on-node,
|
|
and the library choice (`@dnd-kit`). Specified the mutation call
|
|
(`updatePage({ id, parentPageId, sortOrder })`).
|
|
|
|
### 6. Page tree search/filter
|
|
|
|
**Problem.** With 20+ pages (realistic for a detailed initiative), scanning a
|
|
tree visually breaks down. There was no search.
|
|
|
|
**Fix.** Added a collapsible search filter in the sidebar header. Fuzzy
|
|
substring match, ancestor preservation (so matching leaf nodes still show
|
|
their tree path), and `Esc` to clear. The toggle button sits between the
|
|
"Pages" title and the [+] button.
|
|
|
|
### 7. Read-only lockout during agent refine
|
|
|
|
**Problem.** When the refine agent is running, it rewrites page content
|
|
server-side. If the user is simultaneously typing in the editor, the next
|
|
server push will overwrite their changes with no warning. This is a data loss
|
|
scenario.
|
|
|
|
**Fix.** Added a full "Read-Only Lockout" section. The editor goes
|
|
`contenteditable="false"` with reduced opacity and a warning banner using
|
|
status-warning tokens. The lockout auto-clears when the agent finishes. Users
|
|
can still read and navigate during the lock.
|
|
|
|
### 8. Refine panel internal layout
|
|
|
|
**Problem.** The original wireframe showed the refine panel as a 320px column
|
|
with "[spinner] Architect is refining..." and nothing else. The actual
|
|
implementation (verified in `RefineAgentPanel.tsx`) has five distinct states:
|
|
idle (spawn dialog), running (spinner), waiting (question form), completed
|
|
(change set / proposals), and crashed (error + retry). None of these were
|
|
wireframed.
|
|
|
|
**Fix.** Added wireframes for all five states with full internal layout:
|
|
idle with instruction textarea, running with live output terminal, question
|
|
form with numbered questions and answer textareas, completed with per-proposal
|
|
Accept/Reject cards plus bulk actions, and crashed with error + retry button.
|
|
Also bumped the panel from 320px to 360px because the proposal cards with
|
|
Accept/Reject buttons need the room.
|
|
|
|
### 9. Word count / reading time
|
|
|
|
**Problem.** Content pages had no feedback on document length. For planning
|
|
documents that agents will consume, knowing that a page is 3,000 words vs 300
|
|
words matters for understanding agent processing time and content density.
|
|
|
|
**Fix.** Added a persistent `~{words} words · {minutes}m` footer below the
|
|
editor, right-aligned, in `text-xs text-muted-foreground`. Calculation is
|
|
debounced off `editor.getText()`. Hidden on empty state.
|
|
|
|
### 10. Slash command menu
|
|
|
|
**Problem.** The placeholder says "use / for commands" but the wireframe never
|
|
showed what the command menu looks like. A developer implementing this has no
|
|
visual spec for the floating popover.
|
|
|
|
**Fix.** Added a full wireframe of the slash command menu: floating popover
|
|
anchored to cursor, all command options listed with icons, keyboard navigation
|
|
behavior, styling tokens, and scroll behavior for long menus.
|
|
|
|
### Open questions for next review
|
|
|
|
1. **Collaborative editing.** If two humans (or a human + agent) could
|
|
theoretically edit the same page, should the content tab show presence
|
|
indicators (avatars/cursors)? The current lockout approach sidesteps this
|
|
but is not a long-term solution.
|
|
|
|
2. **Page versioning.** Should pages have a revision history? The refine agent
|
|
creates proposals, but if the user manually edits a page and breaks it,
|
|
there is no undo beyond browser undo. A page history (snapshots on save)
|
|
would mitigate this.
|
|
|
|
3. **Tree collapse state persistence.** Should expanded/collapsed tree nodes
|
|
persist across page reloads? Currently the tree is always fully expanded.
|
|
For deep trees, remembering collapse state in `localStorage` or URL state
|
|
would reduce visual noise.
|
|
|
|
4. **Max nesting depth.** Should there be a hard limit on page nesting depth?
|
|
At 12px indent per level, depth 8 consumes 96px of the 240px sidebar.
|
|
Consider capping at depth 5 or 6 and showing a warning if users try to
|
|
nest deeper.
|