@thanh01.pmt/presentation-kit 0.2.14 → 0.2.15

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.
package/dist/ai/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkJIIUW2TN_cjs = require('../chunk-JIIUW2TN.cjs');
3
+ var chunkSUGKWGJJ_cjs = require('../chunk-SUGKWGJJ.cjs');
4
4
  var zod = require('zod');
5
5
 
6
6
  var listSlidePresetsSchema = zod.z.object({
@@ -64,7 +64,7 @@ var generateDeckOutlineSchema = zod.z.object({
64
64
  // src/ai/tools.ts
65
65
  function executeListSlidePresets(params) {
66
66
  const category = params?.category;
67
- const presets = !category || category === "all" ? chunkJIIUW2TN_cjs.SLIDE_LAYOUT_PRESETS : chunkJIIUW2TN_cjs.getSlideLayoutPresetsByCategory(category);
67
+ const presets = !category || category === "all" ? chunkSUGKWGJJ_cjs.SLIDE_LAYOUT_PRESETS : chunkSUGKWGJJ_cjs.getSlideLayoutPresetsByCategory(category);
68
68
  return {
69
69
  count: presets.length,
70
70
  presets: presets.map((p) => ({
@@ -78,7 +78,7 @@ function executeListSlidePresets(params) {
78
78
  };
79
79
  }
80
80
  function executeCreateSlideFromPreset(params) {
81
- const preset = chunkJIIUW2TN_cjs.getSlideLayoutPresetById(params.presetId);
81
+ const preset = chunkSUGKWGJJ_cjs.getSlideLayoutPresetById(params.presetId);
82
82
  if (!preset) {
83
83
  return {
84
84
  success: false,
@@ -86,7 +86,7 @@ function executeCreateSlideFromPreset(params) {
86
86
  error: `Preset with ID "${params.presetId}" not found. Use listSlidePresets to see available layout templates.`
87
87
  };
88
88
  }
89
- const layoutComment = chunkJIIUW2TN_cjs.serializeLayoutToComment(preset.layout);
89
+ const layoutComment = chunkSUGKWGJJ_cjs.serializeLayoutToComment(preset.layout);
90
90
  const title = params.title;
91
91
  const subtitle = params.subtitle ? `
92
92
  ### ${params.subtitle}` : "";
@@ -227,7 +227,7 @@ Presenter Notes:
227
227
  function executeApplySlideLayout(params) {
228
228
  let layoutData = null;
229
229
  if (params.presetId) {
230
- const preset = chunkJIIUW2TN_cjs.getSlideLayoutPresetById(params.presetId);
230
+ const preset = chunkSUGKWGJJ_cjs.getSlideLayoutPresetById(params.presetId);
231
231
  if (!preset) {
232
232
  return {
233
233
  success: false,
@@ -239,7 +239,7 @@ function executeApplySlideLayout(params) {
239
239
  } else if (params.boxes && params.boxes.length > 0) {
240
240
  layoutData = { boxes: params.boxes };
241
241
  }
242
- const updatedMarkdown = chunkJIIUW2TN_cjs.updateSlideLayoutInMarkdown(
242
+ const updatedMarkdown = chunkSUGKWGJJ_cjs.updateSlideLayoutInMarkdown(
243
243
  params.markdown,
244
244
  params.slideIndex,
245
245
  layoutData
@@ -250,7 +250,7 @@ function executeApplySlideLayout(params) {
250
250
  };
251
251
  }
252
252
  function executeUpdatePresenterNotes(params) {
253
- const { frontmatter, slides } = chunkJIIUW2TN_cjs.splitMarkdownSlides(params.markdown);
253
+ const { frontmatter, slides } = chunkSUGKWGJJ_cjs.splitMarkdownSlides(params.markdown);
254
254
  if (params.slideIndex < 0 || params.slideIndex >= slides.length) {
255
255
  return {
256
256
  success: false,
@@ -469,13 +469,13 @@ function validateHtmlSlideDeck(deck, strict = false) {
469
469
  slides.forEach((slide, idx) => {
470
470
  const slideNumber = idx + 1;
471
471
  const layoutId = slide.layoutId;
472
- const preset = chunkJIIUW2TN_cjs.HTML_SLIDE_PRESETS[layoutId];
472
+ const preset = chunkSUGKWGJJ_cjs.HTML_SLIDE_PRESETS[layoutId];
473
473
  if (!preset) {
474
474
  issues.push({
475
475
  slideIndex: slideNumber,
476
476
  severity: "error",
477
477
  rule: "INVALID_LAYOUT_PRESET",
478
- message: `Unknown layoutId "${slide.layoutId}". Available presets: ${Object.keys(chunkJIIUW2TN_cjs.HTML_SLIDE_PRESETS).join(", ")}`
478
+ message: `Unknown layoutId "${slide.layoutId}". Available presets: ${Object.keys(chunkSUGKWGJJ_cjs.HTML_SLIDE_PRESETS).join(", ")}`
479
479
  });
480
480
  return;
481
481
  }
@@ -624,7 +624,7 @@ function validateMarkdownSlideDeck(markdown, strict = false) {
624
624
  suggestions: ['Provide Markdown slide content delimited by "---".']
625
625
  };
626
626
  }
627
- const { slides: rawSlides } = chunkJIIUW2TN_cjs.splitMarkdownSlides(markdown);
627
+ const { slides: rawSlides } = chunkSUGKWGJJ_cjs.splitMarkdownSlides(markdown);
628
628
  const activeSlides = rawSlides.filter((s) => s.trim().length > 0);
629
629
  const slideCount = activeSlides.length;
630
630
  if (slideCount === 0) {
@@ -872,7 +872,7 @@ Scaffolding Tip: Compare it to ordering coffee at a counter (async buzzer) versu
872
872
  // src/ai/html/tools.ts
873
873
  function handleListHtmlSlidePresets(input) {
874
874
  const category = input.category || "all";
875
- const presets = Object.values(chunkJIIUW2TN_cjs.HTML_SLIDE_PRESETS).filter((p) => category === "all" || p.category === category).map((p) => ({
875
+ const presets = Object.values(chunkSUGKWGJJ_cjs.HTML_SLIDE_PRESETS).filter((p) => category === "all" || p.category === category).map((p) => ({
876
876
  id: p.id,
877
877
  name: p.name,
878
878
  category: p.category,
@@ -888,12 +888,12 @@ function handleListHtmlSlidePresets(input) {
888
888
  return {
889
889
  success: true,
890
890
  presets,
891
- availableThemes: Object.keys(chunkJIIUW2TN_cjs.HTML_THEMES)
891
+ availableThemes: Object.keys(chunkSUGKWGJJ_cjs.HTML_THEMES)
892
892
  };
893
893
  }
894
894
  function handleGenerateHtmlDeck(input) {
895
895
  try {
896
- const result = chunkJIIUW2TN_cjs.compileHtmlDeck(input);
896
+ const result = chunkSUGKWGJJ_cjs.compileHtmlDeck(input);
897
897
  return {
898
898
  success: true,
899
899
  title: result.title,
@@ -909,7 +909,7 @@ function handleGenerateHtmlDeck(input) {
909
909
  }
910
910
  }
911
911
  function handleCreateHtmlSlide(input) {
912
- const preset = chunkJIIUW2TN_cjs.HTML_SLIDE_PRESETS[input.layoutId];
912
+ const preset = chunkSUGKWGJJ_cjs.HTML_SLIDE_PRESETS[input.layoutId];
913
913
  if (!preset) {
914
914
  return {
915
915
  success: false,
package/dist/ai/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SLIDE_LAYOUT_PRESETS, getSlideLayoutPresetsByCategory, getSlideLayoutPresetById, serializeLayoutToComment, updateSlideLayoutInMarkdown, splitMarkdownSlides, HTML_SLIDE_PRESETS, HTML_THEMES, compileHtmlDeck } from '../chunk-A7T5Y2G4.js';
1
+ import { SLIDE_LAYOUT_PRESETS, getSlideLayoutPresetsByCategory, getSlideLayoutPresetById, serializeLayoutToComment, updateSlideLayoutInMarkdown, splitMarkdownSlides, HTML_SLIDE_PRESETS, HTML_THEMES, compileHtmlDeck } from '../chunk-YPYAP4TF.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  var listSlidePresetsSchema = z.object({
@@ -1282,9 +1282,9 @@ var HTML_SLIDE_PRESETS = {
1282
1282
 
1283
1283
  // src/html-engine/shell.ts
1284
1284
  function generateHtmlShell(options) {
1285
- const { title, theme, slidesHtml, slideCount, customHeadTags = "" } = options;
1285
+ const { title, theme, slidesHtml, slideCount, customHeadTags = "", deckId = "" } = options;
1286
1286
  return `<!DOCTYPE html>
1287
- <html lang="en" class="${theme.scheme}">
1287
+ <html lang="en" class="${theme.scheme}"${deckId ? ` data-deck-id="${deckId}"` : ""}>
1288
1288
  <head>
1289
1289
  <meta charset="UTF-8">
1290
1290
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
@@ -1298,6 +1298,7 @@ function generateHtmlShell(options) {
1298
1298
  <!-- Core Presentation Styling & 1920x1080 Scaled Tailwind Configuration -->
1299
1299
  <script src="https://cdn.tailwindcss.com"></script>
1300
1300
  <script>
1301
+ window.tailwind = window.tailwind || {};
1301
1302
  tailwind.config = {
1302
1303
  darkMode: 'class',
1303
1304
  theme: {
@@ -1421,6 +1422,7 @@ function generateHtmlShell(options) {
1421
1422
  left: 50%;
1422
1423
  width: 1920px;
1423
1424
  height: 1080px;
1425
+ transform: translate(-50%, -50%);
1424
1426
  transform-origin: center center;
1425
1427
  background-color: var(--bg);
1426
1428
  overflow: hidden;
@@ -2421,10 +2423,21 @@ function generateHtmlShell(options) {
2421
2423
  const TOTAL_SLIDES = ${slideCount};
2422
2424
  let currentSlide = 0;
2423
2425
  let isEditMode = false;
2424
- const STORAGE_KEY = 'deck_edit_' + encodeURIComponent(document.title.trim() || 'default');
2425
- const originalCanvasHtml = document.getElementById('canvas').innerHTML;
2426
-
2427
2426
  const canvas = document.getElementById('canvas');
2427
+ const originalCanvasHtml = canvas ? canvas.innerHTML : '';
2428
+
2429
+ function computeDeckContentHash(str) {
2430
+ let h = 0;
2431
+ for (let i = 0; i < str.length; i++) {
2432
+ h = (Math.imul(31, h) + str.charCodeAt(i)) | 0;
2433
+ }
2434
+ return Math.abs(h).toString(36);
2435
+ }
2436
+
2437
+ const deckIdAttr = document.documentElement.getAttribute('data-deck-id');
2438
+ const contentHash = computeDeckContentHash(originalCanvasHtml);
2439
+ const deckKeyPrefix = deckIdAttr ? encodeURIComponent(deckIdAttr) : (encodeURIComponent(document.title.trim() || 'deck') + '_' + contentHash);
2440
+ const STORAGE_KEY = 'deck_edit_' + deckKeyPrefix;
2428
2441
  const slides = document.querySelectorAll('.slide-page');
2429
2442
  const progressBar = document.getElementById('progress-bar');
2430
2443
  const counter = document.getElementById('slide-counter');
@@ -2484,7 +2497,7 @@ function generateHtmlShell(options) {
2484
2497
  let timerInterval = null;
2485
2498
  let isTimerRunning = false;
2486
2499
 
2487
- const SCALE_STORAGE_KEY = 'deck_scale_' + encodeURIComponent(document.title.trim() || 'default');
2500
+ const SCALE_STORAGE_KEY = 'deck_scale_' + deckKeyPrefix;
2488
2501
  let scaleState = {
2489
2502
  mode: 'unified', // 'unified' | 'independent'
2490
2503
  factor: 1.0,
@@ -2508,8 +2521,9 @@ function generateHtmlShell(options) {
2508
2521
  // Auto-scale 1920x1080 canvas to fit window
2509
2522
  function resizeCanvas() {
2510
2523
  if (isDeckMode) return;
2511
- const vw = window.innerWidth;
2512
- const vh = window.innerHeight;
2524
+ const vw = window.innerWidth || document.documentElement.clientWidth || 1920;
2525
+ const vh = window.innerHeight || document.documentElement.clientHeight || 1080;
2526
+ if (vw <= 0 || vh <= 0) return;
2513
2527
  const scaleX = vw / 1920;
2514
2528
  const scaleY = vh / 1080;
2515
2529
  const scale = Math.min(scaleX, scaleY);
@@ -2517,7 +2531,10 @@ function generateHtmlShell(options) {
2517
2531
  }
2518
2532
 
2519
2533
  window.addEventListener('resize', resizeCanvas);
2534
+ window.addEventListener('load', resizeCanvas);
2535
+ document.addEventListener('DOMContentLoaded', resizeCanvas);
2520
2536
  resizeCanvas();
2537
+ requestAnimationFrame(resizeCanvas);
2521
2538
 
2522
2539
  function getSlideNotes(slideIndex) {
2523
2540
  if (slideIndex < 0 || slideIndex >= slides.length) return '';
@@ -2690,8 +2707,7 @@ function generateHtmlShell(options) {
2690
2707
  if (!presenterNotesText) return;
2691
2708
  const notes = getSlideNotes(currentSlide);
2692
2709
  if (notes && notes.trim()) {
2693
- presenterNotesText.innerHTML = notes.replace(/
2694
- /g, '<br/>');
2710
+ presenterNotesText.innerHTML = notes.split('\\n').join('<br/>');
2695
2711
  } else {
2696
2712
  presenterNotesText.innerHTML = '<span style="opacity: 0.5; font-style: italic;">No speaker notes for Slide ' + (currentSlide + 1) + '.</span>';
2697
2713
  }
@@ -2708,7 +2724,7 @@ function generateHtmlShell(options) {
2708
2724
 
2709
2725
  function openPresenterConsole() {
2710
2726
  startTimer();
2711
- const popupName = 'PresenterConsole_' + encodeURIComponent(document.title.replace(/W/g, ''));
2727
+ const popupName = 'PresenterConsole_' + encodeURIComponent(document.title.replace(/[^a-zA-Z0-9_]/g, ''));
2712
2728
  const win = window.open('', popupName, 'width=1100,height=720,menubar=no,toolbar=no,location=no,status=no');
2713
2729
  if (!win) {
2714
2730
  togglePresenterDrawer();
@@ -2719,151 +2735,84 @@ function generateHtmlShell(options) {
2719
2735
  const currentNotes = getSlideNotes(currentSlide);
2720
2736
  const curSlideTitle = 'Slide ' + (currentSlide + 1) + ' / ' + TOTAL_SLIDES;
2721
2737
 
2722
- const consoleHtml = '<!DOCTYPE html>
2723
- <html>
2724
- <head>
2725
- ' +
2726
- '<meta charset="UTF-8"><title>Presenter Console \u2014 ' + (document.title || 'Slides') + '</title>
2727
- ' +
2728
- '<style>
2729
- ' +
2730
- '* { box-sizing: border-box; margin: 0; padding: 0; }
2731
- ' +
2732
- 'body { background: #0c0d14; color: #f4f4f5; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; display: flex; flex-direction: column; height: 100vh; overflow: hidden; user-select: none; }
2733
- ' +
2734
- '.top-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 24px; background: #141522; border-bottom: 1px solid rgba(255,255,255,0.12); }
2735
- ' +
2736
- '.timer-badge { font-family: monospace; font-size: 20px; font-weight: 700; color: #38bdf8; background: rgba(56,189,248,0.15); border: 1px solid rgba(56,189,248,0.3); padding: 4px 14px; border-radius: 8px; display: flex; align-items: center; gap: 8px; }
2737
- ' +
2738
- '.grid-container { flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; padding: 20px 24px; overflow: hidden; }
2739
- ' +
2740
- '.panel-card { background: #181926; border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; display: flex; flex-direction: column; overflow: hidden; }
2741
- ' +
2742
- '.card-header { padding: 10px 16px; background: rgba(255,255,255,0.04); border-bottom: 1px solid rgba(255,255,255,0.08); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: #a1a1aa; display: flex; justify-content: space-between; }
2743
- ' +
2744
- '.notes-content { flex: 1; padding: 20px; font-size: 19px; line-height: 1.7; overflow-y: auto; color: #f1f5f9; user-select: text; white-space: pre-wrap; }
2745
- ' +
2746
- '.preview-box { flex: 1; display: flex; align-items: center; justify-content: center; background: #000; overflow: hidden; padding: 16px; }
2747
- ' +
2748
- '.btn { background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.15); color: #fff; padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; }
2749
- ' +
2750
- '.btn:hover { background: rgba(255,255,255,0.2); }
2751
- ' +
2752
- '.btn-nav { font-size: 16px; padding: 10px 24px; border-radius: 8px; }
2753
- ' +
2754
- '.bottom-nav { display: flex; align-items: center; justify-content: space-between; padding: 14px 24px; background: #141522; border-top: 1px solid rgba(255,255,255,0.12); }
2755
- ' +
2756
- '</style>
2757
- </head>
2758
- <body>
2759
- ' +
2760
- '<div class="top-bar">
2761
- ' +
2762
- ' <div style="font-weight: 700; font-size: 16px;">' + (document.title || 'Slide Deck') + '</div>
2763
- ' +
2764
- ' <div style="display: flex; align-items: center; gap: 12px;">
2765
- ' +
2766
- ' <div class="timer-badge">\u23F1 <span id="timer-val">00:00</span></div>
2767
- ' +
2768
- ' <button class="btn" id="btn-toggle-t">Pause</button>
2769
- ' +
2770
- ' <button class="btn" id="btn-reset-t">Reset</button>
2771
- ' +
2772
- ' </div>
2773
- ' +
2774
- '</div>
2775
- ' +
2776
- '<div class="grid-container">
2777
- ' +
2778
- ' <div class="panel-card">
2779
- ' +
2780
- ' <div class="card-header"><span>CURRENT SLIDE</span><span id="slide-num">' + curSlideTitle + '</span></div>
2781
- ' +
2782
- ' <div class="preview-box"><div style="font-size: 22px; color: #94a3b8; text-align: center;">Active Slide On Screen<br/><span style="font-size: 14px; color: #38bdf8;">(Broadcasting Synced)</span></div></div>
2783
- ' +
2784
- ' <div class="card-header" style="border-top: 1px solid rgba(255,255,255,0.08);"><span>NEXT SLIDE PREVIEW</span></div>
2785
- ' +
2786
- ' <div style="padding: 12px 16px; font-size: 14px; color: #94a3b8; background: rgba(0,0,0,0.3); min-height: 80px;" id="next-preview-text">Upcoming: Slide ' + (currentSlide + 2) + '</div>
2787
- ' +
2788
- ' </div>
2789
- ' +
2790
- ' <div class="panel-card">
2791
- ' +
2792
- ' <div class="card-header"><span>SPEAKER NOTES / TALK TRACK</span><div><button class="btn" id="font-dn" style="padding: 2px 8px;">A-</button> <button class="btn" id="font-up" style="padding: 2px 8px;">A+</button></div></div>
2793
- ' +
2794
- ' <div class="notes-content" id="speaker-notes">' + (currentNotes ? currentNotes : '<span style="opacity: 0.4;">No speaker notes for this slide.</span>') + '</div>
2795
- ' +
2796
- ' </div>
2797
- ' +
2798
- '</div>
2799
- ' +
2800
- '<div class="bottom-nav">
2801
- ' +
2802
- ' <button class="btn btn-nav" id="btn-prev-p">\u2039 Previous (\u2190)</button>
2803
- ' +
2804
- ' <span style="font-size: 14px; color: #a1a1aa;">Use Arrow Keys or Space to advance</span>
2805
- ' +
2806
- ' <button class="btn btn-nav" id="btn-next-p" style="background: #0284c7; border-color: #0284c7;">Next (\u2192 / Space) \u203A</button>
2807
- ' +
2808
- '</div>
2809
- ' +
2810
- '<script>
2811
- ' +
2812
- ' const bc = new BroadcastChannel("' + SYNC_CHANNEL_NAME + '");
2813
- ' +
2814
- ' let curSecs = ' + timerSeconds + ';
2815
- ' +
2816
- ' function sendCmd(action, idx) { bc.postMessage({ type: "COMMAND", action: action, index: idx }); }
2817
- ' +
2818
- ' document.getElementById("btn-prev-p").onclick = () => sendCmd("PREV");
2819
- ' +
2820
- ' document.getElementById("btn-next-p").onclick = () => sendCmd("NEXT");
2821
- ' +
2822
- ' document.getElementById("btn-reset-t").onclick = () => sendCmd("RESET_TIMER");
2823
- ' +
2824
- ' document.getElementById("btn-toggle-t").onclick = () => sendCmd("TOGGLE_TIMER");
2825
- ' +
2826
- ' let curFontSize = 19;
2827
- ' +
2828
- ' document.getElementById("font-up").onclick = () => { curFontSize += 2; document.getElementById("speaker-notes").style.fontSize = curFontSize + "px"; };
2829
- ' +
2830
- ' document.getElementById("font-dn").onclick = () => { curFontSize = Math.max(12, curFontSize - 2); document.getElementById("speaker-notes").style.fontSize = curFontSize + "px"; };
2831
- ' +
2832
- ' window.onkeydown = (e) => {
2833
- ' +
2834
- ' if (["ArrowRight", "Space", "PageDown"].includes(e.code)) { e.preventDefault(); sendCmd("NEXT"); }
2835
- ' +
2836
- ' else if (["ArrowLeft", "PageUp"].includes(e.code)) { e.preventDefault(); sendCmd("PREV"); }
2837
- ' +
2838
- ' };
2839
- ' +
2840
- ' bc.onmessage = (e) => {
2841
- ' +
2842
- ' if (!e.data || e.data.type !== "STATE_UPDATE") return;
2843
- ' +
2844
- ' document.getElementById("slide-num").textContent = "Slide " + (e.data.currentSlide + 1) + " / " + e.data.totalSlides;
2845
- ' +
2846
- ' document.getElementById("speaker-notes").textContent = e.data.notes || "No speaker notes for this slide.";
2847
- ' +
2848
- ' document.getElementById("next-preview-text").textContent = e.data.nextNotes ? "Next Notes: " + e.data.nextNotes : "Next: Slide " + (e.data.currentSlide + 2);
2849
- ' +
2850
- ' curSecs = e.data.timerSeconds || 0;
2851
- ' +
2852
- ' const m = String(Math.floor(curSecs / 60)).padStart(2, "0");
2853
- ' +
2854
- ' const s = String(curSecs % 60).padStart(2, "0");
2855
- ' +
2856
- ' document.getElementById("timer-val").textContent = m + ":" + s;
2857
- ' +
2858
- ' document.getElementById("btn-toggle-t").textContent = e.data.timerRunning ? "Pause" : "Start";
2859
- ' +
2860
- ' };
2861
- ' +
2862
- ' bc.postMessage({ type: "REQUEST_STATE" });
2863
- ' +
2864
- '<' + '/script>
2865
- </body>
2866
- </html>';
2738
+ const consoleHtml = [
2739
+ '<!DOCTYPE html>',
2740
+ '<html>',
2741
+ '<head>',
2742
+ '<meta charset="UTF-8"><title>Presenter Console \u2014 ' + (document.title || 'Slides') + '</title>',
2743
+ '<style>',
2744
+ '* { box-sizing: border-box; margin: 0; padding: 0; }',
2745
+ 'body { background: #0c0d14; color: #f4f4f5; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; display: flex; flex-direction: column; height: 100vh; overflow: hidden; user-select: none; }',
2746
+ '.top-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 24px; background: #141522; border-bottom: 1px solid rgba(255,255,255,0.12); }',
2747
+ '.timer-badge { font-family: monospace; font-size: 20px; font-weight: 700; color: #38bdf8; background: rgba(56,189,248,0.15); border: 1px solid rgba(56,189,248,0.3); padding: 4px 14px; border-radius: 8px; display: flex; align-items: center; gap: 8px; }',
2748
+ '.grid-container { flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; padding: 20px 24px; overflow: hidden; }',
2749
+ '.panel-card { background: #181926; border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; display: flex; flex-direction: column; overflow: hidden; }',
2750
+ '.card-header { padding: 10px 16px; background: rgba(255,255,255,0.04); border-bottom: 1px solid rgba(255,255,255,0.08); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: #a1a1aa; display: flex; justify-content: space-between; }',
2751
+ '.notes-content { flex: 1; padding: 20px; font-size: 19px; line-height: 1.7; overflow-y: auto; color: #f1f5f9; user-select: text; white-space: pre-wrap; }',
2752
+ '.preview-box { flex: 1; display: flex; align-items: center; justify-content: center; background: #000; overflow: hidden; padding: 16px; }',
2753
+ '.btn { background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.15); color: #fff; padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; }',
2754
+ '.btn:hover { background: rgba(255,255,255,0.2); }',
2755
+ '.btn-nav { font-size: 16px; padding: 10px 24px; border-radius: 8px; }',
2756
+ '.bottom-nav { display: flex; align-items: center; justify-content: space-between; padding: 14px 24px; background: #141522; border-top: 1px solid rgba(255,255,255,0.12); }',
2757
+ '</style>',
2758
+ '</head>',
2759
+ '<body>',
2760
+ '<div class="top-bar">',
2761
+ ' <div style="font-weight: 700; font-size: 16px;">' + (document.title || 'Slide Deck') + '</div>',
2762
+ ' <div style="display: flex; align-items: center; gap: 12px;">',
2763
+ ' <div class="timer-badge">\u23F1 <span id="timer-val">00:00</span></div>',
2764
+ ' <button class="btn" id="btn-toggle-t">Pause</button>',
2765
+ ' <button class="btn" id="btn-reset-t">Reset</button>',
2766
+ ' </div>',
2767
+ '</div>',
2768
+ '<div class="grid-container">',
2769
+ ' <div class="panel-card">',
2770
+ ' <div class="card-header"><span>CURRENT SLIDE</span><span id="slide-num">' + curSlideTitle + '</span></div>',
2771
+ ' <div class="preview-box"><div style="font-size: 22px; color: #94a3b8; text-align: center;">Active Slide On Screen<br/><span style="font-size: 14px; color: #38bdf8;">(Broadcasting Synced)</span></div></div>',
2772
+ ' <div class="card-header" style="border-top: 1px solid rgba(255,255,255,0.08);"><span>NEXT SLIDE PREVIEW</span></div>',
2773
+ ' <div style="padding: 12px 16px; font-size: 14px; color: #94a3b8; background: rgba(0,0,0,0.3); min-height: 80px;" id="next-preview-text">Upcoming: Slide ' + (currentSlide + 2) + '</div>',
2774
+ ' </div>',
2775
+ ' <div class="panel-card">',
2776
+ ' <div class="card-header"><span>SPEAKER NOTES / TALK TRACK</span><div><button class="btn" id="font-dn" style="padding: 2px 8px;">A-</button> <button class="btn" id="font-up" style="padding: 2px 8px;">A+</button></div></div>',
2777
+ ' <div class="notes-content" id="speaker-notes">' + (currentNotes ? currentNotes : '<span style="opacity: 0.4;">No speaker notes for this slide.</span>') + '</div>',
2778
+ ' </div>',
2779
+ '</div>',
2780
+ '<div class="bottom-nav">',
2781
+ ' <button class="btn btn-nav" id="btn-prev-p">\u2039 Previous (\u2190)</button>',
2782
+ ' <span style="font-size: 14px; color: #a1a1aa;">Use Arrow Keys or Space to advance</span>',
2783
+ ' <button class="btn btn-nav" id="btn-next-p" style="background: #0284c7; border-color: #0284c7;">Next (\u2192 / Space) \u203A</button>',
2784
+ '</div>',
2785
+ '<script>',
2786
+ ' const bc = new BroadcastChannel("' + SYNC_CHANNEL_NAME + '");',
2787
+ ' let curSecs = ' + timerSeconds + ';',
2788
+ ' function sendCmd(action, idx) { bc.postMessage({ type: "COMMAND", action: action, index: idx }); }',
2789
+ ' document.getElementById("btn-prev-p").onclick = () => sendCmd("PREV");',
2790
+ ' document.getElementById("btn-next-p").onclick = () => sendCmd("NEXT");',
2791
+ ' document.getElementById("btn-reset-t").onclick = () => sendCmd("RESET_TIMER");',
2792
+ ' document.getElementById("btn-toggle-t").onclick = () => sendCmd("TOGGLE_TIMER");',
2793
+ ' let curFontSize = 19;',
2794
+ ' document.getElementById("font-up").onclick = () => { curFontSize += 2; document.getElementById("speaker-notes").style.fontSize = curFontSize + "px"; };',
2795
+ ' document.getElementById("font-dn").onclick = () => { curFontSize = Math.max(12, curFontSize - 2); document.getElementById("speaker-notes").style.fontSize = curFontSize + "px"; };',
2796
+ ' window.onkeydown = (e) => {',
2797
+ ' if (["ArrowRight", "Space", "PageDown"].includes(e.code)) { e.preventDefault(); sendCmd("NEXT"); }',
2798
+ ' else if (["ArrowLeft", "PageUp"].includes(e.code)) { e.preventDefault(); sendCmd("PREV"); }',
2799
+ ' };',
2800
+ ' bc.onmessage = (e) => {',
2801
+ ' if (!e.data || e.data.type !== "STATE_UPDATE") return;',
2802
+ ' document.getElementById("slide-num").textContent = "Slide " + (e.data.currentSlide + 1) + " / " + e.data.totalSlides;',
2803
+ ' document.getElementById("speaker-notes").textContent = e.data.notes || "No speaker notes for this slide.";',
2804
+ ' document.getElementById("next-preview-text").textContent = e.data.nextNotes ? "Next Notes: " + e.data.nextNotes : "Next: Slide " + (e.data.currentSlide + 2);',
2805
+ ' curSecs = e.data.timerSeconds || 0;',
2806
+ ' const m = String(Math.floor(curSecs / 60)).padStart(2, "0");',
2807
+ ' const s = String(curSecs % 60).padStart(2, "0");',
2808
+ ' document.getElementById("timer-val").textContent = m + ":" + s;',
2809
+ ' document.getElementById("btn-toggle-t").textContent = e.data.timerRunning ? "Pause" : "Start";',
2810
+ ' };',
2811
+ ' bc.postMessage({ type: "REQUEST_STATE" });',
2812
+ '<' + '/script>',
2813
+ '</body>',
2814
+ '</html>'
2815
+ ].join('\\n');
2867
2816
 
2868
2817
  win.document.open();
2869
2818
  win.document.write(consoleHtml);
@@ -2879,8 +2828,7 @@ function generateHtmlShell(options) {
2879
2828
  const card = document.createElement('div');
2880
2829
  card.className = 'deck-notes-card';
2881
2830
  card.setAttribute('data-for-slide', String(idx));
2882
- card.innerHTML = '<div class="deck-notes-card-header"><span>\u{1F4DD}</span><span>Presenter Notes (Slide ' + (idx + 1) + ')</span></div><div>' + notes.replace(/
2883
- /g, '<br/>') + '</div>';
2831
+ card.innerHTML = '<div class="deck-notes-card-header"><span>\u{1F4DD}</span><span>Presenter Notes (Slide ' + (idx + 1) + ')</span></div><div>' + notes.split('\\n').join('<br/>') + '</div>';
2884
2832
  slide.after(card);
2885
2833
  }
2886
2834
  });
@@ -3220,8 +3168,7 @@ function generateHtmlShell(options) {
3220
3168
  if (scalePanel) scalePanel.style.display = 'none';
3221
3169
 
3222
3170
  // Take snapshot of full HTML
3223
- let cleanHtml = '<!DOCTYPE html>
3224
- ' + document.documentElement.outerHTML;
3171
+ let cleanHtml = '<!DOCTYPE html>' + '\\n' + document.documentElement.outerHTML;
3225
3172
 
3226
3173
  // Clean any temporary runtime inline styles or attributes
3227
3174
  cleanHtml = cleanHtml
@@ -3231,28 +3178,20 @@ function generateHtmlShell(options) {
3231
3178
  .replace(/class="edit-toggle[^"]*"/g, 'class="edit-toggle"');
3232
3179
 
3233
3180
  // Embed current scale settings into :root style definition so exported HTML is permanently styled with chosen scales
3234
- const scaleVarsReplacement =
3235
- '--scale-mode: ' + scaleState.mode + ';
3236
- ' +
3237
- ' --scale-factor: ' + scaleState.factor + ';
3238
- ' +
3239
- ' --scale-headings: ' + scaleState.headings + ';
3240
- ' +
3241
- ' --scale-body: ' + scaleState.body + ';
3242
- ' +
3243
- ' --scale-code: ' + scaleState.code + ';
3244
- ' +
3245
- ' --scale-spacing: ' + scaleState.spacing + ';
3246
- ' +
3247
- ' --scale-headings-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.headings) + ';
3248
- ' +
3249
- ' --scale-body-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.body) + ';
3250
- ' +
3251
- ' --scale-code-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.code) + ';
3252
- ' +
3253
- ' --scale-spacing-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.spacing) + ';';
3254
-
3255
- cleanHtml = cleanHtml.replace(/--scale-mode:s*unified;[sS]*?--scale-spacing-eff:s*1.0;/, scaleVarsReplacement);
3181
+ const scaleVarsReplacement = [
3182
+ '--scale-mode: ' + scaleState.mode + ';',
3183
+ ' --scale-factor: ' + scaleState.factor + ';',
3184
+ ' --scale-headings: ' + scaleState.headings + ';',
3185
+ ' --scale-body: ' + scaleState.body + ';',
3186
+ ' --scale-code: ' + scaleState.code + ';',
3187
+ ' --scale-spacing: ' + scaleState.spacing + ';',
3188
+ ' --scale-headings-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.headings) + ';',
3189
+ ' --scale-body-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.body) + ';',
3190
+ ' --scale-code-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.code) + ';',
3191
+ ' --scale-spacing-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.spacing) + ';'
3192
+ ].join('\\n');
3193
+
3194
+ cleanHtml = cleanHtml.replace(/--scale-mode:\\s*[^;]+;[\\s\\S]*?--scale-spacing-eff:\\s*[^;]+;/, scaleVarsReplacement);
3256
3195
 
3257
3196
  // Create Blob and trigger download
3258
3197
  const blob = new Blob([cleanHtml], { type: 'text/html;charset=utf-8' });
@@ -3421,6 +3360,8 @@ function generateHtmlShell(options) {
3421
3360
  applyScales();
3422
3361
  } else if (e.data.type === 'TOGGLE_SCALE_PANEL') {
3423
3362
  toggleScalePanel();
3363
+ } else if (e.data.type === 'RESIZE') {
3364
+ resizeCanvas();
3424
3365
  }
3425
3366
  });
3426
3367
 
@@ -3457,7 +3398,8 @@ function compileHtmlDeck(deckData, options) {
3457
3398
  theme,
3458
3399
  slidesHtml,
3459
3400
  slideCount,
3460
- customHeadTags: options?.customHeadTags
3401
+ customHeadTags: options?.customHeadTags,
3402
+ deckId: deckData?.id || options?.deckId
3461
3403
  });
3462
3404
  return {
3463
3405
  html: fullHtml,
@@ -3480,5 +3422,5 @@ exports.serializeLayoutToComment = serializeLayoutToComment;
3480
3422
  exports.splitMarkdownSlides = splitMarkdownSlides;
3481
3423
  exports.updateSlideLayoutInMarkdown = updateSlideLayoutInMarkdown;
3482
3424
  exports.updateSlideTextInMarkdown = updateSlideTextInMarkdown;
3483
- //# sourceMappingURL=chunk-JIIUW2TN.cjs.map
3484
- //# sourceMappingURL=chunk-JIIUW2TN.cjs.map
3425
+ //# sourceMappingURL=chunk-SUGKWGJJ.cjs.map
3426
+ //# sourceMappingURL=chunk-SUGKWGJJ.cjs.map