/** * SceneSwitcher Component * * Horizontal row of scene buttons with active indicator. * Click to switch scenes, + button to create new scene. */ import React, { useState, useCallback } from "react"; import type { Scene, TransitionConfig, TransitionType, } from "@livepeer-frameworks/streamcrafter-core"; import { useStudioTranslate } from "../context/StudioI18nContext"; export interface SceneSwitcherProps { scenes: Scene[]; activeSceneId: string | null; onSceneSelect: (sceneId: string) => void; onSceneCreate?: () => void; onSceneDelete?: (sceneId: string) => void; onTransitionTo?: (sceneId: string, transition: TransitionConfig) => Promise; transitionConfig?: TransitionConfig; showTransitionControls?: boolean; className?: string; } const DEFAULT_TRANSITION: TransitionConfig = { type: "fade", durationMs: 500, easing: "ease-in-out", }; export function SceneSwitcher({ scenes, activeSceneId, onSceneSelect, onSceneCreate, onSceneDelete, onTransitionTo, transitionConfig = DEFAULT_TRANSITION, showTransitionControls = true, className = "", }: SceneSwitcherProps) { const t = useStudioTranslate(); const [selectedTransition, setSelectedTransition] = useState( transitionConfig.type ); const [transitionDuration, setTransitionDuration] = useState(transitionConfig.durationMs); const [isTransitioning, setIsTransitioning] = useState(false); const handleSceneClick = useCallback( async (sceneId: string) => { if (sceneId === activeSceneId || isTransitioning) return; if (onTransitionTo) { setIsTransitioning(true); try { await onTransitionTo(sceneId, { type: selectedTransition, durationMs: transitionDuration, easing: transitionConfig.easing, }); } finally { setIsTransitioning(false); } } else { onSceneSelect(sceneId); } }, [ activeSceneId, isTransitioning, onTransitionTo, onSceneSelect, selectedTransition, transitionDuration, transitionConfig.easing, ] ); const handleDeleteClick = useCallback( (e: React.MouseEvent, sceneId: string) => { e.stopPropagation(); if (scenes.length <= 1) return; // Don't delete last scene onSceneDelete?.(sceneId); }, [scenes.length, onSceneDelete] ); return (
{t("scenes")} {showTransitionControls && (
setTransitionDuration(Number(e.target.value))} min={0} max={3000} step={100} title={t("transitionDuration")} /> ms
)}
{scenes.map((scene) => (
handleSceneClick(scene.id)} style={{ backgroundColor: scene.backgroundColor }} > {scene.name} {scene.layers.length} layers {onSceneDelete && scenes.length > 1 && scene.id !== activeSceneId && ( )}
))} {onSceneCreate && ( )}
); } export default SceneSwitcher;