Some checks failed
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Has been cancelled
Centralize primary, secondary, tertiary, and neutral tokens and apply them across theme variables and UI components. Co-authored-by: Cursor <cursoragent@cursor.com>
75 lines
2.7 KiB
TypeScript
75 lines
2.7 KiB
TypeScript
import Link from "next/link";
|
|
import {
|
|
speakers,
|
|
speakerGroupLabels,
|
|
speakerGroupOrder,
|
|
type SpeakerGroup,
|
|
} from "@/content/people";
|
|
import { site } from "@/content/site";
|
|
import { Section } from "@/components/layout/Section";
|
|
import { TopoProseSurface } from "@/components/layout/TopoProseSurface";
|
|
import { SpeakerCard } from "@/components/speakers/SpeakerCard";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
export function Speakers() {
|
|
const grouped = speakerGroupOrder.reduce(
|
|
(acc, group) => {
|
|
const list = speakers.filter((s) => s.group === group);
|
|
if (list.length) acc[group] = list;
|
|
return acc;
|
|
},
|
|
{} as Partial<Record<SpeakerGroup, typeof speakers>>
|
|
);
|
|
|
|
return (
|
|
<Section id="speakers">
|
|
<TopoProseSurface className="max-w-3xl">
|
|
<p className="text-xs font-semibold uppercase tracking-widest text-[#37a47a]">
|
|
Lineup
|
|
</p>
|
|
<h2 className="mt-2 text-4xl font-bold tracking-tight md:text-5xl">
|
|
Meet the voices of GRV Summit
|
|
</h2>
|
|
<p className="mt-4 text-[#5b5b5b] leading-relaxed">
|
|
Keynotes, panelists, judges, and opening speakers — {site.dates.label} at{" "}
|
|
{site.venue.name}.
|
|
</p>
|
|
</TopoProseSurface>
|
|
|
|
<div className="relative z-20 mt-16 space-y-16">
|
|
{(Object.entries(grouped) as [SpeakerGroup, typeof speakers][]).map(
|
|
([group, list]) => (
|
|
<div key={group}>
|
|
<div className="mb-2 flex flex-wrap items-end justify-between gap-4 border-b border-[#37a47a]/15 pb-4">
|
|
<div>
|
|
<h3 className="text-2xl font-bold md:text-3xl">
|
|
{speakerGroupLabels[group]}
|
|
</h3>
|
|
<p className="mt-1 text-sm text-[#5b5b5b]">{site.dates.label}</p>
|
|
</div>
|
|
</div>
|
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
|
{list.map((speaker, i) => (
|
|
<SpeakerCard key={speaker.id} speaker={speaker} revealDelay={i * 60} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
)}
|
|
</div>
|
|
|
|
<div className="mt-12 flex flex-wrap justify-center gap-3">
|
|
<Button className="rounded-full bg-[#37a47a] text-[#ffffff] hover:bg-[#37a47a]/90" asChild>
|
|
<Link href="/program">View full program</Link>
|
|
</Button>
|
|
<Button variant="outline" className="rounded-full" asChild>
|
|
<Link href="/speakers">Full lineup page</Link>
|
|
</Button>
|
|
<Button variant="outline" className="rounded-full" asChild>
|
|
<Link href="/payment">Get tickets</Link>
|
|
</Button>
|
|
</div>
|
|
</Section>
|
|
);
|
|
}
|