{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"c-sortable-1","type":"registry:block","title":"Sortable list of items with drag-and-drop","description":"Sortable list of items with drag-and-drop","dependencies":["sonner"],"registryDependencies":["@reui/badge","@reui/sortable"],"files":[{"path":"c-sortable-1.tsx","type":"registry:block","content":"\"use client\"\n\nimport { useState } from \"react\"\nimport { Badge } from \"@/components/reui/badge\"\nimport {\n  Sortable,\n  SortableItem,\n  SortableItemHandle,\n} from \"@/components/reui/sortable\"\nimport { toast } from \"sonner\"\n\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\ninterface SortableItem {\n  id: string\n  title: string\n  description: string\n  type: \"image\" | \"document\" | \"audio\" | \"video\"\n  size: string\n}\n\nconst defaultItems: SortableItem[] = [\n  {\n    id: \"1\",\n    title: \"Product Demo\",\n    description: \"Main product image\",\n    type: \"image\",\n    size: \"2.4 MB\",\n  },\n  {\n    id: \"2\",\n    title: \"Product Specification\",\n    description: \"Technical details document\",\n    type: \"document\",\n    size: \"1.2 MB\",\n  },\n  {\n    id: \"3\",\n    title: \"Product Demo Video\",\n    description: \"How to use the product\",\n    type: \"video\",\n    size: \"15.7 MB\",\n  },\n  {\n    id: \"4\",\n    title: \"Product Audio Guide\",\n    description: \"Audio instructions\",\n    type: \"audio\",\n    size: \"8.3 MB\",\n  },\n  {\n    id: \"5\",\n    title: \"Product Specification\",\n    description: \"Additional product view\",\n    type: \"image\",\n    size: \"3.1 MB\",\n  },\n]\n\nconst getTypeIcon = (type: SortableItem[\"type\"]) => {\n  switch (type) {\n    case \"image\":\n      return (\n        <IconPlaceholder\n          lucide=\"ImageIcon\"\n          tabler=\"IconPhoto\"\n          hugeicons=\"ImageIcon\"\n          phosphor=\"ImageIcon\"\n          remixicon=\"RiImageLine\"\n          className=\"h-4 w-4\"\n        />\n      )\n    case \"document\":\n      return (\n        <IconPlaceholder\n          lucide=\"FileTextIcon\"\n          tabler=\"IconFileText\"\n          hugeicons=\"File02Icon\"\n          phosphor=\"FileTextIcon\"\n          remixicon=\"RiFileTextLine\"\n          className=\"h-4 w-4\"\n        />\n      )\n    case \"audio\":\n      return (\n        <IconPlaceholder\n          lucide=\"MusicIcon\"\n          tabler=\"IconMusic\"\n          hugeicons=\"MusicNote03Icon\"\n          phosphor=\"MusicNotesIcon\"\n          remixicon=\"RiMusic2Line\"\n          className=\"h-4 w-4\"\n        />\n      )\n    case \"video\":\n      return (\n        <IconPlaceholder\n          lucide=\"VideoIcon\"\n          tabler=\"IconVideo\"\n          hugeicons=\"Video02Icon\"\n          phosphor=\"VideoCameraIcon\"\n          remixicon=\"RiVideoOnLine\"\n          className=\"h-4 w-4\"\n        />\n      )\n  }\n}\n\nconst getTypeColor = (type: SortableItem[\"type\"]) => {\n  switch (type) {\n    case \"image\":\n      return \"primary-light\"\n    case \"document\":\n      return \"success-light\"\n    case \"audio\":\n      return \"destructive-light\"\n    case \"video\":\n      return \"info-light\"\n  }\n}\n\nexport function Pattern() {\n  const [items, setItems] = useState<SortableItem[]>(defaultItems)\n\n  const handleValueChange = (newItems: SortableItem[]) => {\n    setItems(newItems)\n\n    // Show toast with new order\n    toast.success(\"Items reordered successfully!\", {\n      description: newItems\n        .map((item, index) => `${index + 1}. ${item.title}`)\n        .join(\", \"),\n    })\n  }\n\n  const getItemValue = (item: SortableItem) => item.id\n\n  return (\n    <div className=\"mx-auto w-full max-w-xl space-y-8 p-6\">\n      <Sortable\n        value={items}\n        onValueChange={handleValueChange}\n        getItemValue={getItemValue}\n        strategy=\"vertical\"\n        className=\"space-y-2\"\n      >\n        {items.map((item) => (\n          <SortableItem key={item.id} value={item.id}>\n            <div\n              className=\"bg-background border-border hover:bg-accent/50 rounded-md flex cursor-pointer items-center gap-3 border p-3 transition-colors\"\n              onClick={() => {}}\n            >\n              <SortableItemHandle className=\"text-muted-foreground hover:text-foreground\">\n                <IconPlaceholder\n                  lucide=\"GripVerticalIcon\"\n                  tabler=\"IconGripVertical\"\n                  hugeicons=\"DragDropVerticalIcon\"\n                  phosphor=\"DotsSixVerticalIcon\"\n                  remixicon=\"RiDraggable\"\n                  className=\"h-4 w-4\"\n                />\n              </SortableItemHandle>\n\n              <div className=\"text-muted-foreground flex items-center gap-2\">\n                {getTypeIcon(item.type)}\n              </div>\n\n              <div className=\"min-w-0 flex-1\">\n                <h4 className=\"truncate text-sm font-medium\">{item.title}</h4>\n                <p className=\"text-muted-foreground truncate text-xs\">\n                  {item.description}\n                </p>\n              </div>\n\n              <div className=\"flex items-center gap-2\">\n                <Badge variant={getTypeColor(item.type)}>{item.type}</Badge>\n                <span className=\"text-muted-foreground text-xs\">\n                  {item.size}\n                </span>\n              </div>\n            </div>\n          </SortableItem>\n        ))}\n      </Sortable>\n    </div>\n  )\n}","target":"components/examples/c-sortable-1.tsx"}],"meta":{"order":1,"gridSize":1}}