| import { useState, useRef } from 'react'; |
|
|
| const ACCEPTED = '.pdf,.docx,.pptx,.txt,.md'; |
|
|
| const fmtSize = (bytes) => { |
| if (bytes < 1024) return `${bytes} B`; |
| if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; |
| return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; |
| }; |
|
|
| export default function DropZone({ onFile, disabled }) { |
| const [dragging, setDragging] = useState(false); |
| const [chosen, setChosen] = useState(null); |
| const inputRef = useRef(null); |
|
|
| const handleFile = (file) => { |
| if (!file) return; |
| setChosen(file); |
| onFile(file); |
| }; |
|
|
| const onDragOver = (e) => { e.preventDefault(); setDragging(true); }; |
| const onDragLeave = () => setDragging(false); |
| const onDrop = (e) => { |
| e.preventDefault(); |
| setDragging(false); |
| const file = e.dataTransfer.files[0]; |
| if (file) handleFile(file); |
| }; |
| const onChange = (e) => handleFile(e.target.files[0]); |
|
|
| return ( |
| <div> |
| <div |
| className={`drop-zone${dragging ? ' dragging' : ''}`} |
| onDragOver={onDragOver} |
| onDragLeave={onDragLeave} |
| onDrop={onDrop} |
| style={disabled ? { pointerEvents: 'none', opacity: .5 } : {}} |
| > |
| <input |
| ref={inputRef} |
| type="file" |
| accept={ACCEPTED} |
| onChange={onChange} |
| disabled={disabled} |
| id="file-input" |
| /> |
| <div className="drop-icon">馃搫</div> |
| <div className="drop-title"> |
| {dragging ? 'Drop it here!' : 'Click or drag file here'} |
| </div> |
| <div className="drop-sub">PDF 路 DOCX 路 PPTX 路 TXT 路 MD</div> |
| </div> |
| |
| {chosen && ( |
| <div className="file-chosen"> |
| <span className="file-chosen-icon">馃搸</span> |
| <span className="file-chosen-name">{chosen.name}</span> |
| <span className="file-chosen-size">{fmtSize(chosen.size)}</span> |
| </div> |
| )} |
| </div> |
| ); |
| } |
|
|