From 03b3c952c75b7642b537fa2499d081edd1a0a1e4 Mon Sep 17 00:00:00 2001 From: ahmedfahim21 Date: Sun, 13 Jul 2025 00:59:54 +0530 Subject: feat: click to add to timeline --- .../components/editor/media-panel/views/media.tsx | 2 ++ .../components/editor/media-panel/views/text.tsx | 35 +++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) (limited to 'apps/web/src/components/editor/media-panel') diff --git a/apps/web/src/components/editor/media-panel/views/media.tsx b/apps/web/src/components/editor/media-panel/views/media.tsx index 48e54961..36478667 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -24,6 +24,7 @@ import { } from "@/components/ui/select"; import { DraggableMediaItem } from "@/components/ui/draggable-item"; import { useProjectStore } from "@/stores/project-store"; +import { addMediaToTimeline } from "@/lib/timeline-utils"; export function MediaView() { const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore(); @@ -288,6 +289,7 @@ export function MediaView() { name: item.name, }} showPlusOnDrag={false} + onAddToTimeline={(currentTime) => addMediaToTimeline(item, currentTime)} rounded={false} /> diff --git a/apps/web/src/components/editor/media-panel/views/text.tsx b/apps/web/src/components/editor/media-panel/views/text.tsx index bec32c85..fad79343 100644 --- a/apps/web/src/components/editor/media-panel/views/text.tsx +++ b/apps/web/src/components/editor/media-panel/views/text.tsx @@ -1,4 +1,30 @@ import { DraggableMediaItem } from "@/components/ui/draggable-item"; +import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; +import { addTextToTimeline } from "@/lib/timeline-utils"; +import { type TextElement } from "@/types/timeline"; + +let textData: TextElement = { + id: "default-text", + type: "text", + name: "Default text", + content: "Default text", + fontSize: 48, + fontFamily: "Arial", + color: "#ffffff", + backgroundColor: "transparent", + textAlign: "center" as const, + fontWeight: "normal" as const, + fontStyle: "normal" as const, + textDecoration: "none" as const, + x: 0, + y: 0, + rotation: 0, + opacity: 1, + duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, + startTime: 0, + trimStart: 0, + trimEnd: 0, +}; export function TextView() { return ( @@ -11,12 +37,13 @@ export function TextView() { } dragData={{ - id: "default-text", - type: "text", - name: "Default text", - content: "Default text", + id: textData.id, + type: textData.type, + name: textData.name, + content: textData.content, }} aspectRatio={1} + onAddToTimeline={(currentTime) => addTextToTimeline(textData, currentTime)} showLabel={false} /> -- cgit v1.3.1 From dc0e4783fbacad5c7eb3cf0d1141b0166960f809 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Tue, 15 Jul 2025 16:55:04 +0200 Subject: cleanup --- .../components/editor/media-panel/views/media.tsx | 8 +- .../components/editor/media-panel/views/text.tsx | 6 +- apps/web/src/components/editor/timeline.tsx | 19 +-- apps/web/src/lib/timeline-utils.ts | 117 --------------- apps/web/src/stores/timeline-store.ts | 164 ++++++++++++++++++++- 5 files changed, 183 insertions(+), 131 deletions(-) delete mode 100644 apps/web/src/lib/timeline-utils.ts (limited to 'apps/web/src/components/editor/media-panel') diff --git a/apps/web/src/components/editor/media-panel/views/media.tsx b/apps/web/src/components/editor/media-panel/views/media.tsx index 17893156..393d72db 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -24,7 +24,7 @@ import { } from "@/components/ui/select"; import { DraggableMediaItem } from "@/components/ui/draggable-item"; import { useProjectStore } from "@/stores/project-store"; -import { addMediaToTimeline } from "@/lib/timeline-utils"; +import { useTimelineStore } from "@/stores/timeline-store"; export function MediaView() { const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore(); @@ -289,7 +289,11 @@ export function MediaView() { name: item.name, }} showPlusOnDrag={false} - onAddToTimeline={(currentTime) => addMediaToTimeline(item, currentTime)} + onAddToTimeline={(currentTime) => + useTimelineStore + .getState() + .addMediaAtTime(item, currentTime) + } rounded={false} /> diff --git a/apps/web/src/components/editor/media-panel/views/text.tsx b/apps/web/src/components/editor/media-panel/views/text.tsx index fad79343..6d0d310b 100644 --- a/apps/web/src/components/editor/media-panel/views/text.tsx +++ b/apps/web/src/components/editor/media-panel/views/text.tsx @@ -1,6 +1,6 @@ import { DraggableMediaItem } from "@/components/ui/draggable-item"; import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; -import { addTextToTimeline } from "@/lib/timeline-utils"; +import { useTimelineStore } from "@/stores/timeline-store"; import { type TextElement } from "@/types/timeline"; let textData: TextElement = { @@ -43,7 +43,9 @@ export function TextView() { content: textData.content, }} aspectRatio={1} - onAddToTimeline={(currentTime) => addTextToTimeline(textData, currentTime)} + onAddToTimeline={(currentTime) => + useTimelineStore.getState().addTextAtTime(textData, currentTime) + } showLabel={false} /> diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index ff9e0694..c1603542 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -48,7 +48,6 @@ import { useSelectionBox } from "@/hooks/use-selection-box"; import { SnapIndicator } from "./snap-indicator"; import { SnapPoint } from "@/hooks/use-timeline-snapping"; import type { DragData, TimelineTrack } from "@/types/timeline"; -import { addTextToNewTrack, addMediaToNewTrack } from "@/lib/timeline-utils"; import { getTrackHeight, getCumulativeHeightBefore, @@ -229,7 +228,7 @@ export function Timeline() { Math.min( duration, (mouseX + scrollLeft) / - (TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel) + (TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel) ) ); @@ -377,7 +376,7 @@ export function Timeline() { if (dragData.type === "text") { // Always create new text track to avoid overlaps - addTextToNewTrack(dragData); + useTimelineStore.getState().addTextToNewTrack(dragData); } else { // Handle media items const mediaItem = mediaItems.find((item) => item.id === dragData.id); @@ -386,7 +385,7 @@ export function Timeline() { return; } - addMediaToNewTrack(mediaItem); + useTimelineStore.getState().addMediaToNewTrack(mediaItem); } } catch (error) { console.error("Error parsing dropped item data:", error); @@ -414,7 +413,7 @@ export function Timeline() { item.name === processedItem.name && item.url === processedItem.url ); if (addedItem) { - addMediaToNewTrack(addedItem); + useTimelineStore.getState().addMediaToNewTrack(addedItem); } } } catch (error) { @@ -902,19 +901,21 @@ export function Timeline() { return (
{(() => { const formatTime = (seconds: number) => { diff --git a/apps/web/src/lib/timeline-utils.ts b/apps/web/src/lib/timeline-utils.ts deleted file mode 100644 index 994cb314..00000000 --- a/apps/web/src/lib/timeline-utils.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { useTimelineStore } from "@/stores/timeline-store"; -import { type MediaItem } from "@/stores/media-store"; -import { toast } from "sonner"; -import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; -import { DragData, TextElement } from "@/types/timeline"; - - -const findOrCreateTrack = (trackType: "media" | "audio" | "text") => { - const timelineStore = useTimelineStore.getState(); - - // Always create new text track to allow multiple text elements - if (trackType === "text") { - return timelineStore.addTrack(trackType); - } - - const existingTrack = timelineStore.tracks.find(track => track.type === trackType); - return existingTrack ? existingTrack.id : timelineStore.addTrack(trackType); -}; - - -const checkOverlap = (trackId: string, startTime: number, duration: number, excludeElementId?: string) => { - const timelineStore = useTimelineStore.getState(); - const targetTrack = timelineStore.tracks.find(track => track.id === trackId); - - if (!targetTrack) { - return true; - } - - const elementEnd = startTime + duration; - - return targetTrack.elements.some((existingElement) => { - if (excludeElementId && existingElement.id === excludeElementId) { - return false; - } - - const existingStart = existingElement.startTime; - const existingEnd = existingElement.startTime + - (existingElement.duration - existingElement.trimStart - existingElement.trimEnd); - - return startTime < existingEnd && elementEnd > existingStart; - }); -}; - -const addMediaElement = (trackId: string, item: MediaItem, startTime: number) => { - const timelineStore = useTimelineStore.getState(); - - timelineStore.addElementToTrack(trackId, { - type: "media", - mediaId: item.id, - name: item.name, - duration: item.duration || TIMELINE_CONSTANTS.DEFAULT_IMAGE_DURATION, - startTime, - trimStart: 0, - trimEnd: 0, - }); -}; - -const addTextElement = (trackId: string, item: TextElement | DragData, startTime: number) => { - const timelineStore = useTimelineStore.getState(); - - timelineStore.addElementToTrack(trackId, { - type: "text", - name: item.name, - content: ("content" in item ? item.content : "Default Text"), - duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, - startTime, - trimStart: ("trimStart" in item ? item.trimStart : 0), - trimEnd: ("trimEnd" in item ? item.trimEnd : 0), - fontSize: ("fontSize" in item ? item.fontSize : 48), - fontFamily: ("fontFamily" in item ? item.fontFamily : "Arial"), - color: ("color" in item ? item.color : "#ffffff"), - backgroundColor: ("backgroundColor" in item ? item.backgroundColor : "transparent"), - textAlign: ("textAlign" in item ? item.textAlign : "center"), - fontWeight: ("fontWeight" in item ? item.fontWeight : "normal"), - fontStyle: ("fontStyle" in item ? item.fontStyle : "normal"), - textDecoration: ("textDecoration" in item ? item.textDecoration : "none"), - x: ("x" in item ? item.x : 0), - y: ("y" in item ? item.y : 0), - rotation: ("rotation" in item ? item.rotation : 0), - opacity: ("opacity" in item && item.opacity !== undefined ? item.opacity : 1), - }); -}; - - -// Adds a media item to the timeline at the specified time -export const addMediaToTimeline = (item: MediaItem, currentTime: number = 0) => { - const trackType = item.type === "audio" ? "audio" : "media"; - const targetTrackId = findOrCreateTrack(trackType); - - const duration = item.duration || TIMELINE_CONSTANTS.DEFAULT_IMAGE_DURATION; - - if (checkOverlap(targetTrackId, currentTime, duration)) { - toast.error("Cannot place element here - it would overlap with existing elements"); - return; - } - - addMediaElement(targetTrackId, item, currentTime); -}; - -// Adds a text item to the timeline at the specified time -export const addTextToTimeline = (item: TextElement, currentTime: number = 0) => { - const targetTrackId = findOrCreateTrack("text"); - addTextElement(targetTrackId, item, currentTime); -}; - -// Adds a media item to timeline -export const addMediaToNewTrack = (item: MediaItem) => { - const trackType = item.type === "audio" ? "audio" : "media"; - const targetTrackId = findOrCreateTrack(trackType); - addMediaElement(targetTrackId, item, 0); -}; - -// Adds a text item to timeline -export const addTextToNewTrack = (item: TextElement | DragData) => { - const targetTrackId = findOrCreateTrack("text"); - addTextElement(targetTrackId, item, 0); -}; diff --git a/apps/web/src/stores/timeline-store.ts b/apps/web/src/stores/timeline-store.ts index f6b9bfd8..9a2c7361 100644 --- a/apps/web/src/stores/timeline-store.ts +++ b/apps/web/src/stores/timeline-store.ts @@ -5,15 +5,22 @@ import { CreateTimelineElement, TimelineTrack, TextElement, + DragData, sortTracksByOrder, ensureMainTrack, validateElementTrackCompatibility, } from "@/types/timeline"; import { useEditorStore } from "./editor-store"; -import { useMediaStore, getMediaAspectRatio } from "./media-store"; +import { + useMediaStore, + getMediaAspectRatio, + type MediaItem, +} from "./media-store"; import { storageService } from "@/lib/storage/storage-service"; import { useProjectStore } from "./project-store"; import { generateUUID } from "@/lib/utils"; +import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; +import { toast } from "sonner"; // Helper function to manage element naming with suffixes const getElementNameWithSuffix = ( @@ -166,6 +173,17 @@ interface TimelineStore { > > ) => void; + checkElementOverlap: ( + trackId: string, + startTime: number, + duration: number, + excludeElementId?: string + ) => boolean; + findOrCreateTrack: (trackType: TrackType) => string; + addMediaAtTime: (item: MediaItem, currentTime?: number) => boolean; + addTextAtTime: (item: TextElement, currentTime?: number) => boolean; + addMediaToNewTrack: (item: MediaItem) => boolean; + addTextToNewTrack: (item: TextElement | DragData) => boolean; } export const useTimelineStore = create((set, get) => { @@ -963,5 +981,149 @@ export const useTimelineStore = create((set, get) => { toggleSnapping: () => { set((state) => ({ snappingEnabled: !state.snappingEnabled })); }, + + checkElementOverlap: (trackId, startTime, duration, excludeElementId) => { + const track = get()._tracks.find((t) => t.id === trackId); + if (!track) return false; + + const overlap = track.elements.some((element) => { + const elementEnd = + element.startTime + + element.duration - + element.trimStart - + element.trimEnd; + + if (element.id === excludeElementId) { + return false; + } + + return ( + (startTime >= element.startTime && startTime < elementEnd) || + (startTime + duration > element.startTime && + startTime + duration <= elementEnd) || + (startTime < element.startTime && startTime + duration > elementEnd) + ); + }); + return overlap; + }, + + findOrCreateTrack: (trackType) => { + // Always create new text track to allow multiple text elements + if (trackType === "text") { + return get().addTrack(trackType); + } + + const existingTrack = get()._tracks.find((t) => t.type === trackType); + if (existingTrack) { + return existingTrack.id; + } + + return get().addTrack(trackType); + }, + + addMediaAtTime: (item, currentTime = 0) => { + const trackType = item.type === "audio" ? "audio" : "media"; + const targetTrackId = get().findOrCreateTrack(trackType); + + const duration = + item.duration || TIMELINE_CONSTANTS.DEFAULT_IMAGE_DURATION; + + if (get().checkElementOverlap(targetTrackId, currentTime, duration)) { + toast.error( + "Cannot place element here - it would overlap with existing elements" + ); + return false; + } + + get().addElementToTrack(targetTrackId, { + type: "media", + mediaId: item.id, + name: item.name, + duration, + startTime: currentTime, + trimStart: 0, + trimEnd: 0, + }); + return true; + }, + + addTextAtTime: (item, currentTime = 0) => { + const targetTrackId = get().addTrack("text"); // Always create new text track to allow multiple text elements + + get().addElementToTrack(targetTrackId, { + type: "text", + name: item.name || "Text", + content: item.content || "Default Text", + duration: item.duration || TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, + startTime: currentTime, + trimStart: 0, + trimEnd: 0, + fontSize: item.fontSize || 48, + fontFamily: item.fontFamily || "Arial", + color: item.color || "#ffffff", + backgroundColor: item.backgroundColor || "transparent", + textAlign: item.textAlign || "center", + fontWeight: item.fontWeight || "normal", + fontStyle: item.fontStyle || "normal", + textDecoration: item.textDecoration || "none", + x: item.x || 0, + y: item.y || 0, + rotation: item.rotation || 0, + opacity: item.opacity !== undefined ? item.opacity : 1, + }); + return true; + }, + + addMediaToNewTrack: (item) => { + const trackType = item.type === "audio" ? "audio" : "media"; + const targetTrackId = get().findOrCreateTrack(trackType); + + get().addElementToTrack(targetTrackId, { + type: "media", + mediaId: item.id, + name: item.name, + duration: item.duration || TIMELINE_CONSTANTS.DEFAULT_IMAGE_DURATION, + startTime: 0, + trimStart: 0, + trimEnd: 0, + }); + return true; + }, + + addTextToNewTrack: (item) => { + const targetTrackId = get().addTrack("text"); // Always create new text track to allow multiple text elements + + get().addElementToTrack(targetTrackId, { + type: "text", + name: item.name || "Text", + content: + ("content" in item ? item.content : "Default Text") || "Default Text", + duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, + startTime: 0, + trimStart: 0, + trimEnd: 0, + fontSize: ("fontSize" in item ? item.fontSize : 48) || 48, + fontFamily: + ("fontFamily" in item ? item.fontFamily : "Arial") || "Arial", + color: ("color" in item ? item.color : "#ffffff") || "#ffffff", + backgroundColor: + ("backgroundColor" in item ? item.backgroundColor : "transparent") || + "transparent", + textAlign: + ("textAlign" in item ? item.textAlign : "center") || "center", + fontWeight: + ("fontWeight" in item ? item.fontWeight : "normal") || "normal", + fontStyle: + ("fontStyle" in item ? item.fontStyle : "normal") || "normal", + textDecoration: + ("textDecoration" in item ? item.textDecoration : "none") || "none", + x: ("x" in item ? item.x : 0) || 0, + y: ("y" in item ? item.y : 0) || 0, + rotation: ("rotation" in item ? item.rotation : 0) || 0, + opacity: + "opacity" in item && item.opacity !== undefined ? item.opacity : 1, + }); + return true; + }, }; }); -- cgit v1.3.1 From f76169ada15cff51dbf9ce3af148a78c46ed36c6 Mon Sep 17 00:00:00 2001 From: Simon Orzel Date: Wed, 16 Jul 2025 00:48:00 +0200 Subject: feat: refactors media drag overlay and media tab --- .../components/editor/media-panel/views/media.tsx | 77 ++++++++++----------- apps/web/src/components/ui/drag-overlay.tsx | 78 ++++++++++++++++++++-- 2 files changed, 108 insertions(+), 47 deletions(-) (limited to 'apps/web/src/components/editor/media-panel') diff --git a/apps/web/src/components/editor/media-panel/views/media.tsx b/apps/web/src/components/editor/media-panel/views/media.tsx index 5438737f..f8cbb639 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -3,7 +3,7 @@ import { useDragDrop } from "@/hooks/use-drag-drop"; import { processMediaFiles } from "@/lib/media-processing"; import { useMediaStore, type MediaItem } from "@/stores/media-store"; -import { Image, Music, Plus, Upload, Video } from "lucide-react"; +import { Image, Loader2, Music, Plus, Upload, Video } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -203,9 +203,6 @@ export function MediaView() { className={`h-full flex flex-col gap-1 transition-colors relative ${isDragOver ? "bg-accent/30" : ""}`} {...dragProps} > - {/* Show overlay when dragging files over the panel */} - -
{/* Search and filter controls */}
@@ -227,47 +224,45 @@ export function MediaView() { value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} /> +
- {/* Show message if no media, otherwise show media grid */} - {filteredMediaItems.length === 0 ? ( -
-
- -
-

- No media in project -

-

- Drag files here or use the button below -

- -
+ {(isDragOver || filteredMediaItems.length === 0) ? ( + ) : (
void; + isEmptyState?: boolean; } export function DragOverlay({ isVisible, title = "Drop files here", description = "Images, videos, and audio files", + isProcessing = false, + progress = 0, + onClick, + isEmptyState = false, }: DragOverlayProps) { if (!isVisible) return null; + const handleClick = (e: React.MouseEvent) => { + if (isProcessing || !onClick) return; + e.preventDefault(); + e.stopPropagation(); + onClick(); + }; + return ( -
-
- -

{title}

-

{description}

+
+
+ {isProcessing ? ( + + ) : isEmptyState ? ( + + ) : ( + + )} +
+ +
+

+ {isProcessing ? "Processing files..." : title} +

+

+ {isProcessing + ? `Processing your files (${progress}%)` + : description + } +

+ + {!isProcessing && ( +
+ +

+ {isEmptyState + ? "Supports images, videos, and audio files" + : "Or drop your files here" + } +

+
+ )} + + {isProcessing && ( +
+
+
+
+
+ )}
); } -- cgit v1.3.1 From 446745a33ce06273e78b9147e832434df458ef66 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 12:03:44 +0200 Subject: cleanup --- apps/web/src/components/editor/media-panel/views/media.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/web/src/components/editor/media-panel') diff --git a/apps/web/src/components/editor/media-panel/views/media.tsx b/apps/web/src/components/editor/media-panel/views/media.tsx index f8cbb639..198f28de 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -3,7 +3,7 @@ import { useDragDrop } from "@/hooks/use-drag-drop"; import { processMediaFiles } from "@/lib/media-processing"; import { useMediaStore, type MediaItem } from "@/stores/media-store"; -import { Image, Loader2, Music, Plus, Upload, Video } from "lucide-react"; +import { Image, Loader2, Music, Plus, Video } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; -- cgit v1.3.1 From a7e23ec714faabbeaa3b6a673e7e2d86825944bd Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 12:22:09 +0200 Subject: media drag overlay cleanup --- .../components/editor/media-panel/drag-overlay.tsx | 57 ++++++++++++++ .../components/editor/media-panel/views/media.tsx | 20 +---- apps/web/src/components/ui/drag-overlay.tsx | 91 ---------------------- 3 files changed, 60 insertions(+), 108 deletions(-) create mode 100644 apps/web/src/components/editor/media-panel/drag-overlay.tsx delete mode 100644 apps/web/src/components/ui/drag-overlay.tsx (limited to 'apps/web/src/components/editor/media-panel') diff --git a/apps/web/src/components/editor/media-panel/drag-overlay.tsx b/apps/web/src/components/editor/media-panel/drag-overlay.tsx new file mode 100644 index 00000000..3f3820db --- /dev/null +++ b/apps/web/src/components/editor/media-panel/drag-overlay.tsx @@ -0,0 +1,57 @@ +import { Upload, Plus, Image } from "lucide-react"; +import { Button } from "@/components/ui/button"; + +interface MediaDragOverlayProps { + isVisible: boolean; + isProcessing?: boolean; + progress?: number; + onClick?: () => void; + isEmptyState?: boolean; +} + +export function MediaDragOverlay({ + isVisible, + isProcessing = false, + progress = 0, + onClick, + isEmptyState = false, +}: MediaDragOverlayProps) { + if (!isVisible) return null; + + const handleClick = (e: React.MouseEvent) => { + if (isProcessing || !onClick) return; + e.preventDefault(); + e.stopPropagation(); + onClick(); + }; + + return ( +
+
+ +
+ +
+

+ {isProcessing + ? `Processing your files (${progress}%)` + : "Drag and drop videos, photos, and audio files here"} +

+
+ + {isProcessing && ( +
+
+
+
+
+ )} +
+ ); +} diff --git a/apps/web/src/components/editor/media-panel/views/media.tsx b/apps/web/src/components/editor/media-panel/views/media.tsx index e532e540..631fe39a 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -7,7 +7,7 @@ import { Image, Loader2, Music, Plus, Video } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; -import { DragOverlay } from "@/components/ui/drag-overlay"; +import { MediaDragOverlay } from "@/components/editor/media-panel/drag-overlay"; import { ContextMenu, ContextMenuContent, @@ -242,23 +242,9 @@ export function MediaView() {
- {(isDragOver || filteredMediaItems.length === 0) ? ( - void; - isEmptyState?: boolean; -} - -export function DragOverlay({ - isVisible, - title = "Drop files here", - description = "Images, videos, and audio files", - isProcessing = false, - progress = 0, - onClick, - isEmptyState = false, -}: DragOverlayProps) { - if (!isVisible) return null; - - const handleClick = (e: React.MouseEvent) => { - if (isProcessing || !onClick) return; - e.preventDefault(); - e.stopPropagation(); - onClick(); - }; - - return ( -
-
- {isProcessing ? ( - - ) : isEmptyState ? ( - - ) : ( - - )} -
- -
-

- {isProcessing ? "Processing files..." : title} -

-

- {isProcessing - ? `Processing your files (${progress}%)` - : description - } -

-
- - {!isProcessing && ( -
- -

- {isEmptyState - ? "Supports images, videos, and audio files" - : "Or drop your files here" - } -

-
- )} - - {isProcessing && ( -
-
-
-
-
- )} -
- ); -} -- cgit v1.3.1