import { useCallback } from 'react'; import { motion, AnimatePresence } from 'motion/react'; import { Play } from 'lucide-react'; import { cn } from '@/lib/utils'; import { SceneRenderer } from '@/components/stage/scene-renderer'; import { SceneProvider } from '@/lib/contexts/scene-context'; import { Whiteboard } from '@/components/whiteboard'; import { CanvasToolbar } from '@/components/canvas/canvas-toolbar'; import type { CanvasToolbarProps } from '@/components/canvas/canvas-toolbar'; import type { Scene, StageMode } from '@/lib/types/stage'; import { useI18n } from '@/lib/hooks/use-i18n'; import { ClassroomCompletePageConnected } from '@/components/scene-renderers/classroom-complete'; interface CanvasAreaProps extends CanvasToolbarProps { readonly currentScene: Scene | null; readonly mode: StageMode; readonly hideToolbar?: boolean; readonly isPendingScene?: boolean; readonly isCourseComplete?: boolean; readonly isGenerationFailed?: boolean; readonly onRetryGeneration?: () => void; } export function CanvasArea({ currentScene, currentSceneIndex, scenesCount, mode, engineState, isLiveSession, whiteboardOpen, sidebarCollapsed, chatCollapsed, onToggleSidebar, onToggleChat, onPrevSlide, onNextSlide, onPlayPause, onWhiteboardClose, isPresenting, onTogglePresentation, showStopDiscussion, onStopDiscussion, hideToolbar, isPendingScene, isCourseComplete, isGenerationFailed, onRetryGeneration, }: CanvasAreaProps) { const { t } = useI18n(); const showControls = mode === 'playback' && !whiteboardOpen; const showPlayHint = showControls && engineState !== 'playing' && currentScene?.type === 'slide' && !isLiveSession && !isPendingScene; const handleSlideClick = useCallback( (e: React.MouseEvent) => { if (!showControls || isLiveSession || currentScene?.type !== 'slide') return; // Don't trigger page play/pause when clicking inside a video element's visual area. // Video elements may be visually covered by other slide elements (e.g. text), // so we check click coordinates against all video element bounding rects. const container = e.currentTarget as HTMLElement; const videoEls = container.querySelectorAll('[data-video-element]'); for (const el of videoEls) { const rect = el.getBoundingClientRect(); if ( e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom ) { return; } } onPlayPause(); }, [showControls, isLiveSession, onPlayPause, currentScene?.type], ); return (
{/* Slide area — takes remaining space */}
{/* Whiteboard Layer */}
{/* Scene Content */} {currentScene && !whiteboardOpen && (
)} {/* Pending Scene Loading / Completion Overlay */} {isPendingScene && !currentScene && isCourseComplete && ( )} {isPendingScene && !currentScene && !isCourseComplete && ( {isGenerationFailed ? (
{t('stage.generationFailed')} {onRetryGeneration && ( )}
) : (
{/* Spinner */}
{/* Text */} {t('stage.generatingNextPage')}
)} )} {/* Scene Number Badge */} {currentScene && (
{(currentSceneIndex + 1).toString().padStart(2, '0')}
)} {/* Play hint — breathing button when idle or paused (slides only) */} {showPlayHint && ( { e.stopPropagation(); onPlayPause(); }} > )}
{/* ── Canvas Toolbar — in document flow, only when not merged into roundtable ── */} {!hideToolbar && ( )}
); }