--- import AppLayout from '../layouts/AppLayout.astro'; import AvatarPile from '../components/AvatarPile.astro'; import { getUpcomingEvents, getPastEvents, getEventBySlug, getEventAttendees, getEventRsvpCount, getUserRsvp, setEventRsvp, recordActivity, } from '../lib/db'; import { eventKindLabel, defaultActionLabel, pigmentForId } from '../lib/format'; const user = Astro.locals.user; // ── POST: RSVP ────────────────────────────────────────────────────── if (Astro.request.method === 'POST') { const data = await Astro.request.formData(); const action = String(data.get('action') ?? ''); if (action === 'rsvp') { const slug = String(data.get('event_slug') ?? ''); const status = String(data.get('status') ?? '') as 'yes' | 'no' | 'interested'; if (slug && ['yes', 'no', 'interested'].includes(status)) { const ev = getEventBySlug(slug); if (ev) { setEventRsvp(user.id, slug, status); recordActivity(user.id, 'rsvped', 'event', ev.id); } } return Astro.redirect('/events'); } } // ── Data ─────────────────────────────────────────────────────────── const upcoming = getUpcomingEvents(20); const hero = upcoming.find(e => e.kind !== 'office_hours') ?? null; const alsoUpcoming = upcoming.filter(e => e.id !== hero?.id); const past = getPastEvents(8); function parseUtc(s: string): Date { if (/T.*[Zz]$/.test(s) || /[+-]\d{2}:?\d{2}$/.test(s)) return new Date(s); return new Date(s.replace(' ', 'T') + 'Z'); } function fmt(part: Intl.DateTimeFormatOptions, iso: string): string { return new Intl.DateTimeFormat('en-GB', { ...part, timeZone: 'Europe/Copenhagen' }).format(parseUtc(iso)); } function dayNum(iso: string) { return fmt({ day: 'numeric' }, iso); } function weekday(iso: string) { return fmt({ weekday: 'short' }, iso).toUpperCase(); } function monthShort(iso: string) { return fmt({ month: 'short' }, iso).toUpperCase(); } function timeStr(iso: string) { return fmt({ hour: '2-digit', minute: '2-digit', hour12: false }, iso); } const heroAttendees = hero ? getEventAttendees(hero.slug, 'yes') : []; const heroConfirmedCount = heroAttendees.length; const heroMyRsvp = hero ? getUserRsvp(user.id, hero.slug) : null; const heroAudience = hero?.audience ?? 'Members only'; ---

Where the council gathers.

Dinners, working sessions, the occasional summit. Always small, always off the record.

{hero ? (
{weekday(hero.starts_at)} {dayNum(hero.starts_at)} {monthShort(hero.starts_at)}

{hero.title}

{hero.description}

{hero.location}{hero.location && ' · '}{timeStr(hero.starts_at)}{hero.duration_label ? ` · ${hero.duration_label}` : ''}

{hero.capacity ? `${hero.capacity} seats · ` : ''}{heroConfirmedCount} confirmed {heroAttendees.length > 0 && ( )}
{heroMyRsvp === 'yes' ? ( <> You're confirmed ✓ ) : ( )}
) : (

Nothing scheduled yet — when we have something, you'll be the first to know.

)} {alsoUpcoming.length > 0 && (
    {alsoUpcoming.map(ev => (
  • {dayNum(ev.starts_at)} {monthShort(ev.starts_at)}

    {ev.title}

    {[ev.duration_label, ev.audience, ev.location].filter(Boolean).join(' · ') || eventKindLabel(ev.kind)}

  • ))}
)} {past.length > 0 && (
    {past.map(ev => { const monthCode = monthShort(ev.starts_at); const attended = getEventRsvpCount(ev.slug).going; const hasNotes = !!ev.notes_url; const pigA = pigmentForId(ev.id); const pigB = pigmentForId(ev.id + 1); return (
  • {ev.photo_url ? ( ) : hasNotes ? ( {monthCode} ) : ( )}

    {ev.title}

    {fmt({ day: 'numeric', month: 'long', year: 'numeric' }, ev.starts_at)}{ev.location && ` · ${ev.location}`}

    {attended} attended · {hasNotes ? 'Notes shared' : 'No notes'}

  • ); })}
View all past gatherings →
)}