settings/SU-6: ⌘K search palette indexing every setting #837

Closed
opened 2026-05-04 20:03:45 +00:00 by claude-desktop · 1 comment
Collaborator

User story

As an operator, I want to press ⌘K and type a setting name (e.g. "caveman", "container_image"), so that I can jump to it without scrolling 30+ settings across 10+ routes.

Context

After SU-1…SU-5 the settings surface has a clean grouped side-nav, but discovery of individual fields still requires knowing where they live. Linear, Stripe, Tailscale, VSCode all use a search palette as the dominant access pattern.

Acceptance criteria

Manifest

  • New apps/web/src/lib/settings-manifest.ts — static array of { id, label, description?, route, anchor?, group } covering every settings field/section.
  • One entry per addressable setting (not per route — granular).
  • Manifest hand-maintained; lint rule (or test) verifies every data-testid="settings-*" field has a manifest entry, to catch drift.

Palette UI

  • New apps/web/src/components/settings-search.tsx — Base UI dialog or popover, opens on ⌘K (Cmd on macOS, Ctrl elsewhere).
  • Entry point: search input in the global top bar (replaces nothing — additive). Clicking opens the palette; ⌘K shortcut works anywhere.
  • Fuzzy match on label + description.
  • Selecting a result navigates to route, then on mount scrolls anchor (e.g. #caveman-mode) into view and focuses the field.
  • Keyboard: ↑/↓ to move, Enter to pick, Esc to close.

A11y

  • Dialog has role="dialog" + aria-modal + focus trap + focus return (use Base UI primitive — see <Drawer> baseline in apps/web/CLAUDE.md).
  • Result list role="listbox", items role="option" with aria-selected.

Tests

  • Cmd/Ctrl+K opens palette globally.
  • Typing filters; arrow keys move; Enter navigates.
  • Manifest lint catches an orphan data-testid="settings-foo" field with no entry.

Out of scope

  • Recently-used / pinned settings — future.
  • Search across non-settings surfaces — future.

References

  • apps/web/CLAUDE.md — drawer / dialog primitive baseline.
  • apps/web/src/components/drawer.tsx — focus-trap reference.
## User story As an operator, I want to press ⌘K and type a setting name (e.g. "caveman", "container_image"), so that I can jump to it without scrolling 30+ settings across 10+ routes. ## Context After SU-1…SU-5 the settings surface has a clean grouped side-nav, but discovery of individual fields still requires knowing where they live. Linear, Stripe, Tailscale, VSCode all use a search palette as the dominant access pattern. ## Acceptance criteria ### Manifest - [ ] New `apps/web/src/lib/settings-manifest.ts` — static array of `{ id, label, description?, route, anchor?, group }` covering every settings field/section. - [ ] One entry per addressable setting (not per route — granular). - [ ] Manifest hand-maintained; lint rule (or test) verifies every `data-testid="settings-*"` field has a manifest entry, to catch drift. ### Palette UI - [ ] New `apps/web/src/components/settings-search.tsx` — Base UI dialog or popover, opens on ⌘K (Cmd on macOS, Ctrl elsewhere). - [ ] Entry point: search input in the global top bar (replaces nothing — additive). Clicking opens the palette; ⌘K shortcut works anywhere. - [ ] Fuzzy match on `label` + `description`. - [ ] Selecting a result navigates to `route`, then on mount scrolls `anchor` (e.g. `#caveman-mode`) into view and focuses the field. - [ ] Keyboard: ↑/↓ to move, Enter to pick, Esc to close. ### A11y - [ ] Dialog has `role="dialog"` + `aria-modal` + focus trap + focus return (use Base UI primitive — see `<Drawer>` baseline in `apps/web/CLAUDE.md`). - [ ] Result list `role="listbox"`, items `role="option"` with `aria-selected`. ### Tests - [ ] Cmd/Ctrl+K opens palette globally. - [ ] Typing filters; arrow keys move; Enter navigates. - [ ] Manifest lint catches an orphan `data-testid="settings-foo"` field with no entry. ## Out of scope - Recently-used / pinned settings — future. - Search across non-settings surfaces — future. ## References - `apps/web/CLAUDE.md` — drawer / dialog primitive baseline. - `apps/web/src/components/drawer.tsx` — focus-trap reference.
Collaborator

🦵 @charles kicked the queue — re-running implement on @dev.

🦵 @charles kicked the queue — re-running implement on @dev.
Sign in to join this conversation.
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#837
No description provided.