mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
fix(studio): hide the Slideshow tab and panel for non-slideshow compositions
The Slideshow tab rendered unconditionally, showing the branching editor for any composition regardless of whether it was actually a slideshow — a plain video comp offered a tab with nothing meaningful to edit. Gate it on the composition carrying the slideshow JSON island (<script type="application/hyperframes-slideshow+json">), the same definitive marker the CLI's `present` command already requires (it refuses to run without one). Presence-only, not full manifest validation, so a malformed island still surfaces the tab rather than disappearing entirely. Also bounce rightPanelTab off "slideshow" to "renders" if the active composition stops being a slideshow while that tab is open (e.g. switching files), since its button would otherwise vanish with no way back to it. Extracted the gating + scene-list derivation into useSlideshowTabState to keep StudioRightPanel.tsx under the 600-LOC gate.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { useEffect, useMemo, type MutableRefObject } from "react";
|
||||
import { slideshowIslandRegex } from "@hyperframes/core/slideshow";
|
||||
import type { SceneInfo } from "../components/panels/SlideshowPanel";
|
||||
import type { IframeWindow } from "../player/lib/playbackTypes";
|
||||
import type { RightPanelTab } from "../utils/studioHelpers";
|
||||
|
||||
/**
|
||||
* Derives whether the currently-edited composition is a slideshow (carries
|
||||
* the slideshow JSON island — the same definitive marker the CLI's `present`
|
||||
* command requires; it refuses to run without one) and the live scene list
|
||||
* for the Slideshow panel, and bounces `rightPanelTab` off "slideshow" the
|
||||
* moment it stops applying (e.g. the user switches to a non-slideshow file
|
||||
* while that tab was open) so the panel never shows a dangling active tab
|
||||
* whose button is no longer even rendered.
|
||||
*
|
||||
* Extracted from StudioRightPanel to keep that file under the 600-LOC gate.
|
||||
*/
|
||||
export function useSlideshowTabState(params: {
|
||||
editingFileContent: string | null | undefined;
|
||||
previewIframeRef: MutableRefObject<HTMLIFrameElement | null>;
|
||||
refreshKey: number;
|
||||
rightPanelTab: RightPanelTab;
|
||||
setRightPanelTab: (tab: RightPanelTab) => void;
|
||||
}): { isSlideshowComposition: boolean; slideshowScenes: SceneInfo[] } {
|
||||
const { editingFileContent, previewIframeRef, refreshKey, rightPanelTab, setRightPanelTab } =
|
||||
params;
|
||||
|
||||
// Presence-only (not full manifest validation): a malformed island should
|
||||
// still surface the Slideshow tab so the user can see/fix it, rather than
|
||||
// making the whole panel disappear.
|
||||
const isSlideshowComposition = useMemo(
|
||||
() => Boolean(editingFileContent && slideshowIslandRegex("i").test(editingFileContent)),
|
||||
[editingFileContent],
|
||||
);
|
||||
|
||||
// Derive scene list from the live clip manifest in the preview iframe.
|
||||
const slideshowScenes = useMemo<SceneInfo[]>(() => {
|
||||
try {
|
||||
const win = previewIframeRef.current?.contentWindow as IframeWindow | null;
|
||||
return (win?.__clipManifest?.scenes ?? []).map((s) => ({
|
||||
id: s.id,
|
||||
label: s.label,
|
||||
start: s.start,
|
||||
duration: s.duration,
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [previewIframeRef, rightPanelTab, refreshKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (rightPanelTab === "slideshow" && !isSlideshowComposition) {
|
||||
setRightPanelTab("renders");
|
||||
}
|
||||
}, [rightPanelTab, isSlideshowComposition, setRightPanelTab]);
|
||||
|
||||
return { isSlideshowComposition, slideshowScenes };
|
||||
}
|
||||
Reference in New Issue
Block a user