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}
>
-