From 6d19841abf651fc40e8da45baa1e51b0bc733d6c Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 28 Jan 2026 15:12:14 +0100 Subject: [PATCH] de-duplicate code --- .cursor/rules/codebase-index.mdc | 22 +++++ .../editor/panels/assets/views/media.tsx | 48 ++++------ .../hooks/timeline/use-timeline-drag-drop.ts | 95 ++++--------------- apps/web/src/lib/timeline/element-utils.ts | 53 +++++++++++ 4 files changed, 111 insertions(+), 107 deletions(-) diff --git a/.cursor/rules/codebase-index.mdc b/.cursor/rules/codebase-index.mdc index 0474fe98..6dc3b8f2 100644 --- a/.cursor/rules/codebase-index.mdc +++ b/.cursor/rules/codebase-index.mdc @@ -905,6 +905,28 @@ element-utils.ts iconName: string; startTime: number; }): CreateStickerElement + export function buildVideoElement({ + mediaId, + name, + duration, + startTime, + }: { + mediaId: string; + name: string; + duration: number; + startTime: number; + }): CreateVideoElement + export function buildImageElement({ + mediaId, + name, + duration, + startTime, + }: { + mediaId: string; + name: string; + duration: number; + startTime: number; + }): CreateImageElement export function buildUploadAudioElement({ mediaId, name, diff --git a/apps/web/src/components/editor/panels/assets/views/media.tsx b/apps/web/src/components/editor/panels/assets/views/media.tsx index b8c9e548..76ae0064 100644 --- a/apps/web/src/components/editor/panels/assets/views/media.tsx +++ b/apps/web/src/components/editor/panels/assets/views/media.tsx @@ -29,6 +29,11 @@ import { useEditor } from "@/hooks/use-editor"; import { useFileUpload } from "@/hooks/use-file-upload"; import { useRevealItem } from "@/hooks/use-reveal-item"; import { processMediaAssets } from "@/lib/media/processing"; +import { + buildImageElement, + buildUploadAudioElement, + buildVideoElement, +} from "@/lib/timeline/element-utils"; import { useAssetsPanelStore } from "@/stores/assets-panel-store"; import type { MediaAsset } from "@/types/assets"; import type { CreateTimelineElement } from "@/types/timeline"; @@ -644,45 +649,26 @@ function createElementFromMedia({ switch (asset.type) { case "video": - return { - type: "video", - name: asset.name, + return buildVideoElement({ mediaId: asset.id, - startTime, + name: asset.name, duration, - trimStart: 0, - trimEnd: 0, - muted: false, - hidden: false, - transform: { scale: 1, position: { x: 0, y: 0 }, rotate: 0 }, - opacity: 1, - }; + startTime, + }); case "image": - return { - type: "image", - name: asset.name, + return buildImageElement({ mediaId: asset.id, - startTime, + name: asset.name, duration, - trimStart: 0, - trimEnd: 0, - hidden: false, - transform: { scale: 1, position: { x: 0, y: 0 }, rotate: 0 }, - opacity: 1, - }; + startTime, + }); case "audio": - return { - type: "audio", - sourceType: "upload", - name: asset.name, + return buildUploadAudioElement({ mediaId: asset.id, - startTime, + name: asset.name, duration, - trimStart: 0, - trimEnd: 0, - volume: 1, - muted: false, - }; + startTime, + }); default: throw new Error(`Unsupported media type: ${asset.type}`); } diff --git a/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts b/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts index 01c43172..d0d5c8ab 100644 --- a/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts +++ b/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts @@ -7,6 +7,9 @@ import { snapTimeToFrame } from "@/lib/time"; import { buildTextElement, buildStickerElement, + buildUploadAudioElement, + buildVideoElement, + buildImageElement, } from "@/lib/timeline/element-utils"; import { computeDropTarget } from "@/lib/timeline/drop-utils"; import { getDragData, hasDragData } from "@/lib/drag-data"; @@ -261,62 +264,32 @@ export function useTimelineDragDrop({ if (dragData.mediaType === "audio") { editor.timeline.insertElement({ placement: { mode: "explicit", trackId }, - element: { - type: "audio", - sourceType: "upload", + element: buildUploadAudioElement({ mediaId: mediaAsset.id, name: mediaAsset.name, duration, startTime: target.xPosition, - trimStart: 0, - trimEnd: 0, - volume: 1, - muted: false, - }, + }), }); } else if (dragData.mediaType === "video") { editor.timeline.insertElement({ placement: { mode: "explicit", trackId }, - element: { - type: "video", + element: buildVideoElement({ mediaId: mediaAsset.id, name: mediaAsset.name, duration, startTime: target.xPosition, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { - x: 0, - y: 0, - }, - rotate: 0, - }, - opacity: 1, - }, + }), }); } else { editor.timeline.insertElement({ placement: { mode: "explicit", trackId }, - element: { - type: "image", + element: buildImageElement({ mediaId: mediaAsset.id, name: mediaAsset.name, duration, startTime: target.xPosition, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { - x: 0, - y: 0, - }, - rotate: 0, - }, - opacity: 1, - }, + }), }); } }, @@ -377,63 +350,33 @@ export function useTimelineDragDrop({ if (added.type === "audio") { editor.timeline.insertElement({ placement: { mode: "explicit", trackId }, - element: { - type: "audio", - sourceType: "upload", + element: buildUploadAudioElement({ mediaId: added.id, name: added.name, duration, startTime: dropTarget.xPosition, - trimStart: 0, - trimEnd: 0, - volume: 1, buffer: new AudioBuffer({ length: 1, sampleRate: 44100 }), - muted: false, - }, + }), }); } else if (added.type === "video") { editor.timeline.insertElement({ placement: { mode: "explicit", trackId }, - element: { - type: "video", + element: buildVideoElement({ mediaId: added.id, name: added.name, duration, startTime: dropTarget.xPosition, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { - x: 0, - y: 0, - }, - rotate: 0, - }, - opacity: 1, - }, + }), }); } else { editor.timeline.insertElement({ placement: { mode: "explicit", trackId }, - element: { - type: "image", + element: buildImageElement({ mediaId: added.id, name: added.name, duration, startTime: dropTarget.xPosition, - trimStart: 0, - trimEnd: 0, - transform: { - scale: 1, - position: { - x: 0, - y: 0, - }, - rotate: 0, - }, - opacity: 1, - }, + }), }); } } @@ -486,10 +429,10 @@ export function useTimelineDragDrop({ } }, [ - dropTarget, - executeTextDrop, - executeStickerDrop, - executeMediaDrop, + dropTarget, + executeTextDrop, + executeStickerDrop, + executeMediaDrop, executeFileDrop, containerRef, ], diff --git a/apps/web/src/lib/timeline/element-utils.ts b/apps/web/src/lib/timeline/element-utils.ts index 0325ca90..a167e548 100644 --- a/apps/web/src/lib/timeline/element-utils.ts +++ b/apps/web/src/lib/timeline/element-utils.ts @@ -2,6 +2,8 @@ import { DEFAULT_TEXT_ELEMENT } from "@/constants/text-constants"; import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; import type { CreateTimelineElement, + CreateVideoElement, + CreateImageElement, CreateStickerElement, CreateUploadAudioElement, CreateLibraryAudioElement, @@ -165,6 +167,57 @@ export function buildStickerElement({ }; } +export function buildVideoElement({ + mediaId, + name, + duration, + startTime, +}: { + mediaId: string; + name: string; + duration: number; + startTime: number; +}): CreateVideoElement { + return { + type: "video", + mediaId, + name, + duration, + startTime, + trimStart: 0, + trimEnd: 0, + muted: false, + hidden: false, + transform: { scale: 1, position: { x: 0, y: 0 }, rotate: 0 }, + opacity: 1, + }; +} + +export function buildImageElement({ + mediaId, + name, + duration, + startTime, +}: { + mediaId: string; + name: string; + duration: number; + startTime: number; +}): CreateImageElement { + return { + type: "image", + mediaId, + name, + duration, + startTime, + trimStart: 0, + trimEnd: 0, + hidden: false, + transform: { scale: 1, position: { x: 0, y: 0 }, rotate: 0 }, + opacity: 1, + }; +} + export function buildUploadAudioElement({ mediaId, name,