diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-07-06 20:45:29 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-07-06 20:45:29 +0200 |
| commit | 40c7fbb4f86130c83fbd9029e83c5e7550e3219d (patch) | |
| tree | 054d918d282358c084f4fc08462913833de644a5 /apps/web/src/stores/media-store.ts | |
| parent | 0e32c732ddc335d35e6a7f8547f4af68bfd9c369 (diff) | |
| download | opencut-40c7fbb4f86130c83fbd9029e83c5e7550e3219d.tar.gz | |
refactor: move to a typed-tracks system and add support for text
Diffstat (limited to 'apps/web/src/stores/media-store.ts')
| -rw-r--r-- | apps/web/src/stores/media-store.ts | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/apps/web/src/stores/media-store.ts b/apps/web/src/stores/media-store.ts index 48932db5..ab413b14 100644 --- a/apps/web/src/stores/media-store.ts +++ b/apps/web/src/stores/media-store.ts @@ -1,16 +1,25 @@ import { create } from "zustand"; import { storageService } from "@/lib/storage/storage-service"; +export type MediaType = "image" | "video" | "audio"; + export interface MediaItem { id: string; name: string; - type: "image" | "video" | "audio"; + type: MediaType; file: File; - url: string; // Object URL for preview + url?: string; // Object URL for preview thumbnailUrl?: string; // For video thumbnails duration?: number; // For video/audio duration width?: number; // For video/image width height?: number; // For video/image height + // Text-specific properties + content?: string; // Text content + fontSize?: number; // Font size + fontFamily?: string; // Font family + color?: string; // Text color + backgroundColor?: string; // Background color + textAlign?: "left" | "center" | "right"; // Text alignment } interface MediaStore { @@ -25,7 +34,7 @@ interface MediaStore { } // Helper function to determine file type -export const getFileType = (file: File): "image" | "video" | "audio" | null => { +export const getFileType = (file: File): MediaType | null => { const { type } = file; if (type.startsWith("image/")) { @@ -46,7 +55,7 @@ export const getImageDimensions = ( file: File ): Promise<{ width: number; height: number }> => { return new Promise((resolve, reject) => { - const img = new Image(); + const img = new window.Image(); img.addEventListener("load", () => { const width = img.naturalWidth; @@ -69,8 +78,8 @@ export const generateVideoThumbnail = ( file: File ): Promise<{ thumbnailUrl: string; width: number; height: number }> => { return new Promise((resolve, reject) => { - const video = document.createElement("video"); - const canvas = document.createElement("canvas"); + const video = document.createElement("video") as HTMLVideoElement; + const canvas = document.createElement("canvas") as HTMLCanvasElement; const ctx = canvas.getContext("2d"); if (!ctx) { @@ -115,7 +124,7 @@ export const getMediaDuration = (file: File): Promise<number> => { return new Promise((resolve, reject) => { const element = document.createElement( file.type.startsWith("video/") ? "video" : "audio" - ) as HTMLVideoElement | HTMLAudioElement; + ) as HTMLVideoElement; element.addEventListener("loadedmetadata", () => { resolve(element.duration); @@ -162,17 +171,17 @@ export const useMediaStore = create<MediaStore>((set, get) => ({ console.error("Failed to save media item:", error); // Remove from local state if save failed set((state) => ({ - mediaItems: state.mediaItems.filter((item) => item.id !== newItem.id), + mediaItems: state.mediaItems.filter((media) => media.id !== newItem.id), })); } }, - removeMediaItem: async (id) => { + removeMediaItem: async (id: string) => { const state = get(); - const item = state.mediaItems.find((item) => item.id === id); + const item = state.mediaItems.find((media) => media.id === id); // Cleanup object URLs to prevent memory leaks - if (item) { + if (item && item.url) { URL.revokeObjectURL(item.url); if (item.thumbnailUrl) { URL.revokeObjectURL(item.thumbnailUrl); @@ -181,7 +190,7 @@ export const useMediaStore = create<MediaStore>((set, get) => ({ // Remove from local state immediately set((state) => ({ - mediaItems: state.mediaItems.filter((item) => item.id !== id), + mediaItems: state.mediaItems.filter((media) => media.id !== id), })); // Remove from persistent storage @@ -189,7 +198,6 @@ export const useMediaStore = create<MediaStore>((set, get) => ({ await storageService.deleteMediaItem(id); } catch (error) { console.error("Failed to delete media item:", error); - // Could re-add to local state here if needed } }, @@ -211,7 +219,9 @@ export const useMediaStore = create<MediaStore>((set, get) => ({ // Cleanup all object URLs state.mediaItems.forEach((item) => { - URL.revokeObjectURL(item.url); + if (item.url) { + URL.revokeObjectURL(item.url); + } if (item.thumbnailUrl) { URL.revokeObjectURL(item.thumbnailUrl); } |
