UI/UX Spec · Implementation-ready

Erbstücke Wannsee — Views

9 Views: Gate Screen · Galerie · Artikel-Modal · Admin Login · Admin Inventar · Artikel hinzufügen/bearbeiten · Codes · Reservierungen · Übersicht. Alle Mockups auf ~55 % skaliert. Impl-Ref-Tabellen enthalten exakte Tailwind-Klassen und Pixel-Werte.

9 views familie + admin 320px+ WCAG AA kein dark mode
View 01 — Route: /

Gate Screen — Code-Eingabe

Einzige öffentlich sichtbare Seite. Kein Inhalt ohne gültigen Code. Der ?code=-URL-Parameter wird serverseitig in +page.server.ts abgefangen — Cookie setzen → redirect /galerie. Manuelle Eingabe als Fallback.

📱 Alle Viewports — zentrierte Karte
🏡
Erbstücke Wannsee
Gib deinen persönlichen Code ein, um die Artikel zu sehen:
AB3K · · · ·
Noch kein Code? Wende dich an Marcel oder Tante.

Implementierungs-Referenz — Gate Screen

ElementTailwind-KlassenPxNotiz
Seitemin-h-screen bg-canvas flex items-center justify-center p-6Canvas-Hintergrund, vertikal zentriert
Kartebg-surface border border-line rounded-xl p-7 w-full max-w-sm text-center shadow-sm28px padmax-width 384px
Iconw-[52px] h-[52px] rounded-full bg-[#DFF0E6] flex items-center justify-center text-2xl mx-auto mb-3.552pxDekorativ — aria-hidden
Titelfont-serif text-xl font-bold text-ink mb-1.520px/700Lora
Subtexttext-sm text-ink-muted leading-relaxed mb-514pxInter
Code-Inputfont-mono text-base font-semibold tracking-[4px] uppercase text-center w-full h-12 border-1.5 border-line rounded-lg bg-[#FAFAF7] mb-3 focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary/3048pxinputmode="text" autocomplete="off" spellcheck="false"
Weiter-Buttonbg-primary hover:bg-primary-dark text-white w-full min-h-[48px] rounded-lg font-bold text-sm48pxSvelteKit Form Action — funktioniert ohne JS
Fehler-Texttext-xs text-status-taken mt-2 flex items-center gap-1.512px⚠ Icon + Text — kein Farbe allein
Hinweistext-[10px] text-ink-muted leading-relaxed mt-310px
Verhalten
  • GET /?code=AB3K7MN2 → Server liest url.searchParams.get('code'), prüft gegen DB, setzt HTTP-only Cookie family_code, leitet zu /galerie
  • Manuell falscher Code → Fehlermeldung: „Code nicht bekannt — bitte prüfe die Eingabe." mit ⚠-Icon
  • Gültiger Cookie vorhanden → Redirect zu /galerie ohne Gate Screen zu zeigen (hooks.server.ts)
View 02 — Route: /galerie

Galerie — Artikel-Übersicht

Hauptansicht für Familienmitglieder. Telefon: 1-Spalte-Liste (horizontale Karten, Foto 72 px links). Tablet/Desktop: 2-Spalten-Grid (quadratische Karten). Kategorie-Filter als scrollbare Pill-Leiste. Kein Artikel-Titel in der Galerie — nur Kategorie + Status.

📱 Telefon ≤ 767 px — Liste
Markus
Möbel
Schreibtisch Eiche
✓ Frei
Schmuck
Goldbrosche
● Renate
Bücher
Goethe Gesamtausgabe
✓ Meine Reservierung
Kunstwerke
Aquarell Wannsee
✓ Frei
💻 Tablet ≥ 768 px — 2-Spalten-Grid
Markus
Möbel
✓ Frei
Schmuck
● Renate
Bücher
✓ Meine Res.
Kunstwerke
✓ Frei

Implementierungs-Referenz — Galerie

ElementTailwind-KlassenPxNotiz
Navh-11 bg-primary sticky top-0 z-10 flex items-center px-3.544pxSticky — immer sichtbar
App-Logofont-serif text-sm font-bold text-white14px/700Lora
Nutzernameml-auto text-[10px] font-semibold text-white/7510px„Angemeldet als: Markus" — Display-Name aus Cookie
Filter-Leistebg-canvas border-b border-line px-2.5 py-2 flex gap-1.5 overflow-x-auto scrollbar-hide sticky top-11 z-10Sticky unter Nav
Pill aktivbg-primary text-white border-primary text-[10px] font-bold px-2.5 py-1.5 rounded-full min-h-[30px]30px min.
Pill inaktivbg-transparent text-ink-muted border-1.5 border-line text-[10px] font-semibold px-2.5 py-1.5 rounded-full min-h-[30px]
Grid (Telefon)flex flex-col gap-2 p-2.5≤ 767px1-Spalte-Liste
Grid (Tablet+)grid grid-cols-2 gap-2 p-2.5 via md:grid md:grid-cols-2≥ 768px2-Spalten-Grid
Karte (Liste)bg-surface border border-line rounded-lg overflow-hidden flex cursor-pointer hover:shadow-sm transition-shadowKlick öffnet Modal
Karte Foto (Liste)w-[72px] h-[72px] object-cover flex-shrink-072×72alt="" für dekorative Fotos; aria-describedby auf Karte für SR
Karte Foto (Grid)aspect-square w-full object-coverquadratisch
Kategorie-Labeltext-[9px] font-extrabold uppercase tracking-wider text-ink-muted9px
Status Freitext-[10px] font-bold text-status-free10px„✓ Frei"
Status Reservierttext-[10px] font-bold text-status-taken10px„● [Display-Name]"
Status Meinstext-[9px] font-bold bg-[#E8F5EC] text-[#2E6645] px-2 py-0.5 rounded-full border border-[#A8D5B8] mt-0.5 inline-blockBadge„✓ Meine Reservierung"
View 03 — Route: /galerie (Modal über Galerie)

Artikel-Modal — 3 Zustände

Bottom Sheet öffnet sich beim Antippen einer Galerie-Karte. Foto-Galerie mit Wisch-Geste (touch-action: pan-x) und Seitenzähler. Reservierungsbereich passt sich an Status an. Schließen durch Tippen auf Overlay oder Handle-Swipe nach unten.

Zustand A — Frei
Zustand B — Meine Reservierung
Zustand C — Fremde Reservierung

Implementierungs-Referenz — Artikel-Modal

ElementTailwind-KlassenPxNotiz
Overlayfixed inset-0 bg-black/45 flex items-end z-50Klick schließt Modal · role="dialog" aria-modal="true"
Sheetbg-surface rounded-t-xl w-full max-h-[88dvh] overflow-y-auto88dvh maxSvelteKit slide-Transition von unten
Handlew-9 h-1 bg-line rounded mx-auto mt-2.5 mb-3.54pxSwipe-Down schließt Modal
Foto-Galerieaspect-[4/3] w-full object-cover bg-canvas touch-pan-x overflow-hidden4:3Einfaches Swipe — kein JS-Framework nötig
Foto-Zählerabsolute bottom-2 right-2.5 bg-black/45 text-white text-[9px] font-bold px-1.5 py-0.5 rounded-full„1 / 3 →" — ausblenden bei nur 1 Foto
Modal-Bodyp-416px
Kategorie-Badgeinline-block text-[9px] font-extrabold uppercase tracking-wider bg-[#DFF0E6] text-[#2E6645] px-2.5 py-0.5 rounded-full border border-[#A8D5B8] mb-1.5
Artikel-Titelfont-serif text-[18px] font-bold text-ink leading-snug mb-1.518px/700Lora
Notiztext-sm text-ink-muted italic leading-relaxed mb-314pxNur rendern wenn artikel.notiz vorhanden
Reservieren (A)bg-primary hover:bg-primary-dark text-white w-full min-h-[48px] rounded-lg font-bold text-sm48pxForm Action POST
Aufheben (B)bg-[#FBF0F0] border-1.5 border-status-taken text-status-taken w-full min-h-[44px] rounded-lg font-bold text-sm44pxNur wenn reservierung.code_id === locals.familyCode.id
Gesperrt (C)bg-canvas border-1.5 border-line text-[#AAA] w-full min-h-[44px] rounded-lg font-bold text-sm cursor-not-allowed44pxdisabled-Attribut setzen
Reservierungslogik
  • Zustand wird serverseitig bestimmt: reservierungen-Row existiert? → Taken. code_id === locals.familyCode.id? → Mine.
  • POST Reservieren → UNIQUE-Constraint auf reservierungen.artikel_id verhindert Doppel-Reservierung atomar
  • Constraint-Fehler → Galerie neu laden, Modal zeigt Zustand C
View 04 — Route: /admin/login

Admin — Login

Eigenständige Seite mit dunklem Hintergrund (Admin-BG). Vollständig getrennt von der Familien-Ansicht — kein Code-Zugang. Benutzername (Marcel / Renate / Berit) + Passwort. Kein User-Enumeration bei falschen Credentials.

Admin-Zugang
Erbstücke Wannsee
Benutzername
Marcel
Passwort
••••••••

Implementierungs-Referenz — Admin Login

ElementTailwind-KlassenPxNotiz
Seitemin-h-screen bg-admin flex items-center justify-center p-6Admin-Dunkelgrün als Background
Kartebg-surface border border-line rounded-xl p-[22px] w-full max-w-xs22px padKein Shadow — wirkt geerdet auf dunklem BG
Form-Labeltext-[9px] font-extrabold uppercase tracking-wide text-ink-muted mb-1 block9pxImmer <label for="…"> verknüpfen
Inputw-full h-10 border-1.5 border-line rounded-md bg-[#FAFAF7] px-2.5 text-[13px] focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary/3040px
Anmelden-Buttonbg-admin hover:bg-[#1E2C24] text-white w-full min-h-[44px] rounded-md font-bold text-[13px]44pxbcrypt.compare → Cookie admin_session
Fehlertext-xs text-status-taken mt-212pxIdentische Meldung für falschen User + falsches Passwort — kein User-Enumeration
Views 05–08 — Route: /admin/*

Admin-Bereich — Sidebar-Layout

Gemeinsames Layout-Gerüst für alle vier Admin-Bereiche. Desktop: feste Sidebar (176 px) links, Content-Bereich rechts. Mobil: Sidebar klappt zu Hamburger-Drawer. Amber-Linie markiert den aktiven Bereich.

View 05 — /admin/inventar
Inventar
ArtikelKategorieStatus
Schreibtisch EicheMöbel✓ Frei
GoldbroscheSchmuck● Renate
Goethe GesamtausgabeBücher✓ Markus
Löschen nur wenn nicht reserviert.
View 05b — /admin/inventar/neu & /admin/inventar/[id]/bearbeiten — Vollbild Mobile
Zustand A — Kein Foto
← Inventar
Hinzufügen
Öffnet die Kamera. Erstes Foto = Galerie-Thumbnail.
Oder Datei wählen
Kategorie *
Erst Foto aufnehmen…
Titel (optional)
Erst Foto aufnehmen…
Notiz (optional)
Erst Foto aufnehmen…
Zustand B — Mit Fotos
← Inventar
Hinzufügen
Fotos (3)Ziehen = sortieren
Thumbnail
📷Mehr
Kategorie *
Möbel
Titel (optional)
Schreibtisch Eiche
Notiz (optional)
Kleine Schramme oben links.
View 06 — /admin/codes
Zugangscodes
NameCodeRes.
MarkusAB3K7MN23
RenateXP9QRT4W1
BeritLM2J6VH80
View 07 — /admin/reservierungen
Reservierungen
Markus — 3 Artikel
Schreibtisch Eiche
Möbel
Goethe Gesamtausgabe
Bücher
Renate — 1 Artikel
Goldbrosche mit Granat
Schmuck
Berit — 0 Artikel
Noch keine Reservierungen
View 08 — /admin/uebersicht
Übersicht
47
Gesamt
12
Reserviert
35
Frei
KategorieGesamtReserviertFrei
Möbel1459
Bücher18414
Schmuck725
Kunstwerke413
Küche404

Implementierungs-Referenz — Admin-Layout & Artikel hinzufügen

ElementTailwind-KlassenPxNotiz
Outer Layoutflex min-h-screen+layout.svelte unter /admin/
Sidebar Desktopw-44 bg-admin flex-shrink-0 hidden md:flex flex-col py-3176pxDunkelgrün, ab md: sichtbar
Sidebar MobilOverlay-Drawer — Toggle via Svelte $state(false)Hamburger-Icon in Mobile-TopBar
Sidebar-Link aktivflex items-center gap-2 px-3 py-1.5 text-[10px] font-semibold text-white bg-white/10 border-l-[3px] border-accentAmber-Linie links
Sidebar-Link inaktivflex items-center gap-2 px-3 py-1.5 text-[10px] font-semibold text-white/45 border-l-[3px] border-transparent hover:text-white/75
Content-Bereichflex-1 bg-canvas p-3.5 overflow-auto14px
Stat-Karten-Gridgrid grid-cols-3 gap-1.5 mb-3
Kamera-Buttonfont-serif text-sm font-bold bg-primary text-white w-full min-h-[60px] rounded-xl flex items-center justify-center gap-2.560pxTriggert <input capture="environment">
Thumbnail-Stripflex gap-1.5 overflow-x-auto pb-0.5Drag & Drop für Reihenfolge
Thumbnailw-[68px] h-[68px] rounded-lg object-cover flex-shrink-0 relative cursor-grab68×68
Thumbnail Badgeabsolute top-1 left-1 bg-accent text-white text-[7px] font-extrabold px-1.5 py-0.5 rounded-smText: „Thumbnail" — nur auf Index 0
Kategorie (native select)w-full h-[46px] border-1.5 border-primary rounded-lg px-3 text-[13px] text-ink bg-surface appearance-none46pxNative <select> für Mobile-Kompatibilität
Sticky Save Barbg-surface border-t border-line p-2.5 flex gap-2 shadow-[0_-2px_10px_rgba(0,0,0,.06)] flex-shrink-0Sticky unten — immer erreichbar
Code löschen (Bestätigung)Native confirm() oder Svelte Dialog-KomponenteWarnung: „Alle Reservierungen werden gelöscht"
Admin — Implementierungshinweise
  • Sidebar-Navigation: +layout.svelte unter src/routes/admin/ — rendert Sidebar + <slot />
  • Auth-Guard: +layout.server.ts prüft locals.admin → redirect zu /admin/login bei fehlendem Cookie
  • Artikel-Form: gleiche Svelte-Komponente für /neu und /[id]/bearbeiten — Edit füllt Props vor
  • Foto-Upload: verstecktes <input type="file" accept="image/*" capture="environment" multiple> — Kamera-Button triggert via .click()
  • Fotos als createObjectURL()-Preview im Strip, Upload erst beim Speichern via Multipart Form Action → sharp → WebP
  • Code „🔗 Link"-Button: navigator.clipboard.writeText(url) mit visueller Bestätigung (Button-Text → „Kopiert ✓")
  • Löschen von Codes: Bestätigungs-Dialog mit expliziter Warnung über kaskadierte Reservierungs-Löschung