{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"c-kanban-3","type":"registry:block","title":"Kanban board with frame columns","description":"Kanban board with frame columns","dependencies":[],"registryDependencies":["@reui/badge","@reui/frame","@reui/kanban"],"files":[{"path":"c-kanban-3.tsx","type":"registry:block","content":"\"use client\"\n\nimport { ComponentProps, useState } from \"react\"\nimport { Badge } from \"@/components/reui/badge\"\nimport {\n  Frame,\n  FrameHeader,\n  FramePanel,\n  FrameTitle,\n} from \"@/components/reui/frame\"\nimport {\n  Kanban,\n  KanbanBoard,\n  KanbanColumn,\n  KanbanColumnContent,\n  KanbanItem,\n  KanbanItemHandle,\n  KanbanOverlay,\n} from \"@/components/reui/kanban\"\n\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\ninterface Task {\n  id: string\n  title: string\n  label: string\n  labelVariant:\n    | \"primary-light\"\n    | \"success-light\"\n    | \"warning-light\"\n    | \"destructive-light\"\n    | \"info-light\"\n}\n\nconst COLUMNS: Record<string, { title: string; icon: React.ReactNode }> = {\n  todo: {\n    title: \"To Do\",\n    icon: (\n      <IconPlaceholder\n        lucide=\"CircleIcon\"\n        tabler=\"IconCircle\"\n        hugeicons=\"CircleIcon\"\n        phosphor=\"CircleIcon\"\n        remixicon=\"RiCircleLine\"\n        className=\"size-4\"\n      />\n    ),\n  },\n  doing: {\n    title: \"In Progress\",\n    icon: (\n      <IconPlaceholder\n        lucide=\"CircleDot\"\n        tabler=\"IconCircleDot\"\n        hugeicons=\"RefreshDotIcon\"\n        phosphor=\"DotsThreeCircleIcon\"\n        remixicon=\"RiRecordCircleLine\"\n        className=\"text-muted-foreground size-4\"\n      />\n    ),\n  },\n  done: {\n    title: \"Done\",\n    icon: (\n      <IconPlaceholder\n        lucide=\"CircleCheckIcon\"\n        tabler=\"IconCircleCheck\"\n        hugeicons=\"CheckmarkCircle01Icon\"\n        phosphor=\"CheckCircleIcon\"\n        remixicon=\"RiCheckboxCircleLine\"\n        className=\"size-4\"\n      />\n    ),\n  },\n}\n\nfunction TaskCard({\n  task,\n  asHandle,\n  ...props\n}: { task: Task; asHandle?: boolean } & Omit<\n  ComponentProps<typeof KanbanItem>,\n  \"value\" | \"children\"\n>) {\n  const content = (\n    <Frame variant=\"ghost\" spacing=\"sm\" className=\"p-0\">\n      <FramePanel className=\"p-3\">\n        <div className=\"flex flex-col gap-2\">\n          <span className=\"text-sm font-medium\">{task.title}</span>\n          <Badge variant={task.labelVariant} size=\"sm\" className=\"w-fit\">\n            {task.label}\n          </Badge>\n        </div>\n      </FramePanel>\n    </Frame>\n  )\n\n  return (\n    <KanbanItem value={task.id} {...props}>\n      {asHandle ? <KanbanItemHandle>{content}</KanbanItemHandle> : content}\n    </KanbanItem>\n  )\n}\n\nexport function Pattern() {\n  const [columns, setColumns] = useState<Record<string, Task[]>>({\n    todo: [\n      {\n        id: \"1\",\n        title: \"Design landing page\",\n        label: \"Design\",\n        labelVariant: \"info-light\",\n      },\n      {\n        id: \"2\",\n        title: \"Set up CI/CD pipeline\",\n        label: \"DevOps\",\n        labelVariant: \"warning-light\",\n      },\n      {\n        id: \"3\",\n        title: \"Write unit tests\",\n        label: \"Testing\",\n        labelVariant: \"success-light\",\n      },\n    ],\n    doing: [\n      {\n        id: \"4\",\n        title: \"Implement auth flow\",\n        label: \"Backend\",\n        labelVariant: \"primary-light\",\n      },\n      {\n        id: \"5\",\n        title: \"Create component library\",\n        label: \"Frontend\",\n        labelVariant: \"destructive-light\",\n      },\n    ],\n    done: [\n      {\n        id: \"6\",\n        title: \"Project kickoff\",\n        label: \"Planning\",\n        labelVariant: \"info-light\",\n      },\n    ],\n  })\n\n  return (\n    <Kanban\n      value={columns}\n      onValueChange={setColumns}\n      getItemValue={(item) => item.id}\n    >\n      <KanbanBoard className=\"grid auto-rows-fr grid-cols-3\">\n        {Object.entries(columns).map(([columnId, tasks]) => {\n          const col = COLUMNS[columnId] ?? { title: columnId, icon: null }\n          return (\n            <KanbanColumn key={columnId} value={columnId}>\n              <Frame spacing=\"sm\" className=\"h-full\">\n                <FrameHeader className=\"flex flex-row items-center gap-2\">\n                  {col.icon}\n                  <FrameTitle>{col.title}</FrameTitle>\n                  <Badge variant=\"outline\" size=\"sm\" className=\"ml-auto\">\n                    {tasks.length}\n                  </Badge>\n                </FrameHeader>\n                <KanbanColumnContent\n                  value={columnId}\n                  className=\"flex flex-col gap-2 p-0.5\"\n                >\n                  {tasks.map((task) => (\n                    <TaskCard key={task.id} task={task} asHandle />\n                  ))}\n                </KanbanColumnContent>\n              </Frame>\n            </KanbanColumn>\n          )\n        })}\n      </KanbanBoard>\n      <KanbanOverlay className=\"bg-muted/10 rounded-md border-2 border-dashed\" />\n    </Kanban>\n  )\n}","target":"components/examples/c-kanban-3.tsx"}],"meta":{"order":3,"gridSize":1,"label":"Frame Columns"}}