import { useState } from 'react';
// import './FileUpload.css';
import { useDropzone } from 'react-dropzone';
import { useEffect } from 'react';
import { cn } from '@/lib/utils';
import { Trash } from 'lucide-react';
import { AnimatePresence, motion } from 'framer-motion';
const FileUpload = (props) => {
const [files, setFiles] = useState([]);
const { getRootProps, getInputProps, isFocused, isDragAccept, isDragReject } =
useDropzone({
accept: { 'image/*': [] },
onDrop: (acceptedFiles) => {
setFiles((prevFiles) => {
const newFiles = acceptedFiles.filter((file) => {
return !prevFiles.some((prevFile) => prevFile.name === file.name);
});
return [
...prevFiles,
...newFiles.map((file) =>
Object.assign(file, {
preview: URL.createObjectURL(file),
})
),
];
});
},
});
return (
<div className="container group">
{/* button to reset files list */}
<button
type="button"
className="my-4 ml-auto block text-rose-500 border border-red-500 hover:bg-rose-500 hover:text-white transition-colors p-1 rounded"
onClick={() => setFiles([])}
>
Reset
</button>
<div
className={cn(
'flex flex-col items-center p-5 py-32 border-2 border-dashed rounded bg-gray-100 text-gray-500 outline-none transition-colors duration-200 ease-in-out cursor-pointer border-gray-400 hover:border-gray-700 group-hover:text-gray-700',
{
'border-blue-400': isFocused,
},
{
'border-green-400': isDragAccept,
},
{
'border-red-400': isDragReject,
}
)}
{...getRootProps()}
>
<input {...getInputProps()} />
<svg
className="h-12 w-12"
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" />
<path d="M12 12v9" />
<path d="m16 16-4-4-4 4" />
</svg>
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<Previews files={files} setFiles={setFiles} />{' '}
{/* Use the Previews component */}
</div>
);
};
export default FileUpload;
function Previews({ files, setFiles }) {
// animation variants
const dropIn = {
hidden: {
y: '-100vh',
opacity: 0,
},
visible: {
y: '0',
opacity: 1,
transition: {
duration: 0.1,
type: 'spring',
damping: 25,
stiffness: 500,
},
},
exit: {
y: '100vh',
opacity: 0,
},
};
const scaleUp = {
hidden: {
opacity: 0,
scale: 0,
},
visible: {
opacity: 1,
scale: 1,
transition: {
duration: 0.2,
ease: 'easeIn',
},
},
exit: {
opacity: 0,
scale: 0,
transition: {
duration: 0.15,
ease: 'easeOut',
},
},
};
const { getRootProps, getInputProps } = useDropzone({
accept: { 'image/*': [] },
onDrop: (acceptedFiles) => {
const updatedFiles = [
...files,
...acceptedFiles.map((file) =>
Object.assign(file, {
preview: URL.createObjectURL(file),
})
),
];
setFiles(updatedFiles);
},
});
useEffect(() => {
return () => files.forEach((file) => URL.revokeObjectURL(file.preview));
}, [files]);
const thumbs = files.map((file) => (
<motion.div
className={cn(
'inline-flex flex-col items-center justify-center rounded-md border border-gray-300 mb-2 mr-2 px-4 py-8 box-border relative'
)}
key={file.name}
initial="hidden"
animate="visible"
exit="exit"
variants={dropIn}
>
<div className={cn('flex min-w-0 overflow-hidden')}>
<img
src={file.preview}
className={cn('block w-auto h-full')}
onLoad={() => {
URL.revokeObjectURL(file.preview);
}}
/>
</div>
<button
className={cn(
'bg-red-600 text-white hover:text-red-600 hover:bg-white border hover:border-red-600 rounded-bl-md px-1 absolute -top-0 -right-0 aspect-square transition-colors'
)}
onClick={() => {
// Remove the file from the 'files' array
const updatedFiles = files.filter((f) => f !== file);
setFiles(updatedFiles);
}}
>
<Trash className="w-4 aspect-square" />
{/* <svg
className=" w-4 h-4 text-white"
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<rect height="18" rx="2" ry="2" width="18" x="3" y="3" />
<line x1="3" x2="21" y1="9" y2="9" />
<path d="m9 16 3-3 3 3" />
</svg>
<span className="sr-only">Remove File</span> */}
</button>
</motion.div>
));
return (
<aside className={cn('grid grid-cols-6 py-2')}>
<AnimatePresence initial={false} mode="sync">
{thumbs}
</AnimatePresence>
</aside>
);
}| Associated Context | |
|---|---|
| Type | Code Snippet ( .jsx ) |
| Associated Tags | React useDropzone Drag and Drop React useEffect Image Preview Drag/Drop Trash Component AnimatePresence Motion reactjs Use Effect Remove File CSS Styling File Upload Image URL Animation Variants React Hooks Framer Motion Framework: React GitHub: vite-project Object URL React Dropzone React useState FileUpload.jsx |
| Associated Commit Messages | add fileUpload component Update style of FileUpload changed layout of previews to grid modify fileUpload to have remove button, and to not accept same files again add animation to fileUpload component, using framer motion Add a reset button to remove all files from fileUpload |
| 💡 Smart Description | This code creates a button that allows the user to upload files from an image, and displays it in a container. It also includes styles for displaying file names or images The code snippet is a React component that allows users to upload files by dragging and dropping them or selecting them from their device. It displays a container with a message and an icon, and previews the uploaded files with an option to remove them. |
| 🔎 Suggested Searches | React file upload button React useState and useDropzone for FileUpload Framer-motion action eact React dropzone with Image/*' in files list How to create an image URL eact React FileUpload component with drag and drop React useState and useEffect in FileUpload component React useDropzone hook in FileUpload component React Previews component in FileUpload React AnimatePresence and motion in FileUpload component |
| Related Links | https://tailwindcss.com/docs/border-color http://www.w3.org/2000/svg https://www.w3schools.com/jsref/met_document_createelement.asp https://github.com/MrSnor/vite-project/commits https://github.com/MrSnor/vite-project https://tailwindcss.com/docs/transition-property https://www.npmjs.com/package/cn https://www.npmjs.com/package/react-dropzone https://github.com/MrSnor/vite-project/blob/3a98ffdaf59bfac9c484bc14a61e1fab10fd1c4b/src/components/FileUploadAndPrev/FileUpload.jsx https://react-dropzone.js.org/ https://lucide.dev/ |
| Related People | No Related People |
| Sensitive Information | No Sensitive Information Detected |
| Shareable Link | https://mrsnor.pieces.cloud/?p=ca07419713 |