GRV-Summit-Site/components/home/Speakers.tsx
kirukib cb404ec079
Some checks failed
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Has been cancelled
Align site colors with GRV brand book palette.
Centralize primary, secondary, tertiary, and neutral tokens and apply them across theme variables and UI components.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 14:45:22 +03:00

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>
);
}