From be1ae20d9089e81cb84a8294be76fe680a24b60f Mon Sep 17 00:00:00 2001 From: Hyteq Date: Sun, 20 Jul 2025 11:00:22 +0300 Subject: format --- .../components/editor/media-panel/views/media.tsx | 596 ++++++++++----------- .../components/editor/media-panel/views/text.tsx | 106 ++-- 2 files changed, 351 insertions(+), 351 deletions(-) (limited to 'apps/web/src/components/editor/media-panel/views') 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 631fe39a..712dd922 100644 --- a/apps/web/src/components/editor/media-panel/views/media.tsx +++ b/apps/web/src/components/editor/media-panel/views/media.tsx @@ -1,298 +1,298 @@ -"use client"; - -import { useDragDrop } from "@/hooks/use-drag-drop"; -import { processMediaFiles } from "@/lib/media-processing"; -import { useMediaStore, type MediaItem } from "@/stores/media-store"; -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 { MediaDragOverlay } from "@/components/editor/media-panel/drag-overlay"; -import { - ContextMenu, - ContextMenuContent, - ContextMenuItem, - ContextMenuTrigger, -} from "@/components/ui/context-menu"; -import { Input } from "@/components/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { DraggableMediaItem } from "@/components/ui/draggable-item"; -import { useProjectStore } from "@/stores/project-store"; -import { useTimelineStore } from "@/stores/timeline-store"; - -export function MediaView() { - const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore(); - const { activeProject } = useProjectStore(); - const fileInputRef = useRef(null); - const [isProcessing, setIsProcessing] = useState(false); - const [progress, setProgress] = useState(0); - const [searchQuery, setSearchQuery] = useState(""); - const [mediaFilter, setMediaFilter] = useState("all"); - - const processFiles = async (files: FileList | File[]) => { - if (!files || files.length === 0) return; - if (!activeProject) { - toast.error("No active project"); - return; - } - - 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); - } - } catch (error) { - // Show error toast if processing fails - console.error("Error processing files:", error); - toast.error("Failed to process files"); - } finally { - setIsProcessing(false); - setProgress(0); - } - }; - - const { isDragOver, dragProps } = useDragDrop({ - // When files are dropped, process them - onDrop: processFiles, - }); - - const handleFileSelect = () => fileInputRef.current?.click(); // Open file picker - - const handleFileChange = (e: React.ChangeEvent) => { - // 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) { - toast.error("No active project"); - return; - } - - // Media store now handles cascade deletion automatically - await removeMediaItem(activeProject.id, id); - }; - - const formatDuration = (duration: number) => { - // Format seconds as mm:ss - const min = Math.floor(duration / 60); - const sec = Math.floor(duration % 60); - return `${min}:${sec.toString().padStart(2, "0")}`; - }; - - const [filteredMediaItems, setFilteredMediaItems] = useState(mediaItems); - - useEffect(() => { - const filtered = mediaItems.filter((item) => { - if (mediaFilter && mediaFilter !== "all" && item.type !== mediaFilter) { - return false; - } - - if ( - searchQuery && - !item.name.toLowerCase().includes(searchQuery.toLowerCase()) - ) { - return false; - } - - return true; - }); - - setFilteredMediaItems(filtered); - }, [mediaItems, mediaFilter, searchQuery]); - - const renderPreview = (item: MediaItem) => { - // Render a preview for each media type (image, video, audio, unknown) - if (item.type === "image") { - return ( -
- {item.name} -
- ); - } - - if (item.type === "video") { - if (item.thumbnailUrl) { - return ( -
- {item.name} -
-
- {item.duration && ( -
- {formatDuration(item.duration)} -
- )} -
- ); - } - return ( -
-
- ); - } - - if (item.type === "audio") { - return ( -
- - Audio - {item.duration && ( - - {formatDuration(item.duration)} - - )} -
- ); - } - - return ( -
- - Unknown -
- ); - }; - - return ( - <> - {/* Hidden file input for uploading media */} - - -
-
- {/* Search and filter controls */} -
- - setSearchQuery(e.target.value)} - /> - -
-
- -
- {isDragOver || filteredMediaItems.length === 0 ? ( - - ) : ( -
- {/* Render each media item as a draggable button */} - {filteredMediaItems.map((item) => ( - - - - useTimelineStore - .getState() - .addMediaAtTime(item, currentTime) - } - rounded={false} - /> - - - Export clips - handleRemove(e, item.id)} - > - Delete - - - - ))} -
- )} -
-
- - ); -} +"use client"; + +import { useDragDrop } from "@/hooks/use-drag-drop"; +import { processMediaFiles } from "@/lib/media-processing"; +import { useMediaStore, type MediaItem } from "@/stores/media-store"; +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 { MediaDragOverlay } from "@/components/editor/media-panel/drag-overlay"; +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuTrigger, +} from "@/components/ui/context-menu"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { DraggableMediaItem } from "@/components/ui/draggable-item"; +import { useProjectStore } from "@/stores/project-store"; +import { useTimelineStore } from "@/stores/timeline-store"; + +export function MediaView() { + const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore(); + const { activeProject } = useProjectStore(); + const fileInputRef = useRef(null); + const [isProcessing, setIsProcessing] = useState(false); + const [progress, setProgress] = useState(0); + const [searchQuery, setSearchQuery] = useState(""); + const [mediaFilter, setMediaFilter] = useState("all"); + + const processFiles = async (files: FileList | File[]) => { + if (!files || files.length === 0) return; + if (!activeProject) { + toast.error("No active project"); + return; + } + + 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); + } + } catch (error) { + // Show error toast if processing fails + console.error("Error processing files:", error); + toast.error("Failed to process files"); + } finally { + setIsProcessing(false); + setProgress(0); + } + }; + + const { isDragOver, dragProps } = useDragDrop({ + // When files are dropped, process them + onDrop: processFiles, + }); + + const handleFileSelect = () => fileInputRef.current?.click(); // Open file picker + + const handleFileChange = (e: React.ChangeEvent) => { + // 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) { + toast.error("No active project"); + return; + } + + // Media store now handles cascade deletion automatically + await removeMediaItem(activeProject.id, id); + }; + + const formatDuration = (duration: number) => { + // Format seconds as mm:ss + const min = Math.floor(duration / 60); + const sec = Math.floor(duration % 60); + return `${min}:${sec.toString().padStart(2, "0")}`; + }; + + const [filteredMediaItems, setFilteredMediaItems] = useState(mediaItems); + + useEffect(() => { + const filtered = mediaItems.filter((item) => { + if (mediaFilter && mediaFilter !== "all" && item.type !== mediaFilter) { + return false; + } + + if ( + searchQuery && + !item.name.toLowerCase().includes(searchQuery.toLowerCase()) + ) { + return false; + } + + return true; + }); + + setFilteredMediaItems(filtered); + }, [mediaItems, mediaFilter, searchQuery]); + + const renderPreview = (item: MediaItem) => { + // Render a preview for each media type (image, video, audio, unknown) + if (item.type === "image") { + return ( +
+ {item.name} +
+ ); + } + + if (item.type === "video") { + if (item.thumbnailUrl) { + return ( +
+ {item.name} +
+
+ {item.duration && ( +
+ {formatDuration(item.duration)} +
+ )} +
+ ); + } + return ( +
+
+ ); + } + + if (item.type === "audio") { + return ( +
+ + Audio + {item.duration && ( + + {formatDuration(item.duration)} + + )} +
+ ); + } + + return ( +
+ + Unknown +
+ ); + }; + + return ( + <> + {/* Hidden file input for uploading media */} + + +
+
+ {/* Search and filter controls */} +
+ + setSearchQuery(e.target.value)} + /> + +
+
+ +
+ {isDragOver || filteredMediaItems.length === 0 ? ( + + ) : ( +
+ {/* Render each media item as a draggable button */} + {filteredMediaItems.map((item) => ( + + + + useTimelineStore + .getState() + .addMediaAtTime(item, currentTime) + } + rounded={false} + /> + + + Export clips + handleRemove(e, item.id)} + > + Delete + + + + ))} +
+ )} +
+
+ + ); +} diff --git a/apps/web/src/components/editor/media-panel/views/text.tsx b/apps/web/src/components/editor/media-panel/views/text.tsx index 6d0d310b..b47edd8d 100644 --- a/apps/web/src/components/editor/media-panel/views/text.tsx +++ b/apps/web/src/components/editor/media-panel/views/text.tsx @@ -1,53 +1,53 @@ -import { DraggableMediaItem } from "@/components/ui/draggable-item"; -import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; -import { useTimelineStore } from "@/stores/timeline-store"; -import { type TextElement } from "@/types/timeline"; - -let textData: TextElement = { - id: "default-text", - type: "text", - name: "Default text", - content: "Default text", - fontSize: 48, - fontFamily: "Arial", - color: "#ffffff", - backgroundColor: "transparent", - textAlign: "center" as const, - fontWeight: "normal" as const, - fontStyle: "normal" as const, - textDecoration: "none" as const, - x: 0, - y: 0, - rotation: 0, - opacity: 1, - duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, - startTime: 0, - trimStart: 0, - trimEnd: 0, -}; - -export function TextView() { - return ( -
- - Default text -
- } - dragData={{ - id: textData.id, - type: textData.type, - name: textData.name, - content: textData.content, - }} - aspectRatio={1} - onAddToTimeline={(currentTime) => - useTimelineStore.getState().addTextAtTime(textData, currentTime) - } - showLabel={false} - /> - - ); -} +import { DraggableMediaItem } from "@/components/ui/draggable-item"; +import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; +import { useTimelineStore } from "@/stores/timeline-store"; +import { type TextElement } from "@/types/timeline"; + +let textData: TextElement = { + id: "default-text", + type: "text", + name: "Default text", + content: "Default text", + fontSize: 48, + fontFamily: "Arial", + color: "#ffffff", + backgroundColor: "transparent", + textAlign: "center" as const, + fontWeight: "normal" as const, + fontStyle: "normal" as const, + textDecoration: "none" as const, + x: 0, + y: 0, + rotation: 0, + opacity: 1, + duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, + startTime: 0, + trimStart: 0, + trimEnd: 0, +}; + +export function TextView() { + return ( +
+ + Default text +
+ } + dragData={{ + id: textData.id, + type: textData.type, + name: textData.name, + content: textData.content, + }} + aspectRatio={1} + onAddToTimeline={(currentTime) => + useTimelineStore.getState().addTextAtTime(textData, currentTime) + } + showLabel={false} + /> + + ); +} -- cgit v1.3.1