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.json

Code

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">&nbsp;</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