xlibs-components
Version:
Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications
62 lines (61 loc) • 5.49 kB
JavaScript
"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { cn } from '../../lib/utils.js';
import { useRef, useState } from "react";
import { motion } from "framer-motion";
import { IconUpload } from "@tabler/icons-react";
import { useDropzone } from "react-dropzone";
const mainVariant = {
initial: {
x: 0,
y: 0,
},
animate: {
x: 20,
y: -20,
opacity: 0.9,
},
};
const secondaryVariant = {
initial: {
opacity: 0,
},
animate: {
opacity: 1,
},
};
export const FileUpload = ({ onChange, }) => {
const [files, setFiles] = useState([]);
const fileInputRef = useRef(null);
const handleFileChange = (newFiles) => {
setFiles((prevFiles) => [...prevFiles, ...newFiles]);
onChange && onChange(newFiles);
};
const handleClick = () => {
fileInputRef.current?.click();
};
const { getRootProps, isDragActive } = useDropzone({
multiple: false,
noClick: true,
onDrop: handleFileChange,
onDropRejected: (error) => {
console.log(error);
},
});
return (_jsx("div", { className: "w-full", ...getRootProps(), children: _jsxs(motion.div, { onClick: handleClick, whileHover: "animate", className: "p-10 group/file block rounded-lg cursor-pointer w-full relative overflow-hidden", children: [_jsx("input", { ref: fileInputRef, id: "file-upload-handle", type: "file", onChange: (e) => handleFileChange(Array.from(e.target.files || [])), className: "hidden" }), _jsx("div", { className: "absolute inset-0 [mask-image:radial-gradient(ellipse_at_center,white,transparent)]", children: _jsx(GridPattern, {}) }), _jsxs("div", { className: "flex flex-col items-center justify-center", children: [_jsx("p", { className: "relative z-20 font-sans font-bold text-neutral-700 dark:text-neutral-300 text-base", children: "Upload file" }), _jsx("p", { className: "relative z-20 font-sans font-normal text-neutral-400 dark:text-neutral-400 text-base mt-2", children: "Drag or drop your files here or click to upload" }), _jsxs("div", { className: "relative w-full mt-10 max-w-xl mx-auto", children: [files.length > 0 &&
files.map((file, idx) => (_jsxs(motion.div, { layoutId: idx === 0 ? "file-upload" : "file-upload-" + idx, className: cn("relative overflow-hidden z-40 bg-white dark:bg-neutral-900 flex flex-col items-start justify-start md:h-24 p-4 mt-4 w-full mx-auto rounded-md", "shadow-sm"), children: [_jsxs("div", { className: "flex justify-between w-full items-center gap-4", children: [_jsx(motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, layout: true, className: "text-base text-neutral-700 dark:text-neutral-300 truncate max-w-xs", children: file.name }), _jsxs(motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, layout: true, className: "rounded-lg px-2 py-1 w-fit shrink-0 text-sm text-neutral-600 dark:bg-neutral-800 dark:text-white shadow-input", children: [(file.size / (1024 * 1024)).toFixed(2), " MB"] })] }), _jsxs("div", { className: "flex text-sm md:flex-row flex-col items-start md:items-center w-full mt-2 justify-between text-neutral-600 dark:text-neutral-400", children: [_jsx(motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, layout: true, className: "px-1 py-0.5 rounded-md bg-gray-100 dark:bg-neutral-800 ", children: file.type }), _jsxs(motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, layout: true, children: ["modified", " ", new Date(file.lastModified).toLocaleDateString()] })] })] }, "file" + idx))), !files.length && (_jsx(motion.div, { layoutId: "file-upload", variants: mainVariant, transition: {
type: "spring",
stiffness: 300,
damping: 20,
}, className: cn("relative group-hover/file:shadow-2xl z-40 bg-white dark:bg-neutral-900 flex items-center justify-center h-32 mt-4 w-full max-w-[8rem] mx-auto rounded-md", "shadow-[0px_10px_50px_rgba(0,0,0,0.1)]"), children: isDragActive ? (_jsxs(motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "text-neutral-600 flex flex-col items-center", children: ["Drop it", _jsx(IconUpload, { className: "h-4 w-4 text-neutral-600 dark:text-neutral-400" })] })) : (_jsx(IconUpload, { className: "h-4 w-4 text-neutral-600 dark:text-neutral-300" })) })), !files.length && (_jsx(motion.div, { variants: secondaryVariant, className: "absolute opacity-0 border border-dashed border-sky-400 inset-0 z-30 bg-transparent flex items-center justify-center h-32 mt-4 w-full max-w-[8rem] mx-auto rounded-md" }))] })] })] }) }));
};
export function GridPattern() {
const columns = 41;
const rows = 11;
return (_jsx("div", { className: "flex bg-gray-100 dark:bg-neutral-900 shrink-0 flex-wrap justify-center items-center gap-x-px gap-y-px scale-105", children: Array.from({ length: rows }).map((_, row) => Array.from({ length: columns }).map((_, col) => {
const index = row * columns + col;
return (_jsx("div", { className: `w-10 h-10 flex shrink-0 rounded-[2px] ${index % 2 === 0
? "bg-gray-50 dark:bg-neutral-950"
: "bg-gray-50 dark:bg-neutral-950 shadow-[0px_0px_1px_3px_rgba(255,255,255,1)_inset] dark:shadow-[0px_0px_1px_3px_rgba(0,0,0,1)_inset]"}` }, `${col}-${row}`));
})) }));
}