| |
| |
| |
| |
| |
| |
| |
|
|
| import type { SlideContent } from '@/lib/types/stage'; |
| import type { SlideTheme, SlideBackground } from '@/lib/types/slides'; |
| import { useCanvasStore } from '@/lib/store/canvas'; |
| import type { StageStore, APIResult, HighlightOptions, SpotlightOptions } from './stage-api-types'; |
| import { getScene } from './stage-api-defaults'; |
|
|
| |
| |
| |
| |
| |
| |
| export function createCanvasAPI(store: StageStore) { |
| return { |
| |
| |
| |
| |
| |
| |
| |
| setBackground(sceneId: string, background: SlideBackground): APIResult<boolean> { |
| try { |
| const state = store.getState(); |
| const scene = getScene(state.scenes, sceneId); |
|
|
| if (!scene || scene.type !== 'slide') { |
| return { success: false, error: 'Invalid scene' }; |
| } |
|
|
| const content = scene.content as SlideContent; |
|
|
| const newScenes = state.scenes.map((s) => { |
| if (s.id === sceneId) { |
| return { |
| ...s, |
| content: { |
| ...content, |
| canvas: { |
| ...content.canvas, |
| background, |
| }, |
| }, |
| updatedAt: Date.now(), |
| }; |
| } |
| return s; |
| }); |
|
|
| store.setState({ scenes: newScenes }); |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| setTheme(sceneId: string, theme: Partial<SlideTheme>): APIResult<boolean> { |
| try { |
| const state = store.getState(); |
| const scene = getScene(state.scenes, sceneId); |
|
|
| if (!scene || scene.type !== 'slide') { |
| return { success: false, error: 'Invalid scene' }; |
| } |
|
|
| const content = scene.content as SlideContent; |
|
|
| const newScenes = state.scenes.map((s) => { |
| if (s.id === sceneId) { |
| return { |
| ...s, |
| content: { |
| ...content, |
| canvas: { |
| ...content.canvas, |
| theme: { |
| ...content.canvas.theme, |
| ...theme, |
| }, |
| }, |
| }, |
| updatedAt: Date.now(), |
| }; |
| } |
| return s; |
| }); |
|
|
| store.setState({ scenes: newScenes }); |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| highlight( |
| sceneId: string, |
| elementId: string, |
| options: HighlightOptions = {}, |
| ): APIResult<boolean> { |
| const { duration, color = '#ff6b6b', style = 'outline' } = options; |
|
|
| try { |
| |
| |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.setHighlight([elementId], { |
| color, |
| opacity: style === 'fill' ? 0.3 : 0.5, |
| borderWidth: 3, |
| animated: true, |
| }); |
|
|
| |
| if (duration) { |
| setTimeout(() => { |
| canvasStore.clearHighlight(); |
| }, duration); |
| } |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| spotlight( |
| sceneId: string, |
| elementId: string, |
| options: SpotlightOptions = {}, |
| ): APIResult<boolean> { |
| try { |
| |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.setSpotlight(elementId, options); |
|
|
| |
| if (options.duration) { |
| setTimeout(() => { |
| canvasStore.clearSpotlight(); |
| }, options.duration); |
| } |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| clearHighlights(_sceneId: string): APIResult<boolean> { |
| try { |
| |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.clearHighlight(); |
| canvasStore.clearSpotlight(); |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| clearSpotlight(_sceneId?: string): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.clearSpotlight(); |
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| setSpotlightPercentage( |
| sceneId: string, |
| elementId: string, |
| geometry: import('@/lib/types/action').PercentageGeometry, |
| options: SpotlightOptions = {}, |
| ): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.setSpotlightPercentage(elementId, geometry, options); |
|
|
| if (options.duration) { |
| setTimeout(() => { |
| canvasStore.clearSpotlight(); |
| }, options.duration); |
| } |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| setLaser( |
| sceneId: string, |
| elementId: string, |
| geometry: import('@/lib/types/action').PercentageGeometry, |
| options: import('@/lib/store/canvas').LaserOptions = {}, |
| ): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.setLaser(elementId, options); |
|
|
| if (options.duration) { |
| setTimeout(() => { |
| canvasStore.clearLaser(); |
| }, options.duration); |
| } |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| clearLaser(_sceneId: string): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.clearLaser(); |
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| setZoom( |
| sceneId: string, |
| elementId: string, |
| geometry: import('@/lib/types/action').PercentageGeometry, |
| scale: number, |
| ): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.setZoom(elementId, scale); |
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| clearZoom(_sceneId: string): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.clearZoom(); |
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| clearAllEffects(_sceneId: string): APIResult<boolean> { |
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.clearAllEffects(); |
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| highlightMultiple( |
| sceneId: string, |
| elementIds: string[], |
| options: HighlightOptions = {}, |
| ): APIResult<boolean> { |
| const { duration, color = '#ff6b6b' } = options; |
|
|
| try { |
| const canvasStore = useCanvasStore.getState(); |
| canvasStore.setHighlight(elementIds, { |
| color, |
| opacity: 0.3, |
| borderWidth: 3, |
| animated: true, |
| }); |
|
|
| if (duration) { |
| setTimeout(() => { |
| canvasStore.clearHighlight(); |
| }, duration); |
| } |
|
|
| return { success: true, data: true }; |
| } catch (error) { |
| return { success: false, error: String(error) }; |
| } |
| }, |
| }; |
| } |
|
|