# 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 ``.
Native camera opens. After capture β Step 3.
### Step 2b β Gallery
Triggers ``.
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 `` 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 |