- Add organizer model/API, admin and public organizer pages, meetup cards - Refresh events/home/contact; add calendar dialog and carousel components - Optional Plausible via NEXT_PUBLIC_PLAUSIBLE_* env vars in root layout - Prisma migration, seed updates, baseline-and-migrate script Made-with: Cursor
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import { Send, Zap, ExternalLink } from "lucide-react";
|
|
import { api } from "@/lib/api";
|
|
|
|
const CHANNELS = [
|
|
{
|
|
key: "telegram_link" as const,
|
|
title: "Telegram",
|
|
description:
|
|
"Join our Telegram group for quick questions and community chat.",
|
|
Icon: Send,
|
|
},
|
|
{
|
|
key: "nostr_link" as const,
|
|
title: "Nostr",
|
|
description: "Follow us on Nostr for censorship-resistant communication.",
|
|
Icon: Zap,
|
|
},
|
|
{
|
|
key: "x_link" as const,
|
|
title: "X (Twitter)",
|
|
description: "Follow us on X for announcements and updates.",
|
|
Icon: ExternalLink,
|
|
},
|
|
];
|
|
|
|
export function ContactChannelGrid() {
|
|
const [settings, setSettings] = useState<Record<string, string>>({});
|
|
|
|
useEffect(() => {
|
|
api
|
|
.getPublicSettings()
|
|
.then((data) => setSettings(data))
|
|
.catch(() => {});
|
|
}, []);
|
|
|
|
return (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
|
{CHANNELS.map(({ key, title, description, Icon }) => {
|
|
const href = settings[key] || "#";
|
|
const isExternal = href.startsWith("http");
|
|
return (
|
|
<a
|
|
key={key}
|
|
href={href}
|
|
target={isExternal ? "_blank" : undefined}
|
|
rel={isExternal ? "noopener noreferrer" : undefined}
|
|
className="bg-surface-container-low p-8 rounded-xl hover:bg-surface-container transition-colors group"
|
|
>
|
|
<Icon size={28} className="text-primary mb-4" />
|
|
<h2 className="text-xl font-bold mb-2">{title}</h2>
|
|
<p className="text-on-surface-variant text-sm">{description}</p>
|
|
</a>
|
|
);
|
|
})}
|
|
|
|
<div className="bg-surface-container-low p-8 rounded-xl">
|
|
<h2 className="text-xl font-bold mb-2">Meetups</h2>
|
|
<p className="text-on-surface-variant text-sm mb-4">
|
|
The best way to connect is in person. Come to our monthly meetup in
|
|
Brussels.
|
|
</p>
|
|
<Link
|
|
href="/#meetup"
|
|
className="text-primary font-bold text-sm hover:underline"
|
|
>
|
|
See next meetup →
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|