mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(studio): address timeline PR review — drop dead code, add fadeIn keyframes, compSrc test
This commit is contained in:
@@ -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");
|
||||
});
|
||||
});
|
||||
@@ -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<string, string>;
|
||||
@@ -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,
|
||||
|
||||
@@ -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 && (
|
||||
<div
|
||||
className="absolute inset-0 flex"
|
||||
style={{ animation: "fadeIn 200ms ease-out", mixBlendMode: "lighten" }}
|
||||
style={{ animation: "hf-thumb-fade 200ms ease-out", mixBlendMode: "lighten" }}
|
||||
>
|
||||
{Array.from({ length: frameCount }).map((_, i) => (
|
||||
<div
|
||||
|
||||
@@ -35,17 +35,13 @@ export interface TimelineTheme {
|
||||
clipRadius: string;
|
||||
}
|
||||
|
||||
const UNIFIED_STYLE: TimelineTrackStyle = {
|
||||
const TRACK_STYLE: TimelineTrackStyle = {
|
||||
clip: "#1c2028",
|
||||
accent: "#3CE6AC",
|
||||
label: "#dde1e8",
|
||||
iconBackground: "rgba(255,255,255,0.06)",
|
||||
};
|
||||
|
||||
function createTrackStyle(_tag: string): TimelineTrackStyle {
|
||||
return UNIFIED_STYLE;
|
||||
}
|
||||
|
||||
export const defaultTimelineTheme: TimelineTheme = {
|
||||
shellBackground: "#0A0A0B",
|
||||
shellBorder: "rgba(255,255,255,0.05)",
|
||||
@@ -74,16 +70,8 @@ export const defaultTimelineTheme: TimelineTheme = {
|
||||
clipRadius: "6px",
|
||||
};
|
||||
|
||||
export function getTimelineTrackStyle(tag: string): TimelineTrackStyle {
|
||||
const normalized = tag.toLowerCase();
|
||||
if (
|
||||
normalized.startsWith("h") &&
|
||||
normalized.length === 2 &&
|
||||
"123456".includes(normalized[1] ?? "")
|
||||
) {
|
||||
return createTrackStyle("h1");
|
||||
}
|
||||
return createTrackStyle(normalized);
|
||||
export function getTimelineTrackStyle(_tag: string): TimelineTrackStyle {
|
||||
return TRACK_STYLE;
|
||||
}
|
||||
|
||||
export function getClipHandleOpacity({
|
||||
|
||||
@@ -152,6 +152,11 @@ body {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
@keyframes hf-thumb-fade {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.hf-loader-progress__fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
Reference in New Issue
Block a user