From cb2a7484ed3c6797a33acc2d4ab21130f8f00008 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Sun, 22 Jun 2025 14:50:22 +0200 Subject: [PATCH] add drag and drop to the timeline --- .../web/src/components/editor/media-panel.tsx | 59 ++++--------------- apps/web/src/components/editor/timeline.tsx | 22 ++++++- apps/web/src/components/ui/drag-overlay.tsx | 25 ++++++++ apps/web/src/hooks/use-drag-drop.ts | 52 ++++++++++++++++ 4 files changed, 110 insertions(+), 48 deletions(-) create mode 100644 apps/web/src/components/ui/drag-overlay.tsx create mode 100644 apps/web/src/hooks/use-drag-drop.ts diff --git a/apps/web/src/components/editor/media-panel.tsx b/apps/web/src/components/editor/media-panel.tsx index 1e5aa46..565a4e7 100644 --- a/apps/web/src/components/editor/media-panel.tsx +++ b/apps/web/src/components/editor/media-panel.tsx @@ -2,14 +2,20 @@ import { Button } from "../ui/button"; import { AspectRatio } from "../ui/aspect-ratio"; +import { DragOverlay } from "../ui/drag-overlay"; import { useMediaStore } from "@/stores/media-store"; -import { Plus, Image, Video, Music, Upload } from "lucide-react"; -import { useState, useRef } from "react"; +import { Plus, Image, Video, Music } from "lucide-react"; +import { useDragDrop } from "@/hooks/use-drag-drop"; export function MediaPanel() { const { mediaItems, addMediaItem } = useMediaStore(); - const [isDragOver, setIsDragOver] = useState(false); - const dragCounterRef = useRef(0); + + const { isDragOver, dragProps } = useDragDrop({ + onDrop: (files) => { + // TODO: Handle file drop functionality + console.log("Files dropped on media panel:", files); + }, + }); const handleAddSampleMedia = () => { // Just for testing - add a sample media item @@ -30,55 +36,14 @@ export function MediaPanel() { } }; - const handleDragEnter = (e: React.DragEvent) => { - e.preventDefault(); - dragCounterRef.current += 1; - if (!isDragOver) { - setIsDragOver(true); - } - }; - - const handleDragOver = (e: React.DragEvent) => { - e.preventDefault(); - }; - - const handleDragLeave = (e: React.DragEvent) => { - e.preventDefault(); - dragCounterRef.current -= 1; - if (dragCounterRef.current === 0) { - setIsDragOver(false); - } - }; - - const handleDrop = (e: React.DragEvent) => { - e.preventDefault(); - setIsDragOver(false); - dragCounterRef.current = 0; - // TODO: Handle file drop functionality - }; - return (
- {/* Drag Overlay */} - {isDragOver && ( -
-
- -

Drop files here

-

- Images, videos, and audio files -

-
-
- )} +
{/* Media Grid */} diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index da44022..dd31276 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -17,13 +17,33 @@ import { TooltipTrigger, TooltipProvider, } from "../ui/tooltip"; +import { DragOverlay } from "../ui/drag-overlay"; import { useTimelineStore, type TimelineTrack } from "@/stores/timeline-store"; +import { useDragDrop } from "@/hooks/use-drag-drop"; export function Timeline() { const { tracks, addTrack } = useTimelineStore(); + const { isDragOver, dragProps } = useDragDrop({ + onDrop: (files) => { + // TODO: Handle file drop functionality for timeline + console.log("Files dropped on timeline:", files); + }, + }); + return ( -
+
+ + {/* Toolbar */}
diff --git a/apps/web/src/components/ui/drag-overlay.tsx b/apps/web/src/components/ui/drag-overlay.tsx new file mode 100644 index 0000000..ba6fe08 --- /dev/null +++ b/apps/web/src/components/ui/drag-overlay.tsx @@ -0,0 +1,25 @@ +import { Upload } from "lucide-react"; + +interface DragOverlayProps { + isVisible: boolean; + title?: string; + description?: string; +} + +export function DragOverlay({ + isVisible, + title = "Drop files here", + description = "Images, videos, and audio files", +}: DragOverlayProps) { + if (!isVisible) return null; + + return ( +
+
+ +

{title}

+

{description}

+
+
+ ); +} diff --git a/apps/web/src/hooks/use-drag-drop.ts b/apps/web/src/hooks/use-drag-drop.ts new file mode 100644 index 0000000..6b0c5a9 --- /dev/null +++ b/apps/web/src/hooks/use-drag-drop.ts @@ -0,0 +1,52 @@ +import { useState, useRef } from "react"; + +interface UseDragDropOptions { + onDrop?: (files: FileList) => void; +} + +export function useDragDrop(options: UseDragDropOptions = {}) { + const [isDragOver, setIsDragOver] = useState(false); + const dragCounterRef = useRef(0); + + const handleDragEnter = (e: React.DragEvent) => { + e.preventDefault(); + dragCounterRef.current += 1; + if (!isDragOver) { + setIsDragOver(true); + } + }; + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + }; + + const handleDragLeave = (e: React.DragEvent) => { + e.preventDefault(); + dragCounterRef.current -= 1; + if (dragCounterRef.current === 0) { + setIsDragOver(false); + } + }; + + const handleDrop = (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + dragCounterRef.current = 0; + + if (options.onDrop && e.dataTransfer.files) { + options.onDrop(e.dataTransfer.files); + } + }; + + const dragProps = { + onDragEnter: handleDragEnter, + onDragOver: handleDragOver, + onDragLeave: handleDragLeave, + onDrop: handleDrop, + }; + + return { + isDragOver, + dragProps, + }; +}