docs: add AI capture ratio planning and design specs
This commit is contained in:
234
docs/superpowers/plans/2026-04-22-ai-capture-ratio.md
Normal file
234
docs/superpowers/plans/2026-04-22-ai-capture-ratio.md
Normal file
@@ -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
|
||||
<div className="columns-2 gap-2">
|
||||
{examplePrompts.map((prompt) => (
|
||||
<Button
|
||||
key={prompt}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="mb-2 h-auto w-full break-inside-avoid whitespace-normal rounded-2xl px-3 py-2 text-left text-[11px]"
|
||||
onClick={() => onAiTemplateSelect(prompt)}
|
||||
disabled={aiLoading || !canUseAi}
|
||||
>
|
||||
{prompt}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
```
|
||||
|
||||
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"
|
||||
```
|
||||
83
docs/superpowers/specs/2026-04-22-ai-capture-ratio-design.md
Normal file
83
docs/superpowers/specs/2026-04-22-ai-capture-ratio-design.md
Normal file
@@ -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.
|
||||
Reference in New Issue
Block a user