diff options
| author | Maze <167211895+mazeincoding@users.noreply.github.com> | 2026-01-31 00:20:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-31 00:20:04 +0100 |
| commit | 7bf0984698e43b9aa2dd879f65951318ed410390 (patch) | |
| tree | ccf2cd590a47d550152afc07129cb55c71a9ec35 /apps/web/src/components/ui/draggable-item.tsx | |
| parent | 0173db99448d1c4c6415dcf15272e17551b48b04 (diff) | |
| download | opencut-7bf0984698e43b9aa2dd879f65951318ed410390.tar.gz | |
codebase overhaul (#697)
Diffstat (limited to 'apps/web/src/components/ui/draggable-item.tsx')
| -rw-r--r-- | apps/web/src/components/ui/draggable-item.tsx | 247 |
1 files changed, 0 insertions, 247 deletions
diff --git a/apps/web/src/components/ui/draggable-item.tsx b/apps/web/src/components/ui/draggable-item.tsx deleted file mode 100644 index 9f5c7887..00000000 --- a/apps/web/src/components/ui/draggable-item.tsx +++ /dev/null @@ -1,247 +0,0 @@ -"use client"; - -import { AspectRatio } from "@/components/ui/aspect-ratio"; -import { Button } from "@/components/ui/button"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -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"; -import { DragData } from "@/types/timeline"; - -export interface DraggableMediaItemProps { - name: string; - preview: ReactNode; - dragData: DragData; - onDragStart?: (e: React.DragEvent) => void; - onAddToTimeline?: (currentTime: number) => void; - aspectRatio?: number; - className?: string; - containerClassName?: string; - showPlusOnDrag?: boolean; - showLabel?: boolean; - rounded?: boolean; - variant?: "card" | "compact"; - isDraggable?: boolean; - isHighlighted?: boolean; -} - -export function DraggableMediaItem({ - name, - preview, - dragData, - onDragStart, - onAddToTimeline, - aspectRatio = 16 / 9, - className = "", - containerClassName, - showPlusOnDrag = true, - showLabel = true, - rounded = true, - variant = "card", - isDraggable = true, - isHighlighted = false, -}: DraggableMediaItemProps) { - const [isDragging, setIsDragging] = useState(false); - const [dragPosition, setDragPosition] = useState({ x: 0, y: 0 }); - const dragRef = useRef<HTMLDivElement>(null); - const currentTime = isDraggable - ? usePlaybackStore((state) => state.currentTime) - : 0; - const highlightClassName = "ring-2 ring-primary rounded-sm bg-primary/10"; - - const handleAddToTimeline = () => { - onAddToTimeline?.(currentTime); - }; - - const emptyImg = new window.Image(); - emptyImg.src = - "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="; - - useEffect(() => { - if (!isDragging) return; - - const handleDragOver = (e: DragEvent) => { - setDragPosition({ x: e.clientX, y: e.clientY }); - }; - - document.addEventListener("dragover", handleDragOver); - - return () => { - document.removeEventListener("dragover", handleDragOver); - }; - }, [isDragging]); - - const handleDragStart = (e: React.DragEvent) => { - e.dataTransfer.setDragImage(emptyImg, 0, 0); - - // Set drag data - e.dataTransfer.setData( - "application/x-media-item", - JSON.stringify(dragData) - ); - e.dataTransfer.effectAllowed = "copy"; - - // Set initial position and show custom drag preview - setDragPosition({ x: e.clientX, y: e.clientY }); - setIsDragging(true); - - onDragStart?.(e); - }; - - const handleDragEnd = () => { - setIsDragging(false); - }; - - return ( - <> - {variant === "card" ? ( - <div - ref={dragRef} - className={cn("relative group", containerClassName ?? "w-28 h-28")} - > - <div - className={cn( - "flex flex-col gap-1 p-1 h-auto w-full relative cursor-default", - className, - isHighlighted && highlightClassName - )} - > - <AspectRatio - ratio={aspectRatio} - className={cn( - "bg-panel-accent relative overflow-hidden", - rounded && "rounded-md", - isDraggable && "[&::-webkit-drag-ghost]:opacity-0" // Webkit-specific ghost hiding - )} - draggable={isDraggable} - onDragStart={isDraggable ? handleDragStart : undefined} - onDragEnd={isDraggable ? handleDragEnd : undefined} - > - {preview} - {!isDragging && ( - <PlusButton - className="opacity-0 group-hover:opacity-100" - onClick={handleAddToTimeline} - /> - )} - </AspectRatio> - {showLabel && ( - <span - className="text-[0.7rem] text-muted-foreground truncate w-full text-left" - aria-label={name} - title={name} - > - {name.length > 8 - ? `${name.slice(0, 16)}...${name.slice(-3)}` - : name} - </span> - )} - </div> - </div> - ) : ( - <div - ref={dragRef} - className={cn( - "relative group w-full", - isHighlighted && highlightClassName - )} - > - <div - className={cn( - "h-8 flex items-center gap-3 cursor-default w-full px-1", - isDraggable && "[&::-webkit-drag-ghost]:opacity-0", - className - )} - draggable={isDraggable} - onDragStart={isDraggable ? handleDragStart : undefined} - onDragEnd={isDraggable ? handleDragEnd : undefined} - > - <div className="w-6 h-6 flex-shrink-0 rounded-[0.35rem] overflow-hidden"> - {preview} - </div> - <span className="text-sm truncate flex-1 w-full">{name}</span> - </div> - </div> - )} - - {/* Custom drag preview */} - {isDraggable && - isDragging && - typeof document !== "undefined" && - createPortal( - <div - className="fixed pointer-events-none z-9999" - style={{ - left: dragPosition.x - 40, // Center the preview (half of 80px) - top: dragPosition.y - 40, // Center the preview (half of 80px) - }} - > - <div className="w-[80px]"> - <AspectRatio - ratio={1} - className="relative rounded-md overflow-hidden shadow-2xl ring-3 ring-primary" - > - <div className="w-full h-full [&_img]:w-full [&_img]:h-full [&_img]:object-cover [&_img]:rounded-none"> - {preview} - </div> - {showPlusOnDrag && ( - <PlusButton - onClick={handleAddToTimeline} - tooltipText="Add to timeline or drag to position" - /> - )} - </AspectRatio> - </div> - </div>, - document.body - )} - </> - ); -} - -function PlusButton({ - className, - onClick, - tooltipText, -}: { - className?: string; - onClick?: () => void; - tooltipText?: string; -}) { - const button = ( - <Button - size="icon" - className={cn( - "absolute bottom-2 right-2 size-5 bg-background hover:bg-panel text-foreground", - className - )} - onClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - onClick?.(); - }} - title={tooltipText} - > - <Plus className="size-4!" /> - </Button> - ); - - if (tooltipText) { - return ( - <Tooltip> - <TooltipTrigger asChild>{button}</TooltipTrigger> - <TooltipContent> - <p>{tooltipText}</p> - </TooltipContent> - </Tooltip> - ); - } - - return button; -} |
