Spaces:
Running
Running
| import { useRef, useState } from 'react' | |
| interface FileDropZoneProps { | |
| onFile: (text: string, filename: string) => void | |
| accept?: string | |
| } | |
| export default function FileDropZone({ | |
| onFile, | |
| accept = '.fasta,.fa,.faa,.txt,.csv', | |
| }: FileDropZoneProps) { | |
| const [dragging, setDragging] = useState(false) | |
| const inputRef = useRef<HTMLInputElement>(null) | |
| function readFile(file: File) { | |
| const reader = new FileReader() | |
| reader.onload = () => onFile(String(reader.result ?? ''), file.name) | |
| reader.readAsText(file) | |
| } | |
| return ( | |
| <div | |
| className={'dropzone' + (dragging ? ' dragging' : '')} | |
| onClick={() => inputRef.current?.click()} | |
| onDragOver={(e) => { | |
| e.preventDefault() | |
| setDragging(true) | |
| }} | |
| onDragLeave={() => setDragging(false)} | |
| onDrop={(e) => { | |
| e.preventDefault() | |
| setDragging(false) | |
| const file = e.dataTransfer.files?.[0] | |
| if (file) readFile(file) | |
| }} | |
| > | |
| <div className="dropzone-icon" aria-hidden> | |
| <svg | |
| width="22" | |
| height="22" | |
| viewBox="0 0 24 24" | |
| fill="none" | |
| stroke="currentColor" | |
| strokeWidth="1.8" | |
| strokeLinecap="round" | |
| strokeLinejoin="round" | |
| > | |
| <path d="M12 15V4M8 8l4-4 4 4M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" /> | |
| </svg> | |
| </div> | |
| <div className="dropzone-main"> | |
| Drag & drop a file, or click to browse | |
| </div> | |
| <div className="dropzone-sub">FASTA (.fasta / .fa) or plain text (.txt)</div> | |
| <input | |
| ref={inputRef} | |
| type="file" | |
| accept={accept} | |
| style={{ display: 'none' }} | |
| onChange={(e) => { | |
| const file = e.target.files?.[0] | |
| if (file) readFile(file) | |
| e.target.value = '' | |
| }} | |
| /> | |
| </div> | |
| ) | |
| } | |