{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-upload-2",
  "dependencies": [
    "lucide-react",
    "react-icons"
  ],
  "registryDependencies": [
    "badge",
    "button",
    "card",
    "utils"
  ],
  "files": [
    {
      "path": "src/components/watermelon-ui/file-upload-2.tsx",
      "content": "import React, { useRef, useState, useCallback } from \"react\";\nimport {\n  FaCloudUploadAlt,\n  FaFileAlt,\n  FaFileImage,\n  FaFilePdf,\n  FaTrashAlt,\n  FaCheckCircle,\n  FaExclamationCircle,\n  FaFileVideo,\n  FaFileArchive,\n} from \"react-icons/fa\";\nimport { Card, CardContent, CardHeader } from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\n\nexport type FileStatus = \"idle\" | \"uploading\" | \"success\" | \"error\";\n\nexport interface FileItem {\n  id: string;\n  file: File;\n  progress: number;\n  status: FileStatus;\n  errorMessage?: string;\n}\n\nexport interface FileUploadProps extends Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  \"onDrop\"\n> {\n  onFilesAdded?: (files: File[]) => void;\n  onFileRemove?: (id: string) => void;\n  maxFiles?: number;\n  maxSizeMB?: number;\n  accept?: string;\n  files?: FileItem[];\n}\n\nexport function FileUpload({\n  onFilesAdded,\n  onFileRemove,\n  maxFiles = 5,\n  maxSizeMB = 10,\n  accept,\n  files = [],\n  className,\n  ...props\n}: FileUploadProps) {\n  const [isDragging, setIsDragging] = useState(false);\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  const handleDragOver = useCallback((e: React.DragEvent<HTMLDivElement>) => {\n    e.preventDefault();\n    e.stopPropagation();\n    setIsDragging(true);\n  }, []);\n\n  const handleDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {\n    e.preventDefault();\n    e.stopPropagation();\n    setIsDragging(false);\n  }, []);\n\n  const handleDrop = useCallback(\n    (e: React.DragEvent<HTMLDivElement>) => {\n      e.preventDefault();\n      e.stopPropagation();\n      setIsDragging(false);\n\n      if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n        const droppedFiles = Array.from(e.dataTransfer.files);\n        if (onFilesAdded) {\n          onFilesAdded(droppedFiles);\n        }\n      }\n    },\n    [onFilesAdded],\n  );\n\n  const handleFileSelect = useCallback(\n    (e: React.ChangeEvent<HTMLInputElement>) => {\n      if (e.target.files && e.target.files.length > 0) {\n        const selectedFiles = Array.from(e.target.files);\n        if (onFilesAdded) {\n          onFilesAdded(selectedFiles);\n        }\n      }\n      if (fileInputRef.current) {\n        fileInputRef.current.value = \"\";\n      }\n    },\n    [onFilesAdded],\n  );\n\n  const formatFileSize = (bytes: number) => {\n    if (bytes === 0) return \"0 Bytes\";\n    const k = 1024;\n    const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n  };\n\n  const getFileIcon = (fileType: string) => {\n    if (fileType.includes(\"image/\"))\n      return <FaFileImage className=\"text-primary h-5 w-5\" />;\n    if (fileType.includes(\"pdf\"))\n      return <FaFilePdf className=\"text-destructive h-5 w-5\" />;\n    if (fileType.includes(\"video/\"))\n      return <FaFileVideo className=\"text-secondary-foreground h-5 w-5\" />;\n    if (fileType.includes(\"zip\") || fileType.includes(\"archive\"))\n      return <FaFileArchive className=\"text-muted-foreground h-5 w-5\" />;\n    return <FaFileAlt className=\"text-foreground h-5 w-5\" />;\n  };\n\n  return (\n    <div\n      className={cn(\"mx-auto w-full max-w-sm space-y-6\", className)}\n      {...props}\n    >\n      <Card\n        className={cn(\n          \"group bg-background border-muted/40 relative h-auto w-full max-w-sm cursor-pointer overflow-hidden rounded-[36px] px-2 py-2 transition-all duration-200 ease-in-out\",\n        )}\n        onDragOver={handleDragOver}\n        onDragLeave={handleDragLeave}\n        onDrop={handleDrop}\n        onClick={() => fileInputRef.current?.click()}\n      >\n        <CardHeader className=\"relative z-10\">\n          <div className=\"space-y-2 text-center\">\n            <h2 className=\"text-foreground text-2xl font-semibold tracking-tight\">\n              Upload Documents\n            </h2>\n            <p className=\"text-muted-foreground text-sm\">\n              Securely upload your files, assets and documentation.\n            </p>\n          </div>\n        </CardHeader>\n        <CardContent\n          className={cn(\n            \"bg-muted/60 relative z-10 flex min-h-[300px] flex-col items-center justify-center rounded-4xl border-2 border-dashed text-center backdrop-blur-[2px] transition-colors duration-200\",\n            isDragging\n              ? \"scale-[1.01]\"\n              : \"border-muted-foreground/20 hover:bg-muted/80\",\n          )}\n        >\n          <div className=\"bg-[repeating-linear-gradient(-45deg,theme(colors.muted.foreground/0.05)_0px,theme(colors.muted.foreground/0.05)_1px,transparent_1px,transparent_10px)] pointer-events-none absolute inset-0\" />\n          <input\n            type=\"file\"\n            ref={fileInputRef}\n            className=\"hidden\"\n            multiple={maxFiles > 1}\n            accept={accept}\n            onChange={handleFileSelect}\n          />\n          <div className=\"bg-primary/10 text-primary group-hover:bg-primary/20 mt-6 mb-6 flex h-16 w-16 items-center justify-center rounded-full transition-colors\">\n            <FaCloudUploadAlt className=\"h-8 w-8\" />\n          </div>\n          <h3 className=\"text-foreground mb-2 text-xl font-semibold\">\n            Click to upload{\" \"}\n            <span className=\"text-muted-foreground font-normal\">\n              or drag and drop\n            </span>\n          </h3>\n          <p className=\"text-muted-foreground mb-6 text-sm\">\n            SVG, PNG, JPG, GIF or PDF (max. {maxSizeMB}MB)\n          </p>\n          <Button\n            type=\"button\"\n            variant=\"secondary\"\n            className=\"pointer-events-none mb-6\"\n          >\n            Browse Files\n          </Button>\n        </CardContent>\n\n        {files.length > 0 && (\n          <div className=\"px-2\">\n            <div className=\"flex items-center justify-between\">\n              <h4 className=\"text-foreground text-sm font-medium\">\n                Uploaded Files\n              </h4>\n              <span className=\"text-muted-foreground text-xs font-medium\">\n                {files.length} / {maxFiles}\n              </span>\n            </div>\n            <div className=\"grid gap-3\">\n              {files.map((fileItem) => (\n                <div\n                  key={fileItem.id}\n                  className=\"group text-card-foreground relative flex items-center gap-4 overflow-hidden rounded-none py-2\"\n                >\n                  {fileItem.status === \"uploading\" && (\n                    <div className=\"bg-muted absolute bottom-0 left-0 h-1 w-full\">\n                      <div\n                        className=\"bg-primary h-full transition-all duration-300 ease-in-out\"\n                        style={{ width: `${fileItem.progress}%` }}\n                      />\n                    </div>\n                  )}\n\n                  <div className=\"bg-muted flex-shrink-0 rounded-lg p-3\">\n                    {getFileIcon(fileItem.file.type)}\n                  </div>\n\n                  <div className=\"min-w-0 flex-1\">\n                    <div className=\"mb-1 flex items-center justify-between\">\n                      <p className=\"text-foreground truncate pr-4 text-sm font-medium\">\n                        {fileItem.file.name}\n                      </p>\n                      <div className=\"flex flex-shrink-0 items-center gap-2\">\n                        {fileItem.status === \"success\" && (\n                          <Badge\n                            variant=\"secondary\"\n                            className=\"bg-primary/10 text-primary hover:bg-primary/20 gap-1 border-transparent\"\n                          >\n                            <FaCheckCircle className=\"h-3 w-3\" /> Done\n                          </Badge>\n                        )}\n                        {fileItem.status === \"error\" && (\n                          <Badge variant=\"destructive\" className=\"gap-1\">\n                            <FaExclamationCircle className=\"h-3 w-3\" /> Failed\n                          </Badge>\n                        )}\n                        {fileItem.status === \"uploading\" && (\n                          <span className=\"text-muted-foreground text-xs font-medium\">\n                            {Math.round(fileItem.progress)}%\n                          </span>\n                        )}\n                        <Button\n                          type=\"button\"\n                          variant=\"ghost\"\n                          size=\"icon\"\n                          onClick={(e) => {\n                            e.stopPropagation();\n                            if (onFileRemove) onFileRemove(fileItem.id);\n                          }}\n                          className=\"text-muted-foreground hover:bg-destructive/10 hover:text-destructive h-8 w-8\"\n                        >\n                          <FaTrashAlt className=\"h-3.5 w-3.5\" />\n                          <span className=\"sr-only\">Remove file</span>\n                        </Button>\n                      </div>\n                    </div>\n\n                    <div className=\"text-muted-foreground flex items-center gap-2 text-xs\">\n                      <span>{formatFileSize(fileItem.file.size)}</span>\n                      {fileItem.errorMessage && (\n                        <>\n                          <span>•</span>\n                          <span className=\"text-destructive truncate\">\n                            {fileItem.errorMessage}\n                          </span>\n                        </>\n                      )}\n                    </div>\n                  </div>\n                </div>\n              ))}\n            </div>\n          </div>\n        )}\n      </Card>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/ui/file-upload-2.tsx"
    }
  ],
  "type": "registry:ui"
}
