{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "how-it-works-4",
  "title": "Zig-Zag Steps With Mockups",
  "description": "How it works section of three alternating rows, each pairing a numbered step, description, and checklist with a mock UI preview panel on the opposite side.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "badge"
  ],
  "files": [
    {
      "path": "registry/blocks/how-it-works/4/how-it-works-block.tsx",
      "content": "import type { ReactNode } from \"react\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\n/** Props a call site may pass through to an icon. */\ntype IconProps = { className?: string; size?: number | string }\n\n/** An icon held in data and rendered later, e.g. `<item.icon className=\"size-4\" />`. */\ntype IconRenderer = (props: IconProps) => React.ReactNode\n\ntype Step = {\n  icon: IconRenderer\n  title: string\n  description: string\n  points: string[]\n  Mock: () => ReactNode\n}\n\nfunction MockFrame({ children }: { children: ReactNode }) {\n  return (\n    <div\n      className=\"w-full rounded-lg border border-border bg-card p-4\"\n      aria-hidden=\"true\"\n    >\n      <div className=\"flex items-center gap-1.5\">\n        <span className=\"size-2 rounded-full bg-muted-foreground/30\" />\n        <span className=\"size-2 rounded-full bg-muted-foreground/30\" />\n        <span className=\"size-2 rounded-full bg-muted-foreground/30\" />\n      </div>\n      <div className=\"mt-4\">{children}</div>\n    </div>\n  )\n}\n\n// Step 1 — rows of data sources being connected.\nfunction ConnectMock() {\n  const connected = [true, true, false]\n  return (\n    <MockFrame>\n      <div className=\"mb-3 h-2 w-20 bg-muted\" />\n      <div className=\"flex flex-col gap-2\">\n        {connected.map((isConnected, i) => (\n          <div\n            key={i}\n            className=\"flex items-center gap-3 rounded-md border border-border bg-background p-2.5\"\n          >\n            <div className=\"size-6 shrink-0 rounded-md border border-border bg-muted\" />\n            <div className=\"flex flex-1 flex-col gap-1.5\">\n              <div className=\"h-2 w-2/3 bg-muted\" />\n              <div className=\"h-1.5 w-1/3 bg-muted\" />\n            </div>\n            {isConnected ? (\n              <IconPlaceholder\n                lucide=\"Check\"\n                tabler=\"IconCheck\"\n                hugeicons=\"Tick02Icon\"\n                phosphor=\"Check\"\n                remixicon=\"RiCheckLine\"\n                className=\"size-4 shrink-0 text-success\"\n              />\n            ) : (\n              <span className=\"size-2 shrink-0 rounded-full bg-muted-foreground/30\" />\n            )}\n          </div>\n        ))}\n      </div>\n    </MockFrame>\n  )\n}\n\n// Step 2 — a table with active filters.\nfunction ShapeMock() {\n  return (\n    <MockFrame>\n      <div className=\"mb-3 flex gap-1.5\">\n        <div className=\"h-5 w-16 rounded-md bg-foreground/80\" />\n        <div className=\"h-5 w-12 rounded-md border border-border bg-muted\" />\n        <div className=\"h-5 w-14 rounded-md border border-border bg-muted\" />\n      </div>\n      <div className=\"overflow-hidden rounded-md border border-border\">\n        <div className=\"grid grid-cols-3 gap-2 border-b border-border bg-muted/60 p-2\">\n          <div className=\"h-1.5 bg-muted-foreground/40\" />\n          <div className=\"h-1.5 bg-muted-foreground/40\" />\n          <div className=\"h-1.5 bg-muted-foreground/40\" />\n        </div>\n        {Array.from({ length: 4 }).map((_, i) => (\n          <div\n            key={i}\n            className=\"grid grid-cols-3 gap-2 border-b border-border p-2 last:border-b-0\"\n          >\n            <div className=\"h-1.5 bg-muted\" />\n            <div className=\"h-1.5 bg-muted\" />\n            <div\n              className={\n                \"h-1.5 \" + (i % 2 === 0 ? \"bg-foreground/60\" : \"bg-muted\")\n              }\n            />\n          </div>\n        ))}\n      </div>\n    </MockFrame>\n  )\n}\n\n// Step 3 — a published dashboard with stats and a chart.\nfunction ShipMock() {\n  const bars = [\"h-6\", \"h-10\", \"h-8\", \"h-14\", \"h-11\", \"h-16\", \"h-12\"]\n  return (\n    <MockFrame>\n      <div className=\"grid grid-cols-3 gap-2\">\n        {Array.from({ length: 3 }).map((_, i) => (\n          <div\n            key={i}\n            className=\"flex flex-col gap-1.5 rounded-md border border-border bg-background p-2\"\n          >\n            <div className=\"h-1.5 w-2/3 bg-muted\" />\n            <div className=\"h-3 w-1/2 bg-foreground/70\" />\n          </div>\n        ))}\n      </div>\n      <div className=\"mt-3 flex h-20 items-end gap-1.5 rounded-md border border-border bg-background p-2\">\n        {bars.map((height, i) => (\n          <div key={i} className={\"flex-1 bg-foreground/70 \" + height} />\n        ))}\n      </div>\n    </MockFrame>\n  )\n}\n\nconst steps: Step[] = [\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Cloud\"\n        tabler=\"IconCloud\"\n        hugeicons=\"CloudIcon\"\n        phosphor=\"Cloud\"\n        remixicon=\"RiCloudLine\"\n        {...p}\n      />\n    ),\n    title: \"Connect Your Data\",\n    description:\n      \"Link a database or import a CSV and we map your schema automatically. No pipelines to maintain.\",\n    points: [\"One-click integrations\", \"Automatic schema mapping\"],\n    Mock: ConnectMock,\n  },\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"SlidersHorizontal\"\n        tabler=\"IconAdjustments\"\n        hugeicons=\"PreferenceHorizontalIcon\"\n        phosphor=\"Faders\"\n        remixicon=\"RiEqualizerLine\"\n        {...p}\n      />\n    ),\n    title: \"Shape The View\",\n    description:\n      \"Filter, group, and pivot until the data answers your question. Save any view your team relies on.\",\n    points: [\"Reusable saved views\", \"Shared team filters\"],\n    Mock: ShapeMock,\n  },\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Rocket\"\n        tabler=\"IconRocket\"\n        hugeicons=\"RocketIcon\"\n        phosphor=\"Rocket\"\n        remixicon=\"RiRocket2Line\"\n        {...p}\n      />\n    ),\n    title: \"Ship The Dashboard\",\n    description:\n      \"Publish to a link or embed it in your app. Changes to the source update everywhere instantly.\",\n    points: [\"Public or private links\", \"Live embeds\"],\n    Mock: ShipMock,\n  },\n]\n\nfunction StepRow({ step, index }: { step: Step; index: number }) {\n  const flipped = index % 2 === 1\n  const { Mock } = step\n  return (\n    <div className=\"grid items-center gap-8 md:grid-cols-2 md:gap-12\">\n      <div className={flipped ? \"md:order-2\" : undefined}>\n        <div className=\"flex size-10 items-center justify-center rounded-lg border border-border bg-muted text-foreground\">\n          <step.icon className=\"size-5\" aria-hidden=\"true\" />\n        </div>\n        <h3 className=\"mt-4 font-heading text-xl font-semibold tracking-tight text-balance\">\n          {step.title}\n        </h3>\n        <p className=\"mt-2 text-pretty text-muted-foreground\">\n          {step.description}\n        </p>\n        <ul className=\"mt-4 flex flex-col gap-2\">\n          {step.points.map((point) => (\n            <li key={point} className=\"flex items-center gap-2 text-sm\">\n              <IconPlaceholder\n                lucide=\"Check\"\n                tabler=\"IconCheck\"\n                hugeicons=\"Tick02Icon\"\n                phosphor=\"Check\"\n                remixicon=\"RiCheckLine\"\n                className=\"size-4 shrink-0 text-foreground\"\n                aria-hidden=\"true\"\n              />\n              {point}\n            </li>\n          ))}\n        </ul>\n      </div>\n      <div className={flipped ? \"md:order-1\" : undefined}>\n        <Mock />\n      </div>\n    </div>\n  )\n}\n\nexport default function HowItWorksBlock() {\n  return (\n    <section className=\"flex min-h-svh w-full justify-center bg-background px-6 py-16 text-foreground\">\n      <div className=\"w-full max-w-4xl\">\n        <div className=\"flex flex-col items-center text-center\">\n          <Badge variant=\"secondary\">How It Works</Badge>\n          <h2 className=\"mt-4 font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl\">\n            From raw data to a live dashboard in three steps\n          </h2>\n          <p className=\"mt-4 max-w-2xl text-lg text-pretty text-muted-foreground\">\n            No setup calls, no pipelines. Connect a source and share an answer\n            the same afternoon.\n          </p>\n        </div>\n\n        <div className=\"mt-14 flex flex-col gap-14\">\n          {steps.map((step, index) => (\n            <StepRow key={step.title} step={step} index={index} />\n          ))}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/how-it-works-4.tsx"
    }
  ],
  "cssVars": {
    "light": {
      "success": "oklch(0.432 0.095 166.913)"
    },
    "dark": {
      "success": "oklch(0.765 0.177 163.223)"
    }
  },
  "meta": {
    "height": "1094px",
    "tier": "free"
  },
  "categories": [
    "how-it-works"
  ],
  "type": "registry:block"
}