~ 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.