# 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 | | Save indicator | Bare "Saving..." text, top-right, no success/fail states | `` 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 | | Deep breadcrumbs | N/A | Ellipsis collapse: `Root > ... > Parent > Current` | --- ## 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... | | | | | 192px | 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) --- ## 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) | | | | | | | | 192px | 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) --- ## 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... | | | └── API | | | | | | | | 192px | editor (flex-1) | 320px | | | | | +=============================================================================+ ``` - 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: 320px fixed, editor remains `flex-1` --- ## 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) - `...` is a dropdown trigger showing collapsed intermediate segments - Last two segments always visible - Clicking `...` opens a popover with the full path as clickable links: ``` +---------------------------+ | System Design | | Backend Architecture | | API Layer | +---------------------------+ ``` --- ## Page Tree Sidebar Detail ``` +--------------------------+ | Pages [+] | | | | ├── Architecture [+] | <-- [+] on hover: create child | │ ├── Overview | <-- active page: bg-accent | │ └── Decisions | | ├── Requirements [+] | | └── API Design [+] | | | +--------------------------+ 192px, border-right ``` - Header `[+]` always visible (new in v2) -- creates page under root - Node `[+]` on hover only (unchanged from v1) - FileText icon + truncated title per node - Active page: `bg-accent rounded-md` highlight - Indentation: 12px per depth level - Click navigates; keyboard nav not yet implemented --- ## Loading State ``` +=============================================================================+ | +----------+ | +------------------------------------------+ | | | ░░░░░░ | skeleton | | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | | | | ░░░░░░ | h-64 w-48 | | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | | | | ░░░░░░ | | | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | | | +----------+ | +------------------------------------------+ | | 192px | flex-1 | +=============================================================================+ ``` - Shown while `rootPageQuery.isLoading` - Skeleton shimmer components from `@/components/Skeleton` --- ## Error State ``` +=============================================================================+ | | | [AlertCircle] | | Failed to load editor: | | | | 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`