drag and drop visual

This commit is contained in:
starmorph
2025-05-20 13:22:46 -07:00
parent 06e0de6f85
commit d322066d6a
2 changed files with 53 additions and 1 deletions

View File

@@ -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() {
<div
ref={dropRef}
className="bg-muted relative z-10 mx-auto mb-8 w-full max-w-3xl rounded-2xl border shadow-xs"
className={cn(
"bg-muted relative z-10 mx-auto mb-8 w-full max-w-3xl rounded-2xl border shadow-xs transition-all",
dragOver ? "border-primary border-2 border-dotted" : "",
)}
>
{dragOver && (
<div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center rounded-2xl bg-black/40">
<span className="text-lg font-semibold text-white">
Drop file here
</span>
</div>
)}
<form
onSubmit={handleSubmit}
className="mx-auto grid max-w-3xl grid-rows-[1fr_auto] gap-2"

View File

@@ -21,6 +21,8 @@ export function useFileUpload({
const [contentBlocks, setContentBlocks] =
useState<Base64ContentBlock[]>(initialBlocks);
const dropRef = useRef<HTMLDivElement>(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,
};
}