fix(ui): stabilize theme colors and calendar end time
This commit is contained in:
@@ -52,7 +52,7 @@ RSVP is a party: one or more guest names attached to a single RSVP + optional sh
|
||||
| Method | Path | Body | Notes |
|
||||
|---|---|---|---|
|
||||
| POST | `/api/rsvp` | `{names: string[], message?}` | at least one non-blank name required; insert party + guests, email couple |
|
||||
| GET | `/api/config` | — | `{weddingDate, ceremonyTime, rsvpByDate, venueName, venueAddress, rsvpPhone}` (all RFC3339 where dates) — single source of truth for countdowns, gate, and displayed details |
|
||||
| GET | `/api/config` | — | `{weddingDate, eventEnd, ceremonyTime, rsvpByDate, venueName, venueAddress, rsvpPhone}` (all RFC3339 where dates) — single source of truth for countdowns, calendar, gate, and displayed details |
|
||||
| POST | `/api/photos/upload` | multipart: `name, message?, email?, phone?, files[]` | rejected with 403 if `now < weddingDate`, **enforced server-side** regardless of client clock |
|
||||
| GET | `/healthz` | — | liveness |
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ docker-compose.yml wedding app, published to 127.0.0.1:8080 only
|
||||
```
|
||||
|
||||
## Config
|
||||
Copy `config.example.yaml` to `config.yaml` and fill in the wedding date, SMTP settings, storage path, and (if enabled) the Origin service key. Path is resolved from `CONFIG_PATH` (default `./config.yaml`) — that's the only env var; everything else lives in the file.
|
||||
Copy `config.example.yaml` to `config.yaml` and fill in the wedding date, event end time, SMTP settings, storage path, and (if enabled) the Origin service key. `wedding.event_end` is the explicit local RFC3339 end time used for calendar downloads. Path is resolved from `CONFIG_PATH` (default `./config.yaml`) — that's the only env var; everything else lives in the file.
|
||||
|
||||
When `origin.service_key` is configured, the server registers itself with Origin as the `generic` service type named `ZoeShaldon` immediately at startup and repeats the check-in every 24 hours. Registration failures are logged without taking down the wedding site. Leave the key empty to disable registration.
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ site:
|
||||
|
||||
wedding:
|
||||
date: "2026-11-07T16:00:00+02:00" # RFC3339, guest arrival time; drives countdown + photo upload gate
|
||||
event_end: "2026-11-07T23:30:00+02:00" # RFC3339, local end time used by calendar downloads
|
||||
ceremony_time: "16:00 for 16:30" # display text
|
||||
rsvp_by: "2026-10-01T08:00:00+02:00" # RFC3339, RSVP deadline; drives the RSVP countdown
|
||||
venue_name: "Rivier Plaas Wedding Venue"
|
||||
|
||||
@@ -58,6 +58,7 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]string{
|
||||
"siteUrl": s.cfg.Site.URL,
|
||||
"weddingDate": s.cfg.Wedding.Date.Format(time.RFC3339),
|
||||
"eventEnd": s.cfg.Wedding.EventEnd.Format(time.RFC3339),
|
||||
"ceremonyTime": s.cfg.Wedding.CeremonyTime,
|
||||
"rsvpByDate": s.cfg.Wedding.RSVPBy.Format(time.RFC3339),
|
||||
"venueName": s.cfg.Wedding.VenueName,
|
||||
|
||||
@@ -35,6 +35,7 @@ type SiteConfig struct {
|
||||
|
||||
type WeddingConfig struct {
|
||||
Date time.Time `yaml:"date"`
|
||||
EventEnd time.Time `yaml:"event_end"`
|
||||
CeremonyTime string `yaml:"ceremony_time"`
|
||||
RSVPBy time.Time `yaml:"rsvp_by"`
|
||||
VenueName string `yaml:"venue_name"`
|
||||
@@ -112,6 +113,9 @@ func Load(path string) (*Config, error) {
|
||||
if cfg.Wedding.RSVPBy.IsZero() {
|
||||
return nil, fmt.Errorf("wedding.rsvp_by is required in %s", path)
|
||||
}
|
||||
if cfg.Wedding.EventEnd.IsZero() {
|
||||
return nil, fmt.Errorf("wedding.event_end is required in %s", path)
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export interface WeddingConfig {
|
||||
siteUrl: string;
|
||||
weddingDate: string;
|
||||
eventEnd: string;
|
||||
ceremonyTime: string;
|
||||
rsvpByDate: string;
|
||||
venueName: string;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// fallback while /api/config loads (and when developing the UI without the Go server).
|
||||
export const FALLBACK_SITE_URL = "https://zoeshaldon.warky.info";
|
||||
export const FALLBACK_WEDDING_DATE = "2026-11-07T16:00:00+02:00";
|
||||
export const FALLBACK_EVENT_END = "2026-11-07T23:30:00+02:00";
|
||||
export const FALLBACK_CEREMONY_TIME = "16:00 for 16:30";
|
||||
export const FALLBACK_RSVP_BY_DATE = "2026-10-17T00:00:00+02:00";
|
||||
export const FALLBACK_VENUE_NAME = "Rivier Plaas Wedding Venue";
|
||||
|
||||
@@ -3,6 +3,7 @@ import { fetchConfig } from './api';
|
||||
import {
|
||||
FALLBACK_SITE_URL,
|
||||
FALLBACK_WEDDING_DATE,
|
||||
FALLBACK_EVENT_END,
|
||||
FALLBACK_CEREMONY_TIME,
|
||||
FALLBACK_RSVP_BY_DATE,
|
||||
FALLBACK_VENUE_NAME,
|
||||
@@ -13,6 +14,7 @@ import {
|
||||
export function createWeddingInfo() {
|
||||
let siteUrl = $state(FALLBACK_SITE_URL);
|
||||
let date = $state(new Date(FALLBACK_WEDDING_DATE));
|
||||
let eventEnd = $state(new Date(FALLBACK_EVENT_END));
|
||||
let ceremonyTime = $state(FALLBACK_CEREMONY_TIME);
|
||||
let rsvpByDate = $state(new Date(FALLBACK_RSVP_BY_DATE));
|
||||
let venueName = $state(FALLBACK_VENUE_NAME);
|
||||
@@ -25,6 +27,7 @@ export function createWeddingInfo() {
|
||||
.then((config) => {
|
||||
siteUrl = config.siteUrl;
|
||||
date = new Date(config.weddingDate);
|
||||
eventEnd = new Date(config.eventEnd);
|
||||
ceremonyTime = config.ceremonyTime;
|
||||
rsvpByDate = new Date(config.rsvpByDate);
|
||||
venueName = config.venueName;
|
||||
@@ -46,6 +49,9 @@ export function createWeddingInfo() {
|
||||
get ceremonyTime() {
|
||||
return ceremonyTime;
|
||||
},
|
||||
get eventEnd() {
|
||||
return eventEnd;
|
||||
},
|
||||
get rsvpByDate() {
|
||||
return rsvpByDate;
|
||||
},
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
<main
|
||||
class="text-shadow-sm text-shadow-white/80 dark:text-shadow-black/70 flex flex-1 flex-col"
|
||||
class="text-surface-900 dark:text-surface-100 text-shadow-sm text-shadow-white/80 dark:text-shadow-black/70 flex flex-1 flex-col"
|
||||
>
|
||||
{@render children()}
|
||||
</main>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
const icsUrl = $derived(
|
||||
buildIcsDataUrl({
|
||||
start: wedding.date,
|
||||
end: new Date(wedding.date.getTime() + 7.5 * 60 * 60 * 1000),
|
||||
end: wedding.eventEnd,
|
||||
summary: "Zoé & Shaldon's Wedding",
|
||||
location: `${wedding.venueName}, ${wedding.venueAddress}`,
|
||||
description: `Join us as we say I do! ${wedding.ceremonyTime}.`,
|
||||
|
||||
Reference in New Issue
Block a user