Feature 1
Three alternating feature rows, each pairing a stylized Tailwind-only mock UI with a copy column (eyebrow, headline, paragraph, 3-item checklist).
Preview
Installation
npx shadcn@latest add https://hirael.com/r/feature-01.jsonCode
components/blocks/feature-01.tsx
"use client";
import * as React from "react";
import { Check, Terminal, GitBranch, Gauge } from "lucide-react";
import { cn } from "@/lib/utils";
type FeatureRow = {
eyebrow: string;
headline: string;
body: string;
bullets: readonly string[];
media: "registry" | "branches" | "metrics";
};
const ROWS: readonly FeatureRow[] = [
{
eyebrow: "registry",
headline: "One CLI command, source in your repo.",
body: "Hirael distributes through the same shadcn CLI you already use. The component lands in your codebase as plain TSX, no package pin, no version drift.",
bullets: [
"Resolved against your existing tsconfig paths",
"Drops into components/ui/* by default",
"Zero runtime dependency on Hirael",
],
media: "registry",
},
{
eyebrow: "composition",
headline: "Composition, the shadcn way.",
body: "Every compound component ships as flat top-level exports, no namespacing, no convenience wrappers. The bare name is the root and holds state; every rendered piece carries a data-slot for downstream styling.",
bullets: [
"Flat named exports, compose at the call site",
"data-slot on every rendered piece",
"Same state machine you'd write by hand",
],
media: "branches",
},
{
eyebrow: "performance",
headline: "Built for dense product surfaces.",
body: "Virtualized lists, debounced async, and stable keys are wired in by default, built to hold up under real production data, not just a demo.",
bullets: [
"Stable keyboard nav past 10k rows",
"Async loading with cancellation",
"Tree-shakeable, SSR-safe",
],
media: "metrics",
},
];
function MediaRegistry() {
return (
<div
className="relative w-full rounded-sm border border-border bg-card"
style={{ boxShadow: "6px 6px 0 0 var(--border)" }}
>
<div className="flex items-center justify-between border-b border-border px-4 py-2.5">
<span className="inline-flex items-center gap-2 font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
<Terminal className="size-3" />
install
</span>
<div className="flex items-center gap-1">
<span className="size-1.5 rounded-full bg-border" />
<span className="size-1.5 rounded-full bg-border" />
<span className="size-1.5 rounded-full bg-foreground" />
</div>
</div>
<pre className="overflow-x-auto p-4 font-mono text-[12px] leading-[1.7]">
<code>
<span className="block">
<span className="text-foreground">$</span>{" "}
<span className="text-foreground">npx shadcn add</span>
</span>
<span className="block text-muted-foreground">
{" "}https://hirael.com/r/combobox
</span>
<span className="block"> </span>
<span className="block text-muted-foreground">
✓ resolved registry
</span>
<span className="block text-muted-foreground">
✓ wrote combobox.tsx
</span>
</code>
</pre>
</div>
);
}
function MediaBranches() {
return (
<div
className="relative w-full rounded-sm border border-border bg-card p-5"
style={{ boxShadow: "6px 6px 0 0 var(--border)" }}
>
<div className="mb-4 inline-flex items-center gap-2 font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
<GitBranch className="size-3" />
composition
</div>
<div className="grid grid-cols-1 gap-3">
<div className="rounded-sm border border-border bg-background p-3">
<span className="font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
call site
</span>
<pre className="mt-2 font-mono text-[11px] leading-[1.55]">
<code>
{"<MultiSelect value={v} onValueChange={set}>\n"}
{" <MultiSelectTrigger />\n"}
{" <MultiSelectContent />\n"}
{"</MultiSelect>"}
</code>
</pre>
</div>
<div className="rounded-sm border border-border bg-background p-3">
<span className="font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
rendered DOM
</span>
<pre className="mt-2 font-mono text-[11px] leading-[1.55] text-muted-foreground">
<code>
{'<button data-slot="multi-select-trigger" />\n'}
{'<div data-slot="multi-select-content" />'}
</code>
</pre>
</div>
</div>
</div>
);
}
function MediaMetrics() {
const bars = [38, 52, 44, 68, 49, 81, 62, 74, 58, 88];
return (
<div
className="relative w-full rounded-sm border border-border bg-card p-5"
style={{ boxShadow: "6px 6px 0 0 var(--border)" }}
>
<div className="mb-4 flex items-center justify-between">
<span className="inline-flex items-center gap-2 font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
<Gauge className="size-3" />
render · 10k rows
</span>
<span className="font-mono text-[10px] tabular-nums text-foreground">
14ms p95
</span>
</div>
<div className="flex h-32 items-end gap-1.5">
{bars.map((h, i) => (
<div
key={i}
className={cn(
"flex-1 rounded-[2px]",
i === bars.length - 1 ? "bg-foreground" : "bg-muted",
)}
style={{ height: `${h}%` }}
/>
))}
</div>
<div className="mt-4 grid grid-cols-3 gap-2 border-t border-border pt-4">
{[
{ l: "scroll", v: "60fps" },
{ l: "memory", v: "12 MB" },
{ l: "bundle", v: "+2.1 KB" },
].map((s) => (
<div key={s.l}>
<div className="font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
{s.l}
</div>
<div className="mt-1 font-mono text-sm tabular-nums">{s.v}</div>
</div>
))}
</div>
</div>
);
}
const MEDIA: Record<FeatureRow["media"], React.ComponentType> = {
registry: MediaRegistry,
branches: MediaBranches,
metrics: MediaMetrics,
};
export default function Feature01() {
return (
<section className="bg-background py-20 sm:py-28">
<div className="container w-full">
<div className="flex flex-col gap-20 sm:gap-24">
{ROWS.map((row, i) => {
const Media = MEDIA[row.media];
const mediaFirst = i % 2 === 1;
return (
<div
key={row.headline}
className="grid grid-cols-1 items-center gap-10 lg:grid-cols-12 lg:gap-16"
>
<div
className={cn(
"lg:col-span-6",
mediaFirst ? "lg:order-2" : "lg:order-1",
)}
>
<div className="flex flex-col gap-5">
<span className="font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
{row.eyebrow}
</span>
<h3 className="text-2xl font-semibold leading-[1.1] tracking-[-0.035em] sm:text-3xl">
{row.headline}
</h3>
<p className="max-w-lg text-sm text-muted-foreground sm:text-base">
{row.body}
</p>
<ul className="mt-2 flex flex-col gap-2.5">
{row.bullets.map((b) => (
<li
key={b}
className="flex items-start gap-3 text-sm text-foreground"
>
<span className="mt-0.5 inline-flex size-4 shrink-0 items-center justify-center rounded-[2px] border border-border bg-card">
<Check className="size-3" />
</span>
{b}
</li>
))}
</ul>
</div>
</div>
<div
className={cn(
"lg:col-span-6",
mediaFirst ? "lg:order-1" : "lg:order-2",
)}
>
<Media />
</div>
</div>
);
})}
</div>
</div>
</section>
);
}
Dependencies
npm
lucide-react