From 36898f7681c703b1345ddacc9fc7c941e2db9876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Wed, 20 May 2026 23:28:09 -0400 Subject: [PATCH] =?UTF-8?q?fix(studio):=20address=20timeline=20PR=20review?= =?UTF-8?q?=20=E2=80=94=20drop=20dead=20code,=20add=20fadeIn=20keyframes,?= =?UTF-8?q?=20compSrc=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/hooks/useRenderClipContent.test.ts | 50 +++++++++++++++++++ .../studio/src/hooks/useRenderClipContent.ts | 33 +++++++----- .../components/CompositionThumbnail.tsx | 4 +- .../src/player/components/timelineTheme.ts | 18 ++----- packages/studio/src/styles/studio.css | 5 ++ 5 files changed, 80 insertions(+), 30 deletions(-) create mode 100644 packages/studio/src/hooks/useRenderClipContent.test.ts diff --git a/packages/studio/src/hooks/useRenderClipContent.test.ts b/packages/studio/src/hooks/useRenderClipContent.test.ts new file mode 100644 index 000000000..1239ecbc3 --- /dev/null +++ b/packages/studio/src/hooks/useRenderClipContent.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "vitest"; +import { normalizeCompositionSrc } from "./useRenderClipContent"; + +describe("normalizeCompositionSrc", () => { + const origin = "http://localhost:5190"; + const pid = "my-project"; + + it("strips absolute preview URL to relative path", () => { + const result = normalizeCompositionSrc( + "http://localhost:5190/api/projects/my-project/preview/compositions/intro.html", + pid, + origin, + ); + expect(result).toBe("compositions/intro.html"); + }); + + it("preserves already-relative paths", () => { + const result = normalizeCompositionSrc("compositions/intro.html", pid, origin); + expect(result).toBe("compositions/intro.html"); + }); + + it("preserves absolute URLs from different origins", () => { + const result = normalizeCompositionSrc( + "https://cdn.example.com/compositions/intro.html", + pid, + origin, + ); + expect(result).toBe("https://cdn.example.com/compositions/intro.html"); + }); + + it("preserves absolute URLs for different projects", () => { + const result = normalizeCompositionSrc( + "http://localhost:5190/api/projects/other-project/preview/compositions/intro.html", + pid, + origin, + ); + expect(result).toBe( + "http://localhost:5190/api/projects/other-project/preview/compositions/intro.html", + ); + }); + + it("handles nested composition paths", () => { + const result = normalizeCompositionSrc( + "http://localhost:5190/api/projects/my-project/preview/compositions/scenes/hero.html", + pid, + origin, + ); + expect(result).toBe("compositions/scenes/hero.html"); + }); +}); diff --git a/packages/studio/src/hooks/useRenderClipContent.ts b/packages/studio/src/hooks/useRenderClipContent.ts index 53f334fb5..f065e8276 100644 --- a/packages/studio/src/hooks/useRenderClipContent.ts +++ b/packages/studio/src/hooks/useRenderClipContent.ts @@ -5,6 +5,23 @@ import type { TimelineElement } from "../player"; import { AudioWaveform } from "../player/components/AudioWaveform"; import { getTimelineElementLabel } from "../utils/studioHelpers"; +export function normalizeCompositionSrc( + compSrc: string, + projectId: string, + origin: string, +): string { + try { + const parsed = new URL(compSrc, origin); + const previewPrefix = `/api/projects/${projectId}/preview/`; + if (parsed.pathname.startsWith(previewPrefix)) { + return parsed.pathname.slice(previewPrefix.length); + } + } catch { + // already relative + } + return compSrc; +} + interface UseRenderClipContentOptions { projectIdRef: { current: string | null }; compIdToSrc: Map; @@ -25,15 +42,7 @@ export function useRenderClipContent({ let compSrc = el.compositionSrc; if (compSrc) { - try { - const parsed = new URL(compSrc, window.location.origin); - const previewPrefix = `/api/projects/${pid}/preview/`; - if (parsed.pathname.startsWith(previewPrefix)) { - compSrc = parsed.pathname.slice(previewPrefix.length); - } - } catch { - // already relative - } + compSrc = normalizeCompositionSrc(compSrc, pid, window.location.origin); } if (compSrc && compIdToSrc.size > 0) { const resolved = @@ -50,7 +59,7 @@ export function useRenderClipContent({ previewUrl: `/api/projects/${pid}/preview/comp/${compSrc}`, label: getTimelineElementLabel(el), labelColor: style.label, - accentColor: style.clip, + seekTime: 0, duration: el.duration, }); @@ -63,7 +72,7 @@ export function useRenderClipContent({ previewUrl: activePreviewUrl, label: getTimelineElementLabel(el), labelColor: style.label, - accentColor: style.clip, + selector: el.selector, selectorIndex: el.selectorIndex, seekTime: el.start, @@ -119,7 +128,7 @@ export function useRenderClipContent({ previewUrl: `/api/projects/${pid}/preview`, label: getTimelineElementLabel(el), labelColor: style.label, - accentColor: style.clip, + selector: el.selector, selectorIndex: el.selectorIndex, seekTime: el.start, diff --git a/packages/studio/src/player/components/CompositionThumbnail.tsx b/packages/studio/src/player/components/CompositionThumbnail.tsx index 8876be1b1..605d56070 100644 --- a/packages/studio/src/player/components/CompositionThumbnail.tsx +++ b/packages/studio/src/player/components/CompositionThumbnail.tsx @@ -5,7 +5,6 @@ interface CompositionThumbnailProps { previewUrl: string; label: string; labelColor: string; - accentColor?: string; selector?: string; selectorIndex?: number; seekTime?: number; @@ -52,7 +51,6 @@ export const CompositionThumbnail = memo(function CompositionThumbnail({ previewUrl, label, labelColor, - accentColor: _accentColor = "#6B7280", selector, selectorIndex, seekTime = 2, @@ -112,7 +110,7 @@ export const CompositionThumbnail = memo(function CompositionThumbnail({ {loaded && (
{Array.from({ length: frameCount }).map((_, i) => (