summaryrefslogtreecommitdiff
path: root/apps/web/src
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src')
-rw-r--r--apps/web/src/lib/utils.ts30
-rw-r--r--apps/web/src/stores/media-store.ts3
-rw-r--r--apps/web/src/stores/project-store.ts5
-rw-r--r--apps/web/src/stores/timeline-store.ts13
-rw-r--r--apps/web/src/types/timeline.ts3
5 files changed, 44 insertions, 10 deletions
diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts
index ae939698..dd73059f 100644
--- a/apps/web/src/lib/utils.ts
+++ b/apps/web/src/lib/utils.ts
@@ -5,4 +5,34 @@ import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
+}
+
+/**
+ * Generates a UUID v4 string
+ * Uses crypto.randomUUID() if available, otherwise falls back to a custom implementation
+ */
+export function generateUUID(): string {
+ // Use the native crypto.randomUUID if available
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
+ return crypto.randomUUID();
+ }
+
+ // Secure fallback using crypto.getRandomValues
+ const bytes = new Uint8Array(16);
+ crypto.getRandomValues(bytes);
+
+ // Set version 4 (UUIDv4)
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
+ // Set variant 10xxxxxx
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
+
+ const hex = [...bytes].map(b => b.toString(16).padStart(2, '0'));
+
+ return (
+ hex.slice(0, 4).join('') + '-' +
+ hex.slice(4, 6).join('') + '-' +
+ hex.slice(6, 8).join('') + '-' +
+ hex.slice(8, 10).join('') + '-' +
+ hex.slice(10, 16).join('')
+ );
} \ No newline at end of file
diff --git a/apps/web/src/stores/media-store.ts b/apps/web/src/stores/media-store.ts
index 76cdd638..dc9ad90d 100644
--- a/apps/web/src/stores/media-store.ts
+++ b/apps/web/src/stores/media-store.ts
@@ -1,6 +1,7 @@
import { create } from "zustand";
import { storageService } from "@/lib/storage/storage-service";
import { useTimelineStore } from "./timeline-store";
+import { generateUUID } from "@/lib/utils";
export type MediaType = "image" | "video" | "audio";
@@ -161,7 +162,7 @@ export const useMediaStore = create<MediaStore>((set, get) => ({
addMediaItem: async (projectId, item) => {
const newItem: MediaItem = {
...item,
- id: crypto.randomUUID(),
+ id: generateUUID(),
};
// Add to local state immediately for UI responsiveness
diff --git a/apps/web/src/stores/project-store.ts b/apps/web/src/stores/project-store.ts
index 913c6810..e1a4a72e 100644
--- a/apps/web/src/stores/project-store.ts
+++ b/apps/web/src/stores/project-store.ts
@@ -4,6 +4,7 @@ import { storageService } from "@/lib/storage/storage-service";
import { toast } from "sonner";
import { useMediaStore } from "./media-store";
import { useTimelineStore } from "./timeline-store";
+import { generateUUID } from "@/lib/utils";
interface ProjectStore {
activeProject: TProject | null;
@@ -35,7 +36,7 @@ export const useProjectStore = create<ProjectStore>((set, get) => ({
createNewProject: async (name: string) => {
const newProject: TProject = {
- id: crypto.randomUUID(),
+ id: generateUUID(),
name,
thumbnail: "",
createdAt: new Date(),
@@ -223,7 +224,7 @@ export const useProjectStore = create<ProjectStore>((set, get) => ({
existingNumbers.length > 0 ? Math.max(...existingNumbers) + 1 : 1;
const newProject: TProject = {
- id: crypto.randomUUID(),
+ id: generateUUID(),
name: `(${nextNumber}) ${baseName}`,
thumbnail: project.thumbnail,
createdAt: new Date(),
diff --git a/apps/web/src/stores/timeline-store.ts b/apps/web/src/stores/timeline-store.ts
index 8c934392..bc47e093 100644
--- a/apps/web/src/stores/timeline-store.ts
+++ b/apps/web/src/stores/timeline-store.ts
@@ -13,6 +13,7 @@ import { useEditorStore } from "./editor-store";
import { useMediaStore, getMediaAspectRatio } from "./media-store";
import { storageService } from "@/lib/storage/storage-service";
import { useProjectStore } from "./project-store";
+import { generateUUID } from "@/lib/utils";
// Helper function to manage element naming with suffixes
const getElementNameWithSuffix = (
@@ -279,7 +280,7 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
: "Track";
const newTrack: TimelineTrack = {
- id: crypto.randomUUID(),
+ id: generateUUID(),
name: trackName,
type,
elements: [],
@@ -304,7 +305,7 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
: "Track";
const newTrack: TimelineTrack = {
- id: crypto.randomUUID(),
+ id: generateUUID(),
name: trackName,
type,
elements: [],
@@ -363,7 +364,7 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
const newElement: TimelineElement = {
...elementData,
- id: crypto.randomUUID(),
+ id: generateUUID(),
startTime: elementData.startTime || 0,
trimStart: 0,
trimEnd: 0,
@@ -556,7 +557,7 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
const secondDuration =
element.duration - element.trimStart - element.trimEnd - relativeTime;
- const secondElementId = crypto.randomUUID();
+ const secondElementId = generateUUID();
updateTracksAndSave(
get()._tracks.map((track) =>
@@ -682,7 +683,7 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
// Find existing audio track or prepare to create one
const existingAudioTrack = _tracks.find((t) => t.type === "audio");
- const audioElementId = crypto.randomUUID();
+ const audioElementId = generateUUID();
if (existingAudioTrack) {
// Add audio element to existing audio track
@@ -706,7 +707,7 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
} else {
// Create new audio track with the audio element in a single atomic update
const newAudioTrack: TimelineTrack = {
- id: crypto.randomUUID(),
+ id: generateUUID(),
name: "Audio Track",
type: "audio",
elements: [
diff --git a/apps/web/src/types/timeline.ts b/apps/web/src/types/timeline.ts
index a759de21..17dbb5d1 100644
--- a/apps/web/src/types/timeline.ts
+++ b/apps/web/src/types/timeline.ts
@@ -1,4 +1,5 @@
import { MediaType } from "@/stores/media-store";
+import { generateUUID } from "@/lib/utils";
export type TrackType = "media" | "text" | "audio";
@@ -111,7 +112,7 @@ export function ensureMainTrack(tracks: TimelineTrack[]): TimelineTrack[] {
if (!hasMainTrack) {
// Create main track if it doesn't exist
const mainTrack: TimelineTrack = {
- id: crypto.randomUUID(),
+ id: generateUUID(),
name: "Main Track",
type: "media",
elements: [],