diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-08-26 15:04:25 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-08-26 15:04:25 +0200 |
| commit | b459b46802a760a4a81ce91fdf24390e07375fb0 (patch) | |
| tree | e0070578d2b57acfba5f119cbf1abc6c9db5e741 /apps/web/src/components/editor/media-panel/views/media.tsx | |
| parent | 2f7cd11ca123884969f90a94e59593d355518839 (diff) | |
| download | opencut-b459b46802a760a4a81ce91fdf24390e07375fb0.tar.gz | |
refactor: type-safety & separate concerns
Diffstat (limited to 'apps/web/src/components/editor/media-panel/views/media.tsx')
| -rw-r--r-- | apps/web/src/components/editor/media-panel/views/media.tsx | 64 |
1 files changed, 24 insertions, 40 deletions
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 c84dde70..07a44a7c 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -2,7 +2,8 @@ import { useDragDrop } from "@/hooks/use-drag-drop"; import { processMediaFiles } from "@/lib/media-processing"; -import { useMediaStore, type MediaItem } from "@/stores/media-store"; +import { useMediaStore } from "@/stores/media-store"; +import { MediaFile } from "@/types/media"; import { ArrowDown01, CloudUpload, @@ -13,7 +14,7 @@ import { Music, Video, } from "lucide-react"; -import { useRef, useState, useMemo, useEffect } from "react"; +import { useRef, useState, useMemo } from "react"; import { useHighlightScroll } from "@/hooks/use-highlight-scroll"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -47,7 +48,7 @@ function MediaItemWithContextMenu({ children, onRemove, }: { - item: MediaItem; + item: MediaFile; children: React.ReactNode; onRemove: (e: React.MouseEvent, id: string) => Promise<void>; }) { @@ -68,14 +69,12 @@ function MediaItemWithContextMenu({ } export function MediaView() { - const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore(); + const { mediaFiles, addMediaFile, removeMediaFile } = useMediaStore(); const { activeProject } = useProjectStore(); const { mediaViewMode, setMediaViewMode } = usePanelStore(); const fileInputRef = useRef<HTMLInputElement>(null); const [isProcessing, setIsProcessing] = useState(false); const [progress, setProgress] = useState(0); - const [searchQuery, setSearchQuery] = useState(""); - const [mediaFilter, setMediaFilter] = useState("all"); const [sortBy, setSortBy] = useState<"name" | "type" | "duration" | "size">( "name" ); @@ -96,16 +95,13 @@ export function MediaView() { setIsProcessing(true); setProgress(0); try { - // Process files (extract metadata, generate thumbnails, etc.) const processedItems = await processMediaFiles(files, (p) => setProgress(p) ); - // Add each processed media item to the store for (const item of processedItems) { - await addMediaItem(activeProject.id, item); + await addMediaFile(activeProject.id, item); } } catch (error) { - // Show error toast if processing fails console.error("Error processing files:", error); toast.error("Failed to process files"); } finally { @@ -122,13 +118,11 @@ export function MediaView() { const handleFileSelect = () => fileInputRef.current?.click(); // Open file picker const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { - // When files are selected via file picker, process them if (e.target.files) processFiles(e.target.files); e.target.value = ""; // Reset input }; const handleRemove = async (e: React.MouseEvent, id: string) => { - // Remove a media item from the store e.stopPropagation(); if (!activeProject) { @@ -136,8 +130,7 @@ export function MediaView() { return; } - // Media store now handles cascade deletion automatically - await removeMediaItem(activeProject.id, id); + await removeMediaFile(activeProject.id, id); }; const formatDuration = (duration: number) => { @@ -147,28 +140,15 @@ export function MediaView() { return `${min}:${sec.toString().padStart(2, "0")}`; }; - const [filteredMediaItems, setFilteredMediaItems] = useState(mediaItems); - - useEffect(() => { - let filtered = mediaItems.filter((item) => { + const filteredMediaItems = useMemo(() => { + let filtered = mediaFiles.filter((item) => { if (item.ephemeral) return false; - if (mediaFilter && mediaFilter !== "all" && item.type !== mediaFilter) { - return false; - } - - if ( - searchQuery && - !item.name.toLowerCase().includes(searchQuery.toLowerCase()) - ) { - return false; - } - return true; }); filtered.sort((a, b) => { - let valueA: any; - let valueB: any; + let valueA: string | number; + let valueB: string | number; switch (sortBy) { case "name": @@ -196,8 +176,8 @@ export function MediaView() { return 0; }); - setFilteredMediaItems(filtered); - }, [mediaItems, mediaFilter, searchQuery, sortBy, sortOrder]); + return filtered; + }, [mediaFiles, sortBy, sortOrder]); const previewComponents = useMemo(() => { const previews = new Map<string, React.ReactNode>(); @@ -276,7 +256,7 @@ export function MediaView() { return previews; }, [filteredMediaItems]); - const renderPreview = (item: MediaItem) => previewComponents.get(item.id); + const renderPreview = (item: MediaFile) => previewComponents.get(item.id); return ( <> @@ -481,12 +461,14 @@ function GridView({ highlightedId, registerElement, }: { - filteredMediaItems: MediaItem[]; - renderPreview: (item: MediaItem) => React.ReactNode; + filteredMediaItems: MediaFile[]; + renderPreview: (item: MediaFile) => React.ReactNode; handleRemove: (e: React.MouseEvent, id: string) => Promise<void>; highlightedId: string | null; registerElement: (id: string, element: HTMLElement | null) => void; }) { + const { addElementAtTime } = useTimelineStore(); + return ( <div className="grid gap-2" @@ -507,7 +489,7 @@ function GridView({ }} showPlusOnDrag={false} onAddToTimeline={(currentTime) => - useTimelineStore.getState().addMediaAtTime(item, currentTime) + addElementAtTime(item, currentTime) } rounded={false} variant="card" @@ -527,12 +509,14 @@ function ListView({ highlightedId, registerElement, }: { - filteredMediaItems: MediaItem[]; - renderPreview: (item: MediaItem) => React.ReactNode; + filteredMediaItems: MediaFile[]; + renderPreview: (item: MediaFile) => React.ReactNode; handleRemove: (e: React.MouseEvent, id: string) => Promise<void>; highlightedId: string | null; registerElement: (id: string, element: HTMLElement | null) => void; }) { + const { addElementAtTime } = useTimelineStore(); + return ( <div className="space-y-1"> {filteredMediaItems.map((item) => ( @@ -548,7 +532,7 @@ function ListView({ }} showPlusOnDrag={false} onAddToTimeline={(currentTime) => - useTimelineStore.getState().addMediaAtTime(item, currentTime) + addElementAtTime(item, currentTime) } variant="compact" isHighlighted={highlightedId === item.id} |
