diff --git a/docs/superpowers/plans/2026-04-22-ai-capture-ratio.md b/docs/superpowers/plans/2026-04-22-ai-capture-ratio.md new file mode 100644 index 0000000..bac2663 --- /dev/null +++ b/docs/superpowers/plans/2026-04-22-ai-capture-ratio.md @@ -0,0 +1,234 @@ +# AI Capture Ratio Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Change the non-mobile AI capture composer to a `70 / 30` text-to-attachments split, stack attachment previews one per row, and render example prompts as a masonry-style cluster. + +**Architecture:** Keep the page-level AI capture placement unchanged and make the entire change inside `AIToolbar`. Lock the new layout with source-based tests in `tests/ai-toolbar.test.ts`, then make the smallest JSX/class updates needed in `src/components/ai-toolbar.tsx` to satisfy them. + +**Tech Stack:** Bun test runner, Next.js, React, TypeScript, Tailwind utility classes, Biome, `useIsMobile` + +--- + +### Task 1: Lock the `70 / 30` Desktop Composer Contract + +**Files:** +- Modify: `tests/ai-toolbar.test.ts` +- Test: `tests/ai-toolbar.test.ts` + +- [ ] **Step 1: Write the failing test** + +Replace the current non-mobile composer assertion so it expects a `70 / 30` split instead of equal-width columns. + +```ts +test("desktop composer uses a 70 / 30 row when the page gives it full-width space", () => { + const source = readToolbarSource(); + + expect(source).toContain("isMobile"); + expect(source).toContain('? "grid gap-3"'); + expect(source).toContain( + ': "grid gap-3 grid-cols-[minmax(0,0.7fr)_minmax(0,0.3fr)]"', + ); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `bun test tests/ai-toolbar.test.ts` + +Expected: FAIL because `src/components/ai-toolbar.tsx` still contains the equal-width non-mobile grid. + +- [ ] **Step 3: Write minimal implementation** + +Update the non-mobile composer grid in `src/components/ai-toolbar.tsx`. + +Change this branch: + +```ts +: "grid gap-3 grid-cols-[minmax(0,1fr)_minmax(0,1fr)]" +``` + +To: + +```ts +: "grid gap-3 grid-cols-[minmax(0,0.7fr)_minmax(0,0.3fr)]" +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `bun test tests/ai-toolbar.test.ts` + +Expected: PASS for the updated desktop composer test. + +- [ ] **Step 5: Commit** + +```bash +git add tests/ai-toolbar.test.ts src/components/ai-toolbar.tsx +git commit -m "refactor(ai-toolbar): use 70-30 desktop composer split" +``` + +### Task 2: Lock One-Preview-Per-Row Attachments + +**Files:** +- Modify: `tests/ai-toolbar.test.ts` +- Modify: `src/components/ai-toolbar.tsx` +- Test: `tests/ai-toolbar.test.ts` + +- [ ] **Step 1: Write the failing test** + +Add a test that rejects the old desktop `grid-cols-2` preview layout and expects a row-stacked preview container. + +```ts +test("attachment previews stack one per row instead of using a two-column desktop grid", () => { + const source = readToolbarSource(); + + expect(source).not.toContain('"mt-3 grid gap-2 grid-cols-2"'); + expect(source).toContain('"mt-3 grid gap-2"'); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `bun test tests/ai-toolbar.test.ts` + +Expected: FAIL because the preview container still uses the desktop `grid-cols-2` branch. + +- [ ] **Step 3: Write minimal implementation** + +Simplify the preview container in `src/components/ai-toolbar.tsx` so it uses one shared stacked grid for all widths. + +Replace: + +```ts +className={ + isMobile ? "mt-3 grid gap-2" : "mt-3 grid gap-2 grid-cols-2" +} +``` + +With: + +```ts +className="mt-3 grid gap-2" +``` + +Keep each preview card as-is so the image and remove button behavior do not change. + +- [ ] **Step 4: Run test to verify it passes** + +Run: `bun test tests/ai-toolbar.test.ts` + +Expected: PASS for the stacked-preview contract. + +- [ ] **Step 5: Commit** + +```bash +git add tests/ai-toolbar.test.ts src/components/ai-toolbar.tsx +git commit -m "refactor(ai-toolbar): stack attachment previews by row" +``` + +### Task 3: Lock Masonry-Style Example Prompts + +**Files:** +- Modify: `tests/ai-toolbar.test.ts` +- Modify: `src/components/ai-toolbar.tsx` +- Test: `tests/ai-toolbar.test.ts` + +- [ ] **Step 1: Write the failing test** + +Add a test that locks the example prompt area to a clustered layout instead of a flat single-row strip. + +```ts +test("example prompts use a masonry-style cluster inside the composer footer", () => { + const source = readToolbarSource(); + + expect(source).toContain("Try:"); + expect(source).toContain("columns-2"); + expect(source).toContain("break-inside-avoid"); + expect(source).toContain("w-full text-left"); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `bun test tests/ai-toolbar.test.ts` + +Expected: FAIL because the current prompt chips still live in a flat wrapped flex row. + +- [ ] **Step 3: Write minimal implementation** + +Refactor only the example prompt block in `src/components/ai-toolbar.tsx`. + +Use this structure: + +```tsx +
+ {examplePrompts.map((prompt) => ( + + ))} +
+``` + +Keep the surrounding footer copy and disabled behavior intact. Do not add new helper components. + +- [ ] **Step 4: Run test to verify it passes** + +Run: `bun test tests/ai-toolbar.test.ts` + +Expected: PASS for the prompt-cluster contract. + +- [ ] **Step 5: Commit** + +```bash +git add tests/ai-toolbar.test.ts src/components/ai-toolbar.tsx +git commit -m "refactor(ai-toolbar): cluster example prompts in masonry layout" +``` + +### Task 4: Full Verification + +**Files:** +- Test: `tests/ai-toolbar.test.ts` +- Test: `tests/home-page-layout.test.ts` +- Verify: `src/components/ai-toolbar.tsx` + +- [ ] **Step 1: Run targeted layout tests** + +Run: `bun test tests/ai-toolbar.test.ts tests/home-page-layout.test.ts` + +Expected: PASS with the AI toolbar and page layout contracts still green. + +- [ ] **Step 2: Run the full test suite** + +Run: `bun test` + +Expected: PASS with no new failures. + +- [ ] **Step 3: Run typecheck** + +Run: `bun run type:check` + +Expected: PASS. + +- [ ] **Step 4: Run lint** + +Run: `bun run lint` + +Expected: PASS, with only the pre-existing `src/lib/compose-refs.ts` warning if it still appears. + +- [ ] **Step 5: Commit** + +If Task 4 introduced no code changes, skip a commit here. If a tiny verification-driven tweak was required, commit only that tweak: + +```bash +git add src/components/ai-toolbar.tsx tests/ai-toolbar.test.ts +git commit -m "test(ai-toolbar): verify desktop composer layout contracts" +``` diff --git a/docs/superpowers/specs/2026-04-22-ai-capture-ratio-design.md b/docs/superpowers/specs/2026-04-22-ai-capture-ratio-design.md new file mode 100644 index 0000000..813f486 --- /dev/null +++ b/docs/superpowers/specs/2026-04-22-ai-capture-ratio-design.md @@ -0,0 +1,83 @@ +# AI Capture Ratio Design + +## Summary + +Adjust the non-mobile AI capture composer so the text area and attachments panel use a `70 / 30` split instead of equal columns. Within the attachments panel, image previews should stack vertically with one preview per row. Example prompts should form a masonry-style cluster inside the composer footer rather than reading as a flat uniform row. + +## Goal + +Give the text composer more room for prompt entry while keeping attachments visible and useful as a clearly secondary surface. + +## Scope + +- Update the non-mobile `AIToolbar` layout only. +- Keep mobile behavior unchanged. +- Change the attachments preview layout so each image preview occupies its own full-width row. +- Change the example prompt area so prompts form a masonry-style cluster within their parent. +- Update tests that lock down the desktop layout contract. + +## Non-Goals + +- No changes to the page-level placement of the AI capture section. +- No changes to mobile stacking behavior. +- No changes to attachment upload behavior, image removal behavior, or summary behavior. +- No visual redesign of the prompt footer, buttons, or copy. + + +## Design + +### Main Composer Layout + +For every non-mobile width, the AI capture composer will use a two-column grid with this ratio: + +- Left column: `70%` equivalent width for the text composer +- Right column: `30%` equivalent width for the attachments panel + +Implementation will use a Tailwind arbitrary grid template in the existing `useIsMobile()` branch inside `src/components/ai-toolbar.tsx`. + +### Attachments Preview Layout + +When image previews are present, the attachments panel will render them in a vertical list rather than a two-column thumbnail grid. + +Expected behavior: + +- Each preview takes the full available width of the attachments panel. +- Previews stack top-to-bottom with consistent spacing. +- Existing remove actions stay attached to each preview card. +- Mobile can share the same one-per-row preview layout without introducing a separate preview treatment. + +### Example Prompt Layout + +The example prompt area below the textarea should feel denser and more editorial than a single flat row of chips. + +Expected behavior: + +- Prompts remain inside the existing composer footer area. +- Prompt chips wrap into a masonry-style cluster rather than a rigid single-row strip. +- Chip widths remain content-driven so the cluster feels packed and varied. +- The prompt area should still read as secondary to the textarea itself. + +## Files Affected + +- `src/components/ai-toolbar.tsx` +- `tests/ai-toolbar.test.ts` + +## Testing + +Add or update tests to verify: + +- non-mobile layout uses a `70 / 30` grid split +- desktop/non-mobile preview layout is row-stacked instead of `grid-cols-2` +- example prompts use a masonry-style clustered layout rather than a flat row contract + +Then run: + +- `bun test` +- `bun run type:check` +- `bun run lint` + +## Risks + +- A narrower attachments panel may make attachment copy feel dense, so only the layout ratio should change unless the implementation reveals a real readability issue. +- A vertical preview list may increase panel height when many images are attached, but that is preferable to shrinking previews into a dense grid. +- A masonry prompt cluster can become visually noisy if spacing is too tight, so the implementation should preserve clear separation from the textarea and maintain readable chip padding.