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 772ef4aba..d06aac84a 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -13,6 +13,8 @@ import { Music, Search, Video, + ZoomIn, + ZoomOut, } from "lucide-react"; import { useEffect, useRef, useState, useMemo } from "react"; import { toast } from "sonner"; @@ -34,6 +36,7 @@ import { DraggableMediaItem } from "@/components/ui/draggable-item"; import { useProjectStore } from "@/stores/project-store"; import { useTimelineStore } from "@/stores/timeline-store"; import { ScrollArea } from "@/components/ui/scroll-area"; +import { Slider } from "@/components/ui/slider"; import { Tooltip, TooltipContent, @@ -76,6 +79,12 @@ export function MediaView() { const [progress, setProgress] = useState(0); const [searchQuery, setSearchQuery] = useState(""); const [mediaFilter, setMediaFilter] = useState("all"); + // Get media size from localStorage or default to 3 + const [mediaSize, setMediaSize] = useState(() => { + const stored = localStorage.getItem("mediaSize"); + const parsed = parseInt(stored ?? "", 10); + return !isNaN(parsed) && parsed >= 1 && parsed <= 5 ? parsed : 3; + }); const [sortBy, setSortBy] = useState<"name" | "type" | "duration" | "size">( "name" ); @@ -109,6 +118,23 @@ export function MediaView() { } }; + const handleMediaSizeChange = (size: number) => { + setMediaSize(size); + localStorage.setItem("mediaSize", size.toString()); + }; + + const handleSizeIncrease = () => { + handleMediaSizeChange(Math.min(5, mediaSize + 1)); + }; + + const handleSizeDecrease = () => { + handleMediaSizeChange(Math.max(1, mediaSize - 1)); + }; + + const handleSizeSliderChange = (values: number[]) => { + handleMediaSizeChange(values[0]); + }; + const { isDragOver, dragProps } = useDragDrop({ // When files are dropped, process them onDrop: processFiles, @@ -145,7 +171,7 @@ export function MediaView() { const [filteredMediaItems, setFilteredMediaItems] = useState(mediaItems); useEffect(() => { - let filtered = mediaItems.filter((item) => { + const filtered = mediaItems.filter((item) => { if (mediaFilter && mediaFilter !== "all" && item.type !== mediaFilter) { return false; } @@ -306,6 +332,32 @@ export function MediaView() { Upload
+ {mediaViewMode === "grid" && ( +
+ + + +
+ )} @@ -446,6 +498,7 @@ export function MediaView() { /> ) : mediaViewMode === "grid" ? ( React.ReactNode; handleRemove: (e: React.MouseEvent, id: string) => Promise; + mediaSize: number; }) { + // Map size levels (1-5) to appropriate grid item widths + const getGridItemWidth = (size: number) => { + const sizeMap = { + 1: 90, + 2: 120, + 3: 160, + 4: 190, + 5: 220, + }; + return sizeMap[size as keyof typeof sizeMap] || 120; + }; return (
{filteredMediaItems.map((item) => ( @@ -488,6 +554,7 @@ function GridView({ onRemove={handleRemove} > {filteredMediaItems.map((item) => ( - - - useTimelineStore.getState().addMediaAtTime(item, currentTime) - } - variant="compact" - /> - +
+ + + useTimelineStore.getState().addMediaAtTime(item, currentTime) + } + variant="compact" + /> + +
))}
); diff --git a/apps/web/src/components/ui/draggable-item.tsx b/apps/web/src/components/ui/draggable-item.tsx index ff6766fda..51841405a 100644 --- a/apps/web/src/components/ui/draggable-item.tsx +++ b/apps/web/src/components/ui/draggable-item.tsx @@ -24,6 +24,10 @@ export interface DraggableMediaItemProps { showPlusOnDrag?: boolean; showLabel?: boolean; rounded?: boolean; + /** + * media item size + */ + size?: number; variant?: "card" | "compact"; } @@ -38,6 +42,7 @@ export function DraggableMediaItem({ showPlusOnDrag = true, showLabel = true, rounded = true, + size, variant = "card", }: DraggableMediaItemProps) { const [isDragging, setIsDragging] = useState(false); @@ -88,10 +93,26 @@ export function DraggableMediaItem({ setIsDragging(false); }; + const getMediaTitle = ( + name: string + ): [fileName: string, extension: string] => { + const lastDotIndex = name.lastIndexOf("."); + if (lastDotIndex > 0 && name.length - lastDotIndex <= 5) { + // Split at the last dot if extension is 4 chars or less + return [name.substring(0, lastDotIndex), name.substring(lastDotIndex)]; + } + // No extension or very long extension, return full name + return [name, ""]; + }; + + const [fileName, extension] = getMediaTitle(name); return ( <> {variant === "card" ? ( -
+
@@ -116,13 +137,12 @@ export function DraggableMediaItem({ {showLabel && ( - {name.length > 8 - ? `${name.slice(0, 16)}...${name.slice(-3)}` - : name} + {fileName} + {extension && extension} )}
@@ -139,7 +159,7 @@ export function DraggableMediaItem({ onDragStart={handleDragStart} onDragEnd={handleDragEnd} > -
+
{preview}
{name}