import { listSlides, createSlide, deleteSlide } from './api.js'; import { getEditorValues } from './editors.js'; import { renderPreview } from './preview.js'; import { compileCss } from './preprocessors.js'; import { compileJs } from './js-preprocessors.js'; import { getCurrentMode, getCssType } from './editors.js'; import { getPref } from './preferences.js'; let slides = []; let currentSlideIndex = 0; let isPresenting = false; const $ = (sel) => document.querySelector(sel); function showToast(msg) { const toast = $('#share-toast'); if (!toast) return; toast.textContent = msg; toast.classList.remove('hidden'); setTimeout(() => toast.classList.add('hidden'), 3000); } export async function openSlideManager(fiddleId) { if (!fiddleId) { showToast('Save the fiddle first to use presentation mode'); return; } const modal = $('#presentation-modal'); modal.classList.remove('hidden'); try { const result = await listSlides(fiddleId); slides = result.slides || []; renderSlideList(fiddleId); } catch (e) { showToast('Failed to load slides: ' + e.message); } } function renderSlideList(fiddleId) { const list = $('#slide-list'); list.innerHTML = ''; if (!slides.length) { list.innerHTML = '
No slides yet. Add the current editor state as a slide.
'; } else { slides.forEach((slide, i) => { const item = document.createElement('div'); item.className = 'slide-item'; item.innerHTML = ` ${i + 1} ${escHtml(slide.notes || slide.js.slice(0, 60) || slide.html.slice(0, 60) || '(empty)')} `; list.appendChild(item); }); list.querySelectorAll('.slide-delete-btn').forEach(btn => { btn.addEventListener('click', async (e) => { e.stopPropagation(); try { await deleteSlide(btn.dataset.id); slides = slides.filter(s => s.id !== btn.dataset.id); renderSlideList(fiddleId); } catch (err) { showToast('Delete failed: ' + err.message); } }); }); } // Update slide count const countEl = $('#slide-count'); if (countEl) countEl.textContent = `${slides.length} slide${slides.length !== 1 ? 's' : ''}`; } export async function addCurrentSlide(fiddleId) { if (!fiddleId) return; const { html, css, js } = getEditorValues(); const notes = prompt('Slide notes (optional):') || ''; try { const slide = await createSlide(fiddleId, { html, css, js, notes }); slides.push(slide); renderSlideList(fiddleId); showToast(`Slide ${slides.length} added`); } catch (e) { showToast('Failed to add slide: ' + e.message); } } export async function startPresentation(fiddleId) { if (!fiddleId) { showToast('Save the fiddle first'); return; } try { const result = await listSlides(fiddleId); slides = result.slides || []; } catch (e) { showToast('Failed to load slides: ' + e.message); return; } if (!slides.length) { showToast('Add at least one slide first'); return; } isPresenting = true; currentSlideIndex = 0; const overlay = $('#presentation-overlay'); overlay.classList.remove('hidden'); // Close the manager modal if open $('#presentation-modal').classList.add('hidden'); renderCurrentSlide(); document.addEventListener('keydown', presentationKeyHandler); } export function stopPresentation() { isPresenting = false; const overlay = $('#presentation-overlay'); overlay.classList.add('hidden'); document.removeEventListener('keydown', presentationKeyHandler); } function presentationKeyHandler(e) { if (!isPresenting) return; if (e.key === 'Escape') { e.preventDefault(); stopPresentation(); } else if (e.key === 'ArrowRight' || e.key === 'ArrowDown' || e.key === ' ') { e.preventDefault(); if (currentSlideIndex < slides.length - 1) { currentSlideIndex++; renderCurrentSlide(); } } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); if (currentSlideIndex > 0) { currentSlideIndex--; renderCurrentSlide(); } } } async function renderCurrentSlide() { const slide = slides[currentSlideIndex]; if (!slide) return; const counter = $('#pres-counter'); counter.textContent = `${currentSlideIndex + 1} / ${slides.length}`; const notes = $('#pres-notes'); notes.textContent = slide.notes || ''; // Render the slide's code into the presentation iframe const frame = $('#pres-preview-frame'); const mode = getCurrentMode(); const cssType = getCssType(); try { const compiledCss = await compileCss(slide.css, cssType); const result = await compileJs(slide.js, mode); const { getFrameworkRuntime } = await import('./js-preprocessors.js'); const runtime = getFrameworkRuntime(mode); const allCss = result.extraCss ? `${compiledCss}\n${result.extraCss}` : compiledCss; const finalHtml = result.renderedHtml || slide.html; const finalJs = result.renderedHtml ? '' : result.js; let bodyContent; if (mode === 'vue' || mode === 'svelte') { bodyContent = finalHtml ? `${finalHtml}\n${runtime.bodyHtml}` : runtime.bodyHtml; } else if (runtime.bodyHtml) { bodyContent = `${finalHtml}\n${runtime.bodyHtml}`; } else { bodyContent = finalHtml; } const isModule = result.isModule || mode === 'svelte'; let scripts = ''; if (finalJs) { if (isModule) { scripts = `