| import React from 'react'; | |
| import { motion } from 'framer-motion'; | |
| import { Upload, FileText, Clipboard } from 'lucide-react'; | |
| const FileUploader = ({ | |
| getRootProps, | |
| getInputProps, | |
| isDragActive, | |
| onFileSelect, | |
| fileInputRef, | |
| onFileChange | |
| }) => { | |
| const uploadMethods = [ | |
| { | |
| id: 'drag', | |
| icon: <Upload size={24} />, | |
| title: 'Drag & Drop', | |
| description: 'Drag files directly here', | |
| action: 'drag-drop' | |
| }, | |
| { | |
| id: 'browse', | |
| icon: <FileText size={24} />, | |
| title: 'Browse Files', | |
| description: 'Select from computer', | |
| action: 'browse' | |
| } | |
| ]; | |
| const handleMethodClick = (method) => { | |
| if (method.action === 'browse') { | |
| onFileSelect(); | |
| } | |
| }; | |
| return ( | |
| <div className="file-uploader"> | |
| <motion.div | |
| className={`upload-zone glass-panel ${isDragActive ? 'drag-active' : ''}`} | |
| initial={{ opacity: 0, scale: 0.9 }} | |
| animate={{ opacity: 1, scale: 1 }} | |
| transition={{ duration: 0.5 }} | |
| onDragOver={(e) => e.preventDefault()} | |
| onDrop={(e) => { | |
| e.preventDefault(); | |
| const files = e.dataTransfer.files; | |
| if (files.length > 0) { | |
| const file = files[0]; | |
| onFileChange({ target: { files: [file] } }); | |
| } | |
| }} | |
| > | |
| <input {...getInputProps()} /> | |
| <input | |
| ref={fileInputRef} | |
| type="file" | |
| onChange={onFileChange} | |
| accept=".pdf,.png,.jpg,.jpeg,.html,.htm" | |
| style={{ display: 'none' }} | |
| /> | |
| <div className="upload-content"> | |
| <div className="upload-text"> | |
| <h3>{isDragActive ? 'Drop files here' : 'Document Processing'}</h3> | |
| <p>{isDragActive ? 'Release to process your document' : 'Drag & drop files or click to browse'}</p> | |
| </div> | |
| <div className="upload-actions"> | |
| <div className="button-group"> | |
| <motion.button | |
| className="primary-upload-btn" | |
| onClick={onFileSelect} | |
| whileHover={{ scale: 1.05 }} | |
| whileTap={{ scale: 0.95 }} | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.5 }} | |
| > | |
| <Upload size={20} /> | |
| Upload Files | |
| </motion.button> | |
| <div className="button-divider"></div> | |
| <motion.button | |
| className="paste-btn" | |
| onClick={() => { | |
| // Trigger paste functionality | |
| document.execCommand('paste'); | |
| }} | |
| whileHover={{ scale: 1.05 }} | |
| whileTap={{ scale: 0.95 }} | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.5, delay: 0.1 }} | |
| > | |
| <Clipboard size={18} /> | |
| Paste Image | |
| </motion.button> | |
| </div> | |
| </div> | |
| <div className="supported-formats"> | |
| <p>Supported: PDF, HTML, PNG, JPG, JPEG</p> | |
| </div> | |
| </div> | |
| </motion.div> | |
| <style jsx>{` | |
| .file-uploader { | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .upload-zone { | |
| min-height: 300px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| cursor: default; | |
| } | |
| .upload-zone.drag-active { | |
| border-color: var(--accent-primary); | |
| background: rgba(99, 102, 241, 0.05); | |
| transform: scale(1.02); | |
| } | |
| .upload-content { | |
| text-align: center; | |
| width: 100%; | |
| max-width: 400px; | |
| } | |
| .upload-actions { | |
| margin: 32px 0; | |
| } | |
| .button-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .button-divider { | |
| width: 60px; | |
| height: 1px; | |
| background: rgba(255, 255, 255, 0.15); | |
| } | |
| .primary-upload-btn { | |
| background: linear-gradient(135deg, #8b5cf6 0%, #3b82f6 100%); | |
| border: none; | |
| border-radius: 12px; | |
| padding: 18px 40px; | |
| color: white; | |
| font-size: 1.1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 14px; | |
| box-shadow: 0 4px 20px rgba(139, 92, 246, 0.4); | |
| transition: all 0.3s ease; | |
| } | |
| .primary-upload-btn:hover { | |
| box-shadow: 0 6px 25px rgba(139, 92, 246, 0.6); | |
| transform: translateY(-2px); | |
| } | |
| .paste-btn { | |
| background: transparent; | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 12px 20px; | |
| color: rgba(255, 255, 255, 0.6); | |
| font-size: 0.85rem; | |
| font-weight: 400; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| transition: all 0.3s ease; | |
| } | |
| .paste-btn:hover { | |
| background: rgba(255, 255, 255, 0.05); | |
| border-color: rgba(255, 255, 255, 0.15); | |
| color: rgba(255, 255, 255, 0.8); | |
| } | |
| .upload-divider { | |
| margin: 24px 0; | |
| position: relative; | |
| color: rgba(255, 255, 255, 0.5); | |
| font-size: 0.875rem; | |
| } | |
| .upload-divider::before { | |
| content: ''; | |
| position: absolute; | |
| top: 50%; | |
| left: 0; | |
| right: 0; | |
| height: 1px; | |
| background: rgba(255, 255, 255, 0.1); | |
| z-index: 0; | |
| } | |
| .upload-divider span { | |
| background: rgba(0, 0, 0, 0.3); | |
| padding: 0 16px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .secondary-upload-btn { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 12px 20px; | |
| color: rgba(255, 255, 255, 0.7); | |
| font-size: 0.875rem; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin: 0 auto; | |
| transition: all 0.3s ease; | |
| } | |
| .secondary-upload-btn:hover { | |
| background: rgba(255, 255, 255, 0.08); | |
| color: rgba(255, 255, 255, 0.9); | |
| border-color: rgba(255, 255, 255, 0.2); | |
| } | |
| .secondary-upload-btn.disabled { | |
| opacity: 0.4; | |
| cursor: not-allowed; | |
| pointer-events: none; | |
| } | |
| .supported-formats { | |
| margin-top: 24px; | |
| } | |
| .supported-formats p { | |
| color: rgba(255, 255, 255, 0.4); | |
| font-size: 0.75rem; | |
| margin: 0; | |
| } | |
| .upload-icon { | |
| margin-bottom: 16px; | |
| color: var(--accent-primary); | |
| } | |
| .drag-indicator { | |
| font-size: 3rem; | |
| filter: drop-shadow(0 0 20px rgba(99, 102, 241, 0.5)); | |
| } | |
| .upload-svg { | |
| filter: drop-shadow(0 0 10px rgba(99, 102, 241, 0.3)); | |
| } | |
| .upload-text h3 { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| color: var(--text-primary); | |
| } | |
| .upload-text p { | |
| color: var(--text-secondary); | |
| font-size: 0.875rem; | |
| max-width: 400px; | |
| margin: 0 auto; | |
| } | |
| .upload-methods { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 16px; | |
| width: 100%; | |
| max-width: 800px; | |
| } | |
| .upload-method { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .method-icon { | |
| color: var(--accent-secondary); | |
| flex-shrink: 0; | |
| } | |
| .method-content h4 { | |
| font-size: 0.875rem; | |
| font-weight: 600; | |
| margin-bottom: 4px; | |
| color: var(--text-primary); | |
| } | |
| .method-content p { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| } | |
| @media (max-width: 768px) { | |
| .upload-methods { | |
| grid-template-columns: 1fr; | |
| } | |
| .upload-method { | |
| justify-content: center; | |
| text-align: center; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| } | |
| `}</style> | |
| </div> | |
| ); | |
| }; | |
| export default FileUploader; |