summaryrefslogtreecommitdiff
path: root/apps/web/src/stores/media-store.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-07-06 20:45:29 +0200
committerMaze Winther <mazewinther@gmail.com>2025-07-06 20:45:29 +0200
commit40c7fbb4f86130c83fbd9029e83c5e7550e3219d (patch)
tree054d918d282358c084f4fc08462913833de644a5 /apps/web/src/stores/media-store.ts
parent0e32c732ddc335d35e6a7f8547f4af68bfd9c369 (diff)
downloadopencut-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.ts38
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);
}