slidecanvas 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/PptEditor.tsx","../src/components/Toolbar.tsx","../src/lib/utils.ts","../src/components/Sidebar.tsx","../src/components/EditorCanvas.tsx","../src/lib/pptx-exporter.ts","../src/lib/pptx-parser.ts","../src/components/PresenterMode.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState, useCallback, useMemo, useEffect } from 'react';\nimport type { Presentation, Slide, SlideElement } from '../lib/types';\nimport { Toolbar } from './Toolbar';\nimport { Sidebar } from './Sidebar';\nimport { EditorCanvas } from './EditorCanvas';\nimport { PptxExporter } from '../lib/pptx-exporter';\nimport { PptxParser } from '../lib/pptx-parser';\nimport { PresenterMode } from './PresenterMode';\nimport { GoogleGenerativeAI } from '@google/generative-ai';\n\ninterface PptEditorProps {\n initialPresentation?: Presentation;\n url?: string;\n appName?: string;\n onChange?: (presentation: Presentation) => void;\n geminiApiKey?: string;\n}\n\nexport const PptEditor: React.FC<PptEditorProps> = ({ initialPresentation, url, appName = 'SlideCanvas', onChange, geminiApiKey }) => {\n const [presentation, setPresentation] = useState<Presentation>(\n initialPresentation || { slides: [{ id: 'slide-1', elements: [] }], layout: { width: 12192000, height: 6858000 } }\n );\n\n const [history, setHistory] = useState<Presentation[]>([]);\n const [redoStack, setRedoStack] = useState<Presentation[]>([]);\n\n const [currentSlideIndex, setCurrentSlideIndex] = useState(0);\n const [selectedElementId, setSelectedElementId] = useState<string | null>(null);\n const [isPreviewMode, setIsPreviewMode] = useState(false);\n const [aiResponse, setAiResponse] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n useEffect(() => {\n if (url) {\n handleLoadPresentation(url);\n }\n }, [url]);\n const [isAiLoading, setIsAiLoading] = useState(false);\n const [lastAiPrompt, setLastAiPrompt] = useState<{ id: string, action: 'shorten' | 'reframe' | 'lengthen' } | null>(null);\n\n\n const currentSlide = presentation.slides[currentSlideIndex];\n\n const selectedElement = useMemo(() => {\n return currentSlide.elements.find(el => el.id === selectedElementId) || null;\n }, [currentSlide, selectedElementId]);\n\n const saveToHistory = useCallback((state: Presentation) => {\n setHistory(prevHistory => [...prevHistory.slice(-19), presentation]);\n setRedoStack([]);\n setPresentation(state);\n onChange?.(state);\n }, [onChange, presentation]);\n\n const undo = () => {\n if (history.length === 0) return;\n const last = history[history.length - 1];\n setRedoStack(prev => [...prev, presentation]);\n setHistory(prev => prev.slice(0, -1));\n setPresentation(last);\n };\n\n const redo = () => {\n if (redoStack.length === 0) return;\n const next = redoStack[redoStack.length - 1];\n setHistory(prev => [...prev, presentation]);\n setRedoStack(prev => prev.slice(0, -1));\n setPresentation(next);\n };\n\n const handleUpdateSlide = useCallback((updates: Partial<Slide>) => {\n setPresentation(prev => {\n const newSlides = [...prev.slides];\n newSlides[currentSlideIndex] = { ...newSlides[currentSlideIndex], ...updates };\n const updated = { ...prev, slides: newSlides };\n\n // Note: We can't call saveToHistory inside here easily without dependency issues, \n // but we can move history logic here if needed or keep it simple for now.\n // For now, let's just make it stable.\n setHistory(h => [...h.slice(-19), prev]);\n setRedoStack([]);\n onChange?.(updated);\n return updated;\n });\n }, [currentSlideIndex, onChange]);\n\n const handleElementUpdate = useCallback((elementId: string, updates: Partial<SlideElement>) => {\n setPresentation(prev => {\n const slide = prev.slides[currentSlideIndex];\n const newElements = slide.elements.map(el =>\n el.id === elementId ? { ...el, ...updates } as SlideElement : el\n );\n const newSlides = [...prev.slides];\n newSlides[currentSlideIndex] = { ...slide, elements: newElements };\n const updated = { ...prev, slides: newSlides };\n onChange?.(updated);\n return updated;\n });\n }, [currentSlideIndex, onChange]);\n\n const handleFormatText = (updates: any) => {\n if (!selectedElementId) return;\n const el = currentSlide.elements.find(e => e.id === selectedElementId);\n if (el) {\n handleElementUpdate(selectedElementId, updates);\n // Explicitly save to history for discrete formatting actions\n const slide = presentation.slides[currentSlideIndex];\n const newElements = slide.elements.map(e => e.id === selectedElementId ? { ...e, ...updates } : e);\n const newSlides = [...presentation.slides];\n newSlides[currentSlideIndex] = { ...slide, elements: newElements };\n saveToHistory({ ...presentation, slides: newSlides });\n }\n };\n\n const handleDeleteElement = useCallback(() => {\n if (!selectedElementId) return;\n const slide = presentation.slides[currentSlideIndex];\n const newElements = slide.elements.filter(el => el.id !== selectedElementId);\n handleUpdateSlide({ elements: newElements });\n setSelectedElementId(null);\n }, [selectedElementId, currentSlideIndex, presentation, handleUpdateSlide]);\n\n const handleAddText = () => {\n const newElement: SlideElement = {\n id: `text-${Date.now()}`,\n type: 'text',\n content: 'New Text',\n x: 100,\n y: 100,\n width: 400,\n height: 100,\n fontSize: 48,\n fontFamily: 'Arial',\n color: '#000000',\n zIndex: currentSlide.elements.length\n };\n handleUpdateSlide({ elements: [...currentSlide.elements, newElement] });\n };\n\n const handleAddImage = (file: File) => {\n const url = URL.createObjectURL(file);\n const id = `img-${Date.now()}`;\n const newElement: SlideElement = {\n id,\n type: 'image',\n src: url,\n x: 100,\n y: 100,\n width: 400,\n height: 250,\n zIndex: currentSlide.elements.length\n };\n handleUpdateSlide({ elements: [...currentSlide.elements, newElement] });\n setSelectedElementId(id);\n };\n\n const handleAddShape = (shapeType: 'rect' | 'ellipse') => {\n const newElement: SlideElement = {\n id: `shape-${Date.now()}`,\n type: 'shape',\n shapeType,\n fill: '#3b82f6',\n x: 200,\n y: 200,\n width: 200,\n height: 200,\n zIndex: currentSlide.elements.length\n };\n handleUpdateSlide({ elements: [...currentSlide.elements, newElement] });\n }\n\n const handleAddSlide = () => {\n const newSlide: Slide = { id: `slide-${Date.now()}`, elements: [] };\n saveToHistory({ ...presentation, slides: [...presentation.slides, newSlide] });\n setCurrentSlideIndex(presentation.slides.length);\n };\n\n const handleDeleteSlide = (index: number) => {\n if (presentation.slides.length <= 1) return;\n\n const newSlides = presentation.slides.filter((_, i) => i !== index);\n saveToHistory({ ...presentation, slides: newSlides });\n\n // Adjust current slide index if needed\n if (index <= currentSlideIndex) {\n setCurrentSlideIndex(Math.max(0, currentSlideIndex - 1));\n }\n };\n\n const handleDuplicateSlide = (index: number) => {\n const slideToClone = presentation.slides[index];\n const newSlide: Slide = {\n ...slideToClone,\n id: `slide-${Date.now()}`,\n elements: slideToClone.elements.map(el => ({\n ...el,\n id: `${el.type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n }))\n };\n const newSlides = [...presentation.slides];\n newSlides.splice(index + 1, 0, newSlide);\n saveToHistory({ ...presentation, slides: newSlides });\n setCurrentSlideIndex(index + 1);\n };\n\n const handleReorderSlides = (oldIndex: number, newIndex: number) => {\n if (oldIndex === newIndex) return;\n const newSlides = [...presentation.slides];\n const [removed] = newSlides.splice(oldIndex, 1);\n newSlides.splice(newIndex, 0, removed);\n\n saveToHistory({ ...presentation, slides: newSlides });\n\n if (currentSlideIndex === oldIndex) {\n setCurrentSlideIndex(newIndex);\n } else if (currentSlideIndex > oldIndex && currentSlideIndex <= newIndex) {\n setCurrentSlideIndex(currentSlideIndex - 1);\n } else if (currentSlideIndex < oldIndex && currentSlideIndex >= newIndex) {\n setCurrentSlideIndex(currentSlideIndex + 1);\n }\n };\n\n const handleApplyLayout = (layoutType: 'title' | 'content' | 'split') => {\n let elements: SlideElement[] = [];\n const timestamp = Date.now();\n\n if (layoutType === 'title') {\n elements = [\n {\n id: `text-title-${timestamp}`,\n type: 'text',\n content: 'Presentation Title',\n x: 100,\n y: 200,\n width: 1000,\n height: 150,\n fontSize: 80,\n fontFamily: 'Inter',\n color: '#000000',\n textAlign: 'center',\n isBold: true,\n zIndex: 0\n },\n {\n id: `text-sub-${timestamp}`,\n type: 'text',\n content: 'Subtitle goes here',\n x: 200,\n y: 380,\n width: 800,\n height: 80,\n fontSize: 36,\n fontFamily: 'Inter',\n color: '#64748b',\n textAlign: 'center',\n zIndex: 1\n }\n ];\n } else if (layoutType === 'content') {\n elements = [\n {\n id: `text-title-${timestamp}`,\n type: 'text',\n content: 'Slide Title',\n x: 60,\n y: 40,\n width: 800,\n height: 80,\n fontSize: 48,\n fontFamily: 'Inter',\n color: '#000000',\n isBold: true,\n zIndex: 0\n },\n {\n id: `text-body-${timestamp}`,\n type: 'text',\n content: '• Add your points here\\n• Press Enter for new line\\n• Use the toolbar to format',\n x: 60,\n y: 150,\n width: 1080,\n height: 480,\n fontSize: 28,\n fontFamily: 'Inter',\n color: '#334155',\n zIndex: 1,\n isBulleted: true\n }\n ];\n } else if (layoutType === 'split') {\n elements = [\n {\n id: `text-title-${timestamp}`,\n type: 'text',\n content: 'Comparison Layout',\n x: 60,\n y: 40,\n width: 1080,\n height: 80,\n fontSize: 48,\n fontFamily: 'Inter',\n color: '#000000',\n isBold: true,\n textAlign: 'center',\n zIndex: 0\n },\n {\n id: `text-left-${timestamp}`,\n type: 'text',\n content: 'Left column content goes here.',\n x: 60,\n y: 180,\n width: 520,\n height: 400,\n fontSize: 24,\n fontFamily: 'Inter',\n color: '#334155',\n zIndex: 1\n },\n {\n id: `text-right-${timestamp}`,\n type: 'text',\n content: 'Right column content goes here.',\n x: 620,\n y: 180,\n width: 520,\n height: 400,\n fontSize: 24,\n fontFamily: 'Inter',\n color: '#334155',\n zIndex: 2\n }\n ];\n }\n\n handleUpdateSlide({ elements });\n };\n\n const handleAiAction = async (id: string, action: 'shorten' | 'reframe' | 'lengthen') => {\n const slide = presentation.slides[currentSlideIndex];\n const element = slide.elements.find(el => el.id === id);\n if (!element || element.type !== 'text') return;\n\n setIsAiLoading(true);\n setAiResponse(null);\n setLastAiPrompt({ id, action });\n\n try {\n if (!geminiApiKey) {\n setAiResponse(\"Gemini API key is missing. Please provide it via the 'geminiApiKey' prop.\");\n setIsAiLoading(false);\n return;\n }\n const genAI = new GoogleGenerativeAI(geminiApiKey);\n const model = genAI.getGenerativeModel({\n model: \"gemini-flash-latest\",\n systemInstruction: \"You are a professional presentation assistant. Your task is to transform slide text according to specific user requests (shorten, reframe, or lengthen). \\n\\nCRITICAL RULES:\\n1. Return ONLY the transformed text. \\n2. Do NOT include any explanations, choices, or conversational fillers.\\n3. Do NOT use markdown formatting (like bolding or headers) unless specifically needed for bullet points.\\n4. If the input text is a title/headline, the output should be a professional title/headline.\\n5. If the input text is a bulleted list, the output MUST be a bulleted list using the same bullet style (e.g., '•').\\n6. Maintain the professional tone of the original presentation.\"\n });\n\n const elementContext = element.fontSize > 32 ? \"Title/Headline\" : \"Body Text/List\";\n const prompt = `Action: ${action.toUpperCase()}\\nText Role: ${elementContext}\\nOriginal Text: \"${element.content}\"\\n\\nTransformed Text:`;\n\n const result = await model.generateContent(prompt);\n const response = await result.response;\n setAiResponse(response.text().trim());\n } catch (error) {\n console.error(\"Gemini AI Error:\", error);\n setAiResponse(\"Error generating response. Please check your API key or connection.\");\n } finally {\n setIsAiLoading(false);\n }\n };\n\n const handleAiResponseAction = (action: 'replace' | 'addBelow' | 'regenerate') => {\n if (!aiResponse || !lastAiPrompt) return;\n\n if (action === 'regenerate') {\n handleAiAction(lastAiPrompt.id, lastAiPrompt.action);\n return;\n }\n\n const slide = presentation.slides[currentSlideIndex];\n const originalElement = slide.elements.find(el => el.id === lastAiPrompt.id);\n if (!originalElement || originalElement.type !== 'text') return;\n\n if (action === 'replace') {\n handleElementUpdate(lastAiPrompt.id, { content: aiResponse });\n } else if (action === 'addBelow') {\n const newElement: SlideElement = {\n ...originalElement,\n id: `text-ai-${Date.now()}`,\n content: aiResponse,\n y: originalElement.y + originalElement.height + 20,\n zIndex: slide.elements.length\n };\n handleUpdateSlide({ elements: [...slide.elements, newElement] });\n }\n\n setAiResponse(null);\n setLastAiPrompt(null);\n };\n\n const handleExport = async () => {\n const exporter = new PptxExporter();\n await exporter.export(presentation);\n };\n\n const handlePlay = () => {\n setIsPreviewMode(true);\n const elem = document.documentElement;\n if (elem.requestFullscreen) {\n elem.requestFullscreen();\n }\n };\n\n const handleClosePresenter = () => {\n setIsPreviewMode(false);\n if (document.fullscreenElement) {\n document.exitFullscreen();\n }\n };\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n if (!document.fullscreenElement) {\n setIsPreviewMode(false);\n }\n };\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n return () => document.removeEventListener('fullscreenchange', handleFullscreenChange);\n }, []);\n\n // Keyboard navigation\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Delete' || e.key === 'Backspace') {\n const activeElement = document.activeElement;\n if (activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA' || (activeElement as any)?.isContentEditable) return;\n handleDeleteElement();\n }\n if (e.ctrlKey || e.metaKey) {\n if (e.key === 'z') {\n e.preventDefault();\n if (e.shiftKey) redo(); else undo();\n }\n if (e.key === 'y') {\n e.preventDefault();\n redo();\n }\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [handleDeleteElement, undo, redo]);\n\n const handleNewPresentation = () => {\n saveToHistory({\n slides: [{ id: `slide-${Date.now()}`, elements: [] }],\n layout: { width: 12192000, height: 6858000 }\n });\n setCurrentSlideIndex(0);\n setSelectedElementId(null);\n };\n\n const handleLoadPresentation = async (input: File | string) => {\n setIsAiLoading(true); // Reusing loading state for feedback\n try {\n const parser = new PptxParser();\n let prompt = input;\n if (typeof input === 'string') {\n prompt = `/api/proxy?url=${encodeURIComponent(input.trim())}`;\n }\n const result = await parser.parse(prompt);\n setPresentation(result);\n setHistory([]);\n setRedoStack([]);\n setCurrentSlideIndex(0);\n setSelectedElementId(null);\n } catch (err) {\n console.error('Failed to load PPTX', err);\n alert('Failed to load presentation. Please ensure it is a valid .pptx.');\n } finally {\n setIsAiLoading(false);\n }\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-white overflow-hidden\">\n {isPreviewMode && (\n <PresenterMode\n presentation={presentation}\n initialSlideIndex={currentSlideIndex}\n onClose={handleClosePresenter}\n />\n )}\n <Toolbar\n onAddText={handleAddText}\n onAddImage={handleAddImage}\n onAddShape={handleAddShape}\n onAddSlide={handleAddSlide}\n onExport={handleExport}\n onFormatText={handleFormatText}\n onDeleteElement={handleDeleteElement}\n onApplyLayout={handleApplyLayout}\n onPlay={handlePlay}\n onAiAction={handleAiAction}\n onAiResponseAction={handleAiResponseAction}\n onNewPresentation={handleNewPresentation}\n onLoadPresentation={handleLoadPresentation}\n aiResponse={aiResponse}\n isAiLoading={isAiLoading}\n selectedElement={selectedElement}\n appName={appName}\n />\n <div className=\"flex flex-1 overflow-hidden\">\n <Sidebar\n slides={presentation.slides}\n currentSlideIndex={currentSlideIndex}\n onSelectSlide={setCurrentSlideIndex}\n onDeleteSlide={handleDeleteSlide}\n onDuplicateSlide={handleDuplicateSlide}\n onReorderSlides={handleReorderSlides}\n />\n <div className=\"flex-1 flex items-center justify-center p-12 overflow-auto bg-white\">\n <EditorCanvas\n slide={currentSlide}\n onElementUpdate={handleElementUpdate}\n onSelect={setSelectedElementId}\n />\n </div>\n </div>\n </div>\n );\n};\n","'use client';\n\nimport React, { useState } from 'react';\nimport {\n Type, Image as ImageIcon, MousePointer2,\n Square, Circle, Download, Plus, Trash2,\n Bold, Italic, AlignLeft, AlignCenter, AlignRight,\n List, Layout as LayoutIcon, Columns, FileText,\n History, Share2, Play, Sparkles, RefreshCw\n} from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport { SlideElement } from '../lib/types';\n\ninterface ToolbarProps {\n onAddText: () => void;\n onAddImage: (file: File) => void;\n onAddShape: (type: any) => void;\n onAddSlide: () => void;\n onExport: () => void;\n onFormatText: (updates: any) => void;\n onDeleteElement: () => void;\n onApplyLayout: (type: 'title' | 'content' | 'split') => void;\n onPlay: () => void;\n selectedElement: SlideElement | null;\n appName: string;\n onAiAction: (id: string, action: 'shorten' | 'reframe' | 'lengthen') => void;\n onAiResponseAction: (action: 'replace' | 'addBelow' | 'regenerate') => void;\n aiResponse: string | null;\n isAiLoading: boolean;\n onNewPresentation: () => void;\n onLoadPresentation: (input: File | string) => void;\n}\n\nconst FONTS = [\n 'Inter', 'Lato', 'Open Sans', 'Poppins', 'Roboto', 'Roboto Slab',\n 'Georgia', 'Playfair Display', 'Merriweather', 'Nunito Sans',\n 'Montserrat', 'Oswald', 'Raleway', 'Ubuntu', 'Lora',\n 'PT Sans', 'PT Serif', 'Play', 'Arvo', 'Kanit', 'Times New Roman', 'Arial'\n];\nconst FONT_SIZES = [12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 64, 72, 96];\n\nconst SHAPE_CATEGORIES = [\n {\n name: 'Basic Shapes',\n shapes: ['rect', 'circle', 'triangle', 'rightTriangle', 'rhombus', 'parallelogram', 'trapezoid', 'pentagon', 'hexagon', 'heptagon', 'octagon', 'heart', 'smiley', 'sun', 'moon']\n },\n {\n name: 'Arrows',\n shapes: ['arrowRight', 'arrowLeft', 'arrowUp', 'arrowDown', 'arrowLeftRight', 'arrowUpDown']\n },\n {\n name: 'Stars & Symbols',\n shapes: ['star4', 'star5', 'star6', 'star8', 'cloud', 'lightning']\n },\n {\n name: 'Equation Shapes',\n shapes: ['plus', 'minus', 'multiply', 'divide', 'equal']\n }\n];\n\nconst ShapesDropdown = ({ onAddShape }: { onAddShape: (type: string) => void }) => {\n const [isOpen, setIsOpen] = useState(false);\n\n // Wire up the toggle to the window so the parent button can trigger it\n React.useEffect(() => {\n (window as any)._toggleShapesMenu = () => setIsOpen(!isOpen);\n return () => { (window as any)._toggleShapesMenu = undefined; };\n }, [isOpen]);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"absolute top-full left-0 mt-2 bg-white border border-slate-200 rounded-2xl shadow-2xl p-4 w-[320px] max-h-[480px] overflow-y-auto z-[100] animate-in fade-in zoom-in-95 duration-200\">\n <div className=\"flex flex-col gap-6\">\n {SHAPE_CATEGORIES.map(cat => (\n <div key={cat.name} className=\"flex flex-col gap-2\">\n <span className=\"text-[10px] font-black uppercase tracking-widest text-slate-400 px-1\">{cat.name}</span>\n <div className=\"grid grid-cols-5 gap-1\">\n {cat.shapes.map(s => (\n <button\n key={s}\n onClick={() => { onAddShape(s); setIsOpen(false); }}\n className=\"aspect-square hover:bg-slate-50 rounded-lg flex items-center justify-center border border-transparent hover:border-slate-100 transition-all group\"\n title={s}\n >\n <div className=\"w-6 h-6 bg-slate-100 rounded-sm group-hover:bg-blue-100 group-hover:scale-110 transition-all flex items-center justify-center overflow-hidden\">\n <div className=\"text-[8px] font-bold text-slate-400 group-hover:text-blue-600 uppercase text-center scale-[0.8] leading-tight\">\n {s.slice(0, 3)}\n </div>\n </div>\n </button>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport const Toolbar: React.FC<ToolbarProps> = ({\n onAddText, onAddImage, onAddShape, onAddSlide, onExport,\n onFormatText, onDeleteElement, onApplyLayout, onPlay, selectedElement,\n appName, onAiAction, onAiResponseAction, aiResponse, isAiLoading,\n onNewPresentation, onLoadPresentation\n}) => {\n const fileInputRef = React.useRef<HTMLInputElement>(null);\n const [activeTab, setActiveTab] = useState('Home');\n const [showLayouts, setShowLayouts] = useState(false);\n const [showAiDialog, setShowAiDialog] = useState(false);\n const [showFileMenu, setShowFileMenu] = useState(false);\n const [showUploadModal, setShowUploadModal] = useState(false);\n const [uploadType, setUploadType] = useState<'file' | 'link'>('file');\n const [uploadUrl, setUploadUrl] = useState('');\n\n const isText = selectedElement?.type === 'text';\n const isShape = selectedElement?.type === 'shape';\n\n const PPT_RED = '#B7472A';\n\n return (\n <div className=\"flex flex-col border-b border-slate-200 bg-white z-50 select-none\">\n {/* Ribbon Tabs */}\n <div className=\"flex items-center bg-[#F3F2F1] border-b border-slate-200 h-10\">\n <div className=\"flex items-center h-full px-4 border-r border-slate-200 mr-2 bg-[#B7472A] text-white\">\n <span className=\"font-black text-xs tracking-tighter capitalize\">{appName}</span>\n </div>\n {/* <div className=\"flex h-full\">\n {['File', 'Home', 'Insert', 'Draw', 'Design', 'Transitions', 'Animations', 'Slide Show', 'Review', 'View'].map(tab => (\n <button\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={cn(\n \"px-4 h-10 transition-all flex items-center text-xs font-semibold relative\",\n activeTab === tab\n ? \"text-[#B7472A] bg-white\"\n : \"text-slate-600 hover:bg-slate-200/50\"\n )}\n >\n {tab}\n {activeTab === tab && (\n <div className=\"absolute bottom-0 left-0 right-0 h-[3px] bg-[#B7472A]\" />\n )}\n </button>\n ))}\n </div> */}\n <div className=\"flex h-full relative\">\n <button\n onClick={() => setShowFileMenu(!showFileMenu)}\n className={cn(\n \"px-4 h-10 transition-all flex items-center text-xs font-semibold relative\",\n showFileMenu\n ? \"text-white bg-[#B7472A]\"\n : \"text-slate-600 hover:bg-slate-200/50\"\n )}\n >\n File\n </button>\n\n {showFileMenu && (\n <>\n <div className=\"fixed inset-0 z-[140]\" onClick={() => setShowFileMenu(false)} />\n <div className=\"absolute top-10 left-0 w-48 bg-white border border-slate-200 shadow-xl rounded-b-xl z-[150] py-2 animate-in fade-in slide-in-from-top-1 duration-200\">\n <button\n onClick={() => { onNewPresentation(); setShowFileMenu(false); }}\n className=\"w-full text-left px-4 py-2 text-xs text-slate-700 hover:bg-slate-50 flex items-center gap-3 transition-colors\"\n >\n <Plus size={14} className=\"text-slate-400\" />\n <span>Create New</span>\n </button>\n <button\n onClick={() => { setShowUploadModal(true); setShowFileMenu(false); }}\n className=\"w-full text-left px-4 py-2 text-xs text-slate-700 hover:bg-slate-50 flex items-center gap-3 transition-colors\"\n >\n <Download size={14} className=\"text-slate-400\" />\n <span>Upload</span>\n </button>\n <div className=\"h-[1px] bg-slate-100 my-1 mx-2\" />\n <button\n onClick={() => { onExport(); setShowFileMenu(false); }}\n className=\"w-full text-left px-4 py-2 text-xs text-slate-700 hover:bg-slate-50 flex items-center gap-3 transition-colors\"\n >\n <Share2 size={14} className=\"text-slate-400\" />\n <span>Export PPTX</span>\n </button>\n </div>\n </>\n )}\n </div>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-4 px-4 text-slate-400\">\n {/* <Share2 size={16} className=\"cursor-pointer hover:text-[#B7472A] transition-colors\" /> */}\n <div className=\"h-4 w-[1px] bg-slate-200\" />\n <Play size={16} className=\"cursor-pointer hover:text-[#B7472A] transition-colors\" onClick={onPlay} />\n </div>\n </div>\n\n {/* Ribbon Content */}\n <div className=\"bg-white h-[96px] flex items-center px-6 gap-8 justify-start\">\n\n {/* Slides Group */}\n <div className=\"flex flex-col items-center border-r border-slate-100 pr-8 py-1 min-w-[140px]\">\n <div className=\"flex items-center gap-2 mb-1\">\n <button\n onClick={onAddSlide}\n className=\"flex flex-col items-center justify-center p-2 hover:bg-slate-50 rounded-xl group transition-all\"\n >\n <div className=\"bg-orange-50 p-2 rounded-lg group-hover:scale-110 transition-transform\">\n <Plus size={22} className=\"text-[#B7472A]\" />\n </div>\n <span className=\"text-[10px] font-bold text-slate-700 mt-1\">New Slide</span>\n </button>\n <div className=\"relative\">\n <button\n onClick={() => setShowLayouts(!showLayouts)}\n className={cn(\"p-2 hover:bg-slate-50 rounded-xl transition-all flex flex-col items-center\", showLayouts && \"bg-slate-100\")}\n >\n <LayoutIcon size={20} className=\"text-slate-500\" />\n <span className=\"text-[10px] font-medium text-slate-500 mt-1\">Layout</span>\n </button>\n {showLayouts && (\n <div className=\"absolute top-full left-0 mt-2 bg-white border border-slate-200 rounded-xl shadow-2xl p-2 w-56 flex flex-col gap-1 z-[100] animate-in fade-in zoom-in-95 duration-200\">\n <button onClick={() => { onApplyLayout('title'); setShowLayouts(false); }} className=\"flex items-center gap-3 px-4 py-2.5 hover:bg-slate-50 rounded-lg text-xs font-semibold text-slate-700 transition-colors border border-transparent hover:border-slate-100\"><FileText size={16} className=\"text-blue-500\" /> Title Slide</button>\n <button onClick={() => { onApplyLayout('content'); setShowLayouts(false); }} className=\"flex items-center gap-3 px-4 py-2.5 hover:bg-slate-50 rounded-lg text-xs font-semibold text-slate-700 transition-colors border border-transparent hover:border-slate-100\"><List size={16} className=\"text-emerald-500\" /> Title & Content</button>\n <button onClick={() => { onApplyLayout('split'); setShowLayouts(false); }} className=\"flex items-center gap-3 px-4 py-2.5 hover:bg-slate-50 rounded-lg text-xs font-semibold text-slate-700 transition-colors border border-transparent hover:border-slate-100\"><Columns size={16} className=\"text-purple-500\" /> Two Columns</button>\n </div>\n )}\n </div>\n </div>\n <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Slides</span>\n </div>\n\n {/* Font Group */}\n <div className=\"flex flex-col items-center border-r border-slate-100 px-8 py-1\">\n <div className=\"flex flex-col gap-2 min-w-[220px]\">\n <div className=\"flex items-center gap-1.5\">\n <select\n disabled={!isText}\n value={(selectedElement as any)?.fontFamily || 'Arial'}\n onChange={(e) => onFormatText({ fontFamily: e.target.value })}\n className=\"h-8 px-3 text-xs text-slate-900 border border-slate-200 rounded-lg font-semibold bg-white hover:border-slate-300 outline-none w-36 disabled:opacity-50 transition-colors appearance-none cursor-pointer\"\n >\n {FONTS.map(f => <option key={f} value={f}>{f}</option>)}\n </select>\n <select\n disabled={!isText}\n value={(selectedElement as any)?.fontSize || 24}\n onChange={(e) => onFormatText({ fontSize: parseInt(e.target.value) })}\n className=\"h-8 px-2 text-xs text-slate-900 border border-slate-200 rounded-lg font-semibold bg-white hover:border-slate-300 outline-none w-16 disabled:opacity-50 transition-colors appearance-none cursor-pointer text-center\"\n >\n {FONT_SIZES.map(s => <option key={s} value={s}>{s}</option>)}\n </select>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n disabled={!isText}\n onClick={() => onFormatText({ isBold: !(selectedElement as any).isBold })}\n className={cn(\"p-2 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.isBold ? \"bg-slate-100 text-slate-900\" : \"text-slate-500 hover:bg-slate-50\")}\n >\n <Bold size={16} strokeWidth={3} />\n </button>\n <button\n disabled={!isText}\n onClick={() => onFormatText({ isItalic: !(selectedElement as any).isItalic })}\n className={cn(\"p-2 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.isItalic ? \"bg-slate-100 text-slate-900\" : \"text-slate-500 hover:bg-slate-50\")}\n >\n <Italic size={16} />\n </button>\n <div className=\"h-4 w-[1px] bg-slate-200 mx-2\" />\n <div className=\"relative group p-1 hover:bg-slate-50 rounded-lg transition-colors cursor-pointer\">\n <input\n type=\"color\"\n disabled={!selectedElement}\n value={isText ? ((selectedElement as any).color || '#000000') : ((selectedElement as any)?.fill || '#3b82f6')}\n onChange={(e) => onFormatText(isText ? { color: e.target.value } : { fill: e.target.value })}\n className=\"w-8 h-6 p-0 border-0 bg-transparent cursor-pointer disabled:opacity-30\"\n title=\"Format Color\"\n />\n <div className=\"absolute bottom-1.5 left-2 right-2 h-1 rounded-full\" style={{ backgroundColor: isText ? ((selectedElement as any).color || '#000000') : ((selectedElement as any)?.fill || '#3b82f6') }} />\n </div>\n </div>\n </div>\n <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto pt-1\">Font</span>\n </div>\n\n {/* Paragraph Group */}\n <div className=\"flex flex-col items-center border-r border-slate-100 px-8 py-1\">\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-1 px-1.5 py-1 bg-slate-50 rounded-xl border border-slate-100\">\n <button disabled={!isText} onClick={() => onFormatText({ textAlign: 'left' })} className={cn(\"p-1.5 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.textAlign === 'left' ? \"bg-white shadow-sm text-[#B7472A] scale-110\" : \"text-slate-400\")}><AlignLeft size={16} /></button>\n <button disabled={!isText} onClick={() => onFormatText({ textAlign: 'center' })} className={cn(\"p-1.5 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.textAlign === 'center' ? \"bg-white shadow-sm text-[#B7472A] scale-110\" : \"text-slate-400\")}><AlignCenter size={16} /></button>\n <button disabled={!isText} onClick={() => onFormatText({ textAlign: 'right' })} className={cn(\"p-1.5 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.textAlign === 'right' ? \"bg-white shadow-sm text-[#B7472A] scale-110\" : \"text-slate-400\")}><AlignRight size={16} /></button>\n </div>\n <button\n disabled={!isText}\n onClick={() => onFormatText({ isBulleted: !(selectedElement as any).isBulleted })}\n className={cn(\"p-2 rounded-lg self-start transition-all disabled:opacity-30\", (selectedElement as any)?.isBulleted ? \"bg-slate-100 text-[#B7472A]\" : \"text-slate-500 hover:bg-slate-50\")}\n >\n <List size={18} />\n </button>\n </div>\n <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Paragraph</span>\n </div>\n\n {/* Drawing & Insert Group */}\n <div className=\"flex flex-col items-center border-r border-slate-100 px-8 py-1\">\n <div className=\"flex flex-wrap items-center gap-2 mb-1\">\n <div className=\"relative group/shapes\">\n <button\n className=\"flex flex-col items-center justify-center p-2 hover:bg-slate-50 rounded-xl group transition-all\"\n onClick={() => (window as any)._toggleShapesMenu?.()}\n >\n <div className=\"bg-blue-50 p-2 rounded-lg group-hover:scale-110 transition-transform\">\n <Square size={22} className=\"text-blue-600\" />\n </div>\n <span className=\"text-[10px] font-bold text-slate-700 mt-1\">Shapes</span>\n </button>\n\n {/* Shapes Popover logic - implementing as a simple state-controlled div */}\n <ShapesDropdown onAddShape={(s) => { onAddShape(s); }} />\n </div>\n\n <div className=\"h-10 w-[1px] bg-slate-100 mx-2\" />\n\n <button onClick={onAddText} className=\"p-2.5 hover:bg-slate-50 rounded-xl text-slate-600 transition-colors\" title=\"Text Box\"><Type size={18} /></button>\n <button onClick={() => fileInputRef.current?.click()} className=\"p-2.5 hover:bg-slate-50 rounded-xl text-slate-600 transition-colors\" title=\"Image\">\n <ImageIcon size={18} />\n <input type=\"file\" ref={fileInputRef} className=\"hidden\" accept=\"image/*\" onChange={(e) => e.target.files?.[0] && onAddImage(e.target.files[0])} />\n </button>\n </div>\n <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Drawing</span>\n </div>\n\n {/* AI Text Group */}\n <div className=\"flex flex-col items-center border-r border-slate-100 px-8 py-1\">\n <div className=\"flex flex-col gap-2 relative\">\n <div className=\"flex items-center gap-1.5\">\n <button\n disabled={!isText || isAiLoading}\n onClick={() => onAiAction(selectedElement!.id, 'shorten')}\n className=\"flex items-center gap-2 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 disabled:opacity-20 transition-all group border border-transparent hover:border-slate-100\"\n >\n <Sparkles size={16} className=\"text-purple-500\" />\n <span className=\"text-[10px] font-bold\">Shorten</span>\n </button>\n <button\n disabled={!isText || isAiLoading}\n onClick={() => onAiAction(selectedElement!.id, 'reframe')}\n className=\"flex items-center gap-2 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 disabled:opacity-20 transition-all group border border-transparent hover:border-slate-100\"\n >\n <Sparkles size={16} className=\"text-blue-500\" />\n <span className=\"text-[10px] font-bold\">Reframe</span>\n </button>\n <button\n disabled={!isText || isAiLoading}\n onClick={() => onAiAction(selectedElement!.id, 'lengthen')}\n className=\"flex items-center gap-2 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 disabled:opacity-20 transition-all group border border-transparent hover:border-slate-100\"\n >\n <Sparkles size={16} className=\"text-emerald-500\" />\n <span className=\"text-[10px] font-bold\">Lengthen</span>\n </button>\n </div>\n\n {/* AI Loading State */}\n {isAiLoading && (\n <div className=\"absolute inset-0 bg-white/80 flex items-center justify-center rounded-lg z-10 backdrop-blur-[1px]\">\n <RefreshCw size={18} className=\"text-blue-600 animate-spin\" />\n </div>\n )}\n\n {/* AI Response Dialog */}\n {aiResponse && (\n <div className=\"fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[400px] bg-white border border-slate-200 rounded-2xl shadow-2xl p-6 z-[200] animate-in fade-in zoom-in-95 duration-200\">\n <div className=\"flex items-center gap-2 mb-4\">\n <Sparkles size={20} className=\"text-purple-600\" />\n <h3 className=\"text-sm font-black text-slate-800 uppercase tracking-widest\">AI Generated Response</h3>\n </div>\n <div className=\"bg-slate-50 p-4 rounded-xl mb-6 max-h-[200px] overflow-y-auto border border-slate-100 italic text-slate-700 text-sm leading-relaxed\">\n \"{aiResponse}\"\n </div>\n <div className=\"flex flex-col gap-2\">\n <div className=\"grid grid-cols-2 gap-2\">\n <button\n onClick={() => onAiResponseAction('replace')}\n className=\"px-4 py-2.5 bg-[#B7472A] text-white text-[11px] font-bold rounded-lg hover:bg-[#a33f25] transition-colors shadow-sm\"\n >\n REPLACE CURRENT\n </button>\n <button\n onClick={() => onAiResponseAction('addBelow')}\n className=\"px-4 py-2.5 bg-slate-800 text-white text-[11px] font-bold rounded-lg hover:bg-slate-900 transition-colors shadow-sm\"\n >\n ADD BELOW\n </button>\n </div>\n <div className=\"flex gap-2\">\n <button\n onClick={() => onAiResponseAction('regenerate')}\n className=\"flex-1 px-4 py-2.5 border border-slate-200 text-slate-600 text-[11px] font-bold rounded-lg hover:bg-slate-50 transition-colors flex items-center justify-center gap-2\"\n >\n <RefreshCw size={14} /> REGENERATE\n </button>\n <button\n className=\"px-4 py-2.5 text-slate-400 text-[11px] font-bold hover:text-slate-600 transition-colors\"\n onClick={() => { onAiResponseAction('replace'); }}\n >\n CLOSE\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">AI Text</span>\n </div>\n\n {/* Actions Group */}\n <div className=\"flex flex-col items-center px-8 py-1\">\n <div className=\"flex gap-3\">\n <button\n onClick={onExport}\n className=\"flex flex-col items-center justify-center p-2.5 hover:bg-emerald-50 rounded-xl group transition-all\"\n title=\"Download Presentation\"\n >\n <div className=\"bg-emerald-100/50 p-2 rounded-lg group-hover:scale-110 transition-transform\">\n <Download size={22} className=\"text-emerald-700\" />\n </div>\n </button>\n {selectedElement && (\n <button\n onClick={onDeleteElement}\n className=\"flex flex-col items-center justify-center p-2.5 hover:bg-red-50 rounded-xl group transition-all\"\n title=\"Delete Element\"\n >\n <div className=\"bg-red-100/50 p-2 rounded-lg group-hover:scale-110 transition-transform\">\n <Trash2 size={22} className=\"text-red-600\" />\n </div>\n </button>\n )}\n </div>\n <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Actions</span>\n </div>\n\n <div className=\"flex-1\" />\n\n <div className=\"pr-12 flex flex-col items-end gap-1 group\">\n <div className=\"flex items-center gap-1.5 text-[10px] font-black text-slate-300 group-hover:text-[#B7472A] transition-colors\">\n <History size={12} />\n <span>SAVED AUTOMATICALLY</span>\n </div>\n <div className=\"h-1 w-24 bg-slate-100 rounded-full overflow-hidden\">\n <div className=\"h-full w-full bg-emerald-500/20\" />\n </div>\n </div>\n </div>\n\n {/* Upload Modal */}\n {showUploadModal && (\n <>\n <div className=\"fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-[2000]\" onClick={() => setShowUploadModal(false)} />\n <div className=\"fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[480px] bg-white rounded-3xl shadow-2xl z-[2001] border border-slate-200 p-8 animate-in fade-in zoom-in-95 duration-200\">\n <div className=\"flex justify-between items-center mb-6\">\n <h3 className=\"text-lg font-black text-slate-800 tracking-tight flex items-center gap-3\">\n <div className=\"p-2 bg-blue-50 text-blue-600 rounded-xl\">\n <Download size={20} />\n </div>\n Upload Presentation\n </h3>\n <button onClick={() => setShowUploadModal(false)} className=\"text-slate-400 hover:text-slate-600 transition-colors\">\n <RefreshCw size={20} className=\"rotate-45\" />\n </button>\n </div>\n\n <div className=\"flex gap-2 p-1 bg-slate-50 rounded-2xl mb-8\">\n <button\n onClick={() => setUploadType('file')}\n className={cn(\n \"flex-1 py-3 text-xs font-black rounded-xl transition-all\",\n uploadType === 'file' ? \"bg-white text-blue-600 shadow-sm\" : \"text-slate-500 hover:text-slate-700\"\n )}\n >\n FILE UPLOAD\n </button>\n <button\n onClick={() => setUploadType('link')}\n className={cn(\n \"flex-1 py-3 text-xs font-black rounded-xl transition-all\",\n uploadType === 'link' ? \"bg-white text-blue-600 shadow-sm\" : \"text-slate-500 hover:text-slate-700\"\n )}\n >\n LINK UPLOAD\n </button>\n </div>\n\n {uploadType === 'file' ? (\n <label className=\"flex flex-col items-center justify-center gap-4 py-12 border-2 border-dashed border-slate-200 rounded-3xl hover:border-blue-400 hover:bg-blue-50/50 transition-all cursor-pointer group\">\n <div className=\"p-4 bg-white rounded-2xl shadow-sm border border-slate-100 group-hover:scale-110 transition-transform\">\n <Plus size={24} className=\"text-blue-500\" />\n </div>\n <div className=\"text-center\">\n <p className=\"text-sm font-bold text-slate-700\">Choose a PPTX file</p>\n <p className=\"text-xs text-slate-400 mt-1\">Maximum file size: 50MB</p>\n </div>\n <input\n type=\"file\"\n accept=\".pptx\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (file) {\n onLoadPresentation(file);\n setShowUploadModal(false);\n }\n }}\n />\n </label>\n ) : (\n <div className=\"space-y-4\">\n <div className=\"relative\">\n <input\n type=\"text\"\n placeholder=\"Paste S3 or public URL\"\n value={uploadUrl}\n onChange={(e) => setUploadUrl(e.target.value)}\n className=\"w-full bg-slate-50 border border-slate-200 rounded-2xl px-5 py-4 focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 text-sm placeholder:text-slate-400 text-black\"\n />\n </div>\n <button\n onClick={() => {\n if (uploadUrl.trim()) {\n onLoadPresentation(uploadUrl.trim());\n setShowUploadModal(false);\n }\n }}\n disabled={!uploadUrl.trim()}\n className=\"w-full bg-blue-600 hover:bg-blue-700 disabled:bg-slate-300 text-white font-black py-4 rounded-2xl transition-all shadow-lg shadow-blue-500/20\"\n >\n LOAD PRESENTATION\n </button>\n <p className=\"text-[10px] text-slate-400 text-center uppercase tracking-widest font-black\">\n Supports S3, Dropbox, and public URLS\n </p>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n );\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport React from 'react';\nimport type { Slide } from '../lib/types';\nimport { cn } from '@/lib/utils';\nimport { Trash2, Copy, GripVertical } from 'lucide-react';\nimport {\n DndContext,\n closestCenter,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n DragEndEvent\n} from '@dnd-kit/core';\nimport {\n arrayMove,\n SortableContext,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n useSortable\n} from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\n\ninterface SidebarProps {\n slides: Slide[];\n currentSlideIndex: number;\n onSelectSlide: (index: number) => void;\n onDeleteSlide: (index: number) => void;\n onDuplicateSlide: (index: number) => void;\n onReorderSlides: (oldIndex: number, newIndex: number) => void;\n}\n\nconst SortableSlide = ({\n slide,\n index,\n isActive,\n onSelect,\n onDelete,\n onDuplicate,\n showDelete\n}: {\n slide: Slide,\n index: number,\n isActive: boolean,\n onSelect: () => void,\n onDelete: () => void,\n onDuplicate: () => void,\n showDelete: boolean\n}) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging\n } = useSortable({ id: slide.id });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n zIndex: isDragging ? 2 : 1,\n opacity: isDragging ? 0.5 : 1\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n onClick={onSelect}\n className={cn(\n \"cursor-pointer border-[1.5px] rounded-2xl p-2 transition-all duration-300 group relative select-none\",\n isActive\n ? \"border-[#B7472A] bg-white\"\n : \"border-transparent hover:border-slate-200 bg-white/50 hover:bg-white\"\n )}\n >\n <div className=\"text-[10px] font-bold text-slate-400 mb-1 flex items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n <div {...attributes} {...listeners} className=\"cursor-grab active:cursor-grabbing p-0.5 hover:bg-slate-100 rounded text-slate-300 hover:text-slate-500\">\n <GripVertical size={10} />\n </div>\n <span>SLIDE {index + 1}</span>\n </div>\n <div className=\"flex items-center gap-1\">\n {isActive && <span className=\"h-1.5 w-1.5 rounded-full bg-[#B7472A]\" />}\n <div className=\"flex items-center opacity-0 group-hover:opacity-100 transition-opacity\">\n <button\n onClick={(e) => { e.stopPropagation(); onDuplicate(); }}\n className=\"p-1 hover:bg-blue-50 text-slate-400 hover:text-blue-500 rounded transition-all\"\n title=\"Duplicate Slide\"\n >\n <Copy size={12} />\n </button>\n {showDelete && (\n <button\n onClick={(e) => { e.stopPropagation(); onDelete(); }}\n className=\"p-1 hover:bg-red-50 text-red-400 hover:text-red-500 rounded transition-all\"\n title=\"Delete Slide\"\n >\n <Trash2 size={12} />\n </button>\n )}\n </div>\n </div>\n </div>\n <div className=\"aspect-video bg-white rounded-xl flex items-center justify-center border border-slate-200 overflow-hidden relative group-hover:shadow-sm transition-shadow\">\n {/* Scaled Preview of Slide Content */}\n <div\n className=\"absolute inset-0 origin-top-left pointer-events-none select-none\"\n style={{\n width: '1200px',\n height: '675px',\n transform: 'scale(0.165)', // Scaled to fit roughly 200px width\n backgroundColor: '#ffffff'\n }}\n >\n {slide.elements.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0)).map((el) => {\n const style: React.CSSProperties = {\n position: 'absolute',\n left: el.x,\n top: el.y,\n width: el.width,\n height: el.height,\n opacity: el.opacity ?? 1,\n };\n\n if (el.type === 'text') {\n return (\n <div\n key={el.id}\n style={{\n ...style,\n fontSize: el.fontSize,\n fontFamily: el.fontFamily,\n color: el.color,\n textAlign: el.textAlign || 'left',\n fontWeight: el.isBold ? 'bold' : 'normal',\n fontStyle: el.isItalic ? 'italic' : 'normal',\n lineHeight: 1.2,\n overflow: 'hidden',\n wordBreak: 'break-word',\n whiteSpace: 'pre-wrap'\n }}\n >\n {el.content}\n </div>\n );\n } else if (el.type === 'shape') {\n return (\n <div\n key={el.id}\n style={{\n ...style,\n backgroundColor: el.fill,\n borderRadius: el.shapeType === 'ellipse' ? '50%' : '0'\n }}\n />\n );\n } else if (el.type === 'image') {\n return (\n <img\n key={el.id}\n src={el.src}\n alt=\"\"\n style={{\n ...style,\n objectFit: 'contain'\n }}\n />\n );\n }\n return null;\n })}\n </div>\n </div>\n </div>\n );\n};\n\nexport const Sidebar: React.FC<SidebarProps> = ({\n slides,\n currentSlideIndex,\n onSelectSlide,\n onDeleteSlide,\n onDuplicateSlide,\n onReorderSlides\n}) => {\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 5,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n if (active.id !== over?.id) {\n const oldIndex = slides.findIndex((s) => s.id === active.id);\n const newIndex = slides.findIndex((s) => s.id === over?.id);\n onReorderSlides(oldIndex, newIndex);\n }\n };\n\n return (\n <div className=\"w-64 bg-white border-r border-slate-100 overflow-y-auto p-4 flex flex-col gap-4\">\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragEnd={handleDragEnd}\n >\n <SortableContext\n items={slides.map(s => s.id)}\n strategy={verticalListSortingStrategy}\n >\n {slides.map((slide, index) => (\n <SortableSlide\n key={slide.id}\n slide={slide}\n index={index}\n isActive={index === currentSlideIndex}\n onSelect={() => onSelectSlide(index)}\n onDelete={() => onDeleteSlide(index)}\n onDuplicate={() => onDuplicateSlide(index)}\n showDelete={slides.length > 1}\n />\n ))}\n </SortableContext>\n </DndContext>\n </div>\n );\n};\n","'use client';\n\nimport React, { useEffect, useRef } from 'react';\nimport * as fabric from 'fabric';\nimport type { Slide, SlideElement } from '../lib/types';\n\ninterface CanvasProps {\n slide: Slide;\n onElementUpdate: (elementId: string, updates: Partial<SlideElement>) => void;\n onSelect: (id: string | null) => void;\n}\n\nexport const EditorCanvas: React.FC<CanvasProps> = ({ slide, onElementUpdate, onSelect }) => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const fabricCanvas = useRef<fabric.Canvas | null>(null);\n const isInternalUpdate = useRef(false);\n\n const onElementUpdateRef = useRef(onElementUpdate);\n const onSelectRef = useRef(onSelect);\n\n useEffect(() => {\n onElementUpdateRef.current = onElementUpdate;\n onSelectRef.current = onSelect;\n }, [onElementUpdate, onSelect]);\n\n useEffect(() => {\n if (canvasRef.current && !fabricCanvas.current) {\n fabricCanvas.current = new fabric.Canvas(canvasRef.current, {\n width: 1200,\n height: 675,\n backgroundColor: '#ffffff'\n });\n\n const canvas = fabricCanvas.current;\n\n const clamp = (obj: fabric.Object) => {\n if (obj.left! < 0) obj.set('left', 0);\n if (obj.top! < 0) obj.set('top', 0);\n const bound = obj.getBoundingRect();\n if (bound.left + bound.width > (canvas.width || 1200)) obj.set('left', (canvas.width || 1200) - bound.width);\n if (bound.top + bound.height > (canvas.height || 675)) obj.set('top', (canvas.height || 675) - bound.height);\n };\n\n canvas.on('object:moving', (e) => clamp(e.target!));\n canvas.on('object:scaling', (e) => clamp(e.target!));\n\n const handleUpdate = (e: any) => {\n if (isInternalUpdate.current) return;\n const obj = e.target as any;\n const elementId = obj.get('data')?.id;\n if (obj && elementId) {\n onElementUpdateRef.current(elementId, {\n x: obj.left,\n y: obj.top,\n width: obj.getScaledWidth(),\n height: obj.getScaledHeight(),\n ...(obj.isType('textbox') ? {\n content: (obj as fabric.Textbox).text,\n textAlign: (obj as fabric.Textbox).textAlign as any,\n fontSize: obj.fontSize,\n fontFamily: obj.fontFamily,\n color: obj.fill as string\n } : {\n fill: obj.fill as string\n })\n });\n }\n };\n\n canvas.on('object:modified', handleUpdate);\n canvas.on('text:changed', handleUpdate);\n\n const syncSelection = (e: any) => {\n const obj = e.selected?.[0] || e.target;\n if (obj) {\n const elementId = (obj as any).get('data')?.id;\n onSelectRef.current(elementId);\n }\n };\n\n canvas.on('selection:created', syncSelection);\n canvas.on('selection:updated', syncSelection);\n canvas.on('selection:cleared', () => onSelectRef.current(null));\n\n // Global keyboard navigation\n const handleGlobalKeyDown = (e: KeyboardEvent) => {\n const activeObj = canvas.getActiveObject();\n if (!activeObj) return;\n\n // Don't move if editing text\n if (activeObj.isType('textbox') && (activeObj as fabric.Textbox).isEditing) return;\n\n const step = e.shiftKey ? 10 : 1;\n let moved = false;\n\n switch (e.key) {\n case 'ArrowLeft': activeObj.set('left', activeObj.left - step); moved = true; break;\n case 'ArrowRight': activeObj.set('left', activeObj.left + step); moved = true; break;\n case 'ArrowUp': activeObj.set('top', activeObj.top - step); moved = true; break;\n case 'ArrowDown': activeObj.set('top', activeObj.top + step); moved = true; break;\n }\n\n if (moved) {\n clamp(activeObj);\n canvas.requestRenderAll();\n handleUpdate({ target: activeObj });\n }\n };\n\n window.addEventListener('keydown', handleGlobalKeyDown);\n (canvas as any)._keyboardListener = handleGlobalKeyDown;\n }\n\n return () => {\n if (fabricCanvas.current) {\n const listener = (fabricCanvas.current as any)._keyboardListener;\n if (listener) window.removeEventListener('keydown', listener);\n fabricCanvas.current.dispose();\n fabricCanvas.current = null;\n }\n };\n }, []); // Empty dependency array means this only runs once!\n\n useEffect(() => {\n if (!fabricCanvas.current) return;\n const canvas = fabricCanvas.current;\n\n const syncElements = async () => {\n isInternalUpdate.current = true;\n\n const existingObjs = canvas.getObjects();\n const slideIds = new Set(slide.elements.map(e => e.id));\n\n existingObjs.forEach(obj => {\n const id = (obj as any).get('data')?.id;\n if (id && !slideIds.has(id)) {\n canvas.remove(obj);\n }\n });\n\n const sorted = [...slide.elements].sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));\n\n for (const el of sorted) {\n let obj = existingObjs.find(o => (o as any).get('data')?.id === el.id) as any;\n\n if (obj) {\n // CRITICAL: Skip syncing properties for the object currently being edited.\n // If we update properties (like 'text') while Fabric.js is in editing mode,\n // it resets the cursor position and can cause desync/focus loss.\n if (obj === canvas.getActiveObject() && obj.isType('textbox') && (obj as fabric.Textbox).isEditing) {\n continue;\n }\n\n const updates: any = {\n left: el.x,\n top: el.y,\n opacity: el.opacity !== undefined ? el.opacity : 1,\n zIndex: el.zIndex\n };\n\n if (el.type === 'text' && obj.isType('textbox')) {\n updates.text = el.content || ' ';\n updates.fontSize = el.fontSize || 22;\n updates.fill = el.color || '#000000';\n updates.textAlign = el.textAlign || 'left';\n updates.fontWeight = el.isBold ? 'bold' : 'normal';\n updates.fontStyle = el.isItalic ? 'italic' : 'normal';\n updates.fontFamily = el.fontFamily || 'Arial';\n updates.width = Math.max(el.width || 50, 10);\n } else if (el.type === 'shape') {\n updates.fill = (el as any).fill || '#cccccc';\n updates.scaleX = (el.width || 50) / (obj.width || 1);\n updates.scaleY = (el.height || 50) / (obj.height || 1);\n } else if (el.type === 'image') {\n updates.scaleX = (el.width || 100) / (obj.width || 1);\n updates.scaleY = (el.height || 100) / (obj.height || 1);\n }\n\n obj.set(updates);\n } else {\n let newObj: fabric.Object | null = null;\n const commonProps = {\n left: el.x,\n top: el.y,\n data: { id: el.id },\n originX: 'left' as const,\n originY: 'top' as const,\n opacity: el.opacity !== undefined ? el.opacity : 1\n };\n\n if (el.type === 'text') {\n newObj = new fabric.Textbox(el.content || ' ', {\n ...commonProps,\n width: Math.max(el.width || 200, 10),\n fontSize: el.fontSize || 22,\n fill: el.color || '#000000',\n fontFamily: el.fontFamily || 'Inter, Arial, sans-serif',\n textAlign: el.textAlign || 'left',\n fontWeight: el.isBold ? 'bold' : 'normal',\n fontStyle: el.isItalic ? 'italic' : 'normal',\n splitByGrapheme: false,\n });\n } else if (el.type === 'shape') {\n const shapeFill = (el as any).fill || '#3b82f6';\n if (el.shapeType === 'ellipse') {\n newObj = new fabric.Circle({\n ...commonProps,\n radius: (el.width || 100) / 2,\n scaleY: (el.height || 100) / (el.width || 100),\n fill: shapeFill,\n });\n } else {\n newObj = new fabric.Rect({\n ...commonProps,\n width: el.width || 100,\n height: el.height || 100,\n fill: shapeFill,\n });\n }\n } else if (el.type === 'image') {\n try {\n const img = await fabric.FabricImage.fromURL(el.src);\n img.set({\n ...commonProps,\n scaleX: (el.width || 100) / (img.width || 1),\n scaleY: (el.height || 100) / (img.height || 1),\n } as any);\n newObj = img;\n } catch (err) { console.error(err); }\n }\n\n if (newObj) {\n canvas.add(newObj);\n }\n }\n }\n\n canvas.renderAll();\n isInternalUpdate.current = false;\n };\n\n syncElements();\n }, [slide]);\n\n return (\n <div className=\"border border-slate-200 rounded-xl overflow-hidden bg-white\">\n <canvas ref={canvasRef} />\n </div>\n );\n};\n","import pptxgen from 'pptxgenjs';\nimport type { Presentation } from './types';\n\nexport class PptxExporter {\n async export(presentation: Presentation): Promise<void> {\n const pptx = new pptxgen();\n\n const emuWidth = presentation.layout?.width || 12192000;\n const emuHeight = presentation.layout?.height || 6858000;\n const canvasWidth = 1200;\n const canvasHeight = 675;\n\n const getInchesX = (px: number) => (px / canvasWidth) * (emuWidth / 914400);\n const getInchesY = (px: number) => (px / canvasHeight) * (emuHeight / 914400);\n\n presentation.slides.forEach(slide => {\n const pptxSlide = pptx.addSlide();\n\n // Sort by zIndex for export layering\n const sortedElements = [...slide.elements].sort((a, b) => a.zIndex - b.zIndex);\n\n sortedElements.forEach(el => {\n const transparency = el.opacity !== undefined ? (1 - el.opacity) * 100 : 0;\n const common = {\n x: getInchesX(el.x),\n y: getInchesY(el.y),\n w: getInchesX(el.width),\n h: getInchesY(el.height),\n };\n\n if (el.type === 'text') {\n pptxSlide.addText(el.content, {\n ...common,\n fontSize: (el.fontSize || 18) / 2, // Halve for export\n color: el.color?.replace('#', '') || '000000',\n fontFace: el.fontFamily || 'Arial'\n });\n } else if (el.type === 'image') {\n pptxSlide.addImage({\n ...common,\n path: el.src,\n transparency: transparency\n });\n } else if (el.type === 'shape') {\n const shapeType = el.shapeType === 'ellipse' ? pptx.ShapeType.ellipse : pptx.ShapeType.rect;\n pptxSlide.addShape(shapeType, {\n ...common,\n fill: {\n color: el.fill?.replace('#', '') || 'CCCCCC',\n transparency: transparency > 0 ? Math.min(transparency + 10, 100) : 0 // Slightly lighter as requested\n }\n });\n }\n });\n });\n\n await pptx.writeFile({ fileName: 'presentation.pptx' });\n }\n}\n","import JSZip from 'jszip';\nimport type { Presentation, Slide, SlideElement, ShapeType } from './types';\n\nexport class PptxParser {\n private slideWidth = 12192000;\n private slideHeight = 6858000;\n private readonly CANVAS_WIDTH = 1200;\n private readonly CANVAS_HEIGHT = 675;\n\n async parse(input: File | Blob | ArrayBuffer | string): Promise<Presentation> {\n let data: any = input;\n if (typeof input === 'string') {\n const response = await fetch(input);\n if (!response.ok) {\n const status = response.status;\n const statusText = response.statusText;\n\n let detail = '';\n try {\n const errorJson = await response.json();\n detail = errorJson.details || errorJson.error || '';\n } catch (e) {\n // Ignore if not JSON\n }\n\n throw new Error(`Failed to fetch PPTX from ${input}: ${status} ${statusText} ${detail ? `(${detail})` : ''}`);\n }\n data = await response.arrayBuffer();\n }\n const zip = await JSZip.loadAsync(data);\n const presentationXml = await zip.file('ppt/presentation.xml')?.async('string');\n if (!presentationXml) throw new Error('Invalid PPTX');\n\n const parser = new DOMParser();\n const presentationDoc = parser.parseFromString(presentationXml, 'text/xml');\n\n const sldSz = this.findFirstByLocalName(presentationDoc, 'sldSz');\n if (sldSz) {\n this.slideWidth = parseInt(this.getAttr(sldSz, 'cx') || '12192000');\n this.slideHeight = parseInt(this.getAttr(sldSz, 'cy') || '6858000');\n }\n\n const sldIdList = Array.from(presentationDoc.getElementsByTagNameNS('*', 'sldId'));\n const slides: Slide[] = [];\n\n for (let i = 0; i < sldIdList.length; i++) {\n const slideNum = i + 1;\n const slidePath = `ppt/slides/slide${slideNum}.xml`;\n const slideXml = await zip.file(slidePath)?.async('string');\n if (slideXml) {\n const slide = await this.parseSlide(slideXml, slideNum, zip);\n slides.push(slide);\n }\n }\n\n return {\n slides,\n layout: { width: this.slideWidth, height: this.slideHeight }\n };\n }\n\n private getAttr(el: Element, name: string): string | null {\n return el.getAttribute(name) || el.getAttribute(`a:${name}`) || el.getAttribute(`p:${name}`) || el.getAttribute(`r:${name}`);\n }\n\n private findFirstByLocalName(parent: Document | Element, name: string): Element | null {\n const elements = parent.getElementsByTagNameNS('*', name);\n return elements.length > 0 ? elements[0] : null;\n }\n\n private findAllByLocalName(parent: Document | Element, name: string): Element[] {\n return Array.from(parent.getElementsByTagNameNS('*', name));\n }\n\n private scaleX(emu: number): number {\n return (emu / this.slideWidth) * this.CANVAS_WIDTH;\n }\n\n private scaleY(emu: number): number {\n return (emu / this.slideHeight) * this.CANVAS_HEIGHT;\n }\n\n private parseColor(el: Element): { color: string, opacity: number } {\n const srgbClr = this.findFirstByLocalName(el, 'srgbClr');\n if (srgbClr) {\n const hex = `#${this.getAttr(srgbClr, 'val')}`;\n const alphaNode = this.findFirstByLocalName(srgbClr, 'alpha');\n const opacity = alphaNode ? parseInt(this.getAttr(alphaNode, 'val') || '100000') / 100000 : 1;\n return { color: hex, opacity };\n }\n const schemeClr = this.findFirstByLocalName(el, 'schemeClr');\n if (schemeClr) {\n const alphaNode = this.findFirstByLocalName(schemeClr, 'alpha');\n const opacity = alphaNode ? parseInt(this.getAttr(alphaNode, 'val') || '100000') / 100000 : 1;\n return { color: '#000000', opacity }; // Themes usually default to dark if not specified\n }\n return { color: '#000000', opacity: 1 };\n }\n\n private async resolveImage(relId: string, slideIndex: number, zip: JSZip): Promise<Blob | null> {\n const relsXml = await zip.file(`ppt/slides/_rels/slide${slideIndex}.xml.rels`)?.async('string');\n if (!relsXml) return null;\n\n const parser = new DOMParser();\n const relsDoc = parser.parseFromString(relsXml, 'text/xml');\n const relationship = Array.from(relsDoc.getElementsByTagName('Relationship'))\n .find(r => r.getAttribute('Id') === relId);\n\n const target = relationship?.getAttribute('Target');\n if (target) {\n const mediaPath = (target.startsWith('../') ? `ppt/${target.substring(3)}` : `ppt/slides/${target}`).replace('ppt/slides/../', 'ppt/');\n return await zip.file(mediaPath)?.async('blob') || null;\n }\n return null;\n }\n\n private async parseSlide(xml: string, slideIndex: number, zip: JSZip): Promise<Slide> {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'text/xml');\n const elements: SlideElement[] = [];\n let zIndex = 0;\n\n // Check for Background Image\n const bg = this.findFirstByLocalName(doc, 'bg');\n if (bg) {\n const blip = this.findFirstByLocalName(bg, 'blip');\n const relId = blip?.getAttributeNS('http://schemas.openxmlformats.org/officeDocument/2006/relationships', 'embed') ||\n blip?.getAttribute('r:embed');\n if (relId) {\n const mediaFile = await this.resolveImage(relId, slideIndex, zip);\n if (mediaFile) {\n elements.push({\n id: `bg-${slideIndex}`,\n type: 'image',\n src: URL.createObjectURL(mediaFile),\n x: 0,\n y: 0,\n width: this.CANVAS_WIDTH,\n height: this.CANVAS_HEIGHT,\n zIndex: zIndex++,\n opacity: 1\n });\n }\n }\n }\n\n const spTree = this.findFirstByLocalName(doc, 'spTree');\n if (!spTree) return { id: `slide-${slideIndex}`, elements };\n\n const children = Array.from(spTree.children);\n for (const child of children) {\n const localName = child.localName;\n\n if (localName === 'sp') {\n const txBody = this.findFirstByLocalName(child, 'txBody');\n const xfrm = this.findFirstByLocalName(child, 'xfrm');\n const off = xfrm ? this.findFirstByLocalName(xfrm, 'off') : null;\n const ext = xfrm ? this.findFirstByLocalName(xfrm, 'ext') : null;\n\n if (txBody && off && ext) {\n const paragraphs = this.findAllByLocalName(txBody, 'p');\n let content = '';\n let fontSize = 18;\n let color = '#000000';\n let opacity = 1;\n let isBulleted = false;\n\n for (const p of paragraphs) {\n const pPr = this.findFirstByLocalName(p, 'pPr');\n const buNone = pPr ? this.findFirstByLocalName(pPr, 'buNone') : null;\n if (pPr && !buNone && (this.findFirstByLocalName(pPr, 'buChar') || this.findFirstByLocalName(pPr, 'buAutoNum'))) {\n isBulleted = true;\n content += '• ';\n }\n\n const runs = this.findAllByLocalName(p, 'r');\n for (const r of runs) {\n const t = this.findFirstByLocalName(r, 't');\n if (t) content += t.textContent;\n\n const rPr = this.findFirstByLocalName(r, 'rPr');\n if (rPr) {\n const sz = this.getAttr(rPr, 'sz');\n if (sz) fontSize = (parseInt(sz) / 100) * 2; // Double for editor\n const style = this.parseColor(rPr);\n color = style.color;\n opacity = style.opacity;\n }\n }\n content += '\\n';\n }\n\n if (content.trim()) {\n elements.push({\n id: `el-${slideIndex}-${Date.now()}-${zIndex}`,\n type: 'text',\n content: content.trim(),\n x: this.scaleX(parseInt(this.getAttr(off, 'x') || '0')),\n y: this.scaleY(parseInt(this.getAttr(off, 'y') || '0')),\n width: this.scaleX(parseInt(this.getAttr(ext, 'cx') || '0')),\n height: this.scaleY(parseInt(this.getAttr(ext, 'cy') || '0')),\n fontSize,\n color,\n fontFamily: 'Arial',\n zIndex: zIndex++,\n isBulleted,\n opacity\n });\n continue;\n }\n }\n\n const prstGeom = this.findFirstByLocalName(child, 'prstGeom');\n if (prstGeom && off && ext) {\n const prst = this.getAttr(prstGeom, 'prst');\n const spPr = this.findFirstByLocalName(child, 'spPr');\n const style = spPr ? this.parseColor(spPr) : { color: '#cccccc', opacity: 1 };\n\n elements.push({\n id: `el-${slideIndex}-${Date.now()}-${zIndex}`,\n type: 'shape',\n shapeType: (prst === 'ellipse' || prst === 'circle' ? 'ellipse' : 'rect') as ShapeType,\n fill: style.color,\n opacity: style.opacity,\n x: this.scaleX(parseInt(this.getAttr(off, 'x') || '0')),\n y: this.scaleY(parseInt(this.getAttr(off, 'y') || '0')),\n width: this.scaleX(parseInt(this.getAttr(ext, 'cx') || '0')),\n height: this.scaleY(parseInt(this.getAttr(ext, 'cy') || '0')),\n zIndex: zIndex++\n });\n }\n }\n\n if (localName === 'pic') {\n const blip = this.findFirstByLocalName(child, 'blip');\n const relId = blip?.getAttributeNS('http://schemas.openxmlformats.org/officeDocument/2006/relationships', 'embed') ||\n blip?.getAttribute('r:embed');\n\n const xfrm = this.findFirstByLocalName(child, 'xfrm');\n const off = xfrm ? this.findFirstByLocalName(xfrm, 'off') : null;\n const ext = xfrm ? this.findFirstByLocalName(xfrm, 'ext') : null;\n\n if (relId && off && ext) {\n const mediaFile = await this.resolveImage(relId, slideIndex, zip);\n if (mediaFile) {\n elements.push({\n id: `el-${slideIndex}-${Date.now()}-${zIndex}`,\n type: 'image',\n src: URL.createObjectURL(mediaFile),\n x: this.scaleX(parseInt(this.getAttr(off, 'x') || '0')),\n y: this.scaleY(parseInt(this.getAttr(off, 'y') || '0')),\n width: this.scaleX(parseInt(this.getAttr(ext, 'cx') || '0')),\n height: this.scaleY(parseInt(this.getAttr(ext, 'cy') || '0')),\n zIndex: zIndex++,\n opacity: 1\n });\n }\n }\n }\n }\n\n return { id: `slide-${slideIndex}`, elements };\n }\n}\n","'use client';\n\nimport React, { useEffect, useState } from 'react';\nimport { ChevronLeft, ChevronRight, X } from 'lucide-react';\nimport type { Presentation, Slide } from '../lib/types';\nimport { EditorCanvas } from './EditorCanvas';\n\ninterface PresenterModeProps {\n presentation: Presentation;\n initialSlideIndex: number;\n onClose: () => void;\n}\n\nexport const PresenterMode: React.FC<PresenterModeProps> = ({\n presentation,\n initialSlideIndex,\n onClose\n}) => {\n const [currentIndex, setCurrentIndex] = useState(initialSlideIndex);\n const currentSlide = presentation.slides[currentIndex];\n\n const goToPrevious = () => {\n if (currentIndex > 0) setCurrentIndex(currentIndex - 1);\n };\n\n const goToNext = () => {\n if (currentIndex < presentation.slides.length - 1) setCurrentIndex(currentIndex + 1);\n };\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown') {\n goToNext();\n } else if (e.key === 'ArrowLeft' || e.key === 'Backspace' || e.key === 'PageUp') {\n goToPrevious();\n } else if (e.key === 'Escape') {\n onClose();\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [currentIndex]);\n\n const [scale, setScale] = useState(1);\n\n useEffect(() => {\n const updateScale = () => {\n const padding = 40;\n const availableWidth = window.innerWidth - padding;\n const availableHeight = window.innerHeight - padding;\n const slideWidth = 1200;\n const slideHeight = 675;\n\n const scaleX = availableWidth / slideWidth;\n const scaleY = availableHeight / slideHeight;\n const newScale = Math.min(scaleX, scaleY);\n setScale(newScale);\n };\n\n updateScale();\n window.addEventListener('resize', updateScale);\n return () => window.removeEventListener('resize', updateScale);\n }, []);\n\n return (\n <div className=\"fixed inset-0 z-[99999] bg-[#0A0A0A] flex flex-col items-center justify-center overflow-hidden\">\n {/* Header / Controls */}\n <div className=\"absolute top-0 left-0 right-0 p-6 flex justify-between items-center opacity-0 hover:opacity-100 transition-opacity bg-gradient-to-b from-black/60 to-transparent z-[100] pointer-events-none\">\n <div className=\"text-white/80 font-bold ml-4 pointer-events-auto\">\n Slide {currentIndex + 1} of {presentation.slides.length}\n </div>\n <button\n onClick={onClose}\n className=\"p-3 bg-white/10 hover:bg-white/20 text-white rounded-full transition-all pointer-events-auto\"\n >\n <X size={24} />\n </button>\n </div>\n\n {/* Slide Container */}\n <div className=\"w-full h-full flex items-center justify-center\">\n <div\n className=\"relative shadow-2xl shadow-black/80 bg-white\"\n style={{\n width: '1200px',\n height: '675px',\n transform: `scale(${scale})`,\n transformOrigin: 'center center'\n }}\n >\n <EditorCanvas\n slide={currentSlide}\n onElementUpdate={() => { }} // No editing in presenter mode\n onSelect={() => { }} // No selection in presenter mode\n />\n </div>\n </div>\n\n {/* Navigation Controls */}\n <div className=\"absolute bottom-10 left-1/2 -translate-x-1/2 flex items-center gap-6 opacity-0 hover:opacity-100 transition-opacity bg-black/40 backdrop-blur-md px-6 py-3 rounded-full border border-white/10 pointer-events-auto\">\n <button\n disabled={currentIndex === 0}\n onClick={goToPrevious}\n className=\"p-2 text-white/50 hover:text-white disabled:opacity-20 transition-colors\"\n >\n <ChevronLeft size={32} />\n </button>\n <div className=\"h-6 w-[1px] bg-white/10\" />\n <button\n disabled={currentIndex === presentation.slides.length - 1}\n onClick={goToNext}\n className=\"p-2 text-white/50 hover:text-white disabled:opacity-20 transition-colors\"\n >\n <ChevronRight size={32} />\n </button>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["useState","useCallback","useMemo","useEffect","React","useState","Type","ImageIcon","Square","Download","Plus","Trash2","Bold","Italic","AlignLeft","AlignCenter","AlignRight","List","LayoutIcon","Columns","FileText","History","Share2","Play","Sparkles","RefreshCw","clsx","twMerge","cn","inputs","Fragment","jsx","jsxs","FONTS","FONT_SIZES","SHAPE_CATEGORIES","ShapesDropdown","onAddShape","isOpen","setIsOpen","useState","React","cat","s","Toolbar","onAddText","onAddImage","onAddSlide","onExport","onFormatText","onDeleteElement","onApplyLayout","onPlay","selectedElement","appName","onAiAction","onAiResponseAction","aiResponse","isAiLoading","onNewPresentation","onLoadPresentation","fileInputRef","activeTab","setActiveTab","showLayouts","setShowLayouts","showAiDialog","setShowAiDialog","showFileMenu","setShowFileMenu","showUploadModal","setShowUploadModal","uploadType","setUploadType","uploadUrl","setUploadUrl","isText","isShape","PPT_RED","cn","Plus","Download","Share2","Play","LayoutIcon","FileText","List","Columns","e","f","Bold","Italic","AlignLeft","AlignCenter","AlignRight","_a","Square","Type","ImageIcon","Sparkles","RefreshCw","Trash2","History","file","Trash2","Copy","GripVertical","DndContext","closestCenter","KeyboardSensor","PointerSensor","useSensor","useSensors","SortableContext","sortableKeyboardCoordinates","verticalListSortingStrategy","useSortable","CSS","jsx","jsxs","SortableSlide","slide","index","isActive","onSelect","onDelete","onDuplicate","showDelete","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","cn","__spreadProps","__spreadValues","GripVertical","Copy","Trash2","a","b","el","_a","Sidebar","slides","currentSlideIndex","onSelectSlide","onDeleteSlide","onDuplicateSlide","onReorderSlides","sensors","useSensors","useSensor","PointerSensor","KeyboardSensor","sortableKeyboardCoordinates","DndContext","closestCenter","event","active","over","oldIndex","s","newIndex","SortableContext","verticalListSortingStrategy","useEffect","useRef","fabric","jsx","EditorCanvas","slide","onElementUpdate","onSelect","canvasRef","useRef","fabricCanvas","isInternalUpdate","onElementUpdateRef","onSelectRef","useEffect","canvas","clamp","obj","bound","e","handleUpdate","_a","elementId","__spreadValues","syncSelection","_b","handleGlobalKeyDown","activeObj","step","moved","listener","existingObjs","slideIds","id","sorted","a","b","el","o","updates","newObj","commonProps","__spreadProps","shapeFill","img","err","pptxgen","PptxExporter","presentation","_a","_b","pptx","pptxgen","emuWidth","emuHeight","canvasWidth","canvasHeight","getInchesX","px","getInchesY","slide","pptxSlide","a","b","el","transparency","common","__spreadProps","__spreadValues","shapeType","JSZip","PptxParser","input","_a","_b","data","response","status","statusText","detail","errorJson","e","zip","presentationXml","presentationDoc","sldSz","sldIdList","slides","i","slideNum","slidePath","slideXml","slide","el","name","parent","elements","emu","srgbClr","hex","alphaNode","opacity","schemeClr","relId","slideIndex","relsXml","relsDoc","relationship","r","target","mediaPath","xml","doc","zIndex","bg","blip","mediaFile","spTree","children","child","localName","txBody","xfrm","off","ext","paragraphs","content","fontSize","color","isBulleted","p","pPr","buNone","runs","t","rPr","sz","style","prstGeom","prst","spPr","useEffect","useState","ChevronLeft","ChevronRight","X","jsx","jsxs","PresenterMode","presentation","initialSlideIndex","onClose","currentIndex","setCurrentIndex","useState","currentSlide","goToPrevious","goToNext","useEffect","handleKeyDown","e","scale","setScale","updateScale","availableWidth","availableHeight","slideWidth","slideHeight","scaleX","scaleY","newScale","X","EditorCanvas","ChevronLeft","ChevronRight","GoogleGenerativeAI","jsx","jsxs","PptEditor","initialPresentation","url","appName","onChange","geminiApiKey","presentation","setPresentation","useState","history","setHistory","redoStack","setRedoStack","currentSlideIndex","setCurrentSlideIndex","selectedElementId","setSelectedElementId","isPreviewMode","setIsPreviewMode","aiResponse","setAiResponse","isLoading","setIsLoading","useEffect","handleLoadPresentation","isAiLoading","setIsAiLoading","lastAiPrompt","setLastAiPrompt","currentSlide","selectedElement","useMemo","el","saveToHistory","useCallback","state","prevHistory","undo","last","prev","redo","next","handleUpdateSlide","updates","newSlides","__spreadValues","updated","__spreadProps","h","handleElementUpdate","elementId","slide","newElements","handleFormatText","e","handleDeleteElement","handleAddText","newElement","handleAddImage","file","id","handleAddShape","shapeType","handleAddSlide","newSlide","handleDeleteSlide","index","_","i","handleDuplicateSlide","slideToClone","handleReorderSlides","oldIndex","newIndex","removed","handleApplyLayout","layoutType","elements","timestamp","handleAiAction","action","element","model","GoogleGenerativeAI","elementContext","prompt","response","error","handleAiResponseAction","originalElement","handleExport","PptxExporter","handlePlay","elem","handleClosePresenter","handleFullscreenChange","handleKeyDown","activeElement","handleNewPresentation","input","parser","PptxParser","result","err","PresenterMode","Toolbar","Sidebar","EditorCanvas"]}
1
+ {"version":3,"sources":["#style-inject:#style-inject","../src/tailwind.css","../src/components/PptEditor.tsx","../src/components/Toolbar.tsx","../src/lib/utils.ts","../src/components/Sidebar.tsx","../src/components/EditorCanvas.tsx","../src/lib/pptx-exporter.ts","../src/lib/pptx-parser.ts","../src/components/PresenterMode.tsx"],"sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\"@import\\\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Lato:wght@400;700&family=Open+Sans:wght@400;600;700&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&family=Roboto+Slab:wght@400;700&family=Playfair+Display:wght@400;700&family=Merriweather:wght@400;700&family=Nunito+Sans:wght@400;600;700&family=Montserrat:wght@400;600;700&family=Oswald:wght@400;500&family=Raleway:wght@400;600;700&family=Ubuntu:wght@400;500;700&family=Lora:wght@400;700&family=PT+Sans:wght@400;700&family=PT+Serif:wght@400;700&family=Play:wght@400;700&family=Arvo:wght@400;700&family=Kanit:wght@400;500;600&display=swap\\\";/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: ui-sans-serif, system-ui, sans-serif, \\\"Apple Color Emoji\\\", \\\"Segoe UI Emoji\\\", \\\"Segoe UI Symbol\\\", \\\"Noto Color Emoji\\\";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace;--color-red-50: oklch(97.1% .013 17.38);--color-red-100: oklch(93.6% .032 17.717);--color-red-200: oklch(88.5% .062 18.334);--color-red-400: oklch(70.4% .191 22.216);--color-red-500: oklch(63.7% .237 25.331);--color-red-600: oklch(57.7% .245 27.325);--color-orange-50: oklch(98% .016 73.684);--color-amber-500: oklch(76.9% .188 70.08);--color-emerald-50: oklch(97.9% .021 166.113);--color-emerald-100: oklch(95% .052 163.051);--color-emerald-500: oklch(69.6% .17 162.48);--color-emerald-600: oklch(59.6% .145 163.225);--color-emerald-700: oklch(50.8% .118 165.612);--color-blue-50: oklch(97% .014 254.604);--color-blue-100: oklch(93.2% .032 255.585);--color-blue-400: oklch(70.7% .165 254.624);--color-blue-500: oklch(62.3% .214 259.815);--color-blue-600: oklch(54.6% .245 262.881);--color-blue-700: oklch(48.8% .243 264.376);--color-purple-500: oklch(62.7% .265 303.9);--color-purple-600: oklch(55.8% .288 302.321);--color-slate-50: oklch(98.4% .003 247.858);--color-slate-100: oklch(96.8% .007 247.896);--color-slate-200: oklch(92.9% .013 255.508);--color-slate-300: oklch(86.9% .022 252.894);--color-slate-400: oklch(70.4% .04 256.788);--color-slate-500: oklch(55.4% .046 257.417);--color-slate-600: oklch(44.6% .043 257.281);--color-slate-700: oklch(37.2% .044 257.287);--color-slate-800: oklch(27.9% .041 260.031);--color-slate-900: oklch(20.8% .042 265.755);--color-black: #000;--color-white: #fff;--spacing: .25rem;--container-2xl: 42rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--text-4xl: 2.25rem;--text-4xl--line-height: calc(2.5 / 2.25);--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--font-weight-black: 900;--tracking-tighter: -.05em;--tracking-tight: -.025em;--tracking-widest: .1em;--leading-tight: 1.25;--leading-relaxed: 1.625;--radius-sm: .25rem;--radius-md: .375rem;--radius-lg: .5rem;--radius-xl: .75rem;--radius-2xl: 1rem;--radius-3xl: 1.5rem;--animate-spin: spin 1s linear infinite;--blur-sm: 8px;--blur-md: 12px;--aspect-video: 16 / 9;--default-transition-duration: .15s;--default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:var(--default-font-family, ui-sans-serif, system-ui, sans-serif, \\\"Apple Color Emoji\\\", \\\"Segoe UI Emoji\\\", \\\"Segoe UI Symbol\\\", \\\"Noto Color Emoji\\\");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::placeholder{color:currentcolor;@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]),::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-1{top:calc(var(--spacing) * 1)}.top-1\\\\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-10{top:calc(var(--spacing) * 10)}.top-full{top:100%}.right-0{right:calc(var(--spacing) * 0)}.right-1{right:calc(var(--spacing) * 1)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-1{bottom:calc(var(--spacing) * 1)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-8{bottom:calc(var(--spacing) * 8)}.bottom-10{bottom:calc(var(--spacing) * 10)}.left-0{left:calc(var(--spacing) * 0)}.left-1{left:calc(var(--spacing) * 1)}.left-1\\\\/2{left:50%}.left-2{left:calc(var(--spacing) * 2)}.left-4{left:calc(var(--spacing) * 4)}.z-10{z-index:10}.z-50{z-index:50}.z-\\\\[100\\\\]{z-index:100}.z-\\\\[1000\\\\]{z-index:1000}.z-\\\\[2000\\\\]{z-index:2000}.z-\\\\[2001\\\\]{z-index:2001}.z-\\\\[99999\\\\]{z-index:99999}.mx-1{margin-inline:calc(var(--spacing) * 1)}.mx-1\\\\.5{margin-inline:calc(var(--spacing) * 1.5)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.my-1{margin-block:calc(var(--spacing) * 1)}.my-auto{margin-block:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-auto{margin-top:auto}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-0{margin-bottom:calc(var(--spacing) * 0)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-0{margin-left:calc(var(--spacing) * 0)}.ml-0\\\\.5{margin-left:calc(var(--spacing) * .5)}.ml-4{margin-left:calc(var(--spacing) * 4)}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.table{display:table}.aspect-square{aspect-ratio:1 / 1}.aspect-video{aspect-ratio:var(--aspect-video)}.h-0{height:calc(var(--spacing) * 0)}.h-0\\\\.5{height:calc(var(--spacing) * .5)}.h-1{height:calc(var(--spacing) * 1)}.h-1\\\\.5{height:calc(var(--spacing) * 1.5)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-full{height:100%}.h-screen{height:100vh}.min-h-screen{min-height:100vh}.w-1{width:calc(var(--spacing) * 1)}.w-1\\\\.5{width:calc(var(--spacing) * 1.5)}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-32{width:calc(var(--spacing) * 32)}.w-36{width:calc(var(--spacing) * 36)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-56{width:calc(var(--spacing) * 56)}.w-64{width:calc(var(--spacing) * 64)}.w-\\\\[1px\\\\]{width:1px}.w-\\\\[480px\\\\]{width:480px}.w-full{width:100%}.w-screen{width:100vw}.max-w-2xl{max-width:var(--container-2xl)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\\\\[64px\\\\]{min-width:64px}.min-w-\\\\[68px\\\\]{min-width:68px}.min-w-fit{min-width:fit-content}.flex-1{flex:1}.shrink-0{flex-shrink:0}.origin-center{transform-origin:center}.origin-top-left{transform-origin:0 0}.-translate-x-1{--tw-translate-x: calc(var(--spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-1\\\\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1{--tw-translate-y: calc(var(--spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\\\\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-105{--tw-scale-x: 105%;--tw-scale-y: 105%;--tw-scale-z: 105%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-110{--tw-scale-x: 110%;--tw-scale-y: 110%;--tw-scale-z: 110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.rotate-45{rotate:45deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-grab{cursor:grab}.cursor-pointer{cursor:pointer}.resize{resize:both}.appearance-none{appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-start{justify-content:flex-start}.justify-stretch{justify-content:stretch}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\\\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\\\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}.space-y-2{:where(&>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}}.space-y-4{:where(&>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}}.space-y-6{:where(&>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-full{border-radius:calc(infinity * 1px)}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-b-xl{border-bottom-right-radius:var(--radius-xl);border-bottom-left-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\\\\[1\\\\.5px\\\\]{border-style:var(--tw-border-style);border-width:1.5px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style: dashed;border-style:dashed}.border-\\\\[\\\\#B7472A\\\\]{border-color:#b7472a}.border-emerald-100{border-color:var(--color-emerald-100)}.border-emerald-100\\\\/50{border-color:color-mix(in srgb,oklch(95% .052 163.051) 50%,transparent);@supports (color: color-mix(in lab,red,red)){border-color:color-mix(in oklab,var(--color-emerald-100) 50%,transparent)}}.border-red-200{border-color:var(--color-red-200)}.border-slate-100{border-color:var(--color-slate-100)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-200\\\\/60{border-color:color-mix(in srgb,oklch(92.9% .013 255.508) 60%,transparent);@supports (color: color-mix(in lab,red,red)){border-color:color-mix(in oklab,var(--color-slate-200) 60%,transparent)}}.border-transparent{border-color:transparent}.border-white{border-color:var(--color-white)}.border-white\\\\/10{border-color:color-mix(in srgb,#fff 10%,transparent);@supports (color: color-mix(in lab,red,red)){border-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.bg-\\\\[\\\\#0A0A0A\\\\]{background-color:#0a0a0a}.bg-\\\\[\\\\#B7472A\\\\]{background-color:#b7472a}.bg-black{background-color:var(--color-black)}.bg-black\\\\/40{background-color:color-mix(in srgb,#000 40%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 40%,transparent)}}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-600{background-color:var(--color-blue-600)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-50\\\\/50{background-color:color-mix(in srgb,oklch(97.9% .021 166.113) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-emerald-50) 50%,transparent)}}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-orange-50{background-color:var(--color-orange-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-50\\\\/50{background-color:color-mix(in srgb,oklch(98.4% .003 247.858) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-slate-50) 50%,transparent)}}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-200{background-color:var(--color-slate-200)}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-slate-900\\\\/40{background-color:color-mix(in srgb,oklch(20.8% .042 265.755) 40%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-slate-900) 40%,transparent)}}.bg-transparent{background-color:transparent}.bg-white{background-color:var(--color-white)}.bg-white\\\\/10{background-color:color-mix(in srgb,#fff 10%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.bg-white\\\\/50{background-color:color-mix(in srgb,#fff 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-white) 50%,transparent)}}.bg-white\\\\/80{background-color:color-mix(in srgb,#fff 80%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.bg-gradient-to-b{--tw-gradient-position: to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-black{--tw-gradient-from: var(--color-black);--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-black\\\\/60{--tw-gradient-from: color-mix(in srgb, #000 60%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-gradient-from: color-mix(in oklab, var(--color-black) 60%, transparent)}--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-transparent{--tw-gradient-to: transparent;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.fill-slate-700{fill:var(--color-slate-700)}.p-0{padding:calc(var(--spacing) * 0)}.p-0\\\\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:calc(var(--spacing) * 1)}.p-1\\\\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.p-12{padding:calc(var(--spacing) * 12)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\\\\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0{padding-block:calc(var(--spacing) * 0)}.py-0\\\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\\\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-11{padding-left:calc(var(--spacing) * 11)}.text-center{text-align:center}.text-left{text-align:left}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading, var(--text-4xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading, var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\\\\[7px\\\\]{font-size:7px}.text-\\\\[9px\\\\]{font-size:9px}.text-\\\\[10px\\\\]{font-size:10px}.text-\\\\[11px\\\\]{font-size:11px}.leading-relaxed{--tw-leading: var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading: var(--leading-tight);line-height:var(--leading-tight)}.font-black{--tw-font-weight: var(--font-weight-black);font-weight:var(--font-weight-black)}.font-bold{--tw-font-weight: var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight: var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight: var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\\\\[0\\\\.2em\\\\]{--tw-tracking: .2em;letter-spacing:.2em}.tracking-tight{--tw-tracking: var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-tighter{--tw-tracking: var(--tracking-tighter);letter-spacing:var(--tracking-tighter)}.tracking-widest{--tw-tracking: var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-amber-500{color:var(--color-amber-500)}.text-black{color:var(--color-black)}.text-blue-500{color:var(--color-blue-500)}.text-blue-600{color:var(--color-blue-600)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-600\\\\/70{color:color-mix(in srgb,oklch(59.6% .145 163.225) 70%,transparent);@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,var(--color-emerald-600) 70%,transparent)}}.text-emerald-700{color:var(--color-emerald-700)}.text-purple-500{color:var(--color-purple-500)}.text-purple-600{color:var(--color-purple-600)}.text-red-400{color:var(--color-red-400)}.text-red-600{color:var(--color-red-600)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-800{color:var(--color-slate-800)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.text-white\\\\/50{color:color-mix(in srgb,#fff 50%,transparent);@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,var(--color-white) 50%,transparent)}}.text-white\\\\/80{color:color-mix(in srgb,#fff 80%,transparent);@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0%}.shadow-2xl{--tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / .25));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-black{--tw-shadow-color: #000;@supports (color: color-mix(in lab,red,red)){--tw-shadow-color: color-mix(in oklab, var(--color-black) var(--tw-shadow-alpha), transparent)}}.shadow-black\\\\/80{--tw-shadow-color: color-mix(in srgb, #000 80%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-black) 80%, transparent) var(--tw-shadow-alpha), transparent)}}.shadow-blue-500{--tw-shadow-color: oklch(62.3% .214 259.815);@supports (color: color-mix(in lab,red,red)){--tw-shadow-color: color-mix(in oklab, var(--color-blue-500) var(--tw-shadow-alpha), transparent)}}.shadow-blue-500\\\\/20{--tw-shadow-color: color-mix(in srgb, oklch(62.3% .214 259.815) 20%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-blue-500) 20%, transparent) var(--tw-shadow-alpha), transparent)}}.backdrop-blur-\\\\[1px\\\\]{--tw-backdrop-blur: blur(1px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-md{--tw-backdrop-blur: blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur: blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.duration-200{--tw-duration: .2s;transition-duration:.2s}.duration-300{--tw-duration: .3s;transition-duration:.3s}.duration-500{--tw-duration: .5s;transition-duration:.5s}.outline-none{--tw-outline-style: none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.group-hover\\\\:scale-105{&:is(:where(.group):hover *){@media(hover:hover){--tw-scale-x: 105%;--tw-scale-y: 105%;--tw-scale-z: 105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}}.group-hover\\\\:scale-110{&:is(:where(.group):hover *){@media(hover:hover){--tw-scale-x: 110%;--tw-scale-y: 110%;--tw-scale-z: 110%;scale:var(--tw-scale-x) var(--tw-scale-y)}}}.group-hover\\\\:bg-blue-50{&:is(:where(.group):hover *){@media(hover:hover){background-color:var(--color-blue-50)}}}.group-hover\\\\:bg-blue-100{&:is(:where(.group):hover *){@media(hover:hover){background-color:var(--color-blue-100)}}}.group-hover\\\\:bg-emerald-50{&:is(:where(.group):hover *){@media(hover:hover){background-color:var(--color-emerald-50)}}}.group-hover\\\\:fill-slate-900{&:is(:where(.group):hover *){@media(hover:hover){fill:var(--color-slate-900)}}}.group-hover\\\\:text-blue-600{&:is(:where(.group):hover *){@media(hover:hover){color:var(--color-blue-600)}}}.group-hover\\\\:opacity-100{&:is(:where(.group):hover *){@media(hover:hover){opacity:100%}}}.group-hover\\\\:shadow-sm{&:is(:where(.group):hover *){@media(hover:hover){--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}}.placeholder\\\\:text-slate-400{&::placeholder{color:var(--color-slate-400)}}.hover\\\\:border-blue-400{&:hover{@media(hover:hover){border-color:var(--color-blue-400)}}}.hover\\\\:border-slate-100{&:hover{@media(hover:hover){border-color:var(--color-slate-100)}}}.hover\\\\:border-slate-200{&:hover{@media(hover:hover){border-color:var(--color-slate-200)}}}.hover\\\\:border-slate-300{&:hover{@media(hover:hover){border-color:var(--color-slate-300)}}}.hover\\\\:bg-black{&:hover{@media(hover:hover){background-color:var(--color-black)}}}.hover\\\\:bg-blue-50{&:hover{@media(hover:hover){background-color:var(--color-blue-50)}}}.hover\\\\:bg-blue-50\\\\/50{&:hover{@media(hover:hover){background-color:color-mix(in srgb,oklch(97% .014 254.604) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-blue-50) 50%,transparent)}}}}.hover\\\\:bg-blue-700{&:hover{@media(hover:hover){background-color:var(--color-blue-700)}}}.hover\\\\:bg-red-50{&:hover{@media(hover:hover){background-color:var(--color-red-50)}}}.hover\\\\:bg-slate-50{&:hover{@media(hover:hover){background-color:var(--color-slate-50)}}}.hover\\\\:bg-slate-100{&:hover{@media(hover:hover){background-color:var(--color-slate-100)}}}.hover\\\\:bg-white{&:hover{@media(hover:hover){background-color:var(--color-white)}}}.hover\\\\:bg-white\\\\/20{&:hover{@media(hover:hover){background-color:color-mix(in srgb,#fff 20%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-white) 20%,transparent)}}}}.hover\\\\:text-blue-500{&:hover{@media(hover:hover){color:var(--color-blue-500)}}}.hover\\\\:text-red-500{&:hover{@media(hover:hover){color:var(--color-red-500)}}}.hover\\\\:text-slate-500{&:hover{@media(hover:hover){color:var(--color-slate-500)}}}.hover\\\\:text-slate-600{&:hover{@media(hover:hover){color:var(--color-slate-600)}}}.hover\\\\:text-slate-700{&:hover{@media(hover:hover){color:var(--color-slate-700)}}}.hover\\\\:text-white{&:hover{@media(hover:hover){color:var(--color-white)}}}.hover\\\\:opacity-100{&:hover{@media(hover:hover){opacity:100%}}}.focus\\\\:border-blue-500{&:focus{border-color:var(--color-blue-500)}}.focus\\\\:border-slate-400{&:focus{border-color:var(--color-slate-400)}}.focus\\\\:ring-4{&:focus{--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus\\\\:ring-blue-500\\\\/10{&:focus{--tw-ring-color: color-mix(in srgb, oklch(62.3% .214 259.815) 10%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-ring-color: color-mix(in oklab, var(--color-blue-500) 10%, transparent)}}}.focus\\\\:ring-slate-400\\\\/5{&:focus{--tw-ring-color: color-mix(in srgb, oklch(70.4% .04 256.788) 5%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-ring-color: color-mix(in oklab, var(--color-slate-400) 5%, transparent)}}}.focus\\\\:outline-none{&:focus{--tw-outline-style: none;outline-style:none}}.active\\\\:cursor-grabbing{&:active{cursor:grabbing}}.disabled\\\\:bg-slate-200{&:disabled{background-color:var(--color-slate-200)}}.disabled\\\\:bg-slate-300{&:disabled{background-color:var(--color-slate-300)}}.disabled\\\\:text-slate-400{&:disabled{color:var(--color-slate-400)}}.disabled\\\\:opacity-20{&:disabled{opacity:20%}}.disabled\\\\:opacity-30{&:disabled{opacity:30%}}.disabled\\\\:opacity-50{&:disabled{opacity:50%}}.md\\\\:space-y-8{@media(width>=48rem){:where(&>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}}}.md\\\\:p-12{@media(width>=48rem){padding:calc(var(--spacing) * 12)}}}@keyframes blob{0%{transform:translate(0) scale(1)}33%{transform:translate(30px,-50px) scale(1.1)}66%{transform:translate(-20px,20px) scale(.9)}to{transform:translate(0) scale(1)}}.animate-blob{animation:blob 7s infinite}.animation-delay-2000{animation-delay:2s}.animation-delay-4000{animation-delay:4s}@property --tw-translate-x{syntax: \\\"*\\\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \\\"*\\\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \\\"*\\\"; inherits: false; initial-value: 0;}@property --tw-scale-x{syntax: \\\"*\\\"; inherits: false; initial-value: 1;}@property --tw-scale-y{syntax: \\\"*\\\"; inherits: false; initial-value: 1;}@property --tw-scale-z{syntax: \\\"*\\\"; inherits: false; initial-value: 1;}@property --tw-rotate-x{syntax: \\\"*\\\"; inherits: false;}@property --tw-rotate-y{syntax: \\\"*\\\"; inherits: false;}@property --tw-rotate-z{syntax: \\\"*\\\"; inherits: false;}@property --tw-skew-x{syntax: \\\"*\\\"; inherits: false;}@property --tw-skew-y{syntax: \\\"*\\\"; inherits: false;}@property --tw-space-y-reverse{syntax: \\\"*\\\"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: \\\"*\\\"; inherits: false; initial-value: solid;}@property --tw-gradient-position{syntax: \\\"*\\\"; inherits: false;}@property --tw-gradient-from{syntax: \\\"<color>\\\"; inherits: false; initial-value: #0000;}@property --tw-gradient-via{syntax: \\\"<color>\\\"; inherits: false; initial-value: #0000;}@property --tw-gradient-to{syntax: \\\"<color>\\\"; inherits: false; initial-value: #0000;}@property --tw-gradient-stops{syntax: \\\"*\\\"; inherits: false;}@property --tw-gradient-via-stops{syntax: \\\"*\\\"; inherits: false;}@property --tw-gradient-from-position{syntax: \\\"<length-percentage>\\\"; inherits: false; initial-value: 0%;}@property --tw-gradient-via-position{syntax: \\\"<length-percentage>\\\"; inherits: false; initial-value: 50%;}@property --tw-gradient-to-position{syntax: \\\"<length-percentage>\\\"; inherits: false; initial-value: 100%;}@property --tw-leading{syntax: \\\"*\\\"; inherits: false;}@property --tw-font-weight{syntax: \\\"*\\\"; inherits: false;}@property --tw-tracking{syntax: \\\"*\\\"; inherits: false;}@property --tw-shadow{syntax: \\\"*\\\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \\\"*\\\"; inherits: false;}@property --tw-shadow-alpha{syntax: \\\"<percentage>\\\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \\\"*\\\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \\\"*\\\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \\\"<percentage>\\\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \\\"*\\\"; inherits: false;}@property --tw-ring-shadow{syntax: \\\"*\\\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \\\"*\\\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \\\"*\\\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \\\"*\\\"; inherits: false;}@property --tw-ring-offset-width{syntax: \\\"<length>\\\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \\\"*\\\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \\\"*\\\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-backdrop-blur{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-brightness{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-contrast{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-grayscale{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-hue-rotate{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-invert{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-opacity{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-saturate{syntax: \\\"*\\\"; inherits: false;}@property --tw-backdrop-sepia{syntax: \\\"*\\\"; inherits: false;}@property --tw-duration{syntax: \\\"*\\\"; inherits: false;}@keyframes spin{to{transform:rotate(360deg)}}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-scale-z: 1;--tw-rotate-x: initial;--tw-rotate-y: initial;--tw-rotate-z: initial;--tw-skew-x: initial;--tw-skew-y: initial;--tw-space-y-reverse: 0;--tw-border-style: solid;--tw-gradient-position: initial;--tw-gradient-from: #0000;--tw-gradient-via: #0000;--tw-gradient-to: #0000;--tw-gradient-stops: initial;--tw-gradient-via-stops: initial;--tw-gradient-from-position: 0%;--tw-gradient-via-position: 50%;--tw-gradient-to-position: 100%;--tw-leading: initial;--tw-font-weight: initial;--tw-tracking: initial;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-backdrop-blur: initial;--tw-backdrop-brightness: initial;--tw-backdrop-contrast: initial;--tw-backdrop-grayscale: initial;--tw-backdrop-hue-rotate: initial;--tw-backdrop-invert: initial;--tw-backdrop-opacity: initial;--tw-backdrop-saturate: initial;--tw-backdrop-sepia: initial;--tw-duration: initial}}}\\n\")","'use client';\n\nimport React, { useState, useCallback, useMemo, useEffect } from 'react';\nimport type { Presentation, Slide, SlideElement, PresentationSource } from '../lib/types';\nimport { Toolbar } from './Toolbar';\nimport { Sidebar } from './Sidebar';\nimport { EditorCanvas } from './EditorCanvas';\nimport { PptxExporter } from '../lib/pptx-exporter';\nimport { PptxParser } from '../lib/pptx-parser';\nimport { PresenterMode } from './PresenterMode';\nimport { GoogleGenerativeAI } from '@google/generative-ai';\n\ninterface PptEditorProps {\n initialPresentation?: Presentation;\n url?: string;\n appName?: string;\n onChange?: (presentation: Presentation) => void;\n geminiApiKey?: string;\n width: number | string;\n height: number | string;\n appBgColor?: string;\n showHomeOnEmpty?: boolean;\n initialSource?: PresentationSource;\n onSourceChange?: (source: PresentationSource, url?: string) => void;\n}\n\nexport const PptEditor: React.FC<PptEditorProps> = ({\n initialPresentation, url, appName = 'SlideCanvas', onChange, geminiApiKey,\n width, height, appBgColor = '#B7472A', showHomeOnEmpty = false,\n initialSource, onSourceChange\n}) => {\n const [presentation, setPresentation] = useState<Presentation>(\n initialPresentation || { slides: [{ id: 'slide-1', elements: [] }], layout: { width: 12192000, height: 6858000 } }\n );\n\n const [history, setHistory] = useState<Presentation[]>([]);\n const [redoStack, setRedoStack] = useState<Presentation[]>([]);\n\n const [currentSlideIndex, setCurrentSlideIndex] = useState(0);\n const [selectedElementId, setSelectedElementId] = useState<string | null>(null);\n const [isPreviewMode, setIsPreviewMode] = useState(false);\n const [aiResponse, setAiResponse] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [source, setSource] = useState<PresentationSource | null>(initialSource || (url ? 'url' : null));\n const [showInitialLayout, setShowInitialLayout] = useState(showHomeOnEmpty && !initialPresentation && !url && !initialSource);\n const [urlInput, setUrlInput] = useState('');\n\n useEffect(() => {\n if (url) {\n handleLoadPresentation(url);\n }\n }, [url]);\n const [isAiLoading, setIsAiLoading] = useState(false);\n const [lastAiPrompt, setLastAiPrompt] = useState<{ id: string, action: 'shorten' | 'reframe' | 'lengthen' } | null>(null);\n\n // Calculate UI scale based on width/height\n const uiScale = useMemo(() => {\n const w = typeof width === 'number' ? width : parseInt(String(width));\n if (isNaN(w)) return 1;\n // Base width for 1x scale is 1600px\n // Range: 0.7 to 1.0 (never scale up beyond 1x)\n return Math.min(Math.max(w / 1600, 0.7), 1);\n }, [width]);\n\n const currentSlide = presentation.slides[currentSlideIndex];\n\n const selectedElement = useMemo(() => {\n return currentSlide.elements.find(el => el.id === selectedElementId) || null;\n }, [currentSlide, selectedElementId]);\n\n const saveToHistory = useCallback((state: Presentation) => {\n setHistory(prevHistory => [...prevHistory.slice(-19), presentation]);\n setRedoStack([]);\n setPresentation(state);\n onChange?.(state);\n }, [onChange, presentation]);\n\n const undo = () => {\n if (history.length === 0) return;\n const last = history[history.length - 1];\n setRedoStack(prev => [...prev, presentation]);\n setHistory(prev => prev.slice(0, -1));\n setPresentation(last);\n };\n\n const redo = () => {\n if (redoStack.length === 0) return;\n const next = redoStack[redoStack.length - 1];\n setHistory(prev => [...prev, presentation]);\n setRedoStack(prev => prev.slice(0, -1));\n setPresentation(next);\n };\n\n const handleUpdateSlide = useCallback((updates: Partial<Slide>) => {\n setPresentation(prev => {\n const newSlides = [...prev.slides];\n newSlides[currentSlideIndex] = { ...newSlides[currentSlideIndex], ...updates };\n const updated = { ...prev, slides: newSlides };\n\n // Note: We can't call saveToHistory inside here easily without dependency issues, \n // but we can move history logic here if needed or keep it simple for now.\n // For now, let's just make it stable.\n setHistory(h => [...h.slice(-19), prev]);\n setRedoStack([]);\n onChange?.(updated);\n return updated;\n });\n }, [currentSlideIndex, onChange]);\n\n const handleElementUpdate = useCallback((elementId: string, updates: Partial<SlideElement>) => {\n setPresentation(prev => {\n const slide = prev.slides[currentSlideIndex];\n const newElements = slide.elements.map(el =>\n el.id === elementId ? { ...el, ...updates } as SlideElement : el\n );\n const newSlides = [...prev.slides];\n newSlides[currentSlideIndex] = { ...slide, elements: newElements };\n const updated = { ...prev, slides: newSlides };\n onChange?.(updated);\n return updated;\n });\n }, [currentSlideIndex, onChange]);\n\n const handleFormatText = (updates: any) => {\n if (!selectedElementId) return;\n const el = currentSlide.elements.find(e => e.id === selectedElementId);\n if (el) {\n handleElementUpdate(selectedElementId, updates);\n // Explicitly save to history for discrete formatting actions\n const slide = presentation.slides[currentSlideIndex];\n const newElements = slide.elements.map(e => e.id === selectedElementId ? { ...e, ...updates } : e);\n const newSlides = [...presentation.slides];\n newSlides[currentSlideIndex] = { ...slide, elements: newElements };\n saveToHistory({ ...presentation, slides: newSlides });\n }\n };\n\n const handleDeleteElement = useCallback(() => {\n if (!selectedElementId) return;\n const slide = presentation.slides[currentSlideIndex];\n const newElements = slide.elements.filter(el => el.id !== selectedElementId);\n handleUpdateSlide({ elements: newElements });\n setSelectedElementId(null);\n }, [selectedElementId, currentSlideIndex, presentation, handleUpdateSlide]);\n\n const handleAddText = () => {\n const newElement: SlideElement = {\n id: `text-${Date.now()}`,\n type: 'text',\n content: 'New Text',\n x: 100,\n y: 100,\n width: 400,\n height: 100,\n fontSize: 48,\n fontFamily: 'Arial',\n color: '#000000',\n zIndex: currentSlide.elements.length\n };\n handleUpdateSlide({ elements: [...currentSlide.elements, newElement] });\n };\n\n const handleAddImage = (file: File) => {\n const url = URL.createObjectURL(file);\n const id = `img-${Date.now()}`;\n const newElement: SlideElement = {\n id,\n type: 'image',\n src: url,\n x: 100,\n y: 100,\n width: 400,\n height: 250,\n zIndex: currentSlide.elements.length\n };\n handleUpdateSlide({ elements: [...currentSlide.elements, newElement] });\n setSelectedElementId(id);\n };\n\n const handleAddShape = (shapeType: 'rect' | 'ellipse') => {\n const newElement: SlideElement = {\n id: `shape-${Date.now()}`,\n type: 'shape',\n shapeType,\n fill: '#3b82f6',\n x: 200,\n y: 200,\n width: 200,\n height: 200,\n zIndex: currentSlide.elements.length\n };\n handleUpdateSlide({ elements: [...currentSlide.elements, newElement] });\n }\n\n const handleAddSlide = () => {\n const newSlide: Slide = { id: `slide-${Date.now()}`, elements: [] };\n saveToHistory({ ...presentation, slides: [...presentation.slides, newSlide] });\n setCurrentSlideIndex(presentation.slides.length);\n };\n\n const handleDeleteSlide = (index: number) => {\n if (presentation.slides.length <= 1) return;\n\n const newSlides = presentation.slides.filter((_, i) => i !== index);\n saveToHistory({ ...presentation, slides: newSlides });\n\n // Adjust current slide index if needed\n if (index <= currentSlideIndex) {\n setCurrentSlideIndex(Math.max(0, currentSlideIndex - 1));\n }\n };\n\n const handleDuplicateSlide = (index: number) => {\n const slideToClone = presentation.slides[index];\n const newSlide: Slide = {\n ...slideToClone,\n id: `slide-${Date.now()}`,\n elements: slideToClone.elements.map(el => ({\n ...el,\n id: `${el.type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n }))\n };\n const newSlides = [...presentation.slides];\n newSlides.splice(index + 1, 0, newSlide);\n saveToHistory({ ...presentation, slides: newSlides });\n setCurrentSlideIndex(index + 1);\n };\n\n const handleReorderSlides = (oldIndex: number, newIndex: number) => {\n if (oldIndex === newIndex) return;\n const newSlides = [...presentation.slides];\n const [removed] = newSlides.splice(oldIndex, 1);\n newSlides.splice(newIndex, 0, removed);\n\n saveToHistory({ ...presentation, slides: newSlides });\n\n if (currentSlideIndex === oldIndex) {\n setCurrentSlideIndex(newIndex);\n } else if (currentSlideIndex > oldIndex && currentSlideIndex <= newIndex) {\n setCurrentSlideIndex(currentSlideIndex - 1);\n } else if (currentSlideIndex < oldIndex && currentSlideIndex >= newIndex) {\n setCurrentSlideIndex(currentSlideIndex + 1);\n }\n };\n\n const handleApplyLayout = (layoutType: 'title' | 'content' | 'split') => {\n let elements: SlideElement[] = [];\n const timestamp = Date.now();\n\n if (layoutType === 'title') {\n elements = [\n {\n id: `text-title-${timestamp}`,\n type: 'text',\n content: 'Presentation Title',\n x: 100,\n y: 200,\n width: 1000,\n height: 150,\n fontSize: 80,\n fontFamily: 'Inter',\n color: '#000000',\n textAlign: 'center',\n isBold: true,\n zIndex: 0\n },\n {\n id: `text-sub-${timestamp}`,\n type: 'text',\n content: 'Subtitle goes here',\n x: 200,\n y: 380,\n width: 800,\n height: 80,\n fontSize: 36,\n fontFamily: 'Inter',\n color: '#64748b',\n textAlign: 'center',\n zIndex: 1\n }\n ];\n } else if (layoutType === 'content') {\n elements = [\n {\n id: `text-title-${timestamp}`,\n type: 'text',\n content: 'Slide Title',\n x: 60,\n y: 40,\n width: 800,\n height: 80,\n fontSize: 48,\n fontFamily: 'Inter',\n color: '#000000',\n isBold: true,\n zIndex: 0\n },\n {\n id: `text-body-${timestamp}`,\n type: 'text',\n content: '• Add your points here\\n• Press Enter for new line\\n• Use the toolbar to format',\n x: 60,\n y: 150,\n width: 1080,\n height: 480,\n fontSize: 28,\n fontFamily: 'Inter',\n color: '#334155',\n zIndex: 1,\n isBulleted: true\n }\n ];\n } else if (layoutType === 'split') {\n elements = [\n {\n id: `text-title-${timestamp}`,\n type: 'text',\n content: 'Comparison Layout',\n x: 60,\n y: 40,\n width: 1080,\n height: 80,\n fontSize: 48,\n fontFamily: 'Inter',\n color: '#000000',\n isBold: true,\n textAlign: 'center',\n zIndex: 0\n },\n {\n id: `text-left-${timestamp}`,\n type: 'text',\n content: 'Left column content goes here.',\n x: 60,\n y: 180,\n width: 520,\n height: 400,\n fontSize: 24,\n fontFamily: 'Inter',\n color: '#334155',\n zIndex: 1\n },\n {\n id: `text-right-${timestamp}`,\n type: 'text',\n content: 'Right column content goes here.',\n x: 620,\n y: 180,\n width: 520,\n height: 400,\n fontSize: 24,\n fontFamily: 'Inter',\n color: '#334155',\n zIndex: 2\n }\n ];\n }\n\n handleUpdateSlide({ elements });\n };\n\n const handleAiAction = async (id: string, action: 'shorten' | 'reframe' | 'lengthen') => {\n const slide = presentation.slides[currentSlideIndex];\n const element = slide.elements.find(el => el.id === id);\n if (!element || element.type !== 'text') return;\n\n setIsAiLoading(true);\n setAiResponse(null);\n setLastAiPrompt({ id, action });\n\n try {\n if (!geminiApiKey) {\n setAiResponse(\"Gemini API key is missing. Please provide it via the 'geminiApiKey' prop.\");\n setIsAiLoading(false);\n return;\n }\n const genAI = new GoogleGenerativeAI(geminiApiKey);\n const model = genAI.getGenerativeModel({\n model: \"gemini-flash-latest\",\n systemInstruction: \"You are a professional presentation assistant. Your task is to transform slide text according to specific user requests (shorten, reframe, or lengthen). \\n\\nCRITICAL RULES:\\n1. Return ONLY the transformed text. \\n2. Do NOT include any explanations, choices, or conversational fillers.\\n3. Do NOT use markdown formatting (like bolding or headers) unless specifically needed for bullet points.\\n4. If the input text is a title/headline, the output should be a professional title/headline.\\n5. If the input text is a bulleted list, the output MUST be a bulleted list using the same bullet style (e.g., '•').\\n6. Maintain the professional tone of the original presentation.\"\n });\n\n const elementContext = element.fontSize > 32 ? \"Title/Headline\" : \"Body Text/List\";\n const prompt = `Action: ${action.toUpperCase()}\\nText Role: ${elementContext}\\nOriginal Text: \"${element.content}\"\\n\\nTransformed Text:`;\n\n const result = await model.generateContent(prompt);\n const response = await result.response;\n setAiResponse(response.text().trim());\n } catch (error) {\n console.error(\"Gemini AI Error:\", error);\n setAiResponse(\"Error generating response. Please check your API key or connection.\");\n } finally {\n setIsAiLoading(false);\n }\n };\n\n const handleAiResponseAction = (action: 'replace' | 'addBelow' | 'regenerate') => {\n if (!aiResponse || !lastAiPrompt) return;\n\n if (action === 'regenerate') {\n handleAiAction(lastAiPrompt.id, lastAiPrompt.action);\n return;\n }\n\n const slide = presentation.slides[currentSlideIndex];\n const originalElement = slide.elements.find(el => el.id === lastAiPrompt.id);\n if (!originalElement || originalElement.type !== 'text') return;\n\n if (action === 'replace') {\n handleElementUpdate(lastAiPrompt.id, { content: aiResponse });\n } else if (action === 'addBelow') {\n const newElement: SlideElement = {\n ...originalElement,\n id: `text-ai-${Date.now()}`,\n content: aiResponse,\n y: originalElement.y + originalElement.height + 20,\n zIndex: slide.elements.length\n };\n handleUpdateSlide({ elements: [...slide.elements, newElement] });\n }\n\n setAiResponse(null);\n setLastAiPrompt(null);\n };\n\n const handleExport = async () => {\n const exporter = new PptxExporter();\n await exporter.export(presentation);\n };\n\n const handlePlay = () => {\n setIsPreviewMode(true);\n const elem = document.documentElement;\n if (elem.requestFullscreen) {\n elem.requestFullscreen();\n }\n };\n\n const handleClosePresenter = () => {\n setIsPreviewMode(false);\n if (document.fullscreenElement) {\n document.exitFullscreen();\n }\n };\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n if (!document.fullscreenElement) {\n setIsPreviewMode(false);\n }\n };\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n return () => document.removeEventListener('fullscreenchange', handleFullscreenChange);\n }, []);\n\n // Keyboard navigation\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Delete' || e.key === 'Backspace') {\n const activeElement = document.activeElement;\n if (activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA' || (activeElement as any)?.isContentEditable) return;\n handleDeleteElement();\n }\n if (e.ctrlKey || e.metaKey) {\n if (e.key === 'z') {\n e.preventDefault();\n if (e.shiftKey) redo(); else undo();\n }\n if (e.key === 'y') {\n e.preventDefault();\n redo();\n }\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [handleDeleteElement, undo, redo]);\n\n const updateSource = (newSource: PresentationSource, url?: string) => {\n setSource(newSource);\n onSourceChange?.(newSource, url);\n };\n\n const handleNewPresentation = () => {\n setPresentation({\n slides: [{ id: `slide-${Date.now()}`, elements: [] }],\n layout: { width: 12192000, height: 6858000 }\n });\n setCurrentSlideIndex(0);\n setSelectedElementId(null);\n updateSource('scratch');\n };\n\n const handleLoadPresentation = async (input: File | string) => {\n setIsLoading(true);\n try {\n const parser = new PptxParser();\n let prompt = input;\n if (typeof input === 'string') {\n prompt = `/api/proxy?url=${encodeURIComponent(input.trim())}`;\n updateSource('url', input.trim());\n } else {\n updateSource('uploaded');\n }\n const result = await parser.parse(prompt);\n setPresentation(result);\n setHistory([]);\n setRedoStack([]);\n setCurrentSlideIndex(0);\n setSelectedElementId(null);\n } catch (err) {\n console.error('Failed to load PPTX', err);\n alert('Failed to load presentation. Please ensure it is a valid .pptx.');\n } finally {\n setIsLoading(false);\n }\n };\n\n if (!width || !height) {\n return (\n <div className=\"flex items-center justify-center bg-red-50 text-red-600 p-8 rounded-xl border-2 border-red-200 font-bold\">\n Error: width and height props are compulsory for PptEditor.\n </div>\n );\n }\n\n return (\n <div\n className=\"flex flex-col bg-white relative\"\n style={{\n width: typeof width === 'number' ? `${width}px` : width,\n height: typeof height === 'number' ? `${height}px` : height,\n fontSize: `${16 * uiScale}px`\n }}\n >\n {showInitialLayout && (\n <div className=\"absolute inset-0 z-[2000] bg-white flex flex-col items-center justify-center p-6 md:p-12 overflow-y-auto\">\n <div className=\"max-w-2xl w-full text-center space-y-6 md:space-y-8 animate-in fade-in zoom-in-95 duration-500 my-auto\">\n {/* <div className=\"flex justify-center\">\n <div className=\"p-6 rounded-3xl\" style={{ backgroundColor: `${appBgColor}10` }}>\n <div className=\"p-4 rounded-2xl\" style={{ backgroundColor: appBgColor }}>\n <svg className=\"w-10 h-10 text-white\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7\" />\n </svg>\n </div>\n </div>\n </div> */}\n <div className=\"space-y-2\">\n <h2 className=\"text-4xl font-black tracking-tight text-slate-800\">{appName}</h2>\n <p className=\"text-slate-500 font-medium\">Create stunning presentations in seconds.</p>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <button\n onClick={() => { handleNewPresentation(); setShowInitialLayout(false); }}\n className=\"flex flex-col items-center justify-center gap-3 p-8 border-2 border-slate-100 rounded-3xl hover:border-slate-300 hover:bg-slate-50 transition-all group\"\n >\n <div className=\"p-3 bg-slate-100 rounded-xl group-hover:bg-blue-50 transition-colors\">\n <svg className=\"w-6 h-6 text-blue-600\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n </div>\n <span className=\"text-xs font-black uppercase tracking-widest text-slate-600\">Start New Deck</span>\n </button>\n <label className=\"flex flex-col items-center justify-center gap-3 p-8 border-2 border-slate-100 rounded-3xl hover:border-slate-300 hover:bg-slate-50 transition-all group cursor-pointer\">\n <div className=\"p-3 bg-slate-100 rounded-xl group-hover:bg-emerald-50 transition-colors\">\n <svg className=\"w-6 h-6 text-emerald-600\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-8l-4-4m0 0L8 8m4-4v12\" />\n </svg>\n </div>\n <span className=\"text-xs font-black uppercase tracking-widest text-slate-600\">Upload PPTX</span>\n <input\n type=\"file\"\n accept=\".pptx\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (file) {\n handleLoadPresentation(file);\n setShowInitialLayout(false);\n }\n }}\n />\n </label>\n </div>\n\n {/* URL Input */}\n <div className=\"space-y-4 pt-4 border-t border-slate-100\">\n <div className=\"flex gap-2\">\n <div className=\"flex-1 relative\">\n <svg className=\"absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9h18\" />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Paste presentation URL...\"\n value={urlInput}\n onChange={(e) => setUrlInput(e.target.value)}\n className=\"text-black w-full bg-slate-50 border border-slate-200 rounded-2xl pl-11 pr-5 py-4 focus:outline-none focus:border-slate-400 focus:ring-4 focus:ring-slate-400/5 text-sm transition-all\"\n />\n </div>\n <button\n onClick={() => {\n if (urlInput.trim()) {\n handleLoadPresentation(urlInput.trim());\n setShowInitialLayout(false);\n }\n }}\n disabled={!urlInput.trim() || isLoading}\n style={{ cursor: 'pointer' }}\n className=\"bg-slate-900 hover:bg-black disabled:bg-slate-200 disabled:text-slate-400 text-white font-bold px-8 rounded-2xl transition-all shadow-sm text-sm\"\n >\n Load\n </button>\n </div>\n <p className=\"text-[10px] text-slate-400 font-bold uppercase tracking-widest\">\n Supports S3, public links, and versioned assets\n </p>\n </div>\n </div>\n </div>\n )}\n {isPreviewMode && (\n <PresenterMode\n presentation={presentation}\n initialSlideIndex={currentSlideIndex}\n onClose={handleClosePresenter}\n />\n )}\n <Toolbar\n onAddText={handleAddText}\n onAddImage={handleAddImage}\n onAddShape={handleAddShape}\n onAddSlide={handleAddSlide}\n onExport={handleExport}\n onFormatText={handleFormatText}\n onDeleteElement={handleDeleteElement}\n onApplyLayout={handleApplyLayout}\n onPlay={handlePlay}\n onAiAction={handleAiAction}\n onAiResponseAction={handleAiResponseAction}\n onNewPresentation={handleNewPresentation}\n onLoadPresentation={handleLoadPresentation}\n aiResponse={aiResponse}\n isAiLoading={isAiLoading}\n selectedElement={selectedElement}\n appName={appName}\n appBgColor={appBgColor}\n uiScale={uiScale}\n source={source}\n />\n <div className=\"flex flex-1 overflow-hidden\">\n <Sidebar\n slides={presentation.slides}\n currentSlideIndex={currentSlideIndex}\n onSelectSlide={setCurrentSlideIndex}\n onDeleteSlide={handleDeleteSlide}\n onDuplicateSlide={handleDuplicateSlide}\n onReorderSlides={handleReorderSlides}\n uiScale={uiScale}\n />\n <div className=\"flex-1 flex items-center justify-center p-12 overflow-auto bg-white\">\n <EditorCanvas\n slide={currentSlide}\n onElementUpdate={handleElementUpdate}\n onSelect={setSelectedElementId}\n uiScale={uiScale}\n />\n </div>\n </div>\n </div>\n );\n};\n","'use client';\n\nimport React, { useState } from 'react';\nimport {\n Type, Image as ImageIcon, MousePointer2,\n Square, Circle, Download, Plus, Trash2,\n Bold, Italic, AlignLeft, AlignCenter, AlignRight,\n List, Layout as LayoutIcon, Columns, FileText,\n History, Share2, Play, Sparkles, RefreshCw, Check\n} from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport { SlideElement, PresentationSource } from '../lib/types';\n\ninterface ToolbarProps {\n onAddText: () => void;\n onAddImage: (file: File) => void;\n onAddShape: (type: any) => void;\n onAddSlide: () => void;\n onExport: () => void;\n onFormatText: (updates: any) => void;\n onDeleteElement: () => void;\n onApplyLayout: (type: 'title' | 'content' | 'split') => void;\n onPlay: () => void;\n selectedElement: SlideElement | null;\n appName: string;\n onAiAction: (id: string, action: 'shorten' | 'reframe' | 'lengthen') => void;\n onAiResponseAction: (action: 'replace' | 'addBelow' | 'regenerate') => void;\n aiResponse: string | null;\n isAiLoading: boolean;\n onNewPresentation: () => void;\n onLoadPresentation: (input: File | string) => void;\n appBgColor?: string;\n uiScale: number;\n source: PresentationSource | null;\n}\n\nconst FONTS = [\n 'Inter', 'Lato', 'Open Sans', 'Poppins', 'Roboto', 'Roboto Slab',\n 'Georgia', 'Playfair Display', 'Merriweather', 'Nunito Sans',\n 'Montserrat', 'Oswald', 'Raleway', 'Ubuntu', 'Lora',\n 'PT Sans', 'PT Serif', 'Play', 'Arvo', 'Kanit', 'Times New Roman', 'Arial'\n];\nconst FONT_SIZES = [12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 64, 72, 96];\n\nconst SHAPE_CATEGORIES = [\n {\n name: 'Basic Shapes',\n shapes: ['rect', 'circle', 'triangle', 'rightTriangle', 'rhombus', 'parallelogram', 'trapezoid', 'pentagon', 'hexagon', 'heptagon', 'octagon', 'heart', 'smiley', 'sun', 'moon']\n },\n {\n name: 'Arrows',\n shapes: ['arrowRight', 'arrowLeft', 'arrowUp', 'arrowDown', 'arrowLeftRight', 'arrowUpDown']\n },\n {\n name: 'Stars & Symbols',\n shapes: ['star4', 'star5', 'star6', 'star8', 'cloud', 'lightning']\n },\n {\n name: 'Equation Shapes',\n shapes: ['plus', 'minus', 'multiply', 'divide', 'equal']\n }\n];\n\nconst ShapeIcon = ({ type, className }: { type: string, className?: string }) => {\n switch (type) {\n case 'rect': return <svg viewBox=\"0 0 24 24\" className={className}><rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" fill=\"currentColor\" /></svg>;\n case 'circle': return <svg viewBox=\"0 0 24 24\" className={className}><circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"currentColor\" /></svg>;\n case 'triangle': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 4L20 18H4L12 4Z\" fill=\"currentColor\" /></svg>;\n case 'rightTriangle': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M4 4V20H20L4 4Z\" fill=\"currentColor\" /></svg>;\n case 'rhombus': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 4L20 12L12 20L4 12L12 4Z\" fill=\"currentColor\" /></svg>;\n case 'parallelogram': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M7 4H21L17 20H3L7 4Z\" fill=\"currentColor\" /></svg>;\n case 'trapezoid': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M6 4H18L21 20H3L6 4Z\" fill=\"currentColor\" /></svg>;\n case 'pentagon': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 3L21 9V19H3V9L12 3Z\" fill=\"currentColor\" /></svg>;\n case 'hexagon': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 3L20 7.5V16.5L12 21L4 16.5V7.5L12 3Z\" fill=\"currentColor\" /></svg>;\n case 'heptagon': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 3L18.5 6L21 13L16 20H8L3 13L5.5 6L12 3Z\" fill=\"currentColor\" /></svg>;\n case 'octagon': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M8.5 3H15.5L21 8.5V15.5L15.5 21H8.5L3 15.5V8.5L8.5 3Z\" fill=\"currentColor\" /></svg>;\n case 'heart': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" fill=\"currentColor\" /></svg>;\n case 'smiley': return <svg viewBox=\"0 0 24 24\" className={className}><circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"currentColor\" fillOpacity=\"0.2\" stroke=\"currentColor\" strokeWidth=\"2\" /><circle cx=\"9\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" /><circle cx=\"15\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" /><path d=\"M8 15C8 15 9.5 17 12 17C14.5 17 16 15 16 15\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" /></svg>;\n case 'sun': return <svg viewBox=\"0 0 24 24\" className={className}><circle cx=\"12\" cy=\"12\" r=\"5\" fill=\"currentColor\" /><path d=\"M12 2V4M12 20V22M4 12H2M22 12H20M19.07 4.93L17.66 6.34M6.34 17.66L4.93 19.07M4.93 4.93L6.34 6.34M17.66 17.66L19.07 19.07\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" /></svg>;\n case 'moon': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 3a9 9 0 1 0 9 9 7 7 0 0 1-9-9\" fill=\"currentColor\" /></svg>;\n case 'arrowRight': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M4 11h11.5l-3.5-3.5 1.5-1.5 6 6-6 6-1.5-1.5 3.5-3.5H4z\" fill=\"currentColor\" /></svg>;\n case 'arrowLeft': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M20 11H8.5l3.5-3.5L10.5 6l-6 6 6 6 1.5-1.5-3.5-3.5H20z\" fill=\"currentColor\" /></svg>;\n case 'arrowUp': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M13 20V8.5l3.5 3.5 1.5-1.5-6-6-6 6 1.5 1.5 3.5-3.5V20z\" fill=\"currentColor\" /></svg>;\n case 'arrowDown': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M11 4v11.5l-3.5-3.5-1.5 1.5 6 6 6-6-1.5-1.5-3.5 3.5V4z\" fill=\"currentColor\" /></svg>;\n case 'arrowLeftRight': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M4 12l4-4v3h8V8l4 4-4 4v-3H8v3l-4-4z\" fill=\"currentColor\" /></svg>;\n case 'arrowUpDown': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 4l-4 4h3v8H8l4 4 4-4h-3V8h3l-4-4z\" fill=\"currentColor\" /></svg>;\n case 'star4': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 2l2 8 8 2-8 2-2 8-2-8-8-2 8-2 2-8z\" fill=\"currentColor\" /></svg>;\n case 'star5': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 2l2.5 7.5H22l-6 4.5 2.5 7.5-6.5-4.5-6.5 4.5 2.5-7.5-6-4.5h7.5L12 2z\" fill=\"currentColor\" /></svg>;\n case 'star6': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 2l3 5 6-1-4 4.5 2 6.5-7-3-7 3 2-6.5-4-4.5 6 1 3-5z\" fill=\"currentColor\" /></svg>;\n case 'star8': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M12 2l2 4 4-2-2 4 4 2-4 2 2 4-4-2-2 4-2-4-4 2 2-4-4-2 4-2-2-4 4 2 2-4z\" fill=\"currentColor\" /></svg>;\n case 'cloud': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M17.5 19c-3 0-5.5-2.5-5.5-5.5 0-.2 0-.4.1-.6-2-.8-3.6-2.5-4.1-4.7C6.5 7.4 5 6 3 6c-1.7 0-3 1.3-3 3s1.3 3 3 3c.4 0 .8-.1 1.2-.2C4.1 13 5 14.5 6.5 15.5c.3 1.8 1.4 3.4 3 4.3.4.2.8.3 1.2.4 1.2.4 2.5.6 3.8.6 4.4 0 8-3.6 8-8s-3.6-8-8-8c-.4 0-.8 0-1.2.1-1.2.2-2.3.7-3.2 1.5C11 4.2 12.4 3.5 14 3.5c4.1 0 7.5 3.4 7.5 7.5s-1.8 7.5-4 8z\" fill=\"currentColor\" transform=\"scale(0.8) translate(3,3)\" /></svg>;\n case 'lightning': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M13 2L3 14h9v8l10-12h-9l3-8z\" fill=\"currentColor\" /></svg>;\n case 'plus': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\" fill=\"currentColor\" /></svg>;\n case 'minus': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M19 13H5v-2h14v2z\" fill=\"currentColor\" /></svg>;\n case 'multiply': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z\" fill=\"currentColor\" /></svg>;\n case 'divide': return <svg viewBox=\"0 0 24 24\" className={className}><circle cx=\"12\" cy=\"7\" r=\"2\" fill=\"currentColor\" /><circle cx=\"12\" cy=\"17\" r=\"2\" fill=\"currentColor\" /><rect x=\"5\" y=\"11\" width=\"14\" height=\"2\" fill=\"currentColor\" /></svg>;\n case 'equal': return <svg viewBox=\"0 0 24 24\" className={className}><path d=\"M19 10H5V8h14v2zm0 6H5v-2h14v2z\" fill=\"currentColor\" /></svg>;\n default: return <div className=\"w-6 h-6 bg-slate-200 rounded-sm\" />;\n }\n};\n\nconst ShapesDropdown = ({ onAddShape, uiScale }: { onAddShape: (type: string) => void, uiScale: number }) => {\n const [isOpen, setIsOpen] = useState(false);\n\n // Wire up the toggle to the window so the parent button can trigger it\n React.useEffect(() => {\n (window as any)._toggleShapesMenu = () => setIsOpen(!isOpen);\n return () => { (window as any)._toggleShapesMenu = undefined; };\n }, [isOpen]);\n\n if (!isOpen) return null;\n\n return (\n <div\n className=\"absolute top-full left-0 mt-2 bg-white border border-slate-200 rounded-2xl shadow-2xl p-4 overflow-y-auto z-[100] animate-in fade-in zoom-in-95 duration-200\"\n style={{\n width: `${320 * uiScale}px`,\n maxHeight: `${480 * uiScale}px`\n }}\n >\n <div className=\"flex flex-col gap-6\">\n {SHAPE_CATEGORIES.map(cat => (\n <div key={cat.name} className=\"flex flex-col gap-2\">\n <span className=\"text-[10px] font-black uppercase tracking-widest text-slate-400 px-1\" style={{ fontSize: `${10 * uiScale}px` }}>{cat.name}</span>\n <div className=\"grid grid-cols-5 gap-1\">\n {cat.shapes.map(s => (\n <button\n key={s}\n onClick={() => { onAddShape(s); setIsOpen(false); }}\n className=\"aspect-square hover:bg-slate-50 rounded-lg flex items-center justify-center border border-transparent hover:border-slate-100 transition-all group p-1\"\n title={s}\n >\n <div className=\"w-full h-full bg-slate-100 rounded-sm group-hover:bg-blue-100 group-hover:scale-110 transition-all flex items-center justify-center overflow-hidden p-1.5\">\n <ShapeIcon type={s} className=\"w-full h-full text-slate-400 group-hover:text-blue-600 transition-colors\" />\n </div>\n </button>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport const Toolbar: React.FC<ToolbarProps> = ({\n onAddText, onAddImage, onAddShape, onAddSlide, onExport,\n onFormatText, onDeleteElement, onApplyLayout, onPlay, selectedElement,\n appName, onAiAction, onAiResponseAction, aiResponse, isAiLoading,\n onNewPresentation, onLoadPresentation, appBgColor = '#B7472A', uiScale,\n source\n}) => {\n const fileInputRef = React.useRef<HTMLInputElement>(null);\n const [activeTab, setActiveTab] = useState('Home');\n const [showLayouts, setShowLayouts] = useState(false);\n const [showAiDialog, setShowAiDialog] = useState(false);\n const [showFileMenu, setShowFileMenu] = useState(false);\n const [showUploadModal, setShowUploadModal] = useState(false);\n const [uploadType, setUploadType] = useState<'file' | 'link'>('file');\n const [uploadUrl, setUploadUrl] = useState('');\n\n const isText = selectedElement?.type === 'text';\n const isShape = selectedElement?.type === 'shape';\n\n const PPT_RED = '#B7472A';\n\n return (\n <div\n className=\"flex flex-col border-b border-slate-200 bg-white z-50 select-none\"\n style={{ fontSize: `${12 * uiScale}px` }}\n >\n {/* Main Toolbar Row */}\n <div\n className=\"bg-white flex items-center justify-stretch border-b border-slate-200/60 transition-all duration-300 relative z-[1000]\"\n style={{ height: `${120 * uiScale}px`, overflow: 'visible' }}\n >\n {/* Slides Group */}\n <div className={cn(\"flex-1 flex flex-col items-center border-r border-slate-100 px-3 gap-1 h-full py-2\", uiScale < 0.84 ? \"min-w-0\" : \"min-w-fit\")}>\n <div className=\"flex items-center justify-center gap-1 my-auto\">\n <button\n onClick={onAddSlide}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg group transition-all min-w-[64px]\"\n >\n <div className=\"bg-orange-50 p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Plus size={20} style={{ color: appBgColor }} />\n </div>\n <span className=\"text-[10px] font-bold text-slate-700\">New Slide</span>\n </button>\n\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n\n <div className=\"relative\">\n <button\n onClick={() => setShowLayouts(!showLayouts)}\n className={cn(\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg transition-all min-w-[64px]\", showLayouts && \"bg-slate-100\")}\n >\n <div className=\"p-1.5 rounded-lg\">\n <LayoutIcon size={20} className=\"text-slate-500\" />\n </div>\n <span className=\"text-[10px] font-medium text-slate-500\">Layout</span>\n </button>\n {showLayouts && (\n <div className=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 bg-white border border-slate-200 rounded-xl shadow-2xl p-2 w-56 flex flex-col gap-1 z-[100] animate-in fade-in zoom-in-95 duration-200\">\n <button onClick={() => { onApplyLayout('title'); setShowLayouts(false); }} className=\"flex items-center gap-3 px-4 py-2.5 hover:bg-slate-50 rounded-lg text-xs font-semibold text-slate-700 transition-colors border border-transparent hover:border-slate-100\"><FileText size={16} className=\"text-blue-500\" /> Title Slide</button>\n <button onClick={() => { onApplyLayout('content'); setShowLayouts(false); }} className=\"flex items-center gap-3 px-4 py-2.5 hover:bg-slate-50 rounded-lg text-xs font-semibold text-slate-700 transition-colors border border-transparent hover:border-slate-100\"><List size={16} className=\"text-emerald-500\" /> Title & Content</button>\n <button onClick={() => { onApplyLayout('split'); setShowLayouts(false); }} className=\"flex items-center gap-3 px-4 py-2.5 hover:bg-slate-50 rounded-lg text-xs font-semibold text-slate-700 transition-colors border border-transparent hover:border-slate-100\"><Columns size={16} className=\"text-purple-500\" /> Two Columns</button>\n </div>\n )}\n </div>\n </div>\n {uiScale >= 0.85 && <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Slides</span>}\n </div>\n\n {/* Font Group */}\n <div className={cn(\"flex-1 flex flex-col items-center border-r border-slate-100 px-3 gap-1 h-full py-2\", uiScale < 0.85 ? \"px-2\" : \"px-4\")}>\n <div className=\"flex items-center justify-center gap-1.5 w-full mt-1\">\n <select\n disabled={!isText}\n value={(selectedElement as any)?.fontFamily || 'Arial'}\n onChange={(e) => onFormatText({ fontFamily: e.target.value })}\n className={cn(\"h-7 px-2 text-[11px] text-slate-900 border border-slate-200 rounded-lg font-semibold bg-white hover:border-slate-300 outline-none disabled:opacity-50 transition-colors appearance-none cursor-pointer\", uiScale < 0.85 ? \"flex-1\" : \"w-44\")}\n >\n {FONTS.map(f => <option key={f} value={f}>{f}</option>)}\n </select>\n <select\n disabled={!isText}\n value={(selectedElement as any)?.fontSize || 24}\n onChange={(e) => onFormatText({ fontSize: parseInt(e.target.value) })}\n className=\"h-7 px-1.5 text-[11px] text-slate-900 border border-slate-200 rounded-lg font-semibold bg-white hover:border-slate-300 outline-none w-14 disabled:opacity-50 transition-colors appearance-none cursor-pointer text-center\"\n >\n {FONT_SIZES.map(s => <option key={s} value={s}>{s}</option>)}\n </select>\n </div>\n <div className=\"flex items-center justify-between w-full mt-auto mb-1\">\n <div className=\"flex items-center gap-0.5\">\n <button\n disabled={!isText}\n onClick={() => onFormatText({ isBold: !(selectedElement as any).isBold })}\n className={cn(\"p-1.5 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.isBold ? \"bg-slate-100 text-slate-900\" : \"text-slate-500 hover:bg-slate-50\")}\n >\n <Bold size={14} strokeWidth={3} />\n </button>\n <button\n disabled={!isText}\n onClick={() => onFormatText({ isItalic: !(selectedElement as any).isItalic })}\n className={cn(\"p-1.5 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.isItalic ? \"bg-slate-100 text-slate-900\" : \"text-slate-500 hover:bg-slate-50\")}\n >\n <Italic size={14} />\n </button>\n <button\n disabled={!isText}\n onClick={() => onFormatText({ isBulleted: !(selectedElement as any).isBulleted })}\n className={cn(\"p-1.5 rounded-lg transition-all disabled:opacity-30\", (selectedElement as any)?.isBulleted ? \"bg-slate-100 text-slate-900\" : \"text-slate-500 hover:bg-slate-50\")}\n >\n <List size={14} />\n </button>\n <div className=\"relative group p-1 hover:bg-slate-50 rounded-lg transition-colors cursor-pointer ml-0.5\">\n <input\n type=\"color\"\n disabled={!selectedElement}\n value={isText ? ((selectedElement as any).color || '#000000') : ((selectedElement as any)?.fill || '#3b82f6')}\n onChange={(e) => onFormatText(isText ? { color: e.target.value } : { fill: e.target.value })}\n className=\"w-6 h-4 p-0 border-0 bg-transparent cursor-pointer disabled:opacity-50\"\n title=\"Font/Fill Color\"\n />\n <div className=\"absolute bottom-1 left-1 right-1 h-0.5 rounded-full\" style={{ backgroundColor: isText ? ((selectedElement as any).color || '#000000') : ((selectedElement as any)?.fill || '#3b82f6') }} />\n </div>\n </div>\n <div className=\"h-4 w-[1px] bg-slate-200 mx-1.5\" />\n <div className=\"flex items-center gap-0.5 bg-slate-50/50 p-0.5 rounded-lg\">\n <button disabled={!isText} onClick={() => onFormatText({ textAlign: 'left' })} className={cn(\"p-1 rounded-md transition-all disabled:opacity-30\", (selectedElement as any)?.textAlign === 'left' ? \"bg-white shadow-sm scale-105\" : \"text-slate-400\")} style={{ color: (selectedElement as any)?.textAlign === 'left' ? appBgColor : undefined }}><AlignLeft size={13} /></button>\n <button disabled={!isText} onClick={() => onFormatText({ textAlign: 'center' })} className={cn(\"p-1 rounded-md transition-all disabled:opacity-30\", (selectedElement as any)?.textAlign === 'center' ? \"bg-white shadow-sm scale-105\" : \"text-slate-400\")} style={{ color: (selectedElement as any)?.textAlign === 'center' ? appBgColor : undefined }}><AlignCenter size={13} /></button>\n <button disabled={!isText} onClick={() => onFormatText({ textAlign: 'right' })} className={cn(\"p-1 rounded-md transition-all disabled:opacity-30\", (selectedElement as any)?.textAlign === 'right' ? \"bg-white shadow-sm scale-105\" : \"text-slate-400\")} style={{ color: (selectedElement as any)?.textAlign === 'right' ? appBgColor : undefined }}><AlignRight size={13} /></button>\n </div>\n </div>\n {uiScale >= 0.85 && <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Font</span>}\n </div>\n\n {/* Drawing Group */}\n <div className=\"flex-1 flex flex-col items-center border-r border-slate-100 px-3 gap-1 h-full py-2 shrink-0\">\n <div className=\"flex items-center justify-center gap-2 my-auto\">\n <div className=\"relative group/shapes flex justify-center\">\n <button\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg group transition-all min-w-[64px]\"\n onClick={() => (window as any)._toggleShapesMenu?.()}\n >\n <div className=\"bg-blue-50 p-1.5 rounded-lg group-hover:scale-105 transition-transform\">\n <Square size={20} className=\"text-blue-600\" />\n </div>\n <span className=\"text-[10px] font-bold text-slate-700\">Shapes</span>\n </button>\n <ShapesDropdown onAddShape={(s) => { onAddShape(s); }} uiScale={uiScale} />\n </div>\n\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n\n <button onClick={onAddText} className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 transition-colors min-w-[64px]\" title=\"Text Box\">\n <div className=\"p-1.5\">\n <Type size={20} />\n </div>\n <span className=\"text-[10px] font-medium text-slate-500\">Text Box</span>\n </button>\n\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n\n <button onClick={() => fileInputRef.current?.click()} className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 transition-colors min-w-[64px]\" title=\"Image\">\n <div className=\"p-1.5\">\n <ImageIcon size={20} />\n </div>\n <span className=\"text-[10px] font-medium text-slate-500\">Image</span>\n <input type=\"file\" ref={fileInputRef} className=\"hidden\" accept=\"image/*\" onChange={(e) => e.target.files?.[0] && onAddImage(e.target.files[0])} />\n </button>\n </div>\n {uiScale >= 0.85 && <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Drawing</span>}\n </div>\n\n {/* AI Text Group */}\n <div className=\"flex-1 flex flex-col items-center border-r border-slate-100 px-3 gap-1 h-full py-2 relative\">\n <div className=\"flex items-center justify-center gap-1 my-auto h-full\">\n <button\n disabled={!isText || isAiLoading}\n onClick={() => onAiAction(selectedElement!.id, 'shorten')}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 disabled:opacity-20 transition-all min-w-[64px]\"\n >\n <div className=\"p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Sparkles size={20} className=\"text-purple-500\" />\n </div>\n <span className=\"text-[10px] font-bold\">Shorten</span>\n </button>\n\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n\n <button\n disabled={!isText || isAiLoading}\n onClick={() => onAiAction(selectedElement!.id, 'reframe')}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 disabled:opacity-20 transition-all min-w-[64px]\"\n >\n <div className=\"p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Sparkles size={20} className=\"text-blue-500\" />\n </div>\n <span className=\"text-[10px] font-bold\">Reframe</span>\n </button>\n\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n\n <button\n disabled={!isText || isAiLoading}\n onClick={() => onAiAction(selectedElement!.id, 'lengthen')}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-600 disabled:opacity-20 transition-all min-w-[68px]\"\n >\n <div className=\"p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Sparkles size={20} className=\"text-emerald-500\" />\n </div>\n <span className=\"text-[10px] font-bold text-center leading-tight\">Lengthen</span>\n </button>\n </div>\n\n {/* AI Loading State */}\n {isAiLoading && (\n <div className=\"absolute inset-x-0 top-2 bottom-8 bg-white/80 flex items-center justify-center rounded-lg z-10 backdrop-blur-[1px]\">\n <RefreshCw size={16} className=\"text-blue-600 animate-spin\" />\n </div>\n )}\n {uiScale >= 0.85 && <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">AI Text</span>}\n </div>\n\n {/* Actions Group */}\n <div className=\"flex-1 flex flex-col items-center pl-4 pr-3 gap-1 h-full py-2 relative\">\n <div className=\"flex items-center justify-center gap-1 my-auto h-full\">\n <button\n onClick={onPlay}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-700 transition-all min-w-[64px] group\"\n title=\"Present\"\n >\n <div className=\"p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Play size={20} className=\"fill-slate-700 group-hover:fill-slate-900\" />\n </div>\n <span className=\"text-[10px] font-bold\">Present</span>\n </button>\n\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n\n <button\n onClick={onExport}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-slate-50 rounded-lg text-slate-700 transition-all min-w-[64px] group\"\n title=\"Export\"\n >\n <div className=\"p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Download size={20} className=\"text-emerald-600\" />\n </div>\n <span className=\"text-[10px] font-bold\">Export</span>\n </button>\n\n {selectedElement && (\n <>\n <div className=\"w-[1px] h-10 bg-slate-100 mx-1\" />\n <button\n onClick={onDeleteElement}\n className=\"flex flex-col items-center justify-center gap-1.5 px-3 py-1.5 hover:bg-red-50 rounded-lg text-red-600 transition-all min-w-[64px] group\"\n title=\"Delete\"\n >\n <div className=\"p-1.5 rounded-lg group-hover:scale-110 transition-transform\">\n <Trash2 size={20} />\n </div>\n <span className=\"text-[10px] font-bold\">Delete</span>\n </button>\n </>\n )}\n </div>\n\n <div className=\"absolute bottom-2 right-3 flex items-center gap-1 px-1.5 py-0.5 bg-emerald-50/50 rounded-md border border-emerald-100/50\">\n <Check size={9} className=\"text-emerald-500\" />\n <span className=\"text-[7px] font-black text-emerald-600/70 tracking-tighter uppercase\">Saved</span>\n </div>\n\n {uiScale >= 0.85 && <span className=\"text-[9px] uppercase tracking-[0.2em] font-black text-slate-300 mt-auto\">Actions</span>}\n </div>\n </div>\n\n {/* Upload Modal */}\n {showUploadModal && (\n <>\n <div className=\"fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-[2000]\" onClick={() => setShowUploadModal(false)} />\n <div className=\"fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[480px] bg-white rounded-3xl shadow-2xl z-[2001] border border-slate-200 p-8 animate-in fade-in zoom-in-95 duration-200\">\n <div className=\"flex justify-between items-center mb-6\">\n <h3 className=\"text-lg font-black text-slate-800 tracking-tight flex items-center gap-3\">\n <div className=\"p-2 bg-blue-50 text-blue-600 rounded-xl\">\n <Download size={20} />\n </div>\n Upload Presentation\n </h3>\n <button onClick={() => setShowUploadModal(false)} className=\"text-slate-400 hover:text-slate-600 transition-colors\">\n <RefreshCw size={20} className=\"rotate-45\" />\n </button>\n </div>\n\n <div className=\"flex gap-2 p-1 bg-slate-50 rounded-2xl mb-8\">\n <button\n onClick={() => setUploadType('file')}\n className={cn(\n \"flex-1 py-3 text-xs font-black rounded-xl transition-all\",\n uploadType === 'file' ? \"bg-white text-blue-600 shadow-sm\" : \"text-slate-500 hover:text-slate-700\"\n )}\n >\n FILE UPLOAD\n </button>\n <button\n onClick={() => setUploadType('link')}\n className={cn(\n \"flex-1 py-3 text-xs font-black rounded-xl transition-all\",\n uploadType === 'link' ? \"bg-white text-blue-600 shadow-sm\" : \"text-slate-500 hover:text-slate-700\"\n )}\n >\n LINK UPLOAD\n </button>\n </div>\n\n {uploadType === 'file' ? (\n <label className=\"flex flex-col items-center justify-center gap-4 py-12 border-2 border-dashed border-slate-200 rounded-3xl hover:border-blue-400 hover:bg-blue-50/50 transition-all cursor-pointer group\">\n <div className=\"p-4 bg-white rounded-2xl shadow-sm border border-slate-100 group-hover:scale-110 transition-transform\">\n <Plus size={24} className=\"text-blue-500\" />\n </div>\n <div className=\"text-center\">\n <p className=\"text-sm font-bold text-slate-700\">Choose a PPTX file</p>\n <p className=\"text-xs text-slate-400 mt-1\">Maximum file size: 50MB</p>\n </div>\n <input\n type=\"file\"\n accept=\".pptx\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (file) {\n onLoadPresentation(file);\n setShowUploadModal(false);\n }\n }}\n />\n </label>\n ) : (\n <div className=\"space-y-4\">\n <div className=\"relative\">\n <input\n type=\"text\"\n placeholder=\"Paste S3 or public URL\"\n value={uploadUrl}\n onChange={(e) => setUploadUrl(e.target.value)}\n className=\"w-full bg-slate-50 border border-slate-200 rounded-2xl px-5 py-4 focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 text-sm placeholder:text-slate-400 text-black\"\n />\n </div>\n <button\n onClick={() => {\n if (uploadUrl.trim()) {\n onLoadPresentation(uploadUrl.trim());\n setShowUploadModal(false);\n }\n }}\n disabled={!uploadUrl.trim()}\n className=\"w-full bg-blue-600 hover:bg-blue-700 disabled:bg-slate-300 text-white font-black py-4 rounded-2xl transition-all shadow-lg shadow-blue-500/20\"\n >\n LOAD PRESENTATION\n </button>\n <p className=\"text-[10px] text-slate-400 text-center uppercase tracking-widest font-black\">\n Supports S3, Dropbox, and public URLS\n </p>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n );\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport React from 'react';\nimport type { Slide } from '../lib/types';\nimport { cn } from '@/lib/utils';\nimport { Trash2, Copy, GripVertical } from 'lucide-react';\nimport {\n DndContext,\n closestCenter,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n DragEndEvent\n} from '@dnd-kit/core';\nimport {\n arrayMove,\n SortableContext,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n useSortable\n} from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\n\ninterface SidebarProps {\n slides: Slide[];\n currentSlideIndex: number;\n onSelectSlide: (index: number) => void;\n onDeleteSlide: (index: number) => void;\n onDuplicateSlide: (index: number) => void;\n onReorderSlides: (oldIndex: number, newIndex: number) => void;\n uiScale: number;\n}\n\nconst SortableSlide = ({\n slide,\n index,\n isActive,\n onSelect,\n onDelete,\n onDuplicate,\n showDelete,\n uiScale\n}: {\n slide: Slide,\n index: number,\n isActive: boolean,\n onSelect: () => void,\n onDelete: () => void,\n onDuplicate: () => void,\n showDelete: boolean,\n uiScale: number\n}) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging\n } = useSortable({ id: slide.id });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n zIndex: isDragging ? 2 : 1,\n opacity: isDragging ? 0.5 : 1\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n onClick={onSelect}\n className={cn(\n \"cursor-pointer border-[1.5px] rounded-2xl p-2 transition-all duration-300 group relative select-none\",\n isActive\n ? \"border-[#B7472A] bg-white\"\n : \"border-transparent hover:border-slate-200 bg-white/50 hover:bg-white\"\n )}\n >\n <div className=\"text-[10px] font-bold text-slate-400 mb-1 flex items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n <div {...attributes} {...listeners} className=\"cursor-grab active:cursor-grabbing p-0.5 hover:bg-slate-100 rounded text-slate-300 hover:text-slate-500\">\n <GripVertical size={10} />\n </div>\n <span>SLIDE {index + 1}</span>\n </div>\n <div className=\"flex items-center gap-1\">\n {isActive && <span className=\"h-1.5 w-1.5 rounded-full bg-[#B7472A]\" />}\n <div className=\"flex items-center opacity-0 group-hover:opacity-100 transition-opacity\">\n <button\n onClick={(e) => { e.stopPropagation(); onDuplicate(); }}\n className=\"p-1 hover:bg-blue-50 text-slate-400 hover:text-blue-500 rounded transition-all\"\n title=\"Duplicate Slide\"\n >\n <Copy size={12} />\n </button>\n {showDelete && (\n <button\n onClick={(e) => { e.stopPropagation(); onDelete(); }}\n className=\"p-1 hover:bg-red-50 text-red-400 hover:text-red-500 rounded transition-all\"\n title=\"Delete Slide\"\n >\n <Trash2 size={12} />\n </button>\n )}\n </div>\n </div>\n </div>\n <div className=\"aspect-video bg-white rounded-xl flex items-center justify-center border border-slate-200 overflow-hidden relative group-hover:shadow-sm transition-shadow\">\n {/* Scaled Preview of Slide Content */}\n <div\n className=\"origin-center pointer-events-none select-none shrink-0\"\n style={{\n width: '1200px',\n height: '675px',\n transform: `scale(${(180 * uiScale) / 1200})`, // Perfectly fit within available width\n backgroundColor: '#ffffff'\n }}\n >\n {slide.elements.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0)).map((el) => {\n const style: React.CSSProperties = {\n position: 'absolute',\n left: el.x,\n top: el.y,\n width: el.width,\n height: el.height,\n opacity: el.opacity ?? 1,\n };\n\n if (el.type === 'text') {\n return (\n <div\n key={el.id}\n style={{\n ...style,\n fontSize: el.fontSize,\n fontFamily: el.fontFamily,\n color: el.color,\n textAlign: el.textAlign || 'left',\n fontWeight: el.isBold ? 'bold' : 'normal',\n fontStyle: el.isItalic ? 'italic' : 'normal',\n lineHeight: 1.2,\n overflow: 'hidden',\n wordBreak: 'break-word',\n whiteSpace: 'pre-wrap'\n }}\n >\n {el.content}\n </div>\n );\n } else if (el.type === 'shape') {\n return (\n <div\n key={el.id}\n style={{\n ...style,\n backgroundColor: el.fill,\n borderRadius: el.shapeType === 'ellipse' ? '50%' : '0'\n }}\n />\n );\n } else if (el.type === 'image') {\n return (\n <img\n key={el.id}\n src={el.src}\n alt=\"\"\n style={{\n ...style,\n objectFit: 'contain'\n }}\n />\n );\n }\n return null;\n })}\n </div>\n </div>\n </div>\n );\n};\n\nexport const Sidebar: React.FC<SidebarProps> = ({\n slides,\n currentSlideIndex,\n onSelectSlide,\n onDeleteSlide,\n onDuplicateSlide,\n onReorderSlides,\n uiScale\n}) => {\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 5,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n if (active.id !== over?.id) {\n const oldIndex = slides.findIndex((s) => s.id === active.id);\n const newIndex = slides.findIndex((s) => s.id === over?.id);\n onReorderSlides(oldIndex, newIndex);\n }\n };\n\n return (\n <div\n className=\"bg-white border-r border-slate-100 overflow-y-auto p-4 flex flex-col gap-4\"\n style={{ width: `${256 * uiScale}px` }}\n >\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragEnd={handleDragEnd}\n >\n <SortableContext\n items={slides.map(s => s.id)}\n strategy={verticalListSortingStrategy}\n >\n {slides.map((slide, index) => (\n <SortableSlide\n key={slide.id}\n slide={slide}\n index={index}\n isActive={index === currentSlideIndex}\n onSelect={() => onSelectSlide(index)}\n onDelete={() => onDeleteSlide(index)}\n onDuplicate={() => onDuplicateSlide(index)}\n showDelete={slides.length > 1}\n uiScale={uiScale}\n />\n ))}\n </SortableContext>\n </DndContext>\n </div>\n );\n};\n","'use client';\n\nimport React, { useEffect, useRef } from 'react';\nimport * as fabric from 'fabric';\nimport type { Slide, SlideElement } from '../lib/types';\n\ninterface CanvasProps {\n slide: Slide;\n onElementUpdate: (elementId: string, updates: Partial<SlideElement>) => void;\n onSelect: (id: string | null) => void;\n uiScale: number;\n}\n\nexport const EditorCanvas: React.FC<CanvasProps> = ({ slide, onElementUpdate, onSelect, uiScale }) => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const fabricCanvas = useRef<fabric.Canvas | null>(null);\n const isInternalUpdate = useRef(false);\n\n const onElementUpdateRef = useRef(onElementUpdate);\n const onSelectRef = useRef(onSelect);\n\n useEffect(() => {\n onElementUpdateRef.current = onElementUpdate;\n onSelectRef.current = onSelect;\n }, [onElementUpdate, onSelect]);\n\n useEffect(() => {\n if (canvasRef.current && !fabricCanvas.current) {\n fabricCanvas.current = new fabric.Canvas(canvasRef.current, {\n width: 1200,\n height: 675,\n backgroundColor: '#ffffff'\n });\n\n const canvas = fabricCanvas.current;\n\n const clamp = (obj: fabric.Object) => {\n if (obj.left! < 0) obj.set('left', 0);\n if (obj.top! < 0) obj.set('top', 0);\n const bound = obj.getBoundingRect();\n if (bound.left + bound.width > (canvas.width || 1200)) obj.set('left', (canvas.width || 1200) - bound.width);\n if (bound.top + bound.height > (canvas.height || 675)) obj.set('top', (canvas.height || 675) - bound.height);\n };\n\n canvas.on('object:moving', (e) => clamp(e.target!));\n canvas.on('object:scaling', (e) => clamp(e.target!));\n\n const handleUpdate = (e: any) => {\n if (isInternalUpdate.current) return;\n const obj = e.target as any;\n const elementId = obj.get('data')?.id;\n if (obj && elementId) {\n onElementUpdateRef.current(elementId, {\n x: obj.left,\n y: obj.top,\n width: obj.getScaledWidth(),\n height: obj.getScaledHeight(),\n ...(obj.isType('textbox') ? {\n content: (obj as fabric.Textbox).text,\n textAlign: (obj as fabric.Textbox).textAlign as any,\n fontSize: obj.fontSize,\n fontFamily: obj.fontFamily,\n color: obj.fill as string\n } : {\n fill: obj.fill as string\n })\n });\n }\n };\n\n canvas.on('object:modified', handleUpdate);\n canvas.on('text:changed', handleUpdate);\n\n const syncSelection = (e: any) => {\n const obj = e.selected?.[0] || e.target;\n if (obj) {\n const elementId = (obj as any).get('data')?.id;\n onSelectRef.current(elementId);\n }\n };\n\n canvas.on('selection:created', syncSelection);\n canvas.on('selection:updated', syncSelection);\n canvas.on('selection:cleared', () => onSelectRef.current(null));\n\n // Global keyboard navigation\n const handleGlobalKeyDown = (e: KeyboardEvent) => {\n const activeObj = canvas.getActiveObject();\n if (!activeObj) return;\n\n // Don't move if editing text\n if (activeObj.isType('textbox') && (activeObj as fabric.Textbox).isEditing) return;\n\n const step = e.shiftKey ? 10 : 1;\n let moved = false;\n\n switch (e.key) {\n case 'ArrowLeft': activeObj.set('left', activeObj.left - step); moved = true; break;\n case 'ArrowRight': activeObj.set('left', activeObj.left + step); moved = true; break;\n case 'ArrowUp': activeObj.set('top', activeObj.top - step); moved = true; break;\n case 'ArrowDown': activeObj.set('top', activeObj.top + step); moved = true; break;\n }\n\n if (moved) {\n clamp(activeObj);\n canvas.requestRenderAll();\n handleUpdate({ target: activeObj });\n }\n };\n\n window.addEventListener('keydown', handleGlobalKeyDown);\n (canvas as any)._keyboardListener = handleGlobalKeyDown;\n }\n\n return () => {\n if (fabricCanvas.current) {\n const listener = (fabricCanvas.current as any)._keyboardListener;\n if (listener) window.removeEventListener('keydown', listener);\n fabricCanvas.current.dispose();\n fabricCanvas.current = null;\n }\n };\n }, []); // Empty dependency array means this only runs once!\n\n useEffect(() => {\n if (!fabricCanvas.current) return;\n const canvas = fabricCanvas.current;\n\n const syncElements = async () => {\n isInternalUpdate.current = true;\n\n const existingObjs = canvas.getObjects();\n const slideIds = new Set(slide.elements.map((e: SlideElement) => e.id));\n\n existingObjs.forEach(obj => {\n const id = (obj as any).get('data')?.id;\n if (id && !slideIds.has(id)) {\n canvas.remove(obj);\n }\n });\n\n const sorted = [...slide.elements].sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));\n\n for (const el of sorted) {\n let obj = existingObjs.find((o: fabric.Object) => (o as any).get('data')?.id === el.id) as any;\n\n if (obj) {\n // CRITICAL: Skip syncing properties for the object currently being edited.\n // If we update properties (like 'text') while Fabric.js is in editing mode,\n // it resets the cursor position and can cause desync/focus loss.\n if (obj === canvas.getActiveObject() && obj.isType('textbox') && (obj as fabric.Textbox).isEditing) {\n continue;\n }\n\n const updates: any = {\n left: el.x,\n top: el.y,\n opacity: el.opacity !== undefined ? el.opacity : 1,\n zIndex: el.zIndex\n };\n\n if (el.type === 'text' && obj.isType('textbox')) {\n updates.text = el.content || ' ';\n updates.fontSize = el.fontSize || 22;\n updates.fill = el.color || '#000000';\n updates.textAlign = el.textAlign || 'left';\n updates.fontWeight = el.isBold ? 'bold' : 'normal';\n updates.fontStyle = el.isItalic ? 'italic' : 'normal';\n updates.fontFamily = el.fontFamily || 'Arial';\n updates.width = Math.max(el.width || 50, 10);\n } else if (el.type === 'shape') {\n updates.fill = (el as any).fill || '#cccccc';\n updates.scaleX = (el.width || 50) / (obj.width || 1);\n updates.scaleY = (el.height || 50) / (obj.height || 1);\n } else if (el.type === 'image') {\n updates.scaleX = (el.width || 100) / (obj.width || 1);\n updates.scaleY = (el.height || 100) / (obj.height || 1);\n }\n\n obj.set(updates);\n } else {\n let newObj: fabric.Object | null = null;\n const commonProps = {\n left: el.x,\n top: el.y,\n data: { id: el.id },\n originX: 'left' as const,\n originY: 'top' as const,\n opacity: el.opacity !== undefined ? el.opacity : 1\n };\n\n if (el.type === 'text') {\n newObj = new fabric.Textbox(el.content || ' ', {\n ...commonProps,\n width: Math.max(el.width || 200, 10),\n fontSize: el.fontSize || 22,\n fill: el.color || '#000000',\n fontFamily: el.fontFamily || 'Inter, Arial, sans-serif',\n textAlign: el.textAlign || 'left',\n fontWeight: el.isBold ? 'bold' : 'normal',\n fontStyle: el.isItalic ? 'italic' : 'normal',\n splitByGrapheme: false,\n });\n } else if (el.type === 'shape') {\n const shapeFill = (el as any).fill || '#3b82f6';\n if (el.shapeType === 'ellipse') {\n newObj = new fabric.Circle({\n ...commonProps,\n radius: (el.width || 100) / 2,\n scaleY: (el.height || 100) / (el.width || 100),\n fill: shapeFill,\n });\n } else {\n newObj = new fabric.Rect({\n ...commonProps,\n width: el.width || 100,\n height: el.height || 100,\n fill: shapeFill,\n });\n }\n } else if (el.type === 'image') {\n try {\n const img = await fabric.FabricImage.fromURL(el.src);\n img.set({\n ...commonProps,\n scaleX: (el.width || 100) / (img.width || 1),\n scaleY: (el.height || 100) / (img.height || 1),\n } as any);\n newObj = img;\n } catch (err) { console.error(err); }\n }\n\n if (newObj) {\n canvas.add(newObj);\n }\n }\n }\n\n canvas.renderAll();\n isInternalUpdate.current = false;\n };\n\n syncElements();\n }, [slide]);\n\n return (\n <div\n className=\"border border-slate-200 overflow-hidden bg-white shadow-lg transition-transform duration-300\"\n style={{\n transform: `scale(${uiScale * 0.8})`,\n transformOrigin: 'center center'\n }}\n >\n <canvas ref={canvasRef} />\n </div>\n );\n};\n","import pptxgen from 'pptxgenjs';\nimport type { Presentation } from './types';\n\nexport class PptxExporter {\n async export(presentation: Presentation): Promise<void> {\n const pptx = new pptxgen();\n\n const emuWidth = presentation.layout?.width || 12192000;\n const emuHeight = presentation.layout?.height || 6858000;\n const canvasWidth = 1200;\n const canvasHeight = 675;\n\n const getInchesX = (px: number) => (px / canvasWidth) * (emuWidth / 914400);\n const getInchesY = (px: number) => (px / canvasHeight) * (emuHeight / 914400);\n\n presentation.slides.forEach(slide => {\n const pptxSlide = pptx.addSlide();\n\n // Sort by zIndex for export layering\n const sortedElements = [...slide.elements].sort((a, b) => a.zIndex - b.zIndex);\n\n sortedElements.forEach(el => {\n const transparency = el.opacity !== undefined ? (1 - el.opacity) * 100 : 0;\n const common = {\n x: getInchesX(el.x),\n y: getInchesY(el.y),\n w: getInchesX(el.width),\n h: getInchesY(el.height),\n };\n\n if (el.type === 'text') {\n pptxSlide.addText(el.content, {\n ...common,\n fontSize: (el.fontSize || 18) / 2, // Halve for export\n color: el.color?.replace('#', '') || '000000',\n fontFace: el.fontFamily || 'Arial'\n });\n } else if (el.type === 'image') {\n pptxSlide.addImage({\n ...common,\n path: el.src,\n transparency: transparency\n });\n } else if (el.type === 'shape') {\n const shapeType = el.shapeType === 'ellipse' ? pptx.ShapeType.ellipse : pptx.ShapeType.rect;\n pptxSlide.addShape(shapeType, {\n ...common,\n fill: {\n color: el.fill?.replace('#', '') || 'CCCCCC',\n transparency: transparency > 0 ? Math.min(transparency + 10, 100) : 0 // Slightly lighter as requested\n }\n });\n }\n });\n });\n\n await pptx.writeFile({ fileName: 'presentation.pptx' });\n }\n}\n","import JSZip from 'jszip';\nimport type { Presentation, Slide, SlideElement, ShapeType } from './types';\n\nexport class PptxParser {\n private slideWidth = 12192000;\n private slideHeight = 6858000;\n private readonly CANVAS_WIDTH = 1200;\n private readonly CANVAS_HEIGHT = 675;\n\n async parse(input: File | Blob | ArrayBuffer | string): Promise<Presentation> {\n let data: any = input;\n if (typeof input === 'string') {\n const response = await fetch(input);\n if (!response.ok) {\n const status = response.status;\n const statusText = response.statusText;\n\n let detail = '';\n try {\n const errorJson = await response.json();\n detail = errorJson.details || errorJson.error || '';\n } catch (e) {\n // Ignore if not JSON\n }\n\n throw new Error(`Failed to fetch PPTX from ${input}: ${status} ${statusText} ${detail ? `(${detail})` : ''}`);\n }\n data = await response.arrayBuffer();\n }\n const zip = await JSZip.loadAsync(data);\n const presentationXml = await zip.file('ppt/presentation.xml')?.async('string');\n if (!presentationXml) throw new Error('Invalid PPTX');\n\n const parser = new DOMParser();\n const presentationDoc = parser.parseFromString(presentationXml, 'text/xml');\n\n const sldSz = this.findFirstByLocalName(presentationDoc, 'sldSz');\n if (sldSz) {\n this.slideWidth = parseInt(this.getAttr(sldSz, 'cx') || '12192000');\n this.slideHeight = parseInt(this.getAttr(sldSz, 'cy') || '6858000');\n }\n\n const sldIdList = Array.from(presentationDoc.getElementsByTagNameNS('*', 'sldId'));\n const slides: Slide[] = [];\n\n for (let i = 0; i < sldIdList.length; i++) {\n const slideNum = i + 1;\n const slidePath = `ppt/slides/slide${slideNum}.xml`;\n const slideXml = await zip.file(slidePath)?.async('string');\n if (slideXml) {\n const slide = await this.parseSlide(slideXml, slideNum, zip);\n slides.push(slide);\n }\n }\n\n return {\n slides,\n layout: { width: this.slideWidth, height: this.slideHeight }\n };\n }\n\n private getAttr(el: Element, name: string): string | null {\n return el.getAttribute(name) || el.getAttribute(`a:${name}`) || el.getAttribute(`p:${name}`) || el.getAttribute(`r:${name}`);\n }\n\n private findFirstByLocalName(parent: Document | Element, name: string): Element | null {\n const elements = parent.getElementsByTagNameNS('*', name);\n return elements.length > 0 ? elements[0] : null;\n }\n\n private findAllByLocalName(parent: Document | Element, name: string): Element[] {\n return Array.from(parent.getElementsByTagNameNS('*', name));\n }\n\n private scaleX(emu: number): number {\n return (emu / this.slideWidth) * this.CANVAS_WIDTH;\n }\n\n private scaleY(emu: number): number {\n return (emu / this.slideHeight) * this.CANVAS_HEIGHT;\n }\n\n private parseColor(el: Element): { color: string, opacity: number } {\n const srgbClr = this.findFirstByLocalName(el, 'srgbClr');\n if (srgbClr) {\n const hex = `#${this.getAttr(srgbClr, 'val')}`;\n const alphaNode = this.findFirstByLocalName(srgbClr, 'alpha');\n const opacity = alphaNode ? parseInt(this.getAttr(alphaNode, 'val') || '100000') / 100000 : 1;\n return { color: hex, opacity };\n }\n const schemeClr = this.findFirstByLocalName(el, 'schemeClr');\n if (schemeClr) {\n const alphaNode = this.findFirstByLocalName(schemeClr, 'alpha');\n const opacity = alphaNode ? parseInt(this.getAttr(alphaNode, 'val') || '100000') / 100000 : 1;\n return { color: '#000000', opacity }; // Themes usually default to dark if not specified\n }\n return { color: '#000000', opacity: 1 };\n }\n\n private async resolveImage(relId: string, slideIndex: number, zip: JSZip): Promise<Blob | null> {\n const relsXml = await zip.file(`ppt/slides/_rels/slide${slideIndex}.xml.rels`)?.async('string');\n if (!relsXml) return null;\n\n const parser = new DOMParser();\n const relsDoc = parser.parseFromString(relsXml, 'text/xml');\n const relationship = Array.from(relsDoc.getElementsByTagName('Relationship'))\n .find(r => r.getAttribute('Id') === relId);\n\n const target = relationship?.getAttribute('Target');\n if (target) {\n const mediaPath = (target.startsWith('../') ? `ppt/${target.substring(3)}` : `ppt/slides/${target}`).replace('ppt/slides/../', 'ppt/');\n return await zip.file(mediaPath)?.async('blob') || null;\n }\n return null;\n }\n\n private async parseSlide(xml: string, slideIndex: number, zip: JSZip): Promise<Slide> {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'text/xml');\n const elements: SlideElement[] = [];\n let zIndex = 0;\n\n // Check for Background Image\n const bg = this.findFirstByLocalName(doc, 'bg');\n if (bg) {\n const blip = this.findFirstByLocalName(bg, 'blip');\n const relId = blip?.getAttributeNS('http://schemas.openxmlformats.org/officeDocument/2006/relationships', 'embed') ||\n blip?.getAttribute('r:embed');\n if (relId) {\n const mediaFile = await this.resolveImage(relId, slideIndex, zip);\n if (mediaFile) {\n elements.push({\n id: `bg-${slideIndex}`,\n type: 'image',\n src: URL.createObjectURL(mediaFile),\n x: 0,\n y: 0,\n width: this.CANVAS_WIDTH,\n height: this.CANVAS_HEIGHT,\n zIndex: zIndex++,\n opacity: 1\n });\n }\n }\n }\n\n const spTree = this.findFirstByLocalName(doc, 'spTree');\n if (!spTree) return { id: `slide-${slideIndex}`, elements };\n\n const children = Array.from(spTree.children);\n for (const child of children) {\n const localName = child.localName;\n\n if (localName === 'sp') {\n const txBody = this.findFirstByLocalName(child, 'txBody');\n const xfrm = this.findFirstByLocalName(child, 'xfrm');\n const off = xfrm ? this.findFirstByLocalName(xfrm, 'off') : null;\n const ext = xfrm ? this.findFirstByLocalName(xfrm, 'ext') : null;\n\n if (txBody && off && ext) {\n const paragraphs = this.findAllByLocalName(txBody, 'p');\n let content = '';\n let fontSize = 18;\n let color = '#000000';\n let opacity = 1;\n let isBulleted = false;\n\n for (const p of paragraphs) {\n const pPr = this.findFirstByLocalName(p, 'pPr');\n const buNone = pPr ? this.findFirstByLocalName(pPr, 'buNone') : null;\n if (pPr && !buNone && (this.findFirstByLocalName(pPr, 'buChar') || this.findFirstByLocalName(pPr, 'buAutoNum'))) {\n isBulleted = true;\n content += '• ';\n }\n\n const runs = this.findAllByLocalName(p, 'r');\n for (const r of runs) {\n const t = this.findFirstByLocalName(r, 't');\n if (t) content += t.textContent;\n\n const rPr = this.findFirstByLocalName(r, 'rPr');\n if (rPr) {\n const sz = this.getAttr(rPr, 'sz');\n if (sz) fontSize = (parseInt(sz) / 100) * 2; // Double for editor\n const style = this.parseColor(rPr);\n color = style.color;\n opacity = style.opacity;\n }\n }\n content += '\\n';\n }\n\n if (content.trim()) {\n elements.push({\n id: `el-${slideIndex}-${Date.now()}-${zIndex}`,\n type: 'text',\n content: content.trim(),\n x: this.scaleX(parseInt(this.getAttr(off, 'x') || '0')),\n y: this.scaleY(parseInt(this.getAttr(off, 'y') || '0')),\n width: this.scaleX(parseInt(this.getAttr(ext, 'cx') || '0')),\n height: this.scaleY(parseInt(this.getAttr(ext, 'cy') || '0')),\n fontSize,\n color,\n fontFamily: 'Arial',\n zIndex: zIndex++,\n isBulleted,\n opacity\n });\n continue;\n }\n }\n\n const prstGeom = this.findFirstByLocalName(child, 'prstGeom');\n if (prstGeom && off && ext) {\n const prst = this.getAttr(prstGeom, 'prst');\n const spPr = this.findFirstByLocalName(child, 'spPr');\n const style = spPr ? this.parseColor(spPr) : { color: '#cccccc', opacity: 1 };\n\n elements.push({\n id: `el-${slideIndex}-${Date.now()}-${zIndex}`,\n type: 'shape',\n shapeType: (prst === 'ellipse' || prst === 'circle' ? 'ellipse' : 'rect') as ShapeType,\n fill: style.color,\n opacity: style.opacity,\n x: this.scaleX(parseInt(this.getAttr(off, 'x') || '0')),\n y: this.scaleY(parseInt(this.getAttr(off, 'y') || '0')),\n width: this.scaleX(parseInt(this.getAttr(ext, 'cx') || '0')),\n height: this.scaleY(parseInt(this.getAttr(ext, 'cy') || '0')),\n zIndex: zIndex++\n });\n }\n }\n\n if (localName === 'pic') {\n const blip = this.findFirstByLocalName(child, 'blip');\n const relId = blip?.getAttributeNS('http://schemas.openxmlformats.org/officeDocument/2006/relationships', 'embed') ||\n blip?.getAttribute('r:embed');\n\n const xfrm = this.findFirstByLocalName(child, 'xfrm');\n const off = xfrm ? this.findFirstByLocalName(xfrm, 'off') : null;\n const ext = xfrm ? this.findFirstByLocalName(xfrm, 'ext') : null;\n\n if (relId && off && ext) {\n const mediaFile = await this.resolveImage(relId, slideIndex, zip);\n if (mediaFile) {\n elements.push({\n id: `el-${slideIndex}-${Date.now()}-${zIndex}`,\n type: 'image',\n src: URL.createObjectURL(mediaFile),\n x: this.scaleX(parseInt(this.getAttr(off, 'x') || '0')),\n y: this.scaleY(parseInt(this.getAttr(off, 'y') || '0')),\n width: this.scaleX(parseInt(this.getAttr(ext, 'cx') || '0')),\n height: this.scaleY(parseInt(this.getAttr(ext, 'cy') || '0')),\n zIndex: zIndex++,\n opacity: 1\n });\n }\n }\n }\n }\n\n return { id: `slide-${slideIndex}`, elements };\n }\n}\n","'use client';\n\nimport React, { useEffect, useState } from 'react';\nimport { ChevronLeft, ChevronRight, X } from 'lucide-react';\nimport type { Presentation, Slide } from '../lib/types';\nimport { EditorCanvas } from './EditorCanvas';\n\ninterface PresenterModeProps {\n presentation: Presentation;\n initialSlideIndex: number;\n onClose: () => void;\n}\n\nexport const PresenterMode: React.FC<PresenterModeProps> = ({\n presentation,\n initialSlideIndex,\n onClose\n}) => {\n const [currentIndex, setCurrentIndex] = useState(initialSlideIndex);\n const currentSlide = presentation.slides[currentIndex];\n\n const goToPrevious = () => {\n if (currentIndex > 0) setCurrentIndex(currentIndex - 1);\n };\n\n const goToNext = () => {\n if (currentIndex < presentation.slides.length - 1) setCurrentIndex(currentIndex + 1);\n };\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown') {\n goToNext();\n } else if (e.key === 'ArrowLeft' || e.key === 'Backspace' || e.key === 'PageUp') {\n goToPrevious();\n } else if (e.key === 'Escape') {\n onClose();\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [currentIndex]);\n\n const [scale, setScale] = useState(1);\n\n useEffect(() => {\n const updateScale = () => {\n const padding = 40;\n const availableWidth = window.innerWidth - padding;\n const availableHeight = window.innerHeight - padding;\n const slideWidth = 1200;\n const slideHeight = 675;\n\n const scaleX = availableWidth / slideWidth;\n const scaleY = availableHeight / slideHeight;\n const newScale = Math.min(scaleX, scaleY);\n setScale(newScale);\n };\n\n updateScale();\n window.addEventListener('resize', updateScale);\n return () => window.removeEventListener('resize', updateScale);\n }, []);\n\n return (\n <div className=\"fixed inset-0 z-[99999] bg-[#0A0A0A] flex flex-col items-center justify-center overflow-hidden\">\n {/* Header / Controls */}\n <div className=\"absolute top-0 left-0 right-0 p-6 flex justify-between items-center opacity-0 hover:opacity-100 transition-opacity bg-gradient-to-b from-black/60 to-transparent z-[100] pointer-events-none\">\n <div className=\"text-white/80 font-bold ml-4 pointer-events-auto\">\n Slide {currentIndex + 1} of {presentation.slides.length}\n </div>\n <button\n onClick={onClose}\n className=\"p-3 bg-white/10 hover:bg-white/20 text-white rounded-full transition-all pointer-events-auto\"\n >\n <X size={24} />\n </button>\n </div>\n\n {/* Slide Container */}\n <div className=\"w-full h-full flex items-center justify-center\">\n <div\n className=\"relative shadow-2xl shadow-black/80 bg-white\"\n style={{\n width: '1200px',\n height: '675px',\n transform: `scale(${scale})`,\n transformOrigin: 'center center'\n }}\n >\n <EditorCanvas\n slide={currentSlide}\n onElementUpdate={() => { }} // No editing in presenter mode\n onSelect={() => { }} // No selection in presenter mode\n uiScale={0.75} // Base width of 1200px / 1600px\n />\n </div>\n </div>\n\n {/* Navigation Controls */}\n <div className=\"absolute bottom-10 left-1/2 -translate-x-1/2 flex items-center gap-6 opacity-0 hover:opacity-100 transition-opacity bg-black/40 backdrop-blur-md px-6 py-3 rounded-full border border-white/10 pointer-events-auto\">\n <button\n disabled={currentIndex === 0}\n onClick={goToPrevious}\n className=\"p-2 text-white/50 hover:text-white disabled:opacity-20 transition-colors\"\n >\n <ChevronLeft size={32} />\n </button>\n <div className=\"h-6 w-[1px] bg-white/10\" />\n <button\n disabled={currentIndex === presentation.slides.length - 1}\n onClick={goToNext}\n className=\"p-2 text-white/50 hover:text-white disabled:opacity-20 transition-colors\"\n >\n <ChevronRight size={32} />\n </button>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["styleInject","css","insertAt","head","style","styleInject","useState","useCallback","useMemo","useEffect","React","useState","Type","ImageIcon","Square","Download","Plus","Trash2","Bold","Italic","AlignLeft","AlignCenter","AlignRight","List","LayoutIcon","Columns","FileText","Play","Sparkles","RefreshCw","Check","clsx","twMerge","cn","inputs","Fragment","jsx","jsxs","FONTS","FONT_SIZES","SHAPE_CATEGORIES","ShapeIcon","type","className","ShapesDropdown","onAddShape","uiScale","isOpen","setIsOpen","useState","React","cat","s","Toolbar","onAddText","onAddImage","onAddSlide","onExport","onFormatText","onDeleteElement","onApplyLayout","onPlay","selectedElement","appName","onAiAction","onAiResponseAction","aiResponse","isAiLoading","onNewPresentation","onLoadPresentation","appBgColor","source","fileInputRef","activeTab","setActiveTab","showLayouts","setShowLayouts","showAiDialog","setShowAiDialog","showFileMenu","setShowFileMenu","showUploadModal","setShowUploadModal","uploadType","setUploadType","uploadUrl","setUploadUrl","isText","isShape","PPT_RED","cn","Plus","LayoutIcon","FileText","List","Columns","e","f","Bold","Italic","AlignLeft","AlignCenter","AlignRight","_a","Square","Type","ImageIcon","Sparkles","RefreshCw","Play","Download","Trash2","Check","file","Trash2","Copy","GripVertical","DndContext","closestCenter","KeyboardSensor","PointerSensor","useSensor","useSensors","SortableContext","sortableKeyboardCoordinates","verticalListSortingStrategy","useSortable","CSS","jsx","jsxs","SortableSlide","slide","index","isActive","onSelect","onDelete","onDuplicate","showDelete","uiScale","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","cn","__spreadProps","__spreadValues","GripVertical","e","Copy","Trash2","a","b","el","_a","Sidebar","slides","currentSlideIndex","onSelectSlide","onDeleteSlide","onDuplicateSlide","onReorderSlides","sensors","useSensors","useSensor","PointerSensor","KeyboardSensor","sortableKeyboardCoordinates","handleDragEnd","event","active","over","oldIndex","s","newIndex","DndContext","closestCenter","SortableContext","verticalListSortingStrategy","useEffect","useRef","fabric","jsx","EditorCanvas","slide","onElementUpdate","onSelect","uiScale","canvasRef","useRef","fabricCanvas","isInternalUpdate","onElementUpdateRef","onSelectRef","useEffect","canvas","clamp","obj","bound","handleUpdate","_a","elementId","__spreadValues","syncSelection","_b","handleGlobalKeyDown","activeObj","step","moved","listener","existingObjs","slideIds","id","sorted","a","b","el","o","updates","newObj","commonProps","__spreadProps","shapeFill","img","err","pptxgen","PptxExporter","presentation","_a","_b","pptx","pptxgen","emuWidth","emuHeight","canvasWidth","canvasHeight","getInchesX","px","getInchesY","slide","pptxSlide","a","b","el","transparency","common","__spreadProps","__spreadValues","shapeType","JSZip","PptxParser","input","_a","_b","data","response","status","statusText","detail","errorJson","e","zip","presentationXml","presentationDoc","sldSz","sldIdList","slides","i","slideNum","slidePath","slideXml","slide","el","name","parent","elements","emu","srgbClr","hex","alphaNode","opacity","schemeClr","relId","slideIndex","relsXml","relsDoc","relationship","r","target","mediaPath","xml","doc","zIndex","bg","blip","mediaFile","spTree","children","child","localName","txBody","xfrm","off","ext","paragraphs","content","fontSize","color","isBulleted","p","pPr","buNone","runs","t","rPr","sz","style","prstGeom","prst","spPr","useEffect","useState","ChevronLeft","ChevronRight","X","jsx","jsxs","PresenterMode","presentation","initialSlideIndex","onClose","currentIndex","setCurrentIndex","useState","currentSlide","goToPrevious","goToNext","useEffect","handleKeyDown","e","scale","setScale","updateScale","availableWidth","availableHeight","slideWidth","slideHeight","scaleX","scaleY","newScale","X","EditorCanvas","ChevronLeft","ChevronRight","GoogleGenerativeAI","jsx","jsxs","PptEditor","initialPresentation","url","appName","onChange","geminiApiKey","width","height","appBgColor","showHomeOnEmpty","initialSource","onSourceChange","presentation","setPresentation","useState","history","setHistory","redoStack","setRedoStack","currentSlideIndex","setCurrentSlideIndex","selectedElementId","setSelectedElementId","isPreviewMode","setIsPreviewMode","aiResponse","setAiResponse","isLoading","setIsLoading","source","setSource","showInitialLayout","setShowInitialLayout","urlInput","setUrlInput","useEffect","handleLoadPresentation","isAiLoading","setIsAiLoading","lastAiPrompt","setLastAiPrompt","uiScale","useMemo","w","currentSlide","selectedElement","el","saveToHistory","useCallback","state","prevHistory","undo","last","prev","redo","next","handleUpdateSlide","updates","newSlides","__spreadValues","updated","__spreadProps","h","handleElementUpdate","elementId","slide","newElements","handleFormatText","e","handleDeleteElement","handleAddText","newElement","handleAddImage","file","id","handleAddShape","shapeType","handleAddSlide","newSlide","handleDeleteSlide","index","_","i","handleDuplicateSlide","slideToClone","handleReorderSlides","oldIndex","newIndex","removed","handleApplyLayout","layoutType","elements","timestamp","handleAiAction","action","element","model","GoogleGenerativeAI","elementContext","prompt","response","error","handleAiResponseAction","originalElement","handleExport","PptxExporter","handlePlay","elem","handleClosePresenter","handleFullscreenChange","handleKeyDown","activeElement","updateSource","newSource","handleNewPresentation","input","parser","PptxParser","result","err","_a","PresenterMode","Toolbar","Sidebar","EditorCanvas"]}