managarten/apps/mana/apps
Till JS 2b89bf7955 feat(wardrobe): outfits composer + detail page + tab switcher (M3)
M3 of docs/plans/wardrobe-module.md — layers outfit composition on top
of M2's garment grid. Users can now combine their garments into named
outfits, see them in a second tab under /wardrobe, open a per-outfit
detail page, and edit via the same composer route.

Routes:
- /wardrobe/compose — empty composer, creates a new outfit
- /wardrobe/compose/[outfitId] — composer pre-populated with an
  existing outfit, saves back into it (SvelteKit optional-param
  `[[outfitId]]` folder name). Both wrap OutfitComposer in
  `{#key outfitId ?? 'new'}` so create→edit navigation cleanly
  re-mounts with the right initial state.
- /wardrobe/outfit/[id] — outfit detail; wrapped in `{#key id}`
  for the same reason as the garment detail route.

Components:
- OutfitCard — grid tile. Cover precedence: lastTryOn.imageUrl
  (M4 payload) → 2×2 garment-thumbnail collage → empty state.
  Shows name + "<n> Stücke · <occasion>" line + favorite heart
  overlay when set.
- OutfitComposer — two-column editor. Left: garments grouped by
  category with +/✓ overlay toggles and a scroll container capped
  at 70vh so the right-hand editor doesn't disappear below the
  fold on long libraries. Right: name + description + occasion
  dropdown + season pill-toggles + comma-tags + composition chips
  with hover-× to remove. Click-to-add (no drag-drop — simpler
  mental model, keyboard-accessible for free, 100% of the
  workflow covered).
- OutfitsView — sibling to GridView, renders the outfit grid and
  the "+ Neues Outfit" CTA. Shows a garments-first empty state
  when the user has no clothing at all, an outfit-only empty state
  when they do but haven't composed anything yet.
- DetailOutfitView — cover + metadata card + "Zusammenstellung"
  grid (each garment tile links back to its own detail page).
  Try-On button is a stub for M4 ("kommt bald"); the Try-On
  history strip reads from picture.images via the existing
  useOutfitTryOns query and renders once M4 starts writing those
  back-references.

ListView now toggles between Garments (GridView, default) and
Outfits (OutfitsView) tabs; local state, lost on hard reload,
kept across in-app navigation.

Types: OutfitTryOn gains `imageUrl: string` (mana-media URL cached
alongside the picture.images.id pointer). Needed so the OutfitCard
renders the try-on thumb with one HTTP round-trip instead of a
Dexie→picture.images→mana-media lookup chain. Source of truth
remains the picture.images row; this is just a cache.

No M1 data shape breaks — only additive field on OutfitTryOn and
that type wasn't used anywhere in shipped code yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:45:21 +02:00
..
landing docs: add Apr 16 devlog, remove duplicate devlogs, update MODULE_REGISTRY 2026-04-17 15:27:00 +02:00
web feat(wardrobe): outfits composer + detail page + tab switcher (M3) 2026-04-23 18:45:21 +02:00