~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain

photography-focused photo sharing platform

grain.social
1 collaborator
0
2
69 lines · 2.5 KB Raw History
# Gallery Creation Feature Design

## Overview

Add gallery creation to hatk-template-grain, matching the UX flow from grain-next adapted to SvelteKit 5 + hatk.

## Create Flow

Single `/create` route with 3 steps managed by Svelte 5 `$state`:

### Step 1: Photo Selection

- "+" button in sidebar nav (desktop) and mobile bottom nav, visible only when authenticated
- Opens native file picker (images only, multiple selection, max 10)
- Client-side processing: resize to max 2000x2000px, compress to <900KB JPEG via binary search on quality
- Horizontal thumbnail strip with remove buttons

### Step 2: Gallery Metadata

- Title input (required, max 100 chars) — enables "Next" button
- Description textarea (optional, max 1000 chars)
- Description parsed for rich text facets (@mentions, URLs, hashtags)

### Step 3: Alt Text

- Each photo displayed with alt text input (max 1000 chars)
- Alt text is optional
- "Post" button publishes the gallery

Back navigation between steps preserves all state. Only a full page leave discards the draft.

## Publish Sequence

1. Upload each photo blob via hatk client (`agent.uploadBlob`)
2. Create `social.grain.photo` records (blob ref, dimensions, alt text, createdAt)
3. Create `social.grain.gallery` record (title, description, facets, createdAt)
4. Create `social.grain.gallery.item` records (gallery URI, photo URI, position index, createdAt)
5. On success: invalidate TanStack Query feed caches, navigate to home feed

## Error Handling

- Blob upload failure: stop, show error on that photo, allow retry
- Gallery record failure: stop, orphaned blobs acceptable (AT Protocol handles this)
- Gallery item link failure: partial gallery visible, allow retry
- Disable "Post" button during publish, show progress indicator

## New Files

- `app/routes/create/+page.svelte` — 3-step create flow
- `app/lib/utils/image-resize.ts` — `processPhotos()`, `resizeImage()`, `readFileAsDataURL()`
- `app/lib/utils/rich-text.ts` — `parseTextToFacets()` for mentions, URLs, hashtags

## Modified Files

- Sidebar/nav components — add "+" create button (auth-gated)
- `app/lib/queries.ts` — add mutation helpers for blob upload, photo/gallery/item creation

## Constraints

- Max 10 photos per gallery
- Max 2000x2000px resolution
- Max 900KB per compressed image
- Title max 100 chars
- Description max 1000 chars
- Alt text max 1000 chars per photo

## Draft State

No sessionStorage or external service needed. All draft state lives in `+page.svelte` via Svelte 5 `$state` runes since it's a single route.