diff --git a/AGENTS.md b/AGENTS.md index 7ccf4e2..c722119 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,6 +12,10 @@ Use `pnpm install` to install frontend dependencies. Run `pnpm tauri:dev` for th Follow the existing style rather than introducing new patterns. TypeScript uses 2-space indentation, semicolons, PascalCase for components and types, and camelCase for functions, state, and Tauri payload fields. Keep frontend IPC definitions in `src/lib/api.ts` and shared TS shapes in `src/lib/types.ts`. Rust follows standard `rustfmt` formatting, `snake_case` names, and `#[serde(rename_all = "camelCase")]` for structs crossing the JS bridge. +## Design System Preview + +When adjusting colors, tokens, or component styles, use `design-system.html` (project root) to visually verify changes. It imports `src/styles.css` directly via Vite. Run `pnpm tauri:dev` (port 1420), then open `http://localhost:1420/design-system.html` via Chrome DevTools MCP to preview all tokens and components live. Toggle `[data-theme="dark"]` on `` to check dark mode. + ## Testing Guidelines Backend tests are inline Rust unit tests placed in `mod tests` blocks inside the relevant module files such as `src-tauri/src/git.rs`, `config.rs`, and `actions.rs`. Add tests next to the behavior you change. There is currently no dedicated frontend test harness, so at minimum run `pnpm build` after UI or API changes and `cargo test` after backend edits. diff --git a/CLAUDE.md b/CLAUDE.md index 0c34c94..e5cebc6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -54,6 +54,7 @@ All UI work **must** follow `DESIGN_SYSTEM.md`. Key rules: - **Spacing**: 2px base grid. Common stops: 6, 8, 10, 12, 14, 20, 24px. Follow existing patterns. - **Transitions**: Buttons `140ms ease`, list items `100ms ease`, slide-out `180ms ease-out`. - **Dark mode**: Supports Light / Dark / System. All colors use CSS custom properties (`var(--token)`). When adding new UI, always use existing tokens from `:root` — never hardcode colors. Verify new pages/components look correct in both light and dark mode. +- **Preview**: `design-system.html` at project root renders all tokens and components using the real `src/styles.css`. When adjusting colors or tokens, run `pnpm tauri:dev` (Vite dev server on port 1420), then use Chrome DevTools MCP to open `http://localhost:1420/design-system.html` to visually verify changes in real time. Toggle `[data-theme="dark"]` on `` to check dark mode. ## Notes @@ -64,4 +65,4 @@ All UI work **must** follow `DESIGN_SYSTEM.md`. Key rules: ## UI Layout -Top navigation bar (38px, `titleBarStyle: overlay` with 78px left padding for macOS traffic lights) + full-width content area. Topbar: brand, 4 tabs (Repository, Worktrees, Hooks, Settings), "New Worktree" button on the right. Views: Repository (centered card with repo picker), Worktrees (master-detail grid: 280px worktree list | detail panel), Hooks (inline hooks editor), Settings (language, terminal, shell, tray icon, tooling, logs, config). Create worktree uses a right-side slide-out panel. +Topbar (38px, `titleBarStyle: overlay` with 78px left padding for macOS traffic lights) shows brand + centered repo path. Left sidebar (48px, icon-only) has 4 tabs: Repository, Worktrees, Hooks, Settings. Main content fills the area right of the sidebar. Views: Repository (centered card with repo picker), Worktrees (master-detail grid: 280px worktree list | detail panel; "New Worktree" button in worktree toolbar), Hooks (inline hooks editor), Settings (language, terminal, shell, tray icon, tooling, logs, config). Create worktree uses a right-side slide-out panel. diff --git a/DESIGN_SYSTEM.md b/DESIGN_SYSTEM.md index de888ad..0a671c1 100644 --- a/DESIGN_SYSTEM.md +++ b/DESIGN_SYSTEM.md @@ -45,8 +45,8 @@ Standalone sizes outside the scale: `0.92rem` (sidebar branch name), `1.2rem` (d | Token | Stack | Usage | |---|---|---| -| (`:root`) | `"Avenir Next", "Segoe UI", sans-serif` | All UI text | -| `--font-mono` | `"SF Mono", "JetBrains Mono", monospace` | Code, paths, diffs | +| (`:root`) | `"Avenir Next", "Segoe UI", Roboto, "Noto Sans", Ubuntu, Cantarell, sans-serif` | All UI text | +| `--font-mono` | `"SF Mono", "Cascadia Code", "Fira Code", "JetBrains Mono", Consolas, "Liberation Mono", monospace` | Code, paths, diffs | **No serif fonts.** All headings use the same sans-serif stack. @@ -114,6 +114,68 @@ Use teal **sparingly** — only for interactive states, active indicators, and f | `--border-default` | `rgba(28, 25, 23, 0.12)` | Card/panel borders, topbar, sidebar | | `--border-strong` | `rgba(28, 25, 23, 0.16)` | Input borders | +### Dark Mode Overrides + +Dark mode is activated via `[data-theme="dark"]`. All light-mode tokens above are overridden. Key differences: + +#### Ink (Dark) + +| Token | Value | +|---|---| +| `--ink` | `#dbd6d0` | +| `--ink-strong` | `rgba(219, 214, 208, 0.92)` | +| `--ink-secondary` | `rgba(219, 214, 208, 0.65)` | +| `--ink-tertiary` | `rgba(219, 214, 208, 0.48)` | +| `--ink-ghost` | `rgba(219, 214, 208, 0.3)` | +| `--ink-faint` | `rgba(219, 214, 208, 0.18)` | + +#### Accent (Dark) + +| Token | Value | +|---|---| +| `--teal` | `#52b0a4` | +| `--teal-bg` | `rgba(82, 176, 164, 0.1)` | +| `--teal-bg-strong` | `rgba(82, 176, 164, 0.18)` | +| `--teal-border` | `rgba(82, 176, 164, 0.25)` | +| `--teal-focus` | `rgba(82, 176, 164, 0.48)` | +| `--teal-muted` | `rgba(82, 176, 164, 0.58)` | +| `--teal-hover` | `rgba(82, 176, 164, 0.78)` | + +#### Surfaces (Dark) + +| Token | Value | +|---|---| +| Page background | `#151312` | +| `--surface-card` | `#1e1c19` | +| `--surface-topbar` | `#181614` | +| `--surface-sidebar` | `#1b1917` | +| `--surface-modal` | `#201e1b` | +| `--surface-input` | `#24221f` | +| `--surface-warm` | `#1b1917` | +| `--surface-raised` | `#24221f` | +| `--surface-hover` | `rgba(219, 214, 208, 0.07)` | +| `--surface-subtle` | `rgba(219, 214, 208, 0.04)` | +| `--surface-muted` | `rgba(219, 214, 208, 0.065)` | +| `--surface-strong` | `rgba(219, 214, 208, 0.095)` | +| `--surface-stronger` | `rgba(219, 214, 208, 0.13)` | + +#### Borders (Dark) + +| Token | Value | +|---|---| +| `--border-faint` | `rgba(219, 214, 208, 0.08)` | +| `--border-default` | `rgba(219, 214, 208, 0.12)` | +| `--border-strong` | `rgba(219, 214, 208, 0.17)` | + +#### Semantic Colors (Dark) + +| Token | Value | +|---|---| +| `--success` | `#68c49c` | +| `--danger` | `#e09080` | +| `--warning` | `#cca44a` | +| `--purple` | `#9c8acc` | + --- ## Shadows @@ -165,7 +227,7 @@ Always use ``, ``, `` from `src/components/FormControls |---|---| | Border | `1px solid var(--border-strong)` | | Border Radius | `var(--radius-sm)` | -| Background | `#fefdfb` (light) / `#201e1c` (dark) | +| Background | `#fefdfb` (light) / `#24221f` (dark) | | Focus | Border changes to `var(--teal-focus)` | --- @@ -214,9 +276,21 @@ No per-launcher gradients. No decorative shadows or glows. | Height | `38px` | | Background | `var(--surface-topbar)` (solid, no blur) | | Border | `1px solid var(--border-default)` | -| Left padding (macOS) | `78px` | +| Left padding (macOS) | `78px` (set dynamically via JS) | + +Contains brand mark + name on the left, centered repo path, empty right zone. **No backdrop-filter.** No glass-morphism. + +## Sidebar Navigation + +| Property | Value | +|---|---| +| Width | `48px` | +| Background | transparent (inherits page bg) | +| Tab size | `36px × 36px`, icon-only | +| Active state | Teal icon + `var(--teal-bg)` background | +| Hover state | `var(--ink-secondary)` icon + `var(--surface-hover)` background | -**No backdrop-filter.** No glass-morphism. +Four tabs (top to bottom): Repository, Worktrees, Hooks, Settings. Icons from Lucide. --- @@ -275,7 +349,8 @@ No per-launcher gradients. No decorative shadows or glows. |---|---| | Topbar height | `38px` | | Topbar left padding (macOS) | `78px` | -| Sidebar width (worktrees) | `280px` | +| Sidebar width | `48px` | +| Worktrees list column | `280px` | | Max content width | `640-680px` | | Slide-out panel width | `min(480px, calc(100vw - 60px))` | | Modal max width | `min(900px, 100%)` | @@ -294,3 +369,13 @@ No per-launcher gradients. No decorative shadows or glows. 7. **Toast placement**: bottom-right, one at a time, auto-dismiss 3s. 8. **Modal dismiss**: Escape key + backdrop click. 9. **Typography**: Sans-serif everywhere. No serif fonts. + +--- + +## Live Preview + +`design-system.html` (project root) renders all tokens and components using the real `src/styles.css` via Vite. To preview: + +1. Run `pnpm tauri:dev` (Vite dev server on port 1420) +2. Open `http://localhost:1420/design-system.html` +3. Toggle `[data-theme="dark"]` on `` to verify dark mode diff --git a/design-system.html b/design-system.html new file mode 100644 index 0000000..129d3c2 --- /dev/null +++ b/design-system.html @@ -0,0 +1,393 @@ + + + + + + Grove Design System + + + + + + + + + + Grove Design System + Component & token reference — switch theme to audit both modes + + + Light + Dark + System + + + + + + Ink (Text) + + The quick brown fox--ink + The quick brown fox--ink-strong + The quick brown fox--ink-secondary + The quick brown fox--ink-tertiary + The quick brown fox--ink-ghost + The quick brown fox--ink-faint + + + + + Accent (Teal) + + Teal--teal + --teal-bg + --teal-bg-strong + --teal-border + --teal-focus + Muted teal text--teal-muted + + + + + Surfaces + + --surface-card + --surface-topbar + --surface-sidebar + --surface-input + --surface-hover + --surface-subtle + --surface-muted + --surface-strong + --surface-stronger + + + + + Semantic Colors + + Success--success + Danger--danger + Warning--warning + Purple--purple + + + + + + Buttons + + Primary + Ghost + Danger + Disabled + + + Small Primary + Small Ghost + Small Danger + + + + + + Badges + + neutral + warning + danger + good + PR #42 + PR #99 (link) + + + + + + Form Controls + + + Text Input + Selectmaindevelopstaging + + Textareaecho "hello world" +git status + + + + + + Cards & Panels + + Card with Section Heading + Standard card container with warm white background, 12px radius, border only. + + ⚠️ Warning panel — uncommitted changes detected + ✗ Error banner — failed to fetch remote branches + ~/code/project/.worktrees/feat-dark-mode + + + + + Launcher Icons + + + + + + Claude CLI(Ghostty) + + + + + Codex CLI(Ghostty) + + + + + Cursor + + + + + Gemini CLI(Ghostty) + + + + + Ghostty + + + + $ + iTerm2 + + + + + VS Code + + + + + Warp + + + + + Terminal + + + + + Alacritty + + + + + Kitty + + + + + WezTerm + + + + + OpenCode(Ghostty) + + + + + + Add Custom + + + + + + + + File Changes & Diff + + + Msrc/styles.css + Asrc/components/NewFeature.tsx + Dsrc/deprecated-module.ts + Rsrc/utils.ts → src/lib/utils.ts + ?src/scratch.ts + + @@ -42,7 +42,7 @@ export function App() { const [theme, setTheme] = useState('light'); const [count, setCount] = useState(0);- const color = '#1c1917';+ const color = '#2e7a6e'; return <div>{color}</div>; } + + + + + + Commit List + + + a64cd43fdocs: sync DESIGN_SYSTEM.md with late docs-agent changes@shawn2h ago + 64f8c7c2fix: address code review feedback@shawn3h ago + 7931085afix: prevent watcher restart loop when reloading same repo@shawn5h ago + d47bbb0eRevert "fix: replace stiff neutral grays with warm sand palette"@shawn6h ago + + + + + + + Toast Notifications + + ✓ Worktree created successfully + ✗ Failed to remove worktree + + + + + + Worktree List Items + + + + main + clean2h ago + + + + + feat/dark-mode + 3 filesPR #4215m ago + + + + + fix/watcher-loop + clean1d ago + + + + + + + + Action Logs + + + Commandgit worktree add ../feat-dark-mode feat/dark-mode + SuccessWorktree created at ../feat-dark-mode + Errorfatal: 'nonexistent' is not a valid branch name + InfoPreparing worktree (new branch 'feat/dark-mode') + + + + + + + Typography + + Heading — Avenir Next 700 + Subheading — Avenir Next 600 + Body text in secondary ink, used for descriptions and supporting copy. + Small text in tertiary ink for metadata, timestamps, hints. + Monospace: SF Mono — code, paths, SHA hashes + + + + + + + + diff --git a/src/styles.css b/src/styles.css index 5243f29..ad49847 100644 --- a/src/styles.css +++ b/src/styles.css @@ -151,35 +151,35 @@ --teal-muted: rgba(82, 176, 164, 0.58); --teal-hover: rgba(82, 176, 164, 0.78); - --surface-card: #1c1a18; - --surface-topbar: #171614; - --surface-sidebar: #1a1816; - --surface-modal: #1e1c1a; - --surface-input: #201e1c; - --surface-warm: #1a1816; - --surface-raised: #201e1c; - --surface-hover: rgba(219, 214, 208, 0.055); - --surface-subtle: rgba(219, 214, 208, 0.03); - --surface-muted: rgba(219, 214, 208, 0.05); - --surface-strong: rgba(219, 214, 208, 0.07); - --surface-stronger: rgba(219, 214, 208, 0.1); - - --border-faint: rgba(219, 214, 208, 0.06); - --border-default: rgba(219, 214, 208, 0.1); - --border-strong: rgba(219, 214, 208, 0.14); + --surface-card: #1e1c19; + --surface-topbar: #181614; + --surface-sidebar: #1b1917; + --surface-modal: #201e1b; + --surface-input: #24221f; + --surface-warm: #1b1917; + --surface-raised: #24221f; + --surface-hover: rgba(219, 214, 208, 0.07); + --surface-subtle: rgba(219, 214, 208, 0.04); + --surface-muted: rgba(219, 214, 208, 0.065); + --surface-strong: rgba(219, 214, 208, 0.095); + --surface-stronger: rgba(219, 214, 208, 0.13); + + --border-faint: rgba(219, 214, 208, 0.08); + --border-default: rgba(219, 214, 208, 0.12); + --border-strong: rgba(219, 214, 208, 0.17); --shadow-card: none; - --shadow-modal: 0 8px 32px rgba(0, 0, 0, 0.4); - --shadow-menu: 0 4px 16px rgba(0, 0, 0, 0.35); - --shadow-panel: -2px 0 16px rgba(0, 0, 0, 0.3); + --shadow-modal: 0 8px 32px rgba(0, 0, 0, 0.5); + --shadow-menu: 0 4px 16px rgba(0, 0, 0, 0.45); + --shadow-panel: -2px 0 16px rgba(0, 0, 0, 0.4); - --backdrop: rgba(10, 9, 8, 0.6); + --backdrop: rgba(10, 9, 8, 0.65); --btn-primary-bg: #52b0a4; --btn-primary-text: #151312; - --btn-ghost-bg: rgba(219, 214, 208, 0.07); + --btn-ghost-bg: rgba(219, 214, 208, 0.09); --btn-ghost-text: var(--ink); - --btn-danger-bg: rgba(210, 100, 88, 0.15); + --btn-danger-bg: rgba(210, 100, 88, 0.16); --btn-danger-text: #e09080; --success: #68c49c;
Standard card container with warm white background, 12px radius, border only.
@@ -42,7 +42,7 @@ export function App() { const [theme, setTheme] = useState('light'); const [count, setCount] = useState(0);- const color = '#1c1917';+ const color = '#2e7a6e'; return <div>{color}</div>; }
a64cd43f
64f8c7c2
7931085a
d47bbb0e
Monospace: SF Mono — code, paths, SHA hashes