Files
ClaudeDo/docs/superpowers/plans/2026-04-20-ui-polish-design-parity.md

15 KiB
Raw Permalink Blame History

UI Polish — Design Parity Follow-up

Follow-up to the islands rewrite. Closes visible gaps between the current state and the handoff mock. Execute with subagent-driven development; phases B/C/D can run in parallel.

Goal: Bring the rewrite to pixel-level parity with docs/UI Rewrite/design_handoff_claudedo/ClaudeDo-standalone.html.

Tech stack: Avalonia 12, CommunityToolkit.Mvvm. No new dependencies.

Reference files:

  • Source of truth: docs/UI Rewrite/design_handoff_claudedo/ClaudeDo-standalone.html
  • CSS measurements: docs/UI Rewrite/design_handoff_claudedo/styles.css
  • JSX component structure: docs/UI Rewrite/design_handoff_claudedo/islands.jsx, app.jsx
  • Tokens: src/ClaudeDo.Ui/Design/Tokens.axaml
  • Styles: src/ClaudeDo.Ui/Design/IslandStyles.axaml

Rules for all phases:

  • Use existing token brushes (MossBrush, PeatBrush, AccentSoftBrush, etc.) — do NOT hard-code hex.
  • Use Classes="foo" + selectors in IslandStyles.axaml for reusable styling; inline AXAML setters for one-off values only.
  • Icons: use Projektion.Avalonia PathIcon with Data="{StaticResource IconKey}". Define new StreamGeometry resources in IslandStyles.axaml under an <Icons> section when needed. Pull the SVG paths from the JSX reference.
  • Read the relevant JSX + CSS file in the handoff before implementing each component — those are the source of truth for exact measurements/paddings/colors.
  • Do not touch the data layer, Worker, SignalR, or command wiring. This is a view/style-only pass.

Phase A — Shell + title bar (sequential, run first)

One subagent. Small blast radius; prerequisite for the visual "feel."

Task A1 — Custom title bar

Files:

  • src/ClaudeDo.Ui/Views/MainWindow.axaml + .axaml.cs

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (add title-bar styles + window-control icon-button style)

  • Replace the current title bar Grid with a 3-section layout:

    • Left: brand block — checkbox-style green glyph + CLAUDEDO (mono, uppercase, tracking 1.4, 11px) + separator dot + current-list name eyebrow-style (mono uppercase, TextDim). Bind the list name to Shell.Lists.SelectedList.Name.ToUpperInvariant().
    • Middle: draggable strip (PointerPressed → BeginMoveDrag).
    • Right: three frameless icon buttons (minimize / maximize-restore / close). Close button hover turns BloodBrush. Use PathIcon with inline StreamGeometry for the Lucide-style icons: Minus, Square, X — the exact SVG d strings are in icons.jsx.
  • Title bar height: 36px, background DeepBrush, bottom border 1px LineBrush.

  • Remove the character glyphs currently used for the window controls (, , ) — use PathIcons instead.

  • Commit: style(ui): custom title bar with brand and window controls

Task A2 — Background + island shadow

Files:

  • src/ClaudeDo.Ui/Views/MainWindow.axaml (background layer)

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (island shadow adjust)

  • Under the three-island Grid, add a Border filling the whole row with a subtle radial gradient from DeepBrush (center) to VoidBrush (edges). Use a RadialGradientBrush with 2 stops; keep opacity light.

  • In IslandStyles.axaml, bump the Border.island BoxShadow to match the token IslandShadow value exactly (0 20 40 #59000000, 0 2 4 #4D000000). Verify by inspecting the current style — if it's already set, no-op.

  • Commit: style(ui): background gradient and stronger island shadow


Phase B — Lists island polish (parallel with C, D)

Task B1 — Icon geometries + eyebrow rename + sections

Files:

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (add StreamGeometry icon resources at the top)

  • src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs (map IconKey strings → resource keys, add section grouping)

  • src/ClaudeDo.Ui/Views/Islands/ListsIslandView.axaml

  • Extract the SVG path d strings from icons.jsx for: Sun, Activity (pulse), Star, Calendar, Eye, Inbox, Folder, Search, Plus, MoreHorizontal. Define each as an x:Key="Icon.Sun" StreamGeometry in IslandStyles.axaml.

  • Change Lists eyebrow from WORKSPACE to NAVIGATOR.

  • Add two section-header rows in the ItemsControl: SMART LISTS (above items of Kind=Smart + Virtual) and MY LISTS (above items of Kind=User). Simplest approach: two separate ItemsControls bound to filtered subsets; or wrap items in a CollectionViewSource grouping. Pick the simplest working approach.

  • Per-item icon: bind PathIcon Data="{DynamicResource Icon.{IconKey}}" via a tiny IconGeometryConverter (takes IconKey string → looks up resource). Icon color: TextMute default; AccentBrush (moss) when IsActive.

  • User-list items: use a 6px circle with MossBrush / PeatBrush / SageBrush dot instead of folder icon (map per list index mod colors, or single color if simpler).

  • Active state: remove solid fill. Use AccentSoftBrush (~10% moss) + left 2px accent bar + AccentBrush icon + TextBrush text.

  • Commit: style(ui): lists icons, section headers, active state

Files:

  • src/ClaudeDo.Ui/Views/Islands/ListsIslandView.axaml

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (search style + kbd chip style)

  • Search TextBox: wrap in a Grid ColumnDefinitions="Auto,*,Auto" — left PathIcon Data="{Icon.Search}" (14px, TextFaint), middle TextBox, right Border Classes="kbd" with ⌘K (or Ctrl K on Win). The kbd chip: mono 10px, Surface2 bg, LineBrush border, padding 6,2, radius 4.

  • Under the items list, add:

    • + New list button — plain icon+text row, PathIcon Data="{Icon.Plus}", hover tint.
    • User profile row — avatar circle (initials fallback, seed from Environment.UserName), name (Environment.UserName), subtitle {MachineName} / local mono dim, right PathIcon Data="{Icon.MoreHorizontal}".
  • Commit: style(ui): lists search icon, kbd hint, footer actions


Phase C — Tasks island polish (parallel with B, D)

Task C1 — Header + add-task row styling

Files:

  • src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs (subtitle format, header toolbar properties)

  • src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (kbd-enter, add-task row)

  • Subtitle format: change from {open} open · {running} running · {review} in review to {Weekday}, {Month} {Day} · {open} open to match the mock. Keep the running/review counts visible but move them into a right-aligned mono pill row next to the title (or drop if cleaner).

  • Eyebrow: keep current MONTAG · APR. 20 pattern. Title remains list name.

  • Right-side icon toolbar: three Button Classes="icon-btn"Sort icon, Eye icon (toggle completed), MoreHorizontal. Icons: pull paths from icons.jsx. Wire Eye to an IsShowingCompleted observable (persist in a private field for now; no DB change).

  • Add-task row: wrap the TextBox in a Border with Surface2 bg, rounded 8px, 14px padding. Prepend a circular PathIcon Data="{Icon.Plus}" (20px circle, Surface3 bg). Append a Border Classes="kbd" with ENTER text (only visible when NewTaskTitle has focus — bind visibility to TextBox.IsFocused).

  • Commit: style(ui): tasks header toolbar and add-task row

Task C2 — Task row chips + states

Files:

  • src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs (expose a few more flags: IsOverdue, Tags, StepsCount, StepsCompleted)

  • src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (chip variants, selected accent, done state, live-tail meter)

  • Chip set per row (ItemsControl or StackPanel):

    • Status chip (already present) — ensure color maps per Status → token brush (idle/queued/running/review/error).
    • List chip — small colored bullet (6px circle in MossBrush or similar) + list name.
    • Branch chip — PathIcon Data="{Icon.GitBranch}" (12px) + branch name (mono 10px).
    • Diff chip — +N moss + + M blood.
    • Tags — one chip per tag (#refactor style, Surface2 bg, mono 10px, TextDim).
  • Selected state: add 2px AccentBrush left border on the row Border when IsSelected=true (style selector Border.task-row.selected). Background shifts to AccentSoftBrush.

  • Done state: strike-through title + fade opacity to 0.5. Add Border.task-row:has(.done) equivalent via the existing Done binding — simpler: a TextBlock style selector that flips TextDecorations.

  • Live-tail row (only visible when Status == Running and LiveTail != null): a Border under the chip row with mono 11px ellipsized text + a slim 3px progress Rectangle with MossBrush. For now the progress is static 30% — wire it to a future ProgressFraction property (leave as 0.3 fallback).

  • Ensure task-row Border has Transitions for Background + Margin (smooth hover + select).

  • Commit: style(ui): task row chip set, selected/done states, live tail

Task C3 — Section dividers (OVERDUE / TASKS / COMPLETED)

Files:

  • src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs (group the ObservableCollection into sections)

  • src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml (group headers)

  • Add grouping: transform Items into three sub-collections:

    • OverdueItems — tasks with ScheduledFor < Today and not Done.
    • OpenItems — remaining not-Done tasks.
    • CompletedItems — tasks with Done=true.
  • Expose as three ObservableCollection<TaskRowViewModel> on the VM. Recompute inside LoadForList.

  • View: three ItemsControls stacked in a StackPanel, each preceded by a section header TextBlockOVERDUE (only if non-empty), TASKS, COMPLETED · {N}. Eyebrow style, TextFaint.

  • Commit: style(ui): task section dividers overdue/tasks/completed


Phase D — Details island polish (parallel with B, C)

Task D1 — Header + task row restyle

Files:

  • src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs (expose TaskIdBadge like #T1, computed from task id prefix)

  • src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml

  • Top header block:

    • Eyebrow LOGBOOK + right-aligned #T{shortId} badge (first 3 hex chars of Task.Id, mono TextFaint).
    • Title: keep editable title TextBox but reduce size and match mock.
  • Under header, a new "task strip" row: Ellipse checkbox (bound to Task.Done toggle) + title + right-aligned star button. This is separate from the editable title (mock shows both title as editable heading AND a task-row-style strip with check/star).

  • Commit: style(ui): details header with logbook eyebrow and task-id badge

Task D2 — Agent strip v2

Files:

  • src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs (add Turns, TokensFormatted, ElapsedFormatted, DiffAdditions, DiffDeletions, CommitsOnBranch if not present — most exist)

  • src/ClaudeDo.Ui/Views/Islands/AgentStripView.axaml

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (diff meter bar style)

  • Layout (three rows):

    • Row 1: pulsing status dot + status label (RUNNING etc.) + mono model name + right-aligned stop button (only visible when Running).
    • Row 2: WORKTREE section label + worktree path mono, with a copy-to-clipboard PathIcon Data="{Icon.Copy}" button at the end.
    • Row 3: Branch line — PathIcon Data="{Icon.GitBranch}" + branch mono + arrow + main + commits count chip.
    • Row 4: DIFF label + +{additions} (moss) + {deletions} (blood) + a slim 4px progress-meter Rectangle showing additions vs deletions ratio (moss-filled portion).
  • Action buttons row: Open diff, Worktree, external-link (opens file:// to worktree path in OS explorer).

  • Agent strip should use AgentStripStyle.Classes bound to the running status so colors shift.

  • Commit: style(ui): agent strip with worktree panel and diff meter

Task D3 — Session terminal styling

Files:

  • src/ClaudeDo.Ui/Views/Islands/SessionTerminalView.axaml

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (terminal header, log-line columns, LIVE chip)

  • src/ClaudeDo.Ui/ViewModels/Islands/LogLineViewModel.cs (add TimestampFormatted property)

  • Top bar of the terminal Border: three colored dots (red/yellow/green, 8px Ellipse) + claude-session · {branch} mono text + right-aligned LIVE chip (moss bg, white text, pulsing animation when a task is actively running).

  • Log lines: two-column layout — timestamp (mono 10px, TextFaint, fixed 70px width) + kind marker (e.g. TOOL, CLAUDE, OUT) + text. Kind marker uses attribute selector [Tag=log-tool], color-mapped.

  • Line number/timestamp: add TimestampFormatted to LogLineViewModel populated as DateTime.Now.ToString("HH:mm:ss") on construction. (If real timestamps arrive via SignalR later, swap source.)

  • Ensure auto-scroll still works (existing logic).

  • Commit: style(ui): session terminal header, line columns, LIVE chip

Files:

  • src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml

  • src/ClaudeDo.Ui/Design/IslandStyles.axaml (subtask row style)

  • src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs (delete-task command, close-detail command)

  • Subtasks: each row is a compact Border with rounded 6px, hover background. Check is an Ellipse matching the task-row style (not default WinForms-style CheckBox). Completed items get strike-through + fade.

  • Notes TextBox: Surface2 bg, 12px padding, watermark Notes..., auto-saves on LostFocus (call repository Update).

  • Bottom metadata bar (sticky at the bottom of the Details island — anchor via DockPanel.Dock="Bottom"):

    • Left: PathIcon Data="{Icon.Trash}" delete button (prompts confirmation before calling TaskRepository.DeleteAsync).
    • Middle: Created {Month Day} mono TextFaint.
    • Right: close-details PathIcon Data="{Icon.X}" (clears SelectedTask on TasksIslandViewModel).
  • Commit: style(ui): subtasks, notes, details metadata footer


Execution order

Phase A (A1 → A2)  [sequential, 1 subagent]
   ↓
Phase B, C, D       [parallel, 3 subagents, one per phase]
   ↓
Final build + smoke

Phase A is sequential because it touches MainWindow.axaml and IslandStyles.axaml root setup. Phases B, C, D each own a distinct island. Only potential conflict: all three add icon geometries to IslandStyles.axaml. Mitigation: Phase B is responsible for adding the StreamGeometry icon resources (it needs the most). Phases C and D reference those keys without redefining.

Final pass: run the app, eyeball against the mock, note remaining gaps.