feat(studio): slideshow branching editor panel (#1582)

New Slideshow right-panel tab — slide list, inspector (notes + fragment
hold-points), branch tree, hotspot tool — backed by pure manifest-transform
helpers and a debounced SDK persist that writes the JSON island.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-06-19 01:33:31 -07:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 7af3eb8f80
commit 3861e8e9fc
11 changed files with 1936 additions and 7 deletions
@@ -0,0 +1,68 @@
import { useCallback, type MutableRefObject } from "react";
import type { Composition } from "@hyperframes/sdk";
import type { SlideshowManifest } from "@hyperframes/core/slideshow";
import type { EditHistoryKind } from "../utils/editHistory";
import { persistSlideshowManifest } from "../utils/setSlideshowManifest";
export interface UseSlideshowPersistParams {
sdkSession: Composition | null;
activeCompPath: string | null;
readProjectFile: (path: string) => Promise<string>;
writeProjectFile: (path: string, content: string) => Promise<void>;
recordEdit: (entry: {
label: string;
kind: EditHistoryKind;
files: Record<string, { before: string; after: string }>;
}) => Promise<void>;
reloadPreview: () => void;
domEditSaveTimestampRef: MutableRefObject<number>;
/**
* When provided, rapid writes with the same key coalesce through the
* save-queue infra (via recordEdit's coalesceKey) so back-to-back persists
* collapse to a single undo entry rather than polluting history.
* Pass e.g. `"slideshow-notes:" + activeCompPath` for the notes path.
*/
coalesceKey?: string;
}
export function useSlideshowPersist({
sdkSession,
activeCompPath,
readProjectFile,
writeProjectFile,
recordEdit,
reloadPreview,
domEditSaveTimestampRef,
coalesceKey,
}: UseSlideshowPersistParams): (manifest: SlideshowManifest) => Promise<void> {
return useCallback(
async (manifest: SlideshowManifest) => {
if (!sdkSession) return;
const path = activeCompPath ?? "index.html";
const originalContent = await readProjectFile(path);
await persistSlideshowManifest({
manifest,
sdkSession,
originalContent,
targetPath: path,
deps: {
editHistory: { recordEdit },
writeProjectFile,
reloadPreview,
domEditSaveTimestampRef,
},
coalesceKey,
});
},
[
sdkSession,
activeCompPath,
readProjectFile,
writeProjectFile,
recordEdit,
reloadPreview,
domEditSaveTimestampRef,
coalesceKey,
],
);
}