{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-upload-06",
  "type": "registry:block",
  "title": "File Upload with Status Sections",
  "description": "A file upload with status sections block.",
  "author": "ephraim duncan <https://ephraimduncan.com>",
  "registryDependencies": [
    "button",
    "card",
    "progress",
    "separator"
  ],
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "content/components/file-upload/file-upload-06.tsx",
      "type": "registry:component",
      "target": "components/file-upload-06.tsx",
      "content": "'use client';\n\nimport { CheckCircle, FileText, Loader2, Upload, X } from 'lucide-react';\nimport type React from 'react';\nimport { useRef, useState } from 'react';\nimport { Button } from '@/components/ui/button';\nimport { Card } from '@/components/ui/card';\nimport { Progress } from '@/components/ui/progress';\nimport { Separator } from '@/components/ui/separator';\n\ninterface UploadItem {\n  id: string;\n  name: string;\n  progress: number;\n  status: 'uploading' | 'completed';\n}\n\nexport default function FileUpload06() {\n  const [uploads, setUploads] = useState<UploadItem[]>([\n    {\n      id: 'a1',\n      name: 'design-mock-landing.png',\n      progress: 62,\n      status: 'uploading',\n    },\n    {\n      id: 'b2',\n      name: 'team-headshot-2025-01-09.jpg',\n      progress: 28,\n      status: 'uploading',\n    },\n    {\n      id: 'c3',\n      name: 'logo-v3-final.gif',\n      progress: 100,\n      status: 'completed',\n    },\n  ]);\n  const filePickerRef = useRef<HTMLInputElement>(null);\n\n  const openFilePicker = () => {\n    filePickerRef.current?.click();\n  };\n\n  const onFileInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const selectedFiles = event.target.files;\n    if (selectedFiles) {\n      console.log('Files selected:', selectedFiles);\n    }\n  };\n\n  const onDragOver = (event: React.DragEvent) => {\n    event.preventDefault();\n  };\n\n  const onDropFiles = (event: React.DragEvent) => {\n    event.preventDefault();\n    const droppedFiles = event.dataTransfer.files;\n    if (droppedFiles) {\n      console.log('Files dropped:', droppedFiles);\n    }\n  };\n\n  const removeUploadById = (id: string) => {\n    setUploads(uploads.filter((file) => file.id !== id));\n  };\n\n  const activeUploads = uploads.filter((file) => file.status === 'uploading');\n  const completedUploads = uploads.filter(\n    (file) => file.status === 'completed'\n  );\n\n  return (\n    <div className=\"mx-auto flex w-full max-w-sm flex-col gap-y-6\">\n      <Card\n        className=\"group flex max-h-[200px] w-full cursor-pointer flex-col items-center justify-center gap-4 border-dashed py-8 text-sm shadow-none transition-colors hover:bg-muted/50\"\n        onClick={openFilePicker}\n        onDragOver={onDragOver}\n        onDrop={onDropFiles}\n      >\n        <div className=\"grid space-y-3\">\n          <div className=\"flex items-center gap-x-2 text-muted-foreground\">\n            <Upload className=\"size-5\" />\n            <div>\n              Drop files here or{' '}\n              <Button\n                className=\"h-auto p-0 font-normal text-primary\"\n                onClick={openFilePicker}\n                variant=\"link\"\n              >\n                browse files\n              </Button>{' '}\n              to add\n            </div>\n          </div>\n        </div>\n        <input\n          accept=\"image/png,image/jpeg,image/gif\"\n          className=\"hidden\"\n          multiple\n          onChange={onFileInputChange}\n          ref={filePickerRef}\n          type=\"file\"\n        />\n        <span className=\"mt-2 block text-base/6 text-muted-foreground group-disabled:opacity-50 sm:text-xs\">\n          Supported: JPG, PNG, GIF (max 10 MB)\n        </span>\n      </Card>\n\n      <div className=\"flex flex-col gap-y-4\">\n        {activeUploads.length > 0 && (\n          <div>\n            <h2 className=\"mb-4 flex items-center text-balance font-mono font-normal text-foreground text-lg uppercase sm:text-xs\">\n              <Loader2 className=\"mr-1 size-4 animate-spin\" />\n              Uploading\n            </h2>\n            <div className=\"-mt-2 divide-y\">\n              {activeUploads.map((file) => (\n                <div className=\"group flex items-center py-4\" key={file.id}>\n                  <div className=\"mr-3 grid size-10 shrink-0 place-content-center rounded border bg-muted\">\n                    <FileText className=\"inline size-4 group-hover:hidden\" />\n                    <Button\n                      aria-label=\"Cancel\"\n                      className=\"hidden size-4 h-auto p-0 group-hover:inline\"\n                      onClick={() => removeUploadById(file.id)}\n                      size=\"icon\"\n                      variant=\"ghost\"\n                    >\n                      <X className=\"size-4\" />\n                    </Button>\n                  </div>\n                  <div className=\"mb-1 flex w-full flex-col\">\n                    <div className=\"flex justify-between gap-2\">\n                      <span className=\"select-none text-base/6 text-foreground group-disabled:opacity-50 sm:text-sm/6\">\n                        {file.name}\n                      </span>\n                      <span className=\"text-muted-foreground text-sm tabular-nums\">\n                        {file.progress}%\n                      </span>\n                    </div>\n                    <Progress\n                      className=\"mt-1 h-2 min-w-64\"\n                      value={file.progress}\n                    />\n                  </div>\n                </div>\n              ))}\n            </div>\n          </div>\n        )}\n\n        {activeUploads.length > 0 && completedUploads.length > 0 && (\n          <Separator className=\"my-0\" />\n        )}\n\n        {completedUploads.length > 0 && (\n          <div>\n            <h2 className=\"mb-4 flex items-center text-balance font-mono font-normal text-foreground text-lg uppercase sm:text-xs\">\n              <CheckCircle className=\"mr-1 size-4\" />\n              Finished\n            </h2>\n            <div className=\"-mt-2 divide-y\">\n              {completedUploads.map((file) => (\n                <div className=\"group flex items-center py-4\" key={file.id}>\n                  <div className=\"mr-3 grid size-10 shrink-0 place-content-center rounded border bg-muted\">\n                    <FileText className=\"inline size-4 group-hover:hidden\" />\n                    <Button\n                      aria-label=\"Remove\"\n                      className=\"hidden size-4 h-auto p-0 group-hover:inline\"\n                      onClick={() => removeUploadById(file.id)}\n                      size=\"icon\"\n                      variant=\"ghost\"\n                    >\n                      <X className=\"size-4\" />\n                    </Button>\n                  </div>\n                  <div className=\"mb-1 flex w-full flex-col\">\n                    <div className=\"flex justify-between gap-2\">\n                      <span className=\"select-none text-base/6 text-foreground group-disabled:opacity-50 sm:text-sm/6\">\n                        {file.name}\n                      </span>\n                      <span className=\"text-muted-foreground text-sm tabular-nums\">\n                        {file.progress}%\n                      </span>\n                    </div>\n                    <Progress\n                      className=\"mt-1 h-2 min-w-64\"\n                      value={file.progress}\n                    />\n                  </div>\n                </div>\n              ))}\n            </div>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n"
    }
  ],
  "categories": [
    "file-upload"
  ]
}