Skip to content

Commit ced87fc

Browse files
AmirMohammad CheraghaliAmirMohammad Cheraghali
authored andcommitted
feat: add drag-and-drop file upload support
1 parent 9f04d9e commit ced87fc

2 files changed

Lines changed: 72 additions & 1 deletion

File tree

src/App.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { ChainInfo, CustomColorRule, StructureInfo, Snapshot, Movie, ColorP
1010
import LibraryModal from './components/LibraryModal';
1111
import { ShareModal } from './components/ShareModal';
1212
import { SequenceTrack } from './components/SequenceTrack';
13+
import { DragDropOverlay } from './components/DragDropOverlay';
1314
import { OFFLINE_LIBRARY } from './data/library';
1415
import { fetchPDBMetadata } from './utils/pdbUtils';
1516
import type { PDBMetadata } from './types';
@@ -512,8 +513,53 @@ function App() {
512513
}
513514
};
514515

516+
// Drag and Drop State
517+
const [isDragging, setIsDragging] = useState(false);
518+
519+
const handleDragOver = (e: React.DragEvent) => {
520+
e.preventDefault();
521+
setIsDragging(true);
522+
};
523+
524+
const handleDragEnter = (e: React.DragEvent) => {
525+
e.preventDefault();
526+
setIsDragging(true);
527+
};
528+
529+
const handleDragLeave = (e: React.DragEvent) => {
530+
e.preventDefault();
531+
if (e.relatedTarget === null) {
532+
setIsDragging(false);
533+
}
534+
};
535+
536+
const handleDrop = (e: React.DragEvent) => {
537+
e.preventDefault();
538+
setIsDragging(false);
539+
540+
const files = e.dataTransfer.files;
541+
if (files && files.length > 0) {
542+
const droppedFile = files[0];
543+
const validExtensions = ['.pdb', '.cif', '.ent'];
544+
const fileExt = droppedFile.name.substring(droppedFile.name.lastIndexOf('.')).toLowerCase();
545+
546+
if (validExtensions.includes(fileExt)) {
547+
handleUpload(droppedFile); // Reuse existing upload handler
548+
} else {
549+
alert("Invalid file type. Please drop a .pdb, .cif, or .ent file.");
550+
}
551+
}
552+
};
553+
515554
return (
516-
<main className={`w-full h-full relative overflow-hidden transition-colors duration-300 ${isLightMode ? 'bg-slate-50 text-slate-900' : 'bg-neutral-950 text-white'}`}>
555+
<main
556+
className={`w-full h-full relative overflow-hidden transition-colors duration-300 ${isLightMode ? 'bg-slate-50 text-slate-900' : 'bg-neutral-950 text-white'}`}
557+
onDragOver={handleDragOver}
558+
onDragEnter={handleDragEnter}
559+
onDragLeave={handleDragLeave}
560+
onDrop={handleDrop}
561+
>
562+
<DragDropOverlay isDragging={isDragging} />
517563

518564
<LibraryModal
519565
isOpen={isLibraryOpen}

src/components/DragDropOverlay.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
import React from 'react';
3+
import { UploadCloud } from 'lucide-react';
4+
5+
interface DragDropOverlayProps {
6+
isDragging: boolean;
7+
}
8+
9+
export const DragDropOverlay: React.FC<DragDropOverlayProps> = ({ isDragging }) => {
10+
if (!isDragging) return null;
11+
12+
return (
13+
<div className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center pointer-events-none transition-opacity duration-300">
14+
<div className="bg-neutral-900/80 border-4 border-dashed border-blue-500 rounded-3xl p-12 flex flex-col items-center gap-6 animate-pulse shadow-2xl">
15+
<div className="p-6 bg-blue-500/20 rounded-full">
16+
<UploadCloud size={64} className="text-blue-400" />
17+
</div>
18+
<div className="text-center">
19+
<h2 className="text-3xl font-bold text-white mb-2">Drop to Load</h2>
20+
<p className="text-neutral-400 text-lg">Release your PDB or CIF file here</p>
21+
</div>
22+
</div>
23+
</div>
24+
);
25+
};

0 commit comments

Comments
 (0)