Campfire
Registry

Problem / Solution

Two-panel narrative layout with Problem and Solution components.

slides/02-why.mdx
---
layout: problem-solution
title: Why Campfire
---

<Problem>
  Decks rot inside proprietary tools — unversioned, undiffable,
  and impossible for coding agents to help with.
</Problem>

<Solution>
  The repo is the deck. Files diff, agents edit safely, and
  `camp` serves a live presentation shell.
</Solution>

Installation

Installs the layout plus the Problem and Solution panel components.

camp add problem-solution

Or with any shadcn-compatible CLI:

bunx shadcn@latest add https://campfire-deck.vercel.app/r/problem-solution.json

Copy the three files. They import cn from @/lib/utils — scaffolded by camp init, or camp add utils:

layouts/problem-solution.tsx
import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";

export type ProblemSolutionLayoutProps = ComponentProps<"main"> & {
  /** From the slide's `title` frontmatter. */
  title?: string;
};

/** Pair with the Problem and Solution components installed alongside:
 *
 * ```mdx
 * <Problem>Decks rot in proprietary tools.</Problem>
 * <Solution>Slides are files; the repo is the deck.</Solution>
 * ```
 */
export default function ProblemSolutionLayout({
  title,
  className,
  children,
  ...props
}: ProblemSolutionLayoutProps) {
  return (
    <main
      className={cn("flex h-full flex-col gap-10 p-24", className)}
      data-slot="problem-solution-layout"
      {...props}
    >
      {title ? (
        <h1 className="font-bold font-heading text-6xl tracking-tight">
          {title}
        </h1>
      ) : null}
      <div
        className="grid flex-1 grid-cols-2 items-stretch gap-10"
        data-slot="problem-solution-layout-panels"
      >
        {children}
      </div>
    </main>
  );
}
components/problem.tsx
import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";

export type ProblemProps = ComponentProps<"section">;

/** The "before" panel of a problem/solution narrative. */
export default function Problem({
  className,
  children,
  ...props
}: ProblemProps) {
  return (
    <section
      className={cn(
        "flex flex-col gap-4 rounded-2xl border-2 border-foreground/15 p-10",
        className
      )}
      data-slot="problem"
      {...props}
    >
      <span className="font-semibold text-foreground/50 text-sm uppercase tracking-[0.2em]">
        Problem
      </span>
      <div className="text-2xl leading-relaxed">{children}</div>
    </section>
  );
}
components/solution.tsx
import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";

export type SolutionProps = ComponentProps<"section">;

/** The "after" panel of a problem/solution narrative. */
export default function Solution({
  className,
  children,
  ...props
}: SolutionProps) {
  return (
    <section
      className={cn(
        "flex flex-col gap-4 rounded-2xl border-2 border-primary/50 bg-primary/5 p-10",
        className
      )}
      data-slot="solution"
      {...props}
    >
      <span className="font-semibold text-primary text-sm uppercase tracking-[0.2em]">
        Solution
      </span>
      <div className="text-2xl leading-relaxed">{children}</div>
    </section>
  );
}

Usage

The layout is a two-column grid; Problem and Solution fill one column each. They are ordinary components — you can also use them outside this layout.

slides/02-why.mdx
---
layout: problem-solution
title: Why Campfire
---

<Problem>Decks rot in proprietary tools.</Problem>
<Solution>Slides are files; the repo is the deck.</Solution>

A generic two-column slide without the problem/solution framing is the Split layout.

API Reference

The layout follows the layout contract and exposes data-slot="problem-solution-layout" and problem-solution-layout-panels:

Prop

Type

Problem and Solution extend ComponentProps<"section"> (exposing data-slot="problem" / data-slot="solution") and take only children:

Prop

Type

On this page