From 007e1a5a540e9e9786e7f1c098c4ae6c66c5aa91 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Sat, 18 Apr 2026 09:51:18 +0000 Subject: [PATCH 01/51] checkpoint: pre-yolo 2026-04-18T09:51:18 From 526060ba905515efa2ba8607e646f3cec4daba0a Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Sat, 18 Apr 2026 10:34:37 +0000 Subject: [PATCH 02/51] docs: UI redesign design spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Greenfield rewrite spec for the docsiq web UI. Locks: - Navigation: Linear-style labeled sidebar + Raycast-style prominent ⌘K, with G+letter chord shortcuts, collapsible via ⌘- Responsive: mobile drawer / tablet icon rail / desktop labeled - Home: stats strip + since-last-visit activity feed + right rail - Notes: focused ~620px column with ⌘/ tree and ⌘L links drawers - Visual: Geist Sans+Mono, #0f1115 base, #3ecf8e accent (choice B) - Stack: React 19 + Vite 6 + shadcn/ui + Tailwind 4 + TanStack Query + Zustand + React Router 6 + React Hook Form + Zod + Framer Motion (all reduced-motion-gated) + markdown-it + d3-force + CodeMirror 6 Non-negotiables from rules/ui.md baked in: WCAG AA, prefers-reduced- motion, prefers-color-scheme, 100ms interaction, mobile-first, tokens only, i18n-ready, RTL-ready, fonts self-hosted per rules/build.md. Acceptance criteria (§19) + out-of-scope (§17) + risks (§18) all explicit. Next: invoke superpowers:writing-plans. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../specs/2026-04-18-ui-redesign-design.md | 539 ++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-18-ui-redesign-design.md diff --git a/docs/superpowers/specs/2026-04-18-ui-redesign-design.md b/docs/superpowers/specs/2026-04-18-ui-redesign-design.md new file mode 100644 index 0000000..fc40673 --- /dev/null +++ b/docs/superpowers/specs/2026-04-18-ui-redesign-design.md @@ -0,0 +1,539 @@ +# docsiq UI Redesign — Design Spec + +**Date:** 2026-04-18 +**Status:** Ready for user review +**Supersedes:** current hand-rolled React + CSS UI under `ui/src/` +**Follows rules:** `~/.claude/rules/{ui,build,testing,performance,dependencies,security,git}.md` + +--- + +## 1. Goal + +Greenfield redesign of docsiq's embedded web UI. One coherent, keyboard-first, responsive interface for an investigator-style workflow, replacing the hand-rolled React + CSS implementation that grew from the kgraph port. + +Backend API and MCP surface remain unchanged (acceptance criterion). UI ships as static assets embedded via `//go:embed ui/dist/` in the Go binary — same distribution story as today. + +--- + +## 2. User profile + dominant workflow + +**Solo developer. UI-secondary.** Primary interface is Claude Code via MCP tools + hooks. UI is opened 5–20 min/day to: + +- browse notes captured automatically during AI sessions +- search across notes and indexed docs +- investigate the entity graph +- debug MCP tool calls +- curate / audit the index + +Design priorities follow from this profile: fast to parse when opened, keyboard-first, minimal chrome, information-dense where needed, never "dashboard for dashboard's sake". + +--- + +## 3. Constraints (locked by `~/.claude/rules/`) + +- **Air-gapped build** — all fonts, icons, and assets vendored locally. No Google Fonts, no CDN, no external analytics. +- **WCAG AA** — text contrast ≥ 4.5:1 (body) / 3:1 (large). Full keyboard nav. Visible `:focus-visible` rings. Correct ARIA. +- **Respect user prefs** — `prefers-color-scheme` sets theme default; `prefers-reduced-motion` disables non-essential motion; `prefers-contrast` honored. +- **Performance targets** — interaction response < 100 ms; TTI < 2.5 s on median device/network; 60 fps (< 16 ms frame). +- **Design system** — tokens only (color / space / radius / type / motion). Arbitrary values are a code smell. +- **Mobile-first responsive**, not desktop-down. +- **Dark mode default**, themeable. +- **i18n-ready** from day one: strings externalized, CSS logical properties only (no `margin-left`; use `margin-inline-start`), `dir="rtl"` support in root. + +--- + +## 4. Architecture + +### 4.1 Navigation — combined Linear + Raycast + +**Default (desktop ≥ 1024 px):** labeled 220 px sidebar + top bar with prominent ⌘K. + +**Sections (in order):** Home, Notes, Documents, Graph, MCP console. Project selector at sidebar bottom. + +**Keyboard:** `G H`, `G N`, `G D`, `G G`, `G M` (Linear-style chords); `⌘K` command palette; `⌘\` toggle sidebar collapse. + +**Sidebar collapse:** user toggle via `⌘\` → 48 px icon rail; state persisted to `localStorage`. + +**Command palette (⌘K):** powered by shadcn `` (cmdk). Single search input hits in parallel: notes (FTS5), documents (hybrid), entities, projects, and page jumps. Result types distinguished by leading monospace badge. + +### 4.2 Responsive breakdown + +| Breakpoint | Nav treatment | Notes workspace | Graph view | +|---|---|---|---| +| `< 640 px` (mobile) | Hamburger + ⌕ icon button; drawer slide-out | Tabs: Note / Tree / Links | Pinch-zoom, reduced node density | +| `640–1023 px` (tablet) | 44 px icon rail persistent; ⌕ button in top bar | Tree + Note 2-col; Links inline strip | Desktop layout at smaller scale | +| `1024–1439 px` (desktop) | 220 px labeled sidebar (collapsible) | Focused column + drawers (⌘/, ⌘L) | Full-viewport SVG | +| `≥ 1440 px` (wide) | Same as desktop, max widths kept | Focused column still ~620 px | More nodes shown | + +Touch targets ≥ 44 px. No hover-only interactions on touch. Keyboard shortcut hints hidden on touch devices. + +### 4.3 Routing + +- **React Router 6** — fixes the current `replaceState` hack. Browser back/forward works naturally. +- URL = source of truth for current view + project: `/` (Home), `/notes/:key?`, `/docs/:id?`, `/graph`, `/mcp`. +- Project selection as search param: `?project=`, default `_default`. +- `pushState` on navigation, `replaceState` only for query-param-only updates (filters, search text). + +--- + +## 5. Home screen + +**Layout:** 5-tile stats strip + "since your last visit" activity feed as main column + right rail (desktop only) with graph glance and pinned notes. + +### Stats strip (5 tiles) +- Notes (with `+N` delta in accent color) +- Documents +- Entities +- Communities +- Last updated (relative time) + +### Activity feed +- Chronological, newest first, typed event badges: + - `+ NOTE` (green accent) + - `INDEX` (blue semantic) + - `GRAPH` (purple semantic) + - `ERROR` (red semantic) +- "Since your last visit" section header. +- "Last visit" = `localStorage` timestamp updated on navigation away from Home. +- Paginated: 20 newest + "view full activity" link to a dedicated timeline route (deferred to post-v1). + +### Right rail (desktop ≥ 1024 px only) +- **Graph glance** — small SVG preview of the current project's graph (~30 nodes max). Clickable → Graph view. +- **Pinned notes** — up to 5 note keys marked as pinned. Click → note view. Pin toggle is a backend extension (deferred); v1 shows the 5 most-recently-written notes. + +On tablet: right rail content drops below the activity feed. On mobile: stacked in order (stats → feed → graph preview). + +--- + +## 6. Notes workspace (`/notes/:key?`) + +**Pattern:** focused reading column, ~620 px max. Tree and Links are drawer panels opened on demand. + +### Reading mode (default) +- Frontmatter stripped from display, title rendered as H1. +- Metadata row under title: key path, last updated, inbound/outbound link counts. +- Body: markdown renderer (new, better than current — see §6.3). +- Wikilinks `[[target]]` are primary in-page navigation; click → navigate to target note. +- Aliased wikilinks `[[target|alias]]` **render the alias** (fixes current bug). + +### Edit mode +- Click body or press `E` → inline editor (CodeMirror 6 or Monaco — see §9). +- Frontmatter editable as YAML. +- `⌘S` saves. Dirty state shown in tab title (`*`) and nav. +- Cancel (`Escape`) with confirm-discard if dirty. + +### Drawers +- `⌘/` → tree drawer (left, 300 px). Folder-structured tree; click a key to navigate; `+` button to create. +- `⌘L` → links drawer (right, 280 px). Inbound + outbound lists, click to navigate. +- Both drawers pinned-open persistable to `localStorage` per user preference. + +### Search sub-route +- `/notes/search?q=…` — dedicated search view with highlighted snippets, scored results. +- Debounced input (300 ms) — fixes current non-debounced bug. + +### Responsive +- Tablet: tree always visible (240 px), focused column beside, links as inline strip. +- Mobile: three tabs at top: Note / Tree / Links. + +### 6.3 Markdown rendering (scope v1) +**Supported:** +- Headings (ATX) +- Bold, italic, inline code +- Fenced code blocks with syntax highlighting (Shiki, vendored languages list: ts, tsx, go, bash, json, yaml, md, sql, py, rust) +- Unordered + ordered lists (1 level of nesting) +- Links (external → `target="_blank" rel="noopener noreferrer"`) +- Images (`loading="lazy"`) +- Blockquotes +- Horizontal rules +- GitHub-style tables (header + body only, no alignment flags) +- Inline math `\(...\)` rendered as styled code +- `[[wikilinks]]` + `[[target|alias]]` + +**Explicitly not in v1:** +- Task list checkboxes +- Setext headings +- Reference-style links +- Nested blockquotes / nested tables +- Math block rendering (KaTeX / MathJax) +- Mermaid diagrams + +Use **markdown-it** (MIT, actively maintained, ~80 KB gzip incl. plugins we need; smaller than micromark+remark full stack we'd otherwise need). + +--- + +## 7. Other screens (lower-fidelity specs) + +### 7.1 Documents (`/docs/:id?`) +- List view: table of indexed docs with columns (title, type, last indexed, chunks, entities). Click row → doc detail. +- Detail view: focused column with doc structure outline, entity list, chunk preview. Link to raw source. +- Upload modal (triggered from list view header): drag-drop + file picker + URL crawler tab. Progress via existing SSE (`/api/upload/progress?job_id=…`). + +### 7.2 Graph (`/graph`) +- Full-viewport SVG, force layout (d3-force, already in scope). +- Filters (left drawer): entity types, communities, date range. +- Layer toggle: Entities / Notes / Both (note overlay uses `--accent-notes` hue). +- Node click → side panel with details + neighborhood. +- `⌘+` / `⌘-` zoom, `0` reset, `/` focus search. + +### 7.3 MCP console (`/mcp`) +- Power-user / debugging screen. Kept from current implementation with visual refresh. +- List of recent tool calls with request + response JSON, latency, auth status. +- Filter by tool name; click → full request/response in modal. +- Deprioritized for visual polish; functional parity with current is acceptable for v1. + +### 7.4 No dedicated Upload, Search, Stats, Communities, or Overview routes +- Upload = modal from Documents +- Unified search = `⌘K` palette +- Stats = stats strip on Home +- Communities = filter/overlay inside Graph +- Overview = Home + +This collapses the current 8-tab TopNav to **5 destinations**. + +--- + +## 8. Visual system — Terminal (choice B) + +### 8.1 Palette — dark (default) +``` +--color-base #0f1115 /* app background */ +--color-surface-1 #14171d /* cards, sidebar */ +--color-surface-2 #1b1f26 /* elevated / popover */ +--color-border #1e2128 +--color-border-strong #2a2f38 +--color-text #e4e6ec +--color-text-muted #6f7482 +--color-text-faint #4a4f59 + +--color-accent #3ecf8e /* primary */ +--color-accent-hover #4ad89a +--color-accent-contrast #0f1115 + +/* Event semantics (theme-independent) */ +--semantic-new #3ecf8e +--semantic-index #6ba6ff +--semantic-graph #b08fe8 +--semantic-error #e06060 +--semantic-warn #f3b54a +``` + +### 8.2 Palette — light (auto from `prefers-color-scheme` + manual toggle) +``` +--color-base #f8f9fb +--color-surface-1 #ffffff +--color-surface-2 #f1f3f6 +--color-border #e5e8ec +--color-border-strong #c8ced6 +--color-text #0f1115 +--color-text-muted #5e6672 +--color-text-faint #8c93a0 + +--color-accent #1faa69 /* darker for AA on white */ +--color-accent-hover #1a9a5f +--color-accent-contrast #ffffff + +/* Event semantics (darker variants for AA on light bg) */ +--semantic-new #1faa69 +--semantic-index #2968d4 +--semantic-graph #7246c2 +--semantic-error #c03030 +--semantic-warn #b8801e +``` + +### 8.3 Typography +- **Sans:** Geist (400, 500, 600). Body text, UI labels, headings. +- **Mono:** Geist Mono (400, 500). Keyboard shortcuts, keys, timestamps, event badges, code. +- **Font feature settings:** `"cv11", "ss01", "ss03"` (Geist's tabular numerals for aligned tables). +- **Vendored to** `ui/public/fonts/`, loaded via `@font-face` with `font-display: swap`. +- **Font sizes (tokens):** 11 (micro), 12 (caption), 13 (small), 14 (body), 16 (large body), 18 (h3), 22 (h2), 28 (h1), 36 (display). No other sizes allowed. +- **Line heights:** 1.4 tight (UI), 1.6 relaxed (reading body). + +### 8.4 Spacing tokens +`4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 96` — px. No arbitrary values in Tailwind classes. + +### 8.5 Radius tokens +- `4` — inputs, small badges +- `6` — cards, buttons (default) +- `10` — modals, popovers +- `999` — pill (sparingly; only for status dots and small count chips) + +### 8.6 Shadow / elevation +- `--shadow-sm` — `0 1px 2px rgba(0,0,0,.2)` (dark) / `0 1px 2px rgba(15,17,21,.04)` (light) +- `--shadow-md` — popovers, dropdowns +- `--shadow-lg` — modals, command palette +- Never use shadow as primary boundary; borders do that job. + +--- + +## 9. Tech stack + +``` +React 19 — kept +Vite 6 — kept (static build for //go:embed) +TypeScript 5.7 — kept + +shadcn/ui — component primitives, copy-pasted into src/components/ui/ +Tailwind CSS 4 — utility-first styling, JIT +Radix primitives — backing shadcn, already in stack +lucide-react — icons (already vendored via npm) +cmdk — command palette (via shadcn ) + +TanStack Query v5 — server state, replaces manual fetch + loading flags +Zustand v5 — client state (theme, sidebar-collapsed, project slug) +React Router 6 — routing +React Hook Form v7 + Zod v3 — forms + validation + +Framer Motion v11 — motion, always gated by prefers-reduced-motion +markdown-it + shiki — note markdown rendering + code highlighting +d3-force — graph layout (lightweight, tree-shakeable) +CodeMirror 6 — markdown editor (inline-edit mode) + +Vitest 3 + Testing Library — unit + component tests +MSW v2 — mock API for integration tests + +Geist Sans + Geist Mono — fonts, Apache 2.0, self-hosted +``` + +**Bundle budget:** ≤ 450 KB JS / ≤ 135 KB gzip. First CI run after each PR publishes the bundle size; regressions > 5% fail the check. + +--- + +## 10. Motion philosophy + +- **Purposeful motion only.** Each animation justifies itself against: does it show a relationship (drawer slides in from the side it belongs to), provides orientation (route transition fades the old view out), or confirms an action (pulse on copy)? If not — no animation. +- **Durations:** 120–180 ms for UI state changes (hover, focus, small toggles); 250–400 ms for content transitions (drawer, modal, route change). +- **Easing:** `cubic-bezier(0.3, 0, 0, 1)` for enter (ease-out); `cubic-bezier(0.7, 0, 1, 0.3)` for exit (ease-in). Tokenized as `--ease-out`, `--ease-in`. +- **Entry style:** opacity + translate (never scale — scale animations read as decorative at this fidelity). +- **`prefers-reduced-motion: reduce`** — every motion either becomes instant (opacity swap with no translate) or reduces to opacity-only fade. Framer Motion's `useReducedMotion()` hook respected throughout. +- **Framer Motion scope:** drawer slide-in/out, modal / command-palette enter/exit, route transition. Everything else is CSS transitions on discrete properties (`color`, `background-color`, `border-color`, `opacity`) — no `all`. + +--- + +## 11. Accessibility requirements + +- **WCAG AA** contrast on all text. Validated via automated check in CI (axe-core or pa11y). +- **Keyboard:** every interactive element reachable via Tab. Focus order follows reading order. `:focus-visible` ring uses `--color-accent` (2 px outline + 2 px offset). +- **ARIA:** `role="navigation"` on sidebar + top bar, `role="main"` on content, `role="complementary"` on right rail. `aria-label` on all icon-only buttons. `aria-live="polite"` region for toast notifications and upload progress. +- **Skip link:** "Skip to main content" as first tab-stop, visible on focus. +- **Screen reader:** landmark regions, descriptive page titles on route change, proper heading hierarchy (one `

` per route). +- **Form labels:** every input has an associated `