{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-upload-01",
  "type": "registry:block",
  "title": "File Upload with Preview",
  "description": "A file upload with preview block.",
  "author": "ephraim duncan <https://ephraimduncan.com>",
  "registryDependencies": [
    "button",
    "card",
    "input",
    "label",
    "select",
    "tooltip"
  ],
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "content/components/file-upload/file-upload-01.tsx",
      "type": "registry:component",
      "target": "components/file-upload-01.tsx",
      "content": "'use client';\n\nimport { HelpCircle, Trash2, Upload } from 'lucide-react';\nimport { useRef, useState } from 'react';\nimport { Button } from '@/components/ui/button';\nimport { Card, CardContent } from '@/components/ui/card';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from '@/components/ui/select';\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\n\nexport default function FileUpload01() {\n  const fileInputRef = useRef<HTMLInputElement>(null);\n  const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);\n  const [fileProgresses, setFileProgresses] = useState<Record<string, number>>(\n    {}\n  );\n\n  const handleFileSelect = (files: FileList | null) => {\n    if (!files) return;\n\n    const newFiles = Array.from(files);\n    setUploadedFiles((prev) => [...prev, ...newFiles]);\n\n    // Simulate upload progress for each file\n    newFiles.forEach((file) => {\n      let progress = 0;\n      const interval = setInterval(() => {\n        progress += Math.random() * 10;\n        if (progress >= 100) {\n          progress = 100;\n          clearInterval(interval);\n        }\n        setFileProgresses((prev) => ({\n          ...prev,\n          [file.name]: Math.min(progress, 100),\n        }));\n      }, 300);\n    });\n  };\n\n  const handleBoxClick = () => {\n    fileInputRef.current?.click();\n  };\n\n  const handleDragOver = (e: React.DragEvent) => {\n    e.preventDefault();\n  };\n\n  const handleDrop = (e: React.DragEvent) => {\n    e.preventDefault();\n    handleFileSelect(e.dataTransfer.files);\n  };\n\n  const removeFile = (filename: string) => {\n    setUploadedFiles((prev) => prev.filter((file) => file.name !== filename));\n    setFileProgresses((prev) => {\n      const newProgresses = { ...prev };\n      delete newProgresses[filename];\n      return newProgresses;\n    });\n  };\n\n  return (\n    <div className=\"flex items-center justify-center p-10\">\n      <Card className=\"mx-auto w-full max-w-lg rounded-lg bg-background p-0 shadow-md\">\n        <CardContent className=\"p-0\">\n          <div className=\"p-6 pb-4\">\n            <div className=\"flex items-start justify-between\">\n              <div>\n                <h2 className=\"text-balance font-medium text-foreground text-lg\">\n                  Create a new project\n                </h2>\n                <p className=\"mt-1 text-pretty text-muted-foreground text-sm\">\n                  Drag and drop files to create a new project.\n                </p>\n              </div>\n            </div>\n          </div>\n\n          <div className=\"mt-2 px-6 pb-4\">\n            <div className=\"grid grid-cols-2 gap-4\">\n              <div>\n                <Label className=\"mb-2\" htmlFor=\"projectName\">\n                  Project name\n                </Label>\n                <Input\n                  defaultValue=\"Open Source Stripe\"\n                  id=\"projectName\"\n                  type=\"text\"\n                />\n              </div>\n\n              <div>\n                <Label className=\"mb-2\" htmlFor=\"projectLead\">\n                  Project lead\n                </Label>\n                <Select\n                  defaultValue=\"1\"\n                  items={{\n                    '1': 'Ephraim Duncan',\n                    '2': 'Lucas Smith',\n                    '3': 'Timur Ercan',\n                  }}\n                >\n                  <SelectTrigger className=\"w-full ps-2\" id=\"projectLead\">\n                    <SelectValue placeholder=\"Select project lead\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectGroup>\n                      <SelectItem value=\"1\">\n                        <img\n                          alt=\"Ephraim Duncan\"\n                          className=\"size-5 rounded\"\n                          height={20}\n                          src=\"https://blocks.so/avatar-01.png\"\n                          width={20}\n                        />\n                        <span className=\"truncate\">Ephraim Duncan</span>\n                      </SelectItem>\n                      <SelectItem value=\"2\">\n                        <img\n                          alt=\"Lucas Smith\"\n                          className=\"size-5 rounded\"\n                          height={20}\n                          src=\"https://blocks.so/avatar-03.png\"\n                          width={20}\n                        />\n                        <span className=\"truncate\">Lucas Smith</span>\n                      </SelectItem>\n                      <SelectItem value=\"3\">\n                        <img\n                          alt=\"Timur Ercan\"\n                          className=\"size-5 rounded\"\n                          height={20}\n                          src=\"https://blocks.so/avatar-02.jpg\"\n                          width={20}\n                        />\n                        <span className=\"truncate\">Timur Ercan</span>\n                      </SelectItem>\n                    </SelectGroup>\n                  </SelectContent>\n                </Select>\n              </div>\n            </div>\n          </div>\n\n          <div className=\"px-6\">\n            <div\n              className=\"flex cursor-pointer flex-col items-center justify-center rounded-md border-2 border-border border-dashed p-8 text-center\"\n              onClick={handleBoxClick}\n              onDragOver={handleDragOver}\n              onDrop={handleDrop}\n            >\n              <div className=\"mb-2 rounded-full bg-muted p-3\">\n                <Upload className=\"h-5 w-5 text-muted-foreground\" />\n              </div>\n              <p className=\"text-pretty font-medium text-foreground text-sm\">\n                Upload a project image\n              </p>\n              <p className=\"mt-1 text-pretty text-muted-foreground text-sm\">\n                or,{' '}\n                <label\n                  className=\"cursor-pointer font-medium text-primary hover:text-primary/90\"\n                  htmlFor=\"fileUpload\"\n                  onClick={(e) => e.stopPropagation()}\n                >\n                  click to browse\n                </label>{' '}\n                (4MB max)\n              </p>\n              <input\n                accept=\"image/*\"\n                className=\"hidden\"\n                id=\"fileUpload\"\n                onChange={(e) => handleFileSelect(e.target.files)}\n                ref={fileInputRef}\n                type=\"file\"\n              />\n            </div>\n          </div>\n\n          <div\n            className={cn(\n              'space-y-3 px-6 pb-5',\n              uploadedFiles.length > 0 ? 'mt-4' : ''\n            )}\n          >\n            {uploadedFiles.map((file, index) => {\n              const imageUrl = URL.createObjectURL(file);\n\n              return (\n                <div\n                  className=\"flex flex-col rounded-lg border border-border p-2\"\n                  key={file.name + index}\n                  onLoad={() => {\n                    return () => URL.revokeObjectURL(imageUrl);\n                  }}\n                >\n                  <div className=\"flex items-center gap-2\">\n                    <div className=\"row-span-2 flex h-14 w-18 items-center justify-center self-start overflow-hidden rounded-sm bg-muted\">\n                      <img\n                        alt={file.name}\n                        className=\"h-full w-full object-cover\"\n                        src={imageUrl}\n                      />\n                    </div>\n\n                    <div className=\"flex-1 pr-1\">\n                      <div className=\"flex items-center justify-between\">\n                        <div className=\"flex items-center gap-2\">\n                          <span className=\"max-w-[250px] truncate text-foreground text-sm\">\n                            {file.name}\n                          </span>\n                          <span className=\"whitespace-nowrap text-muted-foreground text-sm\">\n                            {Math.round(file.size / 1024)} KB\n                          </span>\n                        </div>\n                        <Button\n                          className=\"bg-transparent! hover:text-red-500\"\n                          onClick={() => removeFile(file.name)}\n                          size=\"icon-sm\"\n                          variant=\"ghost\"\n                        >\n                          <Trash2 className=\"h-4 w-4\" />\n                        </Button>\n                      </div>\n\n                      <div className=\"flex items-center gap-2\">\n                        <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-muted\">\n                          <div\n                            className=\"h-full bg-primary\"\n                            style={{\n                              width: `${fileProgresses[file.name] || 0}%`,\n                            }}\n                          />\n                        </div>\n                        <span className=\"whitespace-nowrap text-muted-foreground text-xs\">\n                          {Math.round(fileProgresses[file.name] || 0)}%\n                        </span>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              );\n            })}\n          </div>\n\n          <div className=\"flex items-center justify-between rounded-b-lg border-border border-t bg-muted px-6 py-3\">\n            <TooltipProvider delay={0}>\n              <Tooltip>\n                <TooltipTrigger\n                  render={\n                    <Button\n                      className=\"flex items-center text-muted-foreground hover:text-foreground\"\n                      size=\"sm\"\n                      variant=\"ghost\"\n                    />\n                  }\n                >\n                  <HelpCircle className=\"mr-1 h-4 w-4\" />\n                  Need help?\n                </TooltipTrigger>\n                <TooltipContent className=\"border bg-background py-3 text-foreground\">\n                  <div className=\"space-y-1\">\n                    <p className=\"text-pretty font-medium text-[13px]\">\n                      Need assistance?\n                    </p>\n                    <p className=\"max-w-[200px] text-pretty text-muted-foreground text-xs dark:text-muted-background\">\n                      Upload project images by dragging and dropping files or\n                      using the file browser. Supported formats: JPG, PNG, SVG.\n                      Maximum file size: 4MB.\n                    </p>\n                  </div>\n                </TooltipContent>\n              </Tooltip>\n            </TooltipProvider>\n\n            <div className=\"flex gap-2\">\n              <Button\n                className=\"h-9 px-4 font-medium text-sm\"\n                variant=\"outline\"\n              >\n                Cancel\n              </Button>\n              <Button className=\"h-9 px-4 font-medium text-sm\">Continue</Button>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n  );\n}\n"
    }
  ],
  "categories": [
    "file-upload"
  ]
}