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 --- apps/web/src/components/ui/draggable-item.tsx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'apps/web/src/components/ui') diff --git a/apps/web/src/components/ui/draggable-item.tsx b/apps/web/src/components/ui/draggable-item.tsx index 16518dde..c1f81e16 100644 --- a/apps/web/src/components/ui/draggable-item.tsx +++ b/apps/web/src/components/ui/draggable-item.tsx @@ -6,12 +6,14 @@ import { ReactNode, useState, useRef, useEffect } from "react"; import { createPortal } from "react-dom"; import { Plus } from "lucide-react"; import { cn } from "@/lib/utils"; +import { usePlaybackStore } from "@/stores/playback-store"; export interface DraggableMediaItemProps { name: string; preview: ReactNode; dragData: Record; onDragStart?: (e: React.DragEvent) => void; + onAddToTimeline?: (currentTime: number) => void; aspectRatio?: number; className?: string; showPlusOnDrag?: boolean; @@ -24,6 +26,7 @@ export function DraggableMediaItem({ preview, dragData, onDragStart, + onAddToTimeline, aspectRatio = 16 / 9, className = "", showPlusOnDrag = true, @@ -33,6 +36,11 @@ export function DraggableMediaItem({ const [isDragging, setIsDragging] = useState(false); const [dragPosition, setDragPosition] = useState({ x: 0, y: 0 }); const dragRef = useRef(null); + const currentTime = usePlaybackStore((state) => state.currentTime); + + const handleAddToTimeline = () => { + onAddToTimeline?.(currentTime); + }; const emptyImg = new window.Image(); emptyImg.src = @@ -92,7 +100,10 @@ export function DraggableMediaItem({ > {preview} {!isDragging && ( - + )} {showLabel && ( @@ -128,7 +139,7 @@ export function DraggableMediaItem({
{preview}
- {showPlusOnDrag && } + {showPlusOnDrag && } , @@ -138,11 +149,16 @@ export function DraggableMediaItem({ ); } -function PlusButton({ className }: { className?: string }) { +function PlusButton({ className, onClick }: { className?: string; onClick?: () => void }) { return ( -- cgit v1.3.1 From fd2aa00074db0fd157bd41c0b6ddf061452f3aaa Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Tue, 15 Jul 2025 17:40:19 +0200 Subject: style: tooltip --- apps/web/src/components/ui/tooltip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/web/src/components/ui') diff --git a/apps/web/src/components/ui/tooltip.tsx b/apps/web/src/components/ui/tooltip.tsx index 0da023e6..4971e262 100644 --- a/apps/web/src/components/ui/tooltip.tsx +++ b/apps/web/src/components/ui/tooltip.tsx @@ -20,7 +20,7 @@ const TooltipContent = React.forwardRef< ref={ref} sideOffset={sideOffset} className={cn( - "z-50 overflow-hidden rounded-md bg-foreground/10 px-3 py-1.5 text-xs text-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + "z-50 overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className )} {...props} -- 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/ui') 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 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/ui') 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