Skip to content
6

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';

interface 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',
  },
];

const 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>
  );
};

const 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>
  );
};

const 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,
};

const 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>
  );
};

export default Feature01;

Dependencies

npm

lucide-react