feat(ui): elegant wedding white/silver/gold redesign

Reskin the whole app via design tokens in tailwind-theme.css (remapped
color ramps) plus a define-once component layer in lib/styles/components.css
(.btn, .card, .input, .chip, .badge, .sheet, …). Buttons are muted/outlined
gold rather than flat fills. Self-host Inter + Fraunces (woff2) under the
existing font-src 'self' CSP. Restyle the shared components and the account,
admin, host, join, recover and upload screens against the new tokens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-18 17:28:42 +02:00
parent 5546fb82e6
commit f243bfe89a
22 changed files with 696 additions and 545 deletions

View File

@@ -437,12 +437,7 @@
Kopieren
</button>
</div>
<button
onclick={() => (pinModal = null)}
class="w-full rounded-lg bg-blue-600 py-2 text-sm font-semibold text-white hover:bg-blue-700 active:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-400 dark:active:bg-blue-400"
>
Schließen
</button>
<button onclick={() => (pinModal = null)} class="btn btn-primary btn-block"> Schließen </button>
{/if}
</Modal>
@@ -458,17 +453,10 @@
ansehen, Keepsake herunterladen) bleibt bestehen. Rückgängig machbar über „Entsperren“.
</p>
<div class="flex gap-2">
<button
onclick={() => (banTarget = null)}
class="flex-1 rounded-lg border border-gray-300 py-2 text-sm text-gray-700 hover:bg-gray-50 active:bg-gray-100 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:active:bg-gray-800"
>
<button onclick={() => (banTarget = null)} class="btn btn-secondary flex-1">
Abbrechen
</button>
<button
onclick={confirmBan}
disabled={banSubmitting}
class="flex-1 rounded-lg bg-red-600 py-2 text-sm font-medium text-white hover:bg-red-700 active:bg-red-700 disabled:opacity-50 dark:bg-red-500 dark:hover:bg-red-400 dark:active:bg-red-400"
>
<button onclick={confirmBan} disabled={banSubmitting} class="btn btn-danger flex-1">
{banSubmitting ? 'Wird gesperrt…' : 'Sperren'}
</button>
</div>
@@ -551,15 +539,13 @@
{/if}
<!-- ── Statistiken ─────────────────────────────────────────────── -->
<div
class="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
>
<div class="card overflow-hidden">
<button
onclick={() => (statsOpen = !statsOpen)}
aria-expanded={statsOpen}
class="flex w-full items-center justify-between px-5 py-4"
>
<h2 class="font-semibold text-gray-900 dark:text-gray-100">Statistiken</h2>
<h2 class="section-title">Statistiken</h2>
<svg
class="h-5 w-5 text-gray-400 dark:text-gray-500 transition-transform duration-200 {statsOpen
? 'rotate-180'
@@ -580,50 +566,50 @@
<div
class="grid grid-cols-2 gap-3 border-t border-gray-100 p-4 dark:border-gray-700 sm:grid-cols-4"
>
<div class="rounded-xl bg-gray-50 p-4 text-center dark:bg-gray-900/60">
<div class="surface-muted p-4 text-center">
<p class="text-2xl font-bold text-gray-900 dark:text-gray-100">{users.length}</p>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Teilnehmer</p>
</div>
<div class="rounded-xl bg-gray-50 p-4 text-center dark:bg-gray-900/60">
<div class="surface-muted p-4 text-center">
<p class="text-2xl font-bold text-gray-900 dark:text-gray-100">
{users.reduce((s, u) => s + u.upload_count, 0)}
</p>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Uploads</p>
</div>
<div class="rounded-xl bg-gray-50 p-4 text-center dark:bg-gray-900/60">
<p
class="text-2xl font-bold {event.uploads_locked
? 'text-red-600 dark:text-red-400'
: 'text-green-600 dark:text-green-400'}"
<div class="surface-muted flex flex-col items-center p-4 text-center">
<span
class="inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold {event.uploads_locked
? 'bg-red-100 text-red-700 dark:bg-red-950/50 dark:text-red-300'
: 'bg-green-100 text-green-700 dark:bg-green-950/50 dark:text-green-300'}"
>
<span class="h-1.5 w-1.5 rounded-full bg-current"></span>
{event.uploads_locked ? 'Gesperrt' : 'Offen'}
</p>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Uploads</p>
</span>
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">Uploads</p>
</div>
<div class="rounded-xl bg-gray-50 p-4 text-center dark:bg-gray-900/60">
<p
class="text-2xl font-bold {event.export_released
? 'text-blue-600 dark:text-blue-400'
: 'text-gray-400 dark:text-gray-500'}"
<div class="surface-muted flex flex-col items-center p-4 text-center">
<span
class="inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold {event.export_released
? 'bg-purple-100 text-purple-800 dark:bg-purple-950/50 dark:text-purple-200'
: 'bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-300'}"
>
{event.export_released ? 'Ja' : 'Nein'}
</p>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Freigegeben</p>
<span class="h-1.5 w-1.5 rounded-full bg-current"></span>
{event.export_released ? 'Freigegeben' : 'Noch nicht'}
</span>
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">Galerie</p>
</div>
</div>
</div>
</div>
<!-- ── Event-Einstellungen ─────────────────────────────────────── -->
<div
class="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
>
<div class="card overflow-hidden">
<button
onclick={() => (settingsOpen = !settingsOpen)}
aria-expanded={settingsOpen}
class="flex w-full items-center justify-between px-5 py-4"
>
<h2 class="font-semibold text-gray-900 dark:text-gray-100">Event-Einstellungen</h2>
<h2 class="section-title">Event-Einstellungen</h2>
<svg
class="h-5 w-5 text-gray-400 dark:text-gray-500 transition-transform duration-200 {settingsOpen
? 'rotate-180'
@@ -644,10 +630,10 @@
<div class="flex flex-wrap gap-3 border-t border-gray-100 p-5 dark:border-gray-700">
<button
onclick={toggleEventLock}
class="rounded-lg px-4 py-2 text-sm font-medium transition
class="rounded-lg border px-4 py-2 text-sm font-medium transition
{event.uploads_locked
? 'bg-green-600 text-white hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-400'
: 'bg-amber-500 text-white hover:bg-amber-600 dark:bg-amber-500 dark:hover:bg-amber-400'}"
? 'border-green-600 bg-green-600 text-white hover:bg-green-700 dark:border-green-500 dark:bg-green-500 dark:hover:bg-green-400'
: 'border-gray-300 bg-white text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700'}"
>
{event.uploads_locked ? 'Uploads wieder öffnen' : 'Uploads sperren'}
</button>
@@ -662,10 +648,7 @@
run: releaseGallery
})}
disabled={event.export_released}
class="rounded-lg px-4 py-2 text-sm font-medium transition
{event.export_released
? 'cursor-default bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-500'
: 'bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-400'}"
class="btn btn-primary btn-sm"
>
{event.export_released ? 'Galerie bereits freigegeben' : 'Galerie freigeben'}
</button>
@@ -751,15 +734,13 @@
</div>
<!-- ── Nutzerverwaltung ───────────────────────────────────────── -->
<div
class="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
>
<div class="card overflow-hidden">
<button
onclick={() => (usersOpen = !usersOpen)}
aria-expanded={usersOpen}
class="flex w-full items-center justify-between px-5 py-4"
>
<h2 class="font-semibold text-gray-900 dark:text-gray-100">Nutzerverwaltung</h2>
<h2 class="section-title">Nutzerverwaltung</h2>
<svg
class="h-5 w-5 text-gray-400 dark:text-gray-500 transition-transform duration-200 {usersOpen
? 'rotate-180'
@@ -818,21 +799,12 @@
>{user.display_name}</span
>
{#if user.role === 'host'}
<span
class="rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-900/40 dark:text-blue-200"
>Host</span
>
<span class="badge badge-primary">Host</span>
{:else if user.role === 'admin'}
<span
class="rounded-full bg-purple-100 px-2 py-0.5 text-xs font-medium text-purple-700 dark:bg-purple-900/40 dark:text-purple-200"
>Admin</span
>
<span class="badge badge-gold">Admin</span>
{/if}
{#if user.is_banned}
<span
class="rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-700 dark:bg-red-900/40 dark:text-red-200"
>Gesperrt</span
>
<span class="badge badge-danger">Gesperrt</span>
{/if}
</div>
<p class="text-xs text-gray-400 dark:text-gray-500">