Centered CTA with heading, description and a Book a walkthrough button above three onboarding steps on Milestones, joined by one rule and aligned left, center and right.
import { cn } from "cn"
import { Heading } from "@/components/editorial/heading"
import {
Milestone,
MilestoneContent,
MilestoneDescription,
MilestoneMarker,
Milestones,
MilestoneTitle,
} from "@/components/editorial/milestones"
import {
Section,
SectionActions,
SectionContent,
SectionDescription,
SectionHeader,
SectionTitleGroup,
} from "@/components/editorial/section"
import { buttonVariants } from "@/components/ui/button"
const COPY = {
title: "We’ll get you started",
body: "We help you choose the components your project needs, then stay with you through every release that follows.",
cta: "Book a walkthrough",
steps: [
{
title: "Map your requirements",
body: "Your project has its own requirements. We go through them with you and pick the blocks, scenes and primitives that fit.",
align: "@2xl:items-start @2xl:text-left",
},
{
title: "Copy into your repo",
body: "The CLI writes the source into your project, where you read it, change it and commit it like your own code.",
align: "@2xl:items-center @2xl:text-center",
},
{
title: "Looking forward",
body: "When the registry adds a component or improves one, a single command brings the change into your repo.",
align: "@2xl:items-end @2xl:text-right",
},
],
} as const
export default function Cta01() {
return (
<Section>
<SectionHeader size="lg" align="center" className="max-w-md">
<SectionTitleGroup>
<Heading size="sm" className="font-medium tracking-[-0.03em]">
{COPY.title}
</Heading>
</SectionTitleGroup>
<SectionDescription variant="muted" size="lg">
{COPY.body}
</SectionDescription>
</SectionHeader>
<SectionActions align="center">
<a
href="#"
data-slot="button"
className={cn(buttonVariants({ size: "lg" }))}
>
{COPY.cta}
</a>
</SectionActions>
<SectionContent>
{/* One rule across all three, or the gaps leave each segment hanging. */}
<Milestones
cols={3}
rule="horizon"
className="gap-12 before:h-0.5 before:bg-muted before:bg-none @2xl:grid-cols-3 @2xl:gap-8 @2xl:before:block"
>
{COPY.steps.map((step) => (
<Milestone key={step.title} className={`gap-19 ${step.align}`}>
<MilestoneMarker className="hidden bg-foreground ring-0 @2xl:block" />
<MilestoneContent className="gap-3">
<MilestoneTitle className="font-sans text-base/8 font-medium tracking-normal">
{step.title}
</MilestoneTitle>
<MilestoneDescription className="max-w-xs text-sm/7 wrap-break-word">
{step.body}
</MilestoneDescription>
</MilestoneContent>
</Milestone>
))}
</Milestones>
</SectionContent>
</Section>
)
}
pnpm dlx shadcn add @01orbital/cta-01npx shadcn add @01orbital/cta-01yarn shadcn add @01orbital/cta-01bunx --bun shadcn add @01orbital/cta-01Free under the MIT license. Add the @01orbital registry to components.json once (install guide), then run the command.
It lands at components/blocks/cta/cta-01/index.tsx, as source you own and edit.
import Cta01 from "@/components/blocks/cta/cta-01"
export default function Example() {
return <Cta01 />
}npm: cn. The CLI installs them for you.
Registry pieces it installs with it:
buttonCardstock Notice CTA
Dark announcement CTA as a notice on a cardstock panel under a warm overhead GlowRig, the same lamp pooling on the card, with a GrainVeil over the wall, an eyebrow, a large headline, a line and one button. Pulls in Geist Mono and Hanken Grotesk.
Dark Email Signup CTA
Pinned-dark email signup with a centered Instrument Serif headline, description and a glass pill input group holding the email field and Get started button, over a warm grained floor.