import { ScreenElement } from './ScreenElement'; import { HighlightOverlay } from './HighlightOverlay'; import { SpotlightOverlay } from './SpotlightOverlay'; import { LaserOverlay } from './LaserOverlay'; import { useSlideBackgroundStyle } from '@/lib/hooks/use-slide-background-style'; import { useCanvasStore } from '@/lib/store'; import { useSceneSelector } from '@/lib/contexts/scene-context'; import { findElementGeometry } from '@/lib/utils/geometry'; import type { SlideContent } from '@/lib/types/stage'; import type { PPTElement, SlideBackground } from '@/lib/types/slides'; import type { PercentageGeometry } from '@/lib/types/action'; import { useViewportSize } from './Canvas/hooks/useViewportSize'; import { useRef, useMemo } from 'react'; import { AnimatePresence } from 'motion/react'; export function ScreenCanvas() { const canvasScale = useCanvasStore.use.canvasScale(); const elements = useSceneSelector( (content) => content.canvas.elements, ); const canvasRef = useRef(null); // Viewport size and positioning const { viewportStyles } = useViewportSize(canvasRef); // Get background style const background = useSceneSelector( (content) => content.canvas.background, ); const { backgroundStyle } = useSlideBackgroundStyle(background); // Get visual effect state const laserElementId = useCanvasStore.use.laserElementId(); const laserOptions = useCanvasStore.use.laserOptions(); const zoomTarget = useCanvasStore.use.zoomTarget(); // Compute laser pointer geometry const laserGeometry = useMemo(() => { if (!laserElementId) return null; const element = elements.find((el) => el.id === laserElementId); if (!element) return null; return findElementGeometry( { type: 'slide', content: { canvas: { elements } } } as Record, laserElementId, ); }, [laserElementId, elements]); // Compute zoom target geometry const zoomGeometry = useMemo(() => { if (!zoomTarget) return null; const element = elements.find((el) => el.id === zoomTarget.elementId); if (!element) return null; return findElementGeometry( { type: 'slide', content: { canvas: { elements } } } as Record, zoomTarget.elementId, ); }, [zoomTarget, elements]); return (
{/* Background layer */}
{/* Content layer - scaled */}
{elements.map((element, index) => ( ))} {/* Highlight overlay - stacked above elements */}
{/* Spotlight overlay - covers the entire slide, positioned via DOM measurement */} {/* Visual effects layer - outside the scale layer, using percentage coordinates */}
{/* Laser pointer overlay */} {laserElementId && laserGeometry && ( )}
); }