feat(ui): enhance Countdown and layout components

* Improve Countdown component styling and structure
* Update layout to include responsive menu and background pattern
* Adjust PhotoBackground and page styles for better presentation
* Add damask pattern SVG for background use
This commit is contained in:
2026-08-11 23:58:28 +02:00
parent 39f5b8d5cc
commit 143161c234
8 changed files with 262 additions and 168 deletions
+84 -36
View File
@@ -1,45 +1,93 @@
<script lang="ts">
import '../app.css';
import favicon from '$lib/assets/favicon.svg';
import { page } from '$app/state';
import Countdown from '$lib/components/Countdown.svelte';
import { createWeddingInfo } from '$lib/wedding-info.svelte';
import "../app.css";
import favicon from "$lib/assets/favicon.svg";
import { page } from "$app/state";
import Countdown from "$lib/components/Countdown.svelte";
import { createWeddingInfo } from "$lib/wedding-info.svelte";
let { children } = $props();
let { children } = $props();
const wedding = createWeddingInfo();
const wedding = createWeddingInfo();
const links = [
{ href: '/', label: 'Home' },
{ href: '/rsvp', label: 'RSVP' },
{ href: '/photos', label: 'Photos' }
];
const links = [
{ href: "/", label: "Home" },
{ href: "/rsvp", label: "RSVP" },
{ href: "/photos", label: "Photos" },
];
let menuOpen = $state(false);
$effect(() => {
page.url.pathname;
menuOpen = false;
});
</script>
<svelte:head><link rel="icon" href={favicon} /></svelte:head>
<div class="bg-surface-50 dark:bg-surface-950 flex min-h-screen flex-col">
<div class="sticky top-0 z-20 flex flex-col">
<nav class="bg-primary-950 flex items-center justify-between px-4 py-3 sm:px-8">
<a href="/" class="text-surface-50 font-malibu text-xl tracking-wide">Zoé &amp; Shaldon</a>
<div class="flex gap-2">
{#each links as link (link.href)}
<a
href={link.href}
class="btn field-sm {page.url.pathname === link.href
? 'preset-filled-secondary-500'
: 'text-surface-100 hover:text-secondary-400'}"
>
{link.label}
</a>
{/each}
</div>
</nav>
<div class="text-surface-50 flex justify-center px-4 py-3 drop-shadow-[0_2px_6px_rgba(0,0,0,0.6)]">
<Countdown target={wedding.date} compact pastMessage="Already married! 🎉" />
</div>
</div>
<main class="flex flex-1 flex-col">
{@render children()}
</main>
<div
class="bg-surface-50 dark:bg-surface-950 flex min-h-screen flex-col bg-[url('/patterns/damask.svg')] bg-repeat [background-size:160px_160px]"
>
<div class="sticky top-0 z-20 flex flex-col">
<nav
class="bg-primary-950 flex items-center justify-between px-4 py-3 sm:px-8"
>
<a
href="/"
class="text-surface-50 font-malibu hidden text-3xl tracking-wide sm:inline"
>Zoé &amp; Shaldon</a
>
<Countdown
target={wedding.date}
compact
pastMessage="Already married! 🎉"
/>
<div class="hidden gap-2 sm:flex">
{#each links as link (link.href)}
<a
href={link.href}
class="btn field-sm {page.url.pathname === link.href
? 'preset-filled-secondary-500'
: 'text-surface-100 hover:text-secondary-400'}"
>
{link.label}
</a>
{/each}
</div>
<button
type="button"
class="text-surface-50 flex items-center justify-center p-2 sm:hidden"
aria-label="Menu"
aria-expanded={menuOpen}
onclick={() => (menuOpen = !menuOpen)}
>
{#if menuOpen}
<svg viewBox="0 0 24 24" class="size-6" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" d="M6 6l12 12M18 6L6 18" />
</svg>
{:else}
<svg viewBox="0 0 24 24" class="size-6" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" d="M4 7h16M4 12h16M4 17h16" />
</svg>
{/if}
</button>
</nav>
{#if menuOpen}
<div class="bg-primary-950 border-primary-800 flex flex-col gap-1 border-t px-4 py-3 sm:hidden">
{#each links as link (link.href)}
<a
href={link.href}
class="btn field-sm w-full {page.url.pathname === link.href
? 'preset-filled-secondary-500'
: 'text-surface-100 hover:text-secondary-400'}"
>
{link.label}
</a>
{/each}
</div>
{/if}
</div>
<main class="flex flex-1 flex-col">
{@render children()}
</main>
</div>
+1 -1
View File
@@ -8,7 +8,7 @@
</script>
<section
class="relative flex flex-1 items-center justify-center overflow-hidden px-4 py-16 text-center"
class="relative flex flex-1 items-center justify-center overflow-hidden px-4 py-16 text-center z-10"
>
<PhotoBackground />
+14 -14
View File
@@ -65,7 +65,7 @@
{#if !isOpen}
<div class="flex flex-col items-center gap-6 text-center">
<h1 class="font-serif text-4xl">Photo uploads open on the wedding day</h1>
<p class="text-surface-600-400 text-lg">Come back on {formatFullDate(wedding.date)} to share your photos with Zoé &amp; Shaldon.</p>
<p class="text-surface-600-400 text-2xl">Come back on {formatFullDate(wedding.date)} to share your photos with Zoé &amp; Shaldon.</p>
</div>
{:else if status === 'done'}
<div class="preset-filled-primary-500 rounded-base max-w-md p-4 text-center">
@@ -74,36 +74,36 @@
{:else}
<div class="w-full max-w-md">
<h1 class="font-serif text-4xl">Share your photos</h1>
<p class="text-surface-600-400 mt-2 mb-8 text-lg">
<p class="text-surface-600-400 mt-2 mb-8 text-2xl">
Upload photos from the day — up to {MAX_FILES} at a time, {MAX_SIZE_MB}MB each.
</p>
<form class="flex flex-col gap-4" onsubmit={onSubmit}>
<label class="label">
<span class="label-text">Name *</span>
<input class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700" type="text" required bind:value={name} disabled={status === 'submitting'} />
<span class="label-text text-2xl">Name *</span>
<input class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700 text-2xl" type="text" required bind:value={name} disabled={status === 'submitting'} />
</label>
<label class="label">
<span class="label-text">Message to the couple (optional)</span>
<textarea class="textarea border border-surface-300 focus:border-primary-500 dark:border-surface-700" rows="3" bind:value={message} disabled={status === 'submitting'}
<span class="label-text text-2xl">Message to the couple (optional)</span>
<textarea class="textarea border border-surface-300 focus:border-primary-500 dark:border-surface-700 text-2xl" rows="3" bind:value={message} disabled={status === 'submitting'}
></textarea>
</label>
<label class="label">
<span class="label-text">Email (optional)</span>
<input class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700" type="email" bind:value={email} disabled={status === 'submitting'} />
<span class="label-text text-2xl">Email (optional)</span>
<input class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700 text-2xl" type="email" bind:value={email} disabled={status === 'submitting'} />
</label>
<label class="label">
<span class="label-text">Phone (optional)</span>
<input class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700" type="tel" bind:value={phone} disabled={status === 'submitting'} />
<span class="label-text text-2xl">Phone (optional)</span>
<input class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700 text-2xl" type="tel" bind:value={phone} disabled={status === 'submitting'} />
</label>
<label class="label">
<span class="label-text">Photos *</span>
<span class="label-text text-2xl">Photos *</span>
<input
class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700"
class="input border border-surface-300 focus:border-primary-500 dark:border-surface-700 text-2xl"
type="file"
accept="image/*"
multiple
@@ -114,10 +114,10 @@
</label>
{#if status === 'error'}
<p class="text-error-500 text-base">{errorMessage}</p>
<p class="text-error-500 text-2xl">{errorMessage}</p>
{/if}
<button class="btn preset-filled-secondary-500 mt-2" type="submit" disabled={status === 'submitting'}>
<button class="btn preset-filled-secondary-500 mt-2 text-2xl" type="submit" disabled={status === 'submitting'}>
{status === 'submitting' ? 'Uploading…' : 'Upload photos'}
</button>
</form>
+2 -2
View File
@@ -7,7 +7,7 @@
<section class="flex flex-1 items-center justify-center px-4 py-16">
<div class="border-surface-300 dark:border-surface-700 flex flex-col items-center gap-4 border px-6 py-10 text-center">
<p class="text-primary-600-400 text-base tracking-[0.25em] uppercase">Scan to visit</p>
<p class="text-primary-600-400 text-2xl tracking-[0.25em] uppercase">Scan to visit</p>
<h1 class="font-malibu text-4xl">Zoé &amp; Shaldon</h1>
<QrCode value={wedding.siteUrl} class="flex flex-col items-center gap-4">
@@ -15,7 +15,7 @@
<QrCode.Pattern />
</QrCode.Frame>
<p class="text-surface-700 dark:text-surface-300 text-base break-all">{wedding.siteUrl}</p>
<p class="text-surface-700 dark:text-surface-300 text-2xl break-all">{wedding.siteUrl}</p>
<QrCode.DownloadTrigger mimeType="image/png" fileName="zoe-and-shaldon-qr.png">
Download PNG
+2 -2
View File
@@ -60,7 +60,7 @@
</script>
<section
class="relative flex flex-1 items-center justify-center overflow-hidden px-4 py-16"
class="relative flex flex-1 items-center justify-center overflow-hidden px-4 py-16 z-10"
>
<PhotoBackground />
@@ -159,7 +159,7 @@
</div>
<label class="label">
<span class="label-text text-surface-100"
<span class="label-text text-surface-100 text-2xl"
>Message to the couple (optional)</span
>
<textarea