# Mobile-First UI/UX Redesign Concept

> **Status: IMPLEMENTED (v0.15).** This document captures the design intent. The redesign
> has shipped — see [BottomNav.svelte](../frontend/src/lib/components/BottomNav.svelte),
> [UploadSheet.svelte](../frontend/src/lib/components/UploadSheet.svelte),
> [CameraCapture.svelte](../frontend/src/lib/components/CameraCapture.svelte),
> [feed/+page.svelte](../frontend/src/routes/feed/+page.svelte),
> [account/+page.svelte](../frontend/src/routes/account/+page.svelte),
> [host/+page.svelte](../frontend/src/routes/host/+page.svelte),
> [admin/+page.svelte](../frontend/src/routes/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"

---

## 2. Feed / Gallery Page

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

### Step 2b — Gallery

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 |
