From d322066d6a86908a176f0915a4897eaefe435d0e Mon Sep 17 00:00:00 2001 From: starmorph Date: Tue, 20 May 2025 13:22:46 -0700 Subject: [PATCH] drag and drop visual --- src/components/thread/index.tsx | 13 ++++++++++- src/hooks/use-file-upload.tsx | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/components/thread/index.tsx b/src/components/thread/index.tsx index 013d729..7025866 100644 --- a/src/components/thread/index.tsx +++ b/src/components/thread/index.tsx @@ -133,6 +133,7 @@ export function Thread() { dropRef, removeBlock, resetBlocks, + dragOver, } = useFileUpload(); const [firstTokenReceived, setFirstTokenReceived] = useState(false); const isLargeScreen = useMediaQuery("(min-width: 1024px)"); @@ -442,8 +443,18 @@ export function Thread() {
+ {dragOver && ( +
+ + Drop file here + +
+ )}
(initialBlocks); const dropRef = useRef(null); + const [dragOver, setDragOver] = useState(false); + const dragCounter = useRef(0); const isDuplicate = (file: File, blocks: Base64ContentBlock[]) => { if (file.type === "application/pdf") { @@ -81,14 +83,45 @@ export function useFileUpload({ useEffect(() => { if (!dropRef.current) return; + // Global drag events with counter for robust dragOver state + const handleWindowDragEnter = (e: DragEvent) => { + if (e.dataTransfer?.types?.includes("Files")) { + dragCounter.current++; + setDragOver(true); + } + }; + const handleWindowDragLeave = (e: DragEvent) => { + if (e.dataTransfer?.types?.includes("Files")) { + dragCounter.current--; + if (dragCounter.current <= 0) { + setDragOver(false); + dragCounter.current = 0; + } + } + }; + const handleWindowDrop = (e: DragEvent) => { + dragCounter.current = 0; + setDragOver(false); + }; + const handleWindowDragEnd = (e: DragEvent) => { + dragCounter.current = 0; + setDragOver(false); + }; + window.addEventListener("dragenter", handleWindowDragEnter); + window.addEventListener("dragleave", handleWindowDragLeave); + window.addEventListener("drop", handleWindowDrop); + window.addEventListener("dragend", handleWindowDragEnd); + const handleDragOver = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); + setDragOver(true); }; const handleDrop = async (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); + setDragOver(false); if (!e.dataTransfer) return; @@ -126,11 +159,13 @@ export function useFileUpload({ const handleDragEnter = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); + setDragOver(true); }; const handleDragLeave = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); + setDragOver(false); }; const element = dropRef.current; @@ -144,6 +179,11 @@ export function useFileUpload({ element.removeEventListener("drop", handleDrop); element.removeEventListener("dragenter", handleDragEnter); element.removeEventListener("dragleave", handleDragLeave); + window.removeEventListener("dragenter", handleWindowDragEnter); + window.removeEventListener("dragleave", handleWindowDragLeave); + window.removeEventListener("drop", handleWindowDrop); + window.removeEventListener("dragend", handleWindowDragEnd); + dragCounter.current = 0; }; }, [contentBlocks]); @@ -160,5 +200,6 @@ export function useFileUpload({ dropRef, removeBlock, resetBlocks, + dragOver, }; }