Files
EventSnap/docs/CONCEPT_MOBILE_UI.md
MechaCat02 9a0ceeced7 docs: realign blueprint with shipped state + add feature/journey/ideas docs
- PROJECT.md, README.md, TEST_GUIDE.md: status line refreshed; rate-limiter
  doc-vs-code drift fixed; HTML export section rewritten for the SvelteKit-
  static viewer; SSE event names + new events documented; config seed block
  extended with planned toggles + privacy_note; decision log entries added.
- docs/CONCEPT_HTML_VIEWER.md, docs/CONCEPT_MOBILE_UI.md: banner the design
  intent as shipped; point at the source-of-truth code paths.
- docs/CONCEPT_DIASHOW.md: planned-then-shipped design for the live diashow
  (two-queue policy, pluggable transitions, data-mode aware).
- docs/FEATURES.md: capability matrix by role (Guest / Host / Admin) plus
  prose per area (auth, posting, feed, moderation, admin, export, gestures,
  data mode, quotas, privacy note, extensibility).
- docs/USER_JOURNEYS.md: step-by-step flows for every supported scenario,
  including PIN reset by host, data mode, privacy note, gestures, and the
  admin toggles.
- docs/IDEAS.md: speculative extensions (global diashow, reactions,
  multi-tenancy, animation pack, etc.) — explicitly out of v0.16 scope.
- backend/migrations/README.md, frontend/src/lib/README.md: codify the
  "never edit a shipped migration" rule and the lib/ conventions
  (one store per concern, gestures via actions, sheets via ContextSheet,
  transitions as drop-in components).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 14:31:06 +02:00

22 KiB
Raw Permalink Blame History

Mobile-First UI/UX Redesign Concept

Status: IMPLEMENTED (v0.15). This document captures the design intent. The redesign has shipped — see BottomNav.svelte, UploadSheet.svelte, CameraCapture.svelte, feed/+page.svelte, account/+page.svelte, host/+page.svelte, admin/+page.svelte. Use this doc as the design reference; treat code as the source of truth for current behaviour.

Overview

EventSnap is intended for mobile use at live events. This document describes the full mobile-first design covering navigation, the feed/gallery, account page, host dashboard, and admin dashboard.


1. Navigation: Bottom Tab Bar

Replace all per-page top-right icon links with a single persistent bottom tab bar present on every page. The bar sits at the very bottom with proper padding-bottom for iPhone home indicator (safe-area-inset-bottom).

Tab Composition by Role

Role Tabs
Guest 🏠 Feed · [📷+] · 👤 Account
Host 🏠 Feed · [📷+] · 👤 Account
Admin 🏠 Feed · [📷+] · 👤 Account

All roles see the same three tabs. Role-specific dashboard links (Host, Admin) live inside the Account page — not as separate tabs. This keeps the bar simple and avoids conditional tab rendering.

Visual Style

  • Frosted glass background: bg-white/85 backdrop-blur-md
  • Thin top border: border-t border-gray-200
  • Subtle shadow upward
  • Active tab: colored icon + small label below
  • Inactive tab: gray icon, small gray label

Upload FAB (Floating Action Button)

The center tab is an elevated circular button, not a flat tab icon:

  • Circle ~56 px diameter, bg-blue-600
  • Icon: camera outline with a small + badge overlaid at bottom-right
  • Raised above the bar with a drop shadow
  • Press: slight scale-down (scale-95) + haptic feedback where available
  • Communicates "capture new or upload existing"

Header

┌─────────────────────────────────────────┐
│  Sommerfest 2025              ≡  ⊞      │
└─────────────────────────────────────────┘
  • Event name left-aligned
  • List/grid view toggle icons right-aligned (≡ list, ⊞ grid)
  • Header collapses on downward scroll (only toggle remains visible), expands on upward scroll

View A — Chronological List (default)

Full-width post cards, newest at top, infinite scroll.

┌─────────────────────────────────────────┐
│  👤 MaxMustermann          · vor 2 Min  │
│ ┌───────────────────────────────────┐   │
│ │                                   │   │
│ │          [photo / video]          │   │
│ │                                   │   │
│ └───────────────────────────────────┘   │
│  Tolle Stimmung! #party #spaß           │
│  ❤️ 12   💬 3                           │
└─────────────────────────────────────────┘
  • Media: full-width, native aspect ratio, capped at 80 vh
  • Avatar: colored initial circle, no photo
  • Timestamp: relative ("vor 2 Min", "vor 1 Std")
  • Tap media → fullscreen lightbox, swipe left/right navigates feed
  • No search bar in list view

View B — Grid View

Transition animation when toggling: list collapses, grid fades/scales in (~200 ms).

Search Bar (grid view only)

┌─────────────────────────────────────────┐
│  🔍  Nutzer oder #Tag suchen…      ×   │
└─────────────────────────────────────────┘
  • Appears below the header only in grid view
  • Slides in as part of the view transition
  • × clears current input
  • Auto-focuses when grid view is activated

Autocomplete Dropdown

Appears immediately on focus and updates on every keystroke. Data source: the already-loaded posts in memory — no extra API calls.

Two suggestion lists are derived at load time:

  • allTags: unique hashtags from all post captions, sorted by frequency descending
  • allUploaders: unique display names, sorted alphabetically
User input Suggestions shown
(focus, empty) Top 3 tags by frequency + top 3 uploaders
# All tags, frequency-sorted
#par Tags with prefix "par": #party, #parade
Max Uploaders matching "max" (case-insensitive)
a Uploaders containing "a" + tags containing "a"

Dropdown layout:

┌─────────────────────────────────────────┐
│  👤 Nutzer                              │
│     MaxMustermann                       │
│     AnnaSchulz                          │
│  # Tags                                 │
│     #party    #tanz    #spaß            │
└─────────────────────────────────────────┘

Max ~5 total suggestions. Tapping a suggestion adds it as an active filter chip and clears the search bar for another entry.

Active Filter Chips

┌─────────────────────────────────────────┐
│  👤 MaxMustermann ×   # party ×         │
│  Alle Filter löschen                    │  ← shown when 2+ chips active
└─────────────────────────────────────────┘

Filter combination logic:

Combination Logic
Two tags: #party + #tanz OR — posts with either tag
Two uploaders: Max + Anna OR — posts from either
Uploader + tag: Max + #party AND — posts by Max that also have #party

Grid Layout

┌───────┬───────┬───────┐
│       │       │       │
│       │       │       │  3-column, equal square cells
├───────┼───────┼───────┤  small gap (2 px)
│       │  ▶    │       │  ← video: small ▶ badge + duration
│       │  0:42 │       │
└───────┴───────┴───────┘
  • Tap cell → fullscreen lightbox, swipe navigates filtered set only
  • Virtualized grid for performance on large events

3. Upload Flow

Step 1 — Source Selection (Bottom Sheet)

Tapping the FAB slides up a bottom sheet (~300 ms spring animation). Frosted glass, rounded top corners, drag handle at top. Tap outside or swipe down to dismiss.

┌──────────────────────────────────┐
│          ▬  (drag handle)        │
│                                  │
│  📸  Kamera                      │
│      Jetzt aufnehmen             │
│                                  │
│  🖼  Galerie                     │
│      Foto oder Video wählen      │
│                                  │
│  [  Abbrechen  ]                 │
└──────────────────────────────────┘

Step 2a — Camera

Triggers <input type="file" accept="image/*,video/*" capture="environment">. Native camera opens. After capture → Step 3.

Triggers <input type="file" accept="image/*,video/*" multiple>. Native gallery picker with multi-select (up to ~10 items). After selection → Step 3.

Step 3 — Preview & Metadata Screen

Full-screen, pushes in from right. Bottom nav hidden (immersive).

┌──────────────────────────────────┐
│  ×  Abbrechen      Hochladen →  │
├──────────────────────────────────┤
│                                  │
│  ┌────┐ ┌────┐ ┌────┐  →        │  ← horizontal scroll, tap to preview
│  │img │ │img │ │ ×  │           │    × on each thumbnail to remove
│  └────┘ └────┘ └────┘           │
│                                  │
│  Beschreibung (optional)         │
│  ┌────────────────────────────┐  │
│  │                            │  │  ← auto-focused
│  └────────────────────────────┘  │
│                                  │
│  # Schnell-Tags                  │
│  [#Feier] [#Spaß] [#Party] …   │  ← tap to append to caption
│                                  │
├──────────────────────────────────┤
│  ┌────────────────────────────┐  │
│  │      📤 Hochladen          │  │  ← sticky, disabled until ≥1 file
│  └────────────────────────────┘  │
└──────────────────────────────────┘

Step 4 — Background Upload + Feedback

  • Tapping "Hochladen" immediately returns to the feed (optimistic UX)
  • Slim progress bar above the bottom tab bar while queue is active
  • FAB gets a small spinning ring badge while uploads are in progress
  • On completion: brief toast near the bottom ("✓ Hochgeladen")
  • Rate-limit countdown banner anchored above the bottom bar (existing behavior)

4. Account Page

Single entry point for profile info and role-based dashboard navigation.

┌─────────────────────────────────────────┐
│              Mein Account               │
├─────────────────────────────────────────┤
│                                         │
│        ┌───────┐                        │
│        │  M    │   MaxMustermann        │
│        └───────┘   🏷 Gast              │
│                    Sommerfest 2025      │
│                    7 Uploads            │
│                                         │
├── Dashboards ───────────────────────────┤  (entire section absent for guests)
│                                         │
│  ⭐  Host-Dashboard                →    │  (host + admin only)
│  🛡  Admin-Dashboard               →    │  (admin only)
│                                         │
├── Konto ────────────────────────────────┤
│                                         │
│  ✏️  Anzeigename ändern             →    │
│  🔑  PIN ändern                     →    │
│  🚪  Event verlassen                →    │  (red text, confirm sheet)
│                                         │
└─────────────────────────────────────────┘
│  🏠 Feed  ·  [📷+]  ·  👤 Account       │
└─────────────────────────────────────────┘
  • "Dashboards" section is entirely absent in the DOM for plain guests — not just hidden
  • "Event verlassen" triggers a bottom-sheet confirmation before action
  • Avatar: colored circle with initial letter

5. Host Dashboard

Accessed via Account → Host-Dashboard. Full-screen page, bottom nav visible.

┌─────────────────────────────────────────┐
│  ←   🎉 Host-Dashboard                  │
├─────────────────────────────────────────┤
│                                         │
│  ── Statistiken ──────────────────────  │
│  ┌──────────┐  ┌──────────┐            │
│  │    24    │  │   156    │            │
│  │  Nutzer  │  │ Uploads  │            │
│  └──────────┘  └──────────┘            │
│                                         │
│  ── Event-Einstellungen ──────────────  │  ← collapsible section
│                                         │
│  Neue Uploads sperren                   │
│  ○────────────●  Gesperrt              │  ← toggle
│  Keine neuen Uploads möglich            │
│                                         │
│  ── Nutzerverwaltung ─────────────────  │  ← collapsible section
│                                         │
│  🔍  Nutzer suchen…                     │
│  ┌───────────────────────────────────┐  │
│  │  👤  MaxMustermann   Gast  [🚫]   │  │
│  │  👤  AnnaSchulz      Gast  [🚫]   │  │
│  │  👤  GesperrterNutzer      [↩]    │  │  ← banned: undo icon
│  └───────────────────────────────────┘  │
│                                         │
└─────────────────────────────────────────┘
│  🏠 Feed  ·  [📷+]  ·  👤 Account       │
└─────────────────────────────────────────┘
  • Sections have a chevron toggle to collapse/expand (helps on small phones)
  • Ban/unban: icon tap + bottom sheet confirmation ("Nutzer wirklich sperren?")
  • User list virtualized for large events

6. Admin Dashboard

Most complex page. Uses an inner tab bar directly below the header to divide the four functional areas. The inner tabs are independent of the bottom nav.

┌─────────────────────────────────────────┐
│  ←   🛡 Admin-Dashboard                 │
├─────────────────────────────────────────┤
│  [Stats] [Config] [Export] [Nutzer]     │  ← inner tab bar (scrollable if needed)
├─────────────────────────────────────────┤
│                                         │
│  [Tab content]                          │
│                                         │
└─────────────────────────────────────────┘
│  🏠 Feed  ·  [📷+]  ·  👤 Account       │
└─────────────────────────────────────────┘

Stats Tab

  ┌──────────┐  ┌──────────┐
  │  156     │  │  24      │
  │ Uploads  │  │ Nutzer   │
  └──────────┘  └──────────┘
  ┌──────────┐  ┌──────────┐
  │  2.1 GB  │  │  3       │
  │ Speicher │  │ Gesperrt │
  └──────────┘  └──────────┘

2×2 metric card grid. Values large and prominent. Optionally expandable to show time-series charts on tap.

Config Tab

  Upload-Limit / Nutzer
  ┌────────────────────────────────┐
  │  10                            │
  └────────────────────────────────┘

  Zeitfenster (Sek.)
  ┌────────────────────────────────┐
  │  60                            │
  └────────────────────────────────┘

  Max. Dateigröße (MB)
  ┌────────────────────────────────┐
  │  50                            │
  └────────────────────────────────┘

  ┌────────────────────────────────┐
  │        💾 Speichern            │  ← sticky at bottom of tab scroll area
  └────────────────────────────────┘

Each setting: full-width label + input. Save button always reachable without scrolling.

Export Tab

  ── Galerie ──────────────────────────
  [  🔓 Galerie freigeben  ]

  ── Export-Jobs ──────────────────────
  [  🔄 Aktualisieren  ]

  ┌───────────────────────────────────┐
  │  HTML-Viewer   ● Fertig  [↓ ZIP]  │
  │  JSON-Export   ⏳ Läuft…          │
  │  ZIP-Archiv    ✗ Fehler   [↺]     │
  └───────────────────────────────────┘

  [  + Neuer Export-Job  ]
  • Status chips: green (Fertig), amber (Läuft), red (Fehler)
  • Download button inline per completed job
  • Only the jobs list refreshes on "Aktualisieren" — no full page re-render

Nutzer Tab

Same structure as Host Nutzerverwaltung, with any additional admin-only actions (e.g. role assignment) added as extra controls per row.


Touch gestures vs. desktop buttons (planned extension)

Where a gesture is more ergonomic on mobile than a button, EventSnap prefers the gesture on touch and mirrors it as an explicit button on desktop. Inspired by Instagram, WhatsApp and Telegram — long-press for context, swipe to dismiss, double-tap to react.

Surface Touch gesture Desktop equivalent
Post card Long-press → context bottom sheet ⋯ kebab in the card corner
Comment row Long-press → bottom sheet ⋯ next to the comment timestamp
User row (Host / Admin dashboards) Long-press → bottom sheet Inline buttons (ban, promote, reset PIN)
Lightbox Swipe left / right ←/→ arrow keys + on-screen chevrons
Lightbox Swipe down to close Esc + ✕ button
Bottom sheet Swipe down to dismiss Click backdrop or × in the sheet header
Feed Pull to refresh Refresh icon next to the view toggle
Post (any) Double-tap → like Click the heart icon

Discoverability rule: every gesture must have a visible button equivalent on the same page. Gestures are never the only path to an action. Helps with stylus users, accessibility, and people who don't know the gesture vocabulary.

Context bottom-sheet pattern (used by every long-press above):

┌──────────────────────────────────┐
│         ▬  (drag handle)         │
│                                  │
│  🗑  Löschen                     │  ← destructive action red
│  📥  Original anzeigen           │
│  🔗  Teilen                      │
│  🚩  Melden                      │  (only on others' content)
│                                  │
│  [        Abbrechen        ]     │
└──────────────────────────────────┘

Each sheet is composed from a shared <ContextSheet> component (planned) with a single actions: ContextAction[] prop. Adding a new gesture context = define the actions array where needed. Drop-in, one file.

Design Principles Summary

Principle Application
Thumb zone All primary actions in bottom ~20% of screen
One-hand operation FAB centered, bottom sheets dismissable with swipe
Minimal taps to upload Source → picker → preview → upload: 4 taps
Immediate feedback Optimistic return to feed, background upload
Progressive disclosure Caption/tags optional; CTA always reachable
No role clutter in nav Role links only in Account, bar stays clean
Collapsible sections Long management pages stay usable on small phones
Inner tabs for complex pages Admin dashboard split across 4 focused tabs
Gestures over chrome Long-press for context menus, swipe to dismiss, double-tap to react — always with a button fallback for desktop and accessibility