{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "roadmap-1",
  "title": "Status Kanban Board",
  "description": "Product roadmap board in Planned, In Progress, and Shipped columns, with vote counts, progress bars, contributor avatars, and shipped dates per card.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "avatar",
    "badge",
    "progress"
  ],
  "files": [
    {
      "path": "registry/blocks/roadmap/1/roadmap-block.tsx",
      "content": "import { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Progress } from \"@/components/ui/progress\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\nimport type * as React from \"react\"\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 Contributor = { name: string; src: string }\n\ntype Item = {\n  title: string\n  description: string\n  tag: string\n  votes?: number\n  progress?: number\n  shipped?: string\n  team?: Contributor[]\n}\n\nconst team: Record<string, Contributor> = {\n  ada: { name: \"Ada\", src: \"https://i.pravatar.cc/64?img=47\" },\n  leo: { name: \"Leo\", src: \"https://i.pravatar.cc/64?img=12\" },\n  mara: { name: \"Mara\", src: \"https://i.pravatar.cc/64?img=32\" },\n  owen: { name: \"Owen\", src: \"https://i.pravatar.cc/64?img=53\" },\n}\n\nconst columns: {\n  status: string\n  icon: IconRenderer\n  items: Item[]\n}[] = [\n  {\n    status: \"Planned\",\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Lightbulb\"\n        tabler=\"IconBulb\"\n        hugeicons=\"Idea01Icon\"\n        phosphor=\"Lightbulb\"\n        remixicon=\"RiLightbulbLine\"\n        {...p}\n      />\n    ),\n    items: [\n      {\n        title: \"Custom dashboards\",\n        description: \"Drag-and-drop widgets to build the view your team needs.\",\n        tag: \"Analytics\",\n        votes: 218,\n      },\n      {\n        title: \"SAML single sign-on\",\n        description: \"Enterprise login with your existing identity provider.\",\n        tag: \"Security\",\n        votes: 156,\n      },\n      {\n        title: \"Public API v2\",\n        description: \"A faster, fully typed API with per-key rate limits.\",\n        tag: \"API\",\n        votes: 132,\n      },\n    ],\n  },\n  {\n    status: \"In Progress\",\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"LoaderCircle\"\n        tabler=\"IconLoader2\"\n        hugeicons=\"Loading03Icon\"\n        phosphor=\"Spinner\"\n        remixicon=\"RiLoader4Line\"\n        {...p}\n      />\n    ),\n    items: [\n      {\n        title: \"Mobile app\",\n        description: \"Native iOS and Android apps with offline support.\",\n        tag: \"Mobile\",\n        progress: 72,\n        team: [team.ada, team.leo, team.mara],\n      },\n      {\n        title: \"Audit log export\",\n        description: \"Stream workspace activity to your SIEM of choice.\",\n        tag: \"Security\",\n        progress: 41,\n        team: [team.owen, team.ada],\n      },\n    ],\n  },\n  {\n    status: \"Shipped\",\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Check\"\n        tabler=\"IconCheck\"\n        hugeicons=\"Tick02Icon\"\n        phosphor=\"Check\"\n        remixicon=\"RiCheckLine\"\n        {...p}\n      />\n    ),\n    items: [\n      {\n        title: \"Command palette\",\n        description: \"Jump anywhere with Command K across your workspace.\",\n        tag: \"Productivity\",\n        shipped: \"Jun 2026\",\n        team: [team.leo, team.mara],\n      },\n      {\n        title: \"Role-based access\",\n        description: \"Admin, Editor, and Viewer roles for every member.\",\n        tag: \"Security\",\n        shipped: \"May 2026\",\n        team: [team.ada, team.owen],\n      },\n    ],\n  },\n]\n\nfunction AvatarStack({ members }: { members: Contributor[] }) {\n  return (\n    <div className=\"flex -space-x-2\">\n      {members.map((member) => (\n        <Avatar key={member.name} className=\"size-6 border-2 border-card\">\n          <AvatarImage\n            src={member.src}\n            alt={member.name}\n            className=\"grayscale\"\n          />\n          <AvatarFallback className=\"text-[10px]\">\n            {member.name[0]}\n          </AvatarFallback>\n        </Avatar>\n      ))}\n    </div>\n  )\n}\n\nexport default function RoadmapBlock() {\n  return (\n    <section className=\"flex w-full items-center justify-center bg-background px-6 py-16 text-foreground\">\n      <div className=\"mx-auto w-full max-w-5xl\">\n        <div className=\"mb-10\">\n          <Badge variant=\"outline\" className=\"mb-4\">\n            Roadmap\n          </Badge>\n          <h2 className=\"font-heading text-3xl font-bold tracking-tight\">\n            What we&apos;re building\n          </h2>\n          <p className=\"mt-3 text-muted-foreground\">\n            A look at what is planned, in progress, and recently shipped.\n          </p>\n        </div>\n\n        <div className=\"grid grid-cols-1 gap-5 md:grid-cols-3\">\n          {columns.map((column) => (\n            <div key={column.status} className=\"flex flex-col gap-3\">\n              <div className=\"flex items-center gap-2\">\n                <column.icon\n                  className=\"size-4 text-muted-foreground\"\n                  aria-hidden=\"true\"\n                />\n                <h3 className=\"font-heading text-sm font-semibold\">\n                  {column.status}\n                </h3>\n                <span className=\"text-xs text-muted-foreground tabular-nums\">\n                  {column.items.length}\n                </span>\n              </div>\n\n              <ul className=\"flex flex-col gap-3\">\n                {column.items.map((item) => (\n                  <li\n                    key={item.title}\n                    className=\"flex flex-col gap-3 rounded-lg border border-border bg-card p-4 transition-colors hover:border-muted-foreground/40\"\n                  >\n                    <div className=\"flex flex-col gap-2\">\n                      <Badge variant=\"secondary\" className=\"w-fit\">\n                        {item.tag}\n                      </Badge>\n                      <h4 className=\"font-heading text-sm font-semibold\">\n                        {item.title}\n                      </h4>\n                      <p className=\"text-xs/relaxed text-muted-foreground\">\n                        {item.description}\n                      </p>\n                    </div>\n\n                    {item.progress != null && (\n                      <div className=\"flex flex-col gap-1.5\">\n                        <div className=\"flex items-center justify-between gap-3\">\n                          {item.team && <AvatarStack members={item.team} />}\n                          <span className=\"text-xs font-medium text-muted-foreground tabular-nums\">\n                            {item.progress}%\n                          </span>\n                        </div>\n                        <Progress\n                          value={item.progress}\n                          aria-label={`${item.title} progress`}\n                        />\n                      </div>\n                    )}\n\n                    {item.votes != null && (\n                      <Badge variant=\"outline\" className=\"w-fit gap-1\">\n                        <IconPlaceholder\n                          lucide=\"ChevronUp\"\n                          tabler=\"IconChevronUp\"\n                          hugeicons=\"ArrowUp01Icon\"\n                          phosphor=\"CaretUp\"\n                          remixicon=\"RiArrowUpSLine\"\n                          className=\"size-3.5\"\n                          aria-hidden=\"true\"\n                        />\n                        {item.votes}\n                      </Badge>\n                    )}\n\n                    {item.shipped != null && (\n                      <div className=\"flex items-center justify-between gap-3\">\n                        {item.team && <AvatarStack members={item.team} />}\n                        <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n                          <IconPlaceholder\n                            lucide=\"Check\"\n                            tabler=\"IconCheck\"\n                            hugeicons=\"Tick02Icon\"\n                            phosphor=\"Check\"\n                            remixicon=\"RiCheckLine\"\n                            className=\"size-3.5\"\n                            aria-hidden=\"true\"\n                          />\n                          {item.shipped}\n                        </span>\n                      </div>\n                    )}\n                  </li>\n                ))}\n              </ul>\n            </div>\n          ))}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/roadmap-1.tsx"
    }
  ],
  "meta": {
    "height": "788px",
    "tier": "free"
  },
  "categories": [
    "roadmap"
  ],
  "type": "registry:block"
}