From 3e89d2998588f8e35c524e523ba2ee853f0f6475 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Mon, 20 Apr 2026 11:31:17 +0200 Subject: refactor: restructure files to their domains, new preview overlay system, and dep graph --- apps/web/src/lib/clipboard/handlers/elements.ts | 48 ------- apps/web/src/lib/clipboard/handlers/index.ts | 49 ------- apps/web/src/lib/clipboard/handlers/keyframes.ts | 170 ----------------------- apps/web/src/lib/clipboard/index.ts | 2 - apps/web/src/lib/clipboard/types.ts | 79 ----------- 5 files changed, 348 deletions(-) delete mode 100644 apps/web/src/lib/clipboard/handlers/elements.ts delete mode 100644 apps/web/src/lib/clipboard/handlers/index.ts delete mode 100644 apps/web/src/lib/clipboard/handlers/keyframes.ts delete mode 100644 apps/web/src/lib/clipboard/index.ts delete mode 100644 apps/web/src/lib/clipboard/types.ts (limited to 'apps/web/src/lib/clipboard') diff --git a/apps/web/src/lib/clipboard/handlers/elements.ts b/apps/web/src/lib/clipboard/handlers/elements.ts deleted file mode 100644 index 1b58ac78..00000000 --- a/apps/web/src/lib/clipboard/handlers/elements.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { PasteCommand } from "@/lib/commands/timeline"; -import type { ClipboardHandler } from "../types"; - -export const ElementsClipboardHandler = { - type: "elements", - - canCopy({ selectedElements }) { - return selectedElements.length > 0; - }, - - copy({ editor, selectedElements }) { - if (selectedElements.length === 0) { - return null; - } - - const results = editor.timeline.getElementsWithTracks({ - elements: selectedElements, - }); - const items = results.map(({ track, element }) => { - const { id: _elementId, ...elementWithoutId } = element; - return { - trackId: track.id, - trackType: track.type, - element: elementWithoutId, - }; - }); - - if (items.length === 0) { - return null; - } - - return { - type: "elements", - items, - }; - }, - - paste(entry, context) { - if (entry.items.length === 0) { - return null; - } - - return new PasteCommand({ - time: context.time, - clipboardItems: entry.items, - }); - }, -} satisfies ClipboardHandler<"elements">; diff --git a/apps/web/src/lib/clipboard/handlers/index.ts b/apps/web/src/lib/clipboard/handlers/index.ts deleted file mode 100644 index 29d4d1d0..00000000 --- a/apps/web/src/lib/clipboard/handlers/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { - ClipboardEntry, - ClipboardEntryType, - ClipboardHandler, - ClipboardHandlerMap, - CopyContext, - PasteContext, -} from "../types"; -import { ElementsClipboardHandler } from "./elements"; -import { KeyframesClipboardHandler } from "./keyframes"; - -export const clipboardHandlers = { - elements: ElementsClipboardHandler, - keyframes: KeyframesClipboardHandler, -} satisfies ClipboardHandlerMap; - -export const clipboardCopyHandlers = [ - KeyframesClipboardHandler, - ElementsClipboardHandler, -] as const satisfies readonly ClipboardHandler[]; - -export function copyClipboardEntry({ - context, -}: { - context: CopyContext; -}): ClipboardEntry | null { - for (const handler of clipboardCopyHandlers) { - if (!handler.canCopy(context)) { - continue; - } - - return handler.copy(context); - } - - return null; -} - -export function buildPasteClipboardCommand({ - entry, - context, -}: { - entry: ClipboardEntry; - context: PasteContext; -}) { - const handler = clipboardHandlers[entry.type] as ClipboardHandler< - typeof entry.type - >; - return handler.paste(entry as never, context); -} diff --git a/apps/web/src/lib/clipboard/handlers/keyframes.ts b/apps/web/src/lib/clipboard/handlers/keyframes.ts deleted file mode 100644 index b746c179..00000000 --- a/apps/web/src/lib/clipboard/handlers/keyframes.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { getKeyframeById } from "@/lib/animation"; -import type { SelectedKeyframeRef } from "@/lib/animation/types"; -import type { TimelineElement } from "@/lib/timeline"; -import { PasteKeyframesCommand } from "@/lib/commands/timeline"; -import type { - ClipboardHandler, - KeyframeClipboardCurvePatch, - KeyframeClipboardItem, -} from "../types"; - -function resolveSingleSourceElement({ - selectedKeyframes, -}: { - selectedKeyframes: SelectedKeyframeRef[]; -}) { - const firstKeyframe = selectedKeyframes[0]; - if (!firstKeyframe) { - return null; - } - - const sourceElement = { - trackId: firstKeyframe.trackId, - elementId: firstKeyframe.elementId, - }; - const isSingleSource = selectedKeyframes.every( - (keyframe) => - keyframe.trackId === sourceElement.trackId && - keyframe.elementId === sourceElement.elementId, - ); - - return isSingleSource ? sourceElement : null; -} - -function getCurvePatches({ - element, - propertyPath, - keyframeId, -}: { - element: TimelineElement; - propertyPath: KeyframeClipboardItem["propertyPath"]; - keyframeId: string; -}): KeyframeClipboardCurvePatch[] { - const binding = element.animations?.bindings[propertyPath]; - if (!binding) { - return []; - } - - return binding.components.flatMap((component) => { - const channel = element.animations?.channels[component.channelId]; - if (channel?.kind !== "scalar") { - return []; - } - - const keyframe = channel.keys.find( - (candidate) => candidate.id === keyframeId, - ); - if (!keyframe) { - return []; - } - - return [ - { - componentKey: component.key, - patch: { - leftHandle: keyframe.leftHandle ?? null, - rightHandle: keyframe.rightHandle ?? null, - segmentToNext: keyframe.segmentToNext, - tangentMode: keyframe.tangentMode, - }, - }, - ]; - }); -} - -function buildClipboardItem({ - element, - propertyPath, - keyframeId, -}: { - element: TimelineElement; - propertyPath: KeyframeClipboardItem["propertyPath"]; - keyframeId: string; -}): (Omit & { time: number }) | null { - const keyframe = getKeyframeById({ - animations: element.animations, - propertyPath, - keyframeId, - }); - if (!keyframe) { - return null; - } - - return { - propertyPath, - time: keyframe.time, - value: keyframe.value, - interpolation: keyframe.interpolation, - curvePatches: getCurvePatches({ - element, - propertyPath, - keyframeId, - }), - }; -} - -export const KeyframesClipboardHandler = { - type: "keyframes", - - canCopy({ selectedKeyframes }) { - return selectedKeyframes.length > 0; - }, - - copy({ editor, selectedKeyframes }) { - const sourceElement = resolveSingleSourceElement({ selectedKeyframes }); - if (!sourceElement) { - return null; - } - - const [result] = editor.timeline.getElementsWithTracks({ - elements: [sourceElement], - }); - if (!result) { - return null; - } - - const rawItems = selectedKeyframes.flatMap((keyframeRef) => { - const item = buildClipboardItem({ - element: result.element, - propertyPath: keyframeRef.propertyPath, - keyframeId: keyframeRef.keyframeId, - }); - return item ? [item] : []; - }); - if (rawItems.length === 0) { - return null; - } - - const minTime = Math.min(...rawItems.map((item) => item.time)); - const items = rawItems - .map(({ time, ...item }) => ({ - ...item, - timeOffset: time - minTime, - })) - .sort( - (left, right) => - left.timeOffset - right.timeOffset || - left.propertyPath.localeCompare(right.propertyPath), - ); - - return { - type: "keyframes", - sourceElement, - items, - }; - }, - - paste(entry, { selectedElements, time }) { - const targetElement = selectedElements[0]; - if (!targetElement || entry.items.length === 0) { - return null; - } - - return new PasteKeyframesCommand({ - trackId: targetElement.trackId, - elementId: targetElement.elementId, - time, - clipboardItems: entry.items, - }); - }, -} satisfies ClipboardHandler<"keyframes">; diff --git a/apps/web/src/lib/clipboard/index.ts b/apps/web/src/lib/clipboard/index.ts deleted file mode 100644 index 76d5bddf..00000000 --- a/apps/web/src/lib/clipboard/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./types"; -export * from "./handlers"; diff --git a/apps/web/src/lib/clipboard/types.ts b/apps/web/src/lib/clipboard/types.ts deleted file mode 100644 index 41e107ef..00000000 --- a/apps/web/src/lib/clipboard/types.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { EditorCore } from "@/core"; -import type { - AnimationInterpolation, - AnimationPath, - AnimationValue, - ScalarCurveKeyframePatch, - SelectedKeyframeRef, -} from "@/lib/animation/types"; -import type { Command } from "@/lib/commands/base-command"; -import type { - CreateTimelineElement, - ElementRef, - TrackType, -} from "@/lib/timeline"; - -export interface ElementClipboardItem { - trackId: string; - trackType: TrackType; - element: CreateTimelineElement; -} - -export interface KeyframeClipboardCurvePatch { - componentKey: string; - patch: ScalarCurveKeyframePatch; -} - -export interface KeyframeClipboardItem { - propertyPath: AnimationPath; - timeOffset: number; - value: AnimationValue; - interpolation: AnimationInterpolation; - curvePatches: KeyframeClipboardCurvePatch[]; -} - -export interface ElementsClipboardEntry { - type: "elements"; - items: ElementClipboardItem[]; -} - -export interface KeyframesClipboardEntry { - type: "keyframes"; - sourceElement: ElementRef; - items: KeyframeClipboardItem[]; -} - -export interface ClipboardEntryByType { - elements: ElementsClipboardEntry; - keyframes: KeyframesClipboardEntry; -} - -export type ClipboardEntry = ClipboardEntryByType[keyof ClipboardEntryByType]; -export type ClipboardEntryType = keyof ClipboardEntryByType; - -export interface CopyContext { - editor: EditorCore; - selectedElements: ElementRef[]; - selectedKeyframes: SelectedKeyframeRef[]; -} - -export interface PasteContext { - editor: EditorCore; - selectedElements: ElementRef[]; - selectedKeyframes: SelectedKeyframeRef[]; - time: number; -} - -export interface ClipboardHandler { - type: TType; - canCopy(context: CopyContext): boolean; - copy(context: CopyContext): ClipboardEntryByType[TType] | null; - paste( - entry: ClipboardEntryByType[TType], - context: PasteContext, - ): Command | null; -} - -export type ClipboardHandlerMap = { - [TType in ClipboardEntryType]: ClipboardHandler; -}; -- cgit v1.3.1