尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证konfirmation
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Digital invitation and RSVP site for Victor's confirmation. React + TypeScript
• Vite + Tailwind CSS, with Supabase for RSVP/wishlist/gallery/admin and
Resend for the confirmation email + calendar invite.查看完整 README ↗Digital invitation and RSVP site for Victor's confirmation. React + TypeScript
@tailwindcss/vite)/admin is a real route; everything else is one
scrolling page with anchor-linked sections/api) — confirmation email + .ics
generation; the only server-side code in the projectnpm install
npm run dev
npm run dev also runs the /api routes locally (see "Email & calendar
invite" below) — no separate server or vercel dev needed.
Place the confirmation video at:
public/videos/victor-hero.mp4
It should show Victor turning his head horizontally — the hero scrubs
through it based on horizontal mouse position (or a gentle automatic drift
on touch devices). See src/hooks/useVideoScrub.ts for the interaction and
src/sections/Hero.tsx for the HERO_VIDEO_OBJECT_POSITION constant if you
need to reposition Victor within the frame (e.g. on tall mobile crops).
Optionally add a poster frame (a single JPG extracted from the video) at
public/images/victor-hero-poster.jpg — shown while the video loads. E.g.:
ffmpeg -i public/videos/victor-hero.mp4 -ss 00:00:02 -vframes 1 public/images/victor-hero-poster.jpg
If VITE_SUPABASE_URL / VITE_SUPABASE_ANON_KEY aren't set, the site runs
in demo mode: RSVP submissions, gift reservations, and photo uploads are
stored in the browser's localStorage instead of a real database, so
everything is still genuinely interactive for local development or a quick
preview deploy. /admin shows a notice explaining that real admin auth
needs Supabase configured — there's no fake login in demo mode. The
confirmation email always requires real Supabase + Resend credentials (see
below), even in demo mode, since it's inherently a real-backend feature.
Demo data resets if localStorage is cleared and is never shared between
visitors — for a real event, connect Supabase (next section).
Create a project at supabase.com.
In the SQL editor, run, in order:
supabase/migrations/0001_init.sql —
all tables, RLS policies, the gallery storage bucket, and seed data.supabase/migrations/0002_event_info_and_gift_email.sql —
adds guest_email to gift reservations (so a reservation can be linked
to an RSVP), a security-definer RPC guests use to see their own
reserved gifts, and the real event details (church, party address,
RSVP deadline).Copy .env.example to .env and fill in:
VITE_SUPABASE_URL / VITE_SUPABASE_ANON_KEY — Project Settings → API
→ "Project URL" / "anon public" key.SUPABASE_SERVICE_ROLE_KEY — same page, "service_role" secret key.
Server-only (used by /api to send the confirmation email regardless
of RLS) — never put this in a VITE_-prefixed variable or client code.cp .env.example .env
Create an admin user: Supabase dashboard → Authentication → Users → Add
user. Use that email/password to log in at /admin. There's no
separate "admin" table — anyone with a Supabase Auth session for this
project can use the dashboard, so only create accounts you trust.
Restart npm run dev.
/api/send-confirmation and
/api/calendar-invite).reservation_token returned when it was created (the browser remembers
it, plus the email if one was given, in localStorage so a returning
guest sees a "fortryd" option automatically).is_published are publicly visible;
uploading/publishing/deleting requires an authenticated session.is_public are publicly readable; editing requires an
authenticated session.Full schema and policies: 0001_init.sql,
0002_event_info_and_gift_email.sql.
When a guest submits the RSVP form (or later reserves/releases a gift under
an email that already has an RSVP), the browser calls
/api/send-confirmation, which:
api/_lib/emailTemplate.ts) and a standards-compliant .ics file
(api/_lib/ics.ts)..ics attached and a "Tilføj til
kalender" button linking to /api/calendar-invite?email=..., which
regenerates and serves the same file on demand.If the email doesn't match an existing RSVP (e.g. someone reserved a gift before RSVPing), this is a silent no-op — not an error — so it never sends a broken email. If Resend/Supabase aren't configured, the RSVP itself still succeeds; the site shows a small "we couldn't email you" note instead of failing.
No church time yet? The .ics file is generated as an all-day event
for 1 May 2027 whenever churchStartTime is empty in /admin → Begivenhed
(or the event_info row) — never a made-up time. Once a start time is set
there, new .ics files use it (defaulting to a 1-hour block if no end time
is set either).
.env:
RESEND_API_KEY — the key from step 3.EMAIL_FROM — e.g. Victors konfirmation <hej@dit-domæne.dk>, using
your verified domain from step 2.| Variable | Required | Description |
|---|---|---|
VITE_SUPABASE_URL | No* | Supabase project URL |
VITE_SUPABASE_ANON_KEY | No* | Supabase anon/public key |
SUPABASE_SERVICE_ROLE_KEY | No** | Server-only. Needed for the confirmation email/.ics |
RESEND_API_KEY | No** | Server-only. Needed for the confirmation email |
EMAIL_FROM | No** | Server-only. Verified sender address (see Resend setup) |
* Omitting both Supabase client vars runs the site in demo mode (see above). For a real event, set both.
** Omitting any of these disables the confirmation email/.ics — the RSVP form and everything else still works. All three are required together for email to actually send.
Search the codebase for PLACEHOLDER to find everything that still needs
real information before launch (parking, dress code, contact person,
accommodation — the church, party address, date and RSVP deadline are
already filled in with real values):
src/data/practicalInfo.ts / the practical_info row in site_settingssrc/data/wishlist.ts — demo-mode-only sample wishesThe event's core facts (church, party address, RSVP deadline, invitation
text, church start time once known) live in src/data/eventInfo.ts as the
fallback and in the event_info row of site_settings as the live,
admin-editable copy — edit either directly or from /admin → Begivenhed.
Once Supabase is connected, the timeline, practical info cards, event info,
and venue location can all be edited from /admin instead of by editing
code.
Uses Open-Meteo (no API key needed). More than
~10 days before 1 May 2027 it shows a real historical average for that
date (last 8 years) rather than a fabricated forecast; within ~10 days it
switches to Open-Meteo's actual forecast. To swap providers later, edit
src/lib/weather/ — the rest of the app only calls getWeatherOutlook().
npm run build, output
dist/) and auto-detects the /api/*.ts files as serverless functions;
no extra configuration is needed for either.SUPABASE_,
RESEND_, and EMAIL_FROM ones are server-only and safe there; Vercel
never sends non-VITE_-prefixed variables to the browser.vercel.json includes an SPA rewrite so /admin (and any deep link)
resolves correctly on refresh; it doesn't need to (and shouldn't) rewrite
/api/*, since Vercel routes those to the serverless functions directly.
src/
components/ Reusable UI (Button, Card, Navigation, Reveal, forms, ...)
sections/ One file per homepage section (Hero, Invitation, Dagen, ...)
pages/ Route-level composition (HomePage, admin/*)
hooks/ useVideoScrub, useSiteSetting, useAdminSession, ...
lib/ Supabase client, api/* data-access layer, weather/*, utils
data/ Editable fallback content (event info, timeline, ...)
types/ Shared TypeScript types
supabase/
migrations/ SQL schema, RLS policies, storage bucket, seed data
api/
send-confirmation.ts POST { email } — sends the confirmation email
calendar-invite.ts GET ?email=... — serves the .ics for download
_lib/ Server-only helpers (Supabase admin client, ICS
builder, email template, Resend client) — never
imported from src/
npm run dev # start dev server (also serves /api locally)
npm run build # type-check (app + api) + production build to dist/
npm run preview # preview the production build locally (static only — /api needs `npm run dev` or Vercel)
npm run lint # oxlint