Support naddr/nevent/note slugs for unindexed posts, cache naddr lookups, render Nostr embeds in markdown, and add a consistency check for events mirrors. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
import { Navbar } from "@/components/public/Navbar";
|
|
import { Footer } from "@/components/public/Footer";
|
|
import { MeetupCard } from "@/components/public/MeetupCard";
|
|
import { AddToCalendarButton } from "@/components/public/AddToCalendarDialog";
|
|
import { fetchMeetupsLive, partitionMeetups } from "@/lib/meetupsData";
|
|
|
|
// Render at request time from the live backend so crawlers (no JS) always get
|
|
// the real list, and the count stays in lock-step with /events.md and /llms.txt.
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function EventsPage() {
|
|
const meetups = await fetchMeetupsLive();
|
|
const { upcoming, past } = partitionMeetups(meetups);
|
|
|
|
return (
|
|
<>
|
|
<Navbar />
|
|
<div className="min-h-screen">
|
|
<header className="pt-24 pb-12 px-8">
|
|
<div className="max-w-6xl mx-auto">
|
|
<p className="uppercase tracking-[0.2em] text-primary mb-2 font-semibold text-xs">
|
|
Belgian Bitcoin Embassy
|
|
</p>
|
|
<h1 className="text-4xl md:text-6xl font-black tracking-tighter mb-4">
|
|
All Events
|
|
</h1>
|
|
<p className="text-on-surface-variant max-w-md leading-relaxed">
|
|
Past and upcoming Bitcoin meetups in Belgium.
|
|
</p>
|
|
</div>
|
|
</header>
|
|
|
|
<div
|
|
className="max-w-6xl mx-auto px-8 pb-24 space-y-20"
|
|
data-upcoming-count={upcoming.length}
|
|
data-past-count={past.length}
|
|
>
|
|
<div>
|
|
<div className="flex items-center justify-between mb-8">
|
|
<h2 className="text-xl font-black flex items-center gap-3">
|
|
Upcoming
|
|
{upcoming.length > 0 && (
|
|
<span className="text-xs font-bold bg-primary/10 text-primary px-2.5 py-1 rounded-full">
|
|
{upcoming.length}
|
|
</span>
|
|
)}
|
|
</h2>
|
|
<AddToCalendarButton />
|
|
</div>
|
|
|
|
{upcoming.length === 0 ? (
|
|
<div className="border border-zinc-800/60 rounded-xl px-8 py-12 text-center">
|
|
<p className="text-on-surface-variant text-sm">
|
|
No upcoming events scheduled. Check back soon.
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
|
{upcoming.map((m) => (
|
|
<MeetupCard key={m.id} meetup={m} />
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{past.length > 0 && (
|
|
<div>
|
|
<h2 className="text-xl font-black mb-8 text-on-surface-variant/60">
|
|
Past Events
|
|
</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
|
{past.map((m) => (
|
|
<MeetupCard key={m.id} meetup={m} muted />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<Footer />
|
|
</>
|
|
);
|
|
}
|