Registry
Agenda
What the talk covers, as numbered rows.
---
layout: agenda
title: Agenda
---
<AgendaItem number="01" heading="The problem" />
<AgendaItem number="02" heading="What we built" />
<AgendaItem number="03" heading="Where it goes next" />Installation
Installs the layout plus the AgendaItem row component.
camp add agendaOr with any shadcn-compatible CLI:
bunx shadcn@latest add https://campfire-deck.vercel.app/r/agenda.jsonCopy both files. They import cn from @/lib/utils — scaffolded by
camp init, or camp add utils:
import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";
export type AgendaLayoutProps = ComponentProps<"main"> & {
/** From the slide's `title` frontmatter. */
title?: string;
};
/** What the talk covers. Pair with the AgendaItem component:
*
* ```mdx
* <AgendaItem number="01" heading="The problem" />
* <AgendaItem number="02" heading="What we built" />
* ```
*/
export default function AgendaLayout({
title,
className,
children,
...props
}: AgendaLayoutProps) {
return (
<main
className={cn(
"flex h-full flex-col justify-center gap-14 p-24",
className
)}
data-slot="agenda-layout"
{...props}
>
{title ? (
<h1 className="font-bold font-heading text-6xl tracking-tight">
{title}
</h1>
) : null}
<div
className="flex max-w-4xl flex-col gap-8"
data-slot="agenda-layout-items"
>
{children}
</div>
</main>
);
}import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";
export type AgendaItemProps = ComponentProps<"div"> & {
/** The item marker, e.g. 1 or "01". */
number: number | string;
/** What this part of the talk covers. */
heading: string;
};
/** A numbered row for agenda slides. Pairs with the agenda layout. */
export default function AgendaItem({
number,
heading,
className,
children,
...props
}: AgendaItemProps) {
return (
<div
className={cn("flex items-baseline gap-8", className)}
data-slot="agenda-item"
{...props}
>
<span
className="font-mono font-semibold text-2xl text-primary tabular-nums"
data-slot="agenda-item-number"
>
{number}
</span>
<div className="flex flex-col gap-1">
<span
className="font-heading font-semibold text-4xl tracking-tight"
data-slot="agenda-item-heading"
>
{heading}
</span>
{children ? (
<div
className="text-xl leading-relaxed opacity-70"
data-slot="agenda-item-detail"
>
{children}
</div>
) : null}
</div>
</div>
);
}Usage
AgendaItem is an ordinary component — reuse it later in the deck as a
"where we are" reminder, restyled through className or data-slot hooks:
---
layout: agenda
title: Agenda
---
<AgendaItem number="01" heading="The problem">
Five minutes of pain.
</AgendaItem>
<AgendaItem number="02" heading="What we built" />API Reference
The layout follows the layout contract and exposes
data-slot="agenda-layout" and agenda-layout-items.
AgendaItem extends ComponentProps<"div"> — native props are forwarded
and className is merged last. Parts expose data-slot="agenda-item",
agenda-item-number, agenda-item-heading, and agenda-item-detail.
Prop
Type