Files

254 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ClaudeDo — Avalonia Handoff
## Overview
ClaudeDo is an agent dispatcher for Claude Code: a Windows desktop app that presents background coding agents as tasks. Each task has a title, a list, a git worktree/branch, an agent status (idle / queued / running / review / error), a live session log, and a diff. The UI is organised as **three floating islands** (Lists / Tasks / Details) over a dark "sea" background, Windows-11 style.
The bundled HTML file is a **design reference**, not production code. Your job is to recreate it as a native Avalonia app — match the look, feel, and interaction model, but use idiomatic AXAML, Avalonia controls, and whatever MVVM / ReactiveUI / CommunityToolkit patterns your codebase already uses.
## Fidelity
**High-fidelity.** All colors, typography, spacing, corner radii, shadows, and interaction states are final. Recreate pixel-perfectly using Avalonia primitives. The one exception: motion — CSS animations translate approximately to Avalonia `Transitions` / `Animation`; the durations and easings in `Tokens.axaml` are the intent.
## What's in this package
| File | Purpose |
|---|---|
| `Tokens.axaml` | `ResourceDictionary` — colors, brushes, spacing, corner radii, typography, shadows, motion durations. **Merge this first in `App.axaml`.** |
| `IslandStyles.axaml` | `Styles` — classed styles for Island, Chip, Button, TextBox, TaskRow, AgentStrip, Terminal, ListItem. Depends on `Tokens.axaml`. |
| `ClaudeDo.html` | The live design reference — open it in a browser to see behavior, hover states, animations, modals. |
| `ClaudeDo-standalone.html` | Fully offline single-file version (no network). Ship this with the handoff. |
| `app.jsx`, `islands.jsx`, `modals.jsx`, `icons.jsx`, `data.jsx`, `styles.css` | Source of the reference. Read `styles.css` for any measurement you need to verify; read the JSX for component structure and state transitions. |
| `ComponentSpec.md` | This file section below — maps every visual element to the AXAML control you should use. |
## How to wire the tokens
In `App.axaml`:
```xml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://YourApp/Design/Tokens.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://YourApp/Design/IslandStyles.axaml" />
</Application.Styles>
```
Pack **Inter Tight** (sans) and **JetBrains Mono** (mono) as embedded resources and reference them via `avares://YourApp/Assets/Fonts/#Inter Tight` in `Tokens.axaml` if the system-font fallback isn't good enough.
---
## Window chrome
The reference shows a Windows-11-style app in a chromeless window with a custom title bar and taskbar. For a native Avalonia app, use `SystemDecorations="None"` + `ExtendClientAreaToDecorationsHint="True"` and draw your own title bar, OR use the platform chrome — the islands-over-sea metaphor works either way. The taskbar strip at the bottom of the reference is decorative; drop it.
## Layout
Root window:
```
┌─────────────────────────────────────────────────────────┐
│ TitleBar │
├─────────────┬──────────────────────────┬────────────────┤
│ Lists │ Tasks │ Details │
│ (260px) │ (1fr, min 340px) │ (320px) │
│ │ │ hides <1100px │
└─────────────┴──────────────────────────┴────────────────┘
```
Use a `Grid` with 3 columns: `260,*,320`. Collapse the Details column when `ActualWidth < 1100` via a bound `ColumnDefinition.Width`. Between columns and around the grid, add 14px gap — put each island in a `Border Classes="island"` with `Margin="7"` so you get the island-to-island gap naturally.
Background of the grid cell: apply `DesktopBackgroundBrush` from tokens, plus a subtle radial-gradient overlay via a `Border` with an opacity mask if desired.
---
## Components
### Island (base container)
- `Border Classes="island"`
- Contents: header section + scrollable body
- Header: inner `Border Classes="island-header"` with an eyebrow label (mono, uppercase, tracking 1.4) and a title
- Body: `ScrollViewer``StackPanel` or `ItemsControl`
- All three columns are islands.
### Lists island (left)
- Search box: `TextBox Classes="search"` with left-aligned search icon (PathIcon)
- Nav items: `ItemsControl` bound to a `Lists` collection
- Each item is `Border Classes="list-item"` (toggle `active` class when selected) containing
- `PathIcon` (16px)
- `TextBlock` (list name, 13px)
- `TextBlock` (count, mono 10px, right-aligned, TextFaintBrush)
- Lists shown: My Day, Important, Planned, Running, Review, Tasks (by project name)
### Tasks island (middle)
Header row:
- Eyebrow: weekday date ("MONDAY · APR 28")
- Title: "My Day" (or current list name) — 24px semibold
- Subtitle: "{N} open · {N} running · {N} in review" — mono 11px TextMute
- Right side: icon buttons (sort, filter, show-completed toggle)
Add-task row:
- `TextBox` with placeholder "Add a task…"
- On Enter: dispatch new task (see ViewModel spec)
Task list:
- `ItemsControl``Border Classes="task-row"` per task
- Row content: `Grid` with columns `Auto,*,Auto`
- Left: `Ellipse Classes="task-check"` (toggles `done` class on completion) — use a `Button` with a templated Ellipse for keyboard support
- Middle: `StackPanel` vertical
- Title: `TextBlock` 14px, strike-through when done
- Meta row: `StackPanel` horizontal with 8px gap, children:
- `Border Classes="chip {status}"` (status chip — Running / Review / Error / Queued / Idle)
- `Border Classes="chip"` with list name
- `Border Classes="chip"` with mono branch name (e.g. `agent/auth-pool`)
- `Border Classes="chip"` with diff stats (`+142 86`)
- Live tail of latest agent output when running — use `TextTrimming="CharacterEllipsis"` in a fixed-width container
- Right: `Button Classes="icon-btn"` (star)
- Selection: toggle `selected` class; add a `Rectangle` with `Width=2` as the left accent bar (child of the task-row Border)
### Details island (right)
Shown when a task is selected. Sections, top to bottom:
1. **Header**: task title (editable — `TextBox` with no visible border, `FontSize=18`), list chip, delete icon button
2. **Agent strip**`Border Classes="agent-strip {status}"`:
- Row 1: status indicator dot + status label ("Running" / "Review" / etc.) + model name ("claude-sonnet-4.5") + turns + tokens + elapsed
- Row 2: Worktree path (mono, truncating)
- Row 3: Branch → Base ("agent/auth-pool ← main") + commit count + diff stats
- Buttons: "Open diff" / "Worktree" / "Stop" (when running) / "Approve & merge" (when review)
3. **Session output**`Border Classes="terminal"` with a `ScrollViewer` auto-scrolled to bottom:
- Each line is a `TextBlock Classes="log-{kind}"` — kinds: sys, tool, claude, stdout, stderr, done, msg
- Below it, a prompt input: `[you]` prefix + `TextBox` to send messages to the agent
4. **Subtasks**`ItemsControl` of checkbox + text rows
5. **Notes** — multi-line `TextBox`, `AcceptsReturn="True"`
6. **Metadata** — created date, last activity, tags (readonly chips)
### Modals
Two modals in the reference: **Diff** and **Worktree**. Use `Window` with `WindowStartupLocation="CenterOwner"` and a scrim (`Border` over the main window with `Background="#BF030504"` + blur via `OpacityMask` or a child `Grid`). Or use `Dialog` if your shell has one.
**Diff modal**: left sidebar of files (each with `+N N` stats), right pane with syntax-colored hunks. Use two `ListBox`-style panels side-by-side. For lines: `del` = red tinted, `add` = green tinted, `ctx` = neutral. Left gutter columns: old line number, new line number, sign (`+` / `` / space).
**Worktree modal**: folder tree with `M` (modified) / `A` (added) badges. `TreeView` fits naturally.
### Status mapping
| Status | Chip color | Icon | When |
|---|---|---|---|
| idle | TextMute | circle | Task created, agent not dispatched |
| queued | Sage | dots | Agent queued behind others |
| running | Accent (moss) | pulse dot | Agent actively working |
| review | Peat | eye | Agent finished; awaiting approval |
| error | Blood | exclamation | Agent failed |
---
## State & interactions
### Task model (MVVM)
```csharp
public class TaskItem : ReactiveObject {
string Id, Title, List;
bool Done, Starred, MyDay;
DateTime? Due, Created;
string Notes;
List<string> Tags;
List<SubTask> Subtasks;
AgentState Agent; // null if not dispatched
}
public class AgentState : ReactiveObject {
AgentStatus Status; // Idle | Queued | Running | Review | Error
string Model, Worktree, Branch, BaseBranch;
int Commits, Turns, Tokens;
DiffStats Diff; // Files, Additions, Deletions
DateTime? StartedAt, FinishedAt;
ObservableCollection<LogLine> Log;
}
```
### Key interactions
- **Toggle done**: click checkbox → flip `Done`, animate strike-through (0.2s ease-out)
- **Select task**: click row → set `SelectedTask`; details island rebinds
- **Add task**: Enter in the add-task textbox → prepend new task; scroll list to top; 0.3s fade-in animation on the new row (use `Animation` with opacity + `TranslateTransform.Y`)
- **Dispatch agent**: "Start agent" button in Details → sets `Agent.Status = Running`, appends sys log "Agent dispatched."
- **Stop agent**: → `Status = Review` (or `Error` on failure), appends sys log
- **Send prompt**: Enter in prompt input → append `[you] {msg}` to log
- **Open diff / worktree**: opens modal; Esc closes
### Keyboard
- `/` focuses the search box in the Lists island
- `Cmd/Ctrl+N` focuses add-task
- `Space` toggles done on selected row
- `Esc` closes any open modal
### Animations
- Task-row hover: background transition 0.1s
- Task-row add: 0.3s opacity + slight Y-slide
- Task-row complete: 0.25s strike-through + fade to `done` styling
- Running status dot: infinite pulse (opacity 0.4 → 1.0, 1.2s)
- Modal open: 0.18s opacity + scale (0.98 → 1.0)
- Backdrop: 0.15s opacity fade
### Responsive
- `< 1100px`: hide Details island; details open as a transient panel or modal on task select
- `< 780px`: hide Lists island; use a hamburger drawer
---
## Design tokens (reference)
All final values live in `Tokens.axaml`. Reproduced here for reading:
**Surfaces**: `#0A0E0C` void · `#0D1311` deep · `#161D1A` surface · `#1C2422` surface-2 · `#222B28` surface-3 · `#2A3330` line
**Text**: `#E4EBE4` primary · `#9AA8A0` dim · `#6B7973` mute · `#4A5550` faint
**Accents**: `#7C9166` moss (primary) · `#8B9D7A` sage · `#D4A574` peat · `#C87060` blood
**Spacing**: 4, 8, 12, 14 (island gap), 18, 24
**Corner radii**: 14 (island) · 12 (modal) · 10 (chip) · 8 (task row, input) · 6 (button) · 999 (pill)
**Typography**: Inter Tight (sans), JetBrains Mono (mono). Scale: 10 (eyebrow) / 11 (mono, micro) / 13 (body) / 14 (task title) / 18 (h3) / 24 (h2) / 32 (h1)
**Shadows**:
- Island: `0 20 40 #59000000, 0 2 4 #4D000000`
- Modal: `0 40 80 #B2000000`
**Motion**: 120ms (fast) / 180ms (base) / 300ms (slow). Easing: cubic-bezier(0.4, 0, 0.2, 1) — use Avalonia's `CubicEaseOut` or a custom `SplineEasing`.
---
## Acceptance checklist
- [ ] Three-island layout with correct spacing and grid collapse at <1100px
- [ ] Lists sidebar with icons, counts, search, active state
- [ ] Task rows with checkbox, title, meta chips (status/list/branch/diff), star
- [ ] Task selection updates Details island
- [ ] Agent strip shows status, model, turns, tokens, elapsed, worktree, branch
- [ ] Session terminal renders all log kinds with distinct colors, auto-scrolls, accepts prompt input
- [ ] Diff modal with file sidebar and tinted add/del lines
- [ ] Worktree modal with M/A badges
- [ ] Status chip tints match the spec
- [ ] Fonts: Inter Tight + JetBrains Mono packed and applied
- [ ] Motion: task add/toggle, running pulse, modal open, hover transitions
- [ ] Keyboard shortcuts wired
## Questions / contact
The HTML reference is the source of truth for any visual ambiguity. Open `ClaudeDo-standalone.html` and inspect directly.