# Ticket 11.1 — Fix Image Attachment

**Phase**: 11 — UI/UX Polish
**Priority**: High
**Depends on**: None

## Description

The image attachment feature in InputArea.svelte is non-functional. The "Take Photo" and "Add Photos" buttons in the attach popup create `<input type="file">` elements and trigger their click events, but have **no `onchange` handler** to process the selected files. Additionally, `PastePreview.svelte` exists as a component but is never rendered in InputArea or ChatLayout.

This ticket fixes the image attachment flow end-to-end:

1. Wire up `onchange` handlers on file inputs to capture selected images
2. Convert images to base64 or read as data URLs
3. Show image thumbnails in the input area (similar to PastePreview)
4. Send images as part of the message (OpenCode accepts image parts in the prompt API)
5. Wire up PastePreview component for clipboard paste and drag-drop of images

## Acceptance Criteria

### AC1: File picker attaches images
```gherkin
Given the user is in the chat input area
When they click "Add Photos" and select one or more images from the file picker
Then thumbnails of the selected images appear in the input area below the textarea
```

### AC2: Camera capture attaches photo
```gherkin
Given the user is on a mobile device with a camera
When they click "Take Photo" and capture an image
Then a thumbnail of the captured photo appears in the input area below the textarea
```

### AC3: Image removal before sending
```gherkin
Given the user has one or more images attached in the input area
When they click the remove button on an image thumbnail
Then that image is removed from the attachment list
And the remaining images (if any) are still displayed
```

### AC4: Images sent as message parts
```gherkin
Given the user has attached one or more images and typed a text message
When they press Send
Then the message payload sent to OpenCode's prompt API includes image parts
And each image part has type "image" with base64-encoded data
And the text content is included as a separate text part
```

### AC5: Clipboard paste attaches image
```gherkin
Given the user has an image copied to their clipboard
When they paste (Cmd/Ctrl+V) while the input area is focused
Then the pasted image appears as a thumbnail in the attachment area
And PastePreview is rendered to display the image
```

### AC6: Drag-and-drop attaches image
```gherkin
Given the user has an image file on their desktop or file manager
When they drag the image file onto the input area and drop it
Then the dropped image appears as a thumbnail in the attachment area
```

### AC7: Large image compression
```gherkin
Given the user attaches an image larger than 5MB
When the image is processed for attachment
Then the image is resized or compressed to be under 5MB
And the thumbnail reflects the compressed version
```

### AC8: Multiple image attachment
```gherkin
Given the user has already attached one image
When they attach additional images via file picker, paste, or drag-drop
Then all images appear as thumbnails in the attachment area
And all images are included in the message payload when sent
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| File input onchange handler | E2E | Selecting files triggers thumbnail rendering in attachment area |
| Image to base64 conversion | Unit | FileReader correctly converts image blob to base64 data URL |
| Image removal from attachment list | E2E | Clicking remove button deletes image from state and DOM |
| Message payload with image parts | Integration | POST to `/session/:id/prompt` includes `parts` array with `type: "image"` entries |
| Clipboard paste image handling | E2E | Pasting image from clipboard adds it to attachment area |
| Drag-drop image handling | E2E | Dropping image file onto input area adds it to attachment area |
| Image size validation/compression | Unit | Images over 5MB are resized; images under 5MB pass through unchanged |
| Multiple image state management | Unit | Attachment store correctly accumulates and removes multiple images |

## Reference

- Broken file inputs: `conduit/src/lib/public/components/layout/InputArea.svelte` (lines 107-123, no onchange)
- Unused component: `conduit/src/lib/public/components/features/PastePreview.svelte`
- OpenCode prompt API: `POST /session/:id/prompt` (accepts `parts` array with `type: "image"`)
- claude-relay image handling: `../claude-relay/lib/public/modules/input.js` (image paste/attach flow)
