@thanh01.pmt/presentation-kit 0.2.9 → 0.2.11
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 +190 -7
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +123 -3
- package/dist/ai/index.d.ts +123 -3
- package/dist/ai/index.js +177 -2
- package/dist/ai/index.js.map +1 -1
- package/dist/chunk-3VGV5KYZ.js +3446 -0
- package/dist/chunk-3VGV5KYZ.js.map +1 -0
- package/dist/chunk-53GLUCYC.cjs +3464 -0
- package/dist/chunk-53GLUCYC.cjs.map +1 -0
- package/dist/{click-css-BP9oqy_1.d.cts → click-css-Ch_jyWaw.d.cts} +1 -1
- package/dist/{click-css-BbhqdtGr.d.ts → click-css-CktIYP3H.d.ts} +1 -1
- package/dist/index.cjs +30 -10
- package/dist/index.d.cts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +2 -2
- package/dist/{presets-B_TY4i2a.d.ts → presets-BUzebXzj.d.ts} +1 -1
- package/dist/{presets-BIw_4ZXR.d.cts → presets-Bkh6NzWf.d.cts} +1 -1
- package/dist/react/index.cjs +365 -107
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +25 -5
- package/dist/react/index.d.ts +25 -5
- package/dist/react/index.js +312 -59
- package/dist/react/index.js.map +1 -1
- package/dist/{types-C1121XLt.d.cts → types-8AVYoEUn.d.cts} +67 -1
- package/dist/{types-C1121XLt.d.ts → types-8AVYoEUn.d.ts} +67 -1
- package/package.json +2 -2
- package/dist/chunk-TV6NFIIV.cjs +0 -878
- package/dist/chunk-TV6NFIIV.cjs.map +0 -1
- package/dist/chunk-ZPASRL75.js +0 -865
- package/dist/chunk-ZPASRL75.js.map +0 -1
package/dist/react/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React$1 from 'react';
|
|
2
|
-
import { B as BuiltInTheme,
|
|
3
|
-
export { M as MermaidBlock,
|
|
4
|
-
export { l as ClickCssOptions, k as ClickPostprocessResult, C as ClickPreprocessResult, d as defineTheme, i as extractMaxClicks, j as generateClickCss, h as postprocessClicks, p as preprocessClicks, r as renderSlide, a as renderSlideAsync, e as resolveTheme } from '../click-css-
|
|
2
|
+
import { B as BuiltInTheme, h as SlideTheme, j as SlideRenderResult, f as HtmlDeckData, b as SlideLayoutData, L as LayoutBoxConfig } from '../types-8AVYoEUn.cjs';
|
|
3
|
+
export { M as MermaidBlock, k as SlideRenderAsyncResult, i as SlideRenderOptions, T as ThemeTokens } from '../types-8AVYoEUn.cjs';
|
|
4
|
+
export { l as ClickCssOptions, k as ClickPostprocessResult, C as ClickPreprocessResult, d as defineTheme, i as extractMaxClicks, j as generateClickCss, h as postprocessClicks, p as preprocessClicks, r as renderSlide, a as renderSlideAsync, e as resolveTheme } from '../click-css-Ch_jyWaw.cjs';
|
|
5
5
|
|
|
6
6
|
/** View mode for slide display */
|
|
7
7
|
type SlideViewMode = 'presentation' | 'deck';
|
|
@@ -80,6 +80,10 @@ interface DeckViewProps {
|
|
|
80
80
|
slideCount: number;
|
|
81
81
|
/** Container CSS class */
|
|
82
82
|
className?: string;
|
|
83
|
+
/** Presenter notes per slide (optional) */
|
|
84
|
+
notes?: string[][];
|
|
85
|
+
/** Whether to render speaker notes below each slide in deck mode */
|
|
86
|
+
showNotes?: boolean;
|
|
83
87
|
}
|
|
84
88
|
/** Props for ThemeSwitcher */
|
|
85
89
|
interface ThemeSwitcherProps {
|
|
@@ -171,6 +175,22 @@ interface SlideActions {
|
|
|
171
175
|
*/
|
|
172
176
|
declare function SlideViewer({ markdown, initialTheme, initialMode, className, showThemeSwitcher, showNavigation, enableKeyboard, enableClicks, fullscreen, showNotes, showDesignMode, themeOptions, onThemeChange, onSlideChange, onModeChange, onRenderComplete, onSaveMarkdown, }: SlideViewerProps): React$1.JSX.Element;
|
|
173
177
|
|
|
178
|
+
interface HtmlSlideViewerProps {
|
|
179
|
+
/** Pre-compiled HTML string. If provided, used directly */
|
|
180
|
+
htmlContent?: string;
|
|
181
|
+
/** Structured deck data. If provided without htmlContent, compiled automatically */
|
|
182
|
+
deckData?: HtmlDeckData;
|
|
183
|
+
/** Deck title displayed on header / download file name */
|
|
184
|
+
title?: string;
|
|
185
|
+
/** Extra CSS classes for wrapper */
|
|
186
|
+
className?: string;
|
|
187
|
+
/** Callback fired when active slide index changes */
|
|
188
|
+
onSlideChange?: (current: number, total: number) => void;
|
|
189
|
+
/** Show top control bar */
|
|
190
|
+
showTopBar?: boolean;
|
|
191
|
+
}
|
|
192
|
+
declare const HtmlSlideViewer: React$1.FC<HtmlSlideViewerProps>;
|
|
193
|
+
|
|
174
194
|
/**
|
|
175
195
|
* PresentationView — Renders a single slide at a time.
|
|
176
196
|
*
|
|
@@ -205,7 +225,7 @@ declare function PresentationView({ html, css, themeCss, layoutCss, currentIndex
|
|
|
205
225
|
* />
|
|
206
226
|
* ```
|
|
207
227
|
*/
|
|
208
|
-
declare function DeckView({ html, css, themeCss, layoutCss, slideCount, className, }: DeckViewProps): React$1.JSX.Element;
|
|
228
|
+
declare function DeckView({ html, css, themeCss, layoutCss, slideCount, className, notes, showNotes, }: DeckViewProps): React$1.JSX.Element;
|
|
209
229
|
|
|
210
230
|
/**
|
|
211
231
|
* ThemeSwitcher — Renders a row of theme toggle buttons.
|
|
@@ -321,4 +341,4 @@ interface UseSlideStateReturn {
|
|
|
321
341
|
*/
|
|
322
342
|
declare function useSlideState(options: UseSlideStateOptions): UseSlideStateReturn;
|
|
323
343
|
|
|
324
|
-
export { BuiltInTheme, DeckView, type DeckViewProps, NavigationBar, type NavigationBarProps, PresentationView, type PresentationViewProps, PresenterNotesDrawer, type PresenterNotesDrawerProps, type SlideActions, SlideDesignOverlay, type SlideDesignOverlayProps, SlideRenderResult, type SlideState, SlideTheme, type SlideViewMode, SlideViewer, type SlideViewerProps, type ThemeOption, ThemeSwitcher, type ThemeSwitcherProps, type UseSlideStateOptions, type UseSlideStateReturn, useSlideState };
|
|
344
|
+
export { BuiltInTheme, DeckView, type DeckViewProps, HtmlSlideViewer, type HtmlSlideViewerProps, NavigationBar, type NavigationBarProps, PresentationView, type PresentationViewProps, PresenterNotesDrawer, type PresenterNotesDrawerProps, type SlideActions, SlideDesignOverlay, type SlideDesignOverlayProps, SlideRenderResult, type SlideState, SlideTheme, type SlideViewMode, SlideViewer, type SlideViewerProps, type ThemeOption, ThemeSwitcher, type ThemeSwitcherProps, type UseSlideStateOptions, type UseSlideStateReturn, useSlideState };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React$1 from 'react';
|
|
2
|
-
import { B as BuiltInTheme,
|
|
3
|
-
export { M as MermaidBlock,
|
|
4
|
-
export { l as ClickCssOptions, k as ClickPostprocessResult, C as ClickPreprocessResult, d as defineTheme, i as extractMaxClicks, j as generateClickCss, h as postprocessClicks, p as preprocessClicks, r as renderSlide, a as renderSlideAsync, e as resolveTheme } from '../click-css-
|
|
2
|
+
import { B as BuiltInTheme, h as SlideTheme, j as SlideRenderResult, f as HtmlDeckData, b as SlideLayoutData, L as LayoutBoxConfig } from '../types-8AVYoEUn.js';
|
|
3
|
+
export { M as MermaidBlock, k as SlideRenderAsyncResult, i as SlideRenderOptions, T as ThemeTokens } from '../types-8AVYoEUn.js';
|
|
4
|
+
export { l as ClickCssOptions, k as ClickPostprocessResult, C as ClickPreprocessResult, d as defineTheme, i as extractMaxClicks, j as generateClickCss, h as postprocessClicks, p as preprocessClicks, r as renderSlide, a as renderSlideAsync, e as resolveTheme } from '../click-css-CktIYP3H.js';
|
|
5
5
|
|
|
6
6
|
/** View mode for slide display */
|
|
7
7
|
type SlideViewMode = 'presentation' | 'deck';
|
|
@@ -80,6 +80,10 @@ interface DeckViewProps {
|
|
|
80
80
|
slideCount: number;
|
|
81
81
|
/** Container CSS class */
|
|
82
82
|
className?: string;
|
|
83
|
+
/** Presenter notes per slide (optional) */
|
|
84
|
+
notes?: string[][];
|
|
85
|
+
/** Whether to render speaker notes below each slide in deck mode */
|
|
86
|
+
showNotes?: boolean;
|
|
83
87
|
}
|
|
84
88
|
/** Props for ThemeSwitcher */
|
|
85
89
|
interface ThemeSwitcherProps {
|
|
@@ -171,6 +175,22 @@ interface SlideActions {
|
|
|
171
175
|
*/
|
|
172
176
|
declare function SlideViewer({ markdown, initialTheme, initialMode, className, showThemeSwitcher, showNavigation, enableKeyboard, enableClicks, fullscreen, showNotes, showDesignMode, themeOptions, onThemeChange, onSlideChange, onModeChange, onRenderComplete, onSaveMarkdown, }: SlideViewerProps): React$1.JSX.Element;
|
|
173
177
|
|
|
178
|
+
interface HtmlSlideViewerProps {
|
|
179
|
+
/** Pre-compiled HTML string. If provided, used directly */
|
|
180
|
+
htmlContent?: string;
|
|
181
|
+
/** Structured deck data. If provided without htmlContent, compiled automatically */
|
|
182
|
+
deckData?: HtmlDeckData;
|
|
183
|
+
/** Deck title displayed on header / download file name */
|
|
184
|
+
title?: string;
|
|
185
|
+
/** Extra CSS classes for wrapper */
|
|
186
|
+
className?: string;
|
|
187
|
+
/** Callback fired when active slide index changes */
|
|
188
|
+
onSlideChange?: (current: number, total: number) => void;
|
|
189
|
+
/** Show top control bar */
|
|
190
|
+
showTopBar?: boolean;
|
|
191
|
+
}
|
|
192
|
+
declare const HtmlSlideViewer: React$1.FC<HtmlSlideViewerProps>;
|
|
193
|
+
|
|
174
194
|
/**
|
|
175
195
|
* PresentationView — Renders a single slide at a time.
|
|
176
196
|
*
|
|
@@ -205,7 +225,7 @@ declare function PresentationView({ html, css, themeCss, layoutCss, currentIndex
|
|
|
205
225
|
* />
|
|
206
226
|
* ```
|
|
207
227
|
*/
|
|
208
|
-
declare function DeckView({ html, css, themeCss, layoutCss, slideCount, className, }: DeckViewProps): React$1.JSX.Element;
|
|
228
|
+
declare function DeckView({ html, css, themeCss, layoutCss, slideCount, className, notes, showNotes, }: DeckViewProps): React$1.JSX.Element;
|
|
209
229
|
|
|
210
230
|
/**
|
|
211
231
|
* ThemeSwitcher — Renders a row of theme toggle buttons.
|
|
@@ -321,4 +341,4 @@ interface UseSlideStateReturn {
|
|
|
321
341
|
*/
|
|
322
342
|
declare function useSlideState(options: UseSlideStateOptions): UseSlideStateReturn;
|
|
323
343
|
|
|
324
|
-
export { BuiltInTheme, DeckView, type DeckViewProps, NavigationBar, type NavigationBarProps, PresentationView, type PresentationViewProps, PresenterNotesDrawer, type PresenterNotesDrawerProps, type SlideActions, SlideDesignOverlay, type SlideDesignOverlayProps, SlideRenderResult, type SlideState, SlideTheme, type SlideViewMode, SlideViewer, type SlideViewerProps, type ThemeOption, ThemeSwitcher, type ThemeSwitcherProps, type UseSlideStateOptions, type UseSlideStateReturn, useSlideState };
|
|
344
|
+
export { BuiltInTheme, DeckView, type DeckViewProps, HtmlSlideViewer, type HtmlSlideViewerProps, NavigationBar, type NavigationBarProps, PresentationView, type PresentationViewProps, PresenterNotesDrawer, type PresenterNotesDrawerProps, type SlideActions, SlideDesignOverlay, type SlideDesignOverlayProps, SlideRenderResult, type SlideState, SlideTheme, type SlideViewMode, SlideViewer, type SlideViewerProps, type ThemeOption, ThemeSwitcher, type ThemeSwitcherProps, type UseSlideStateOptions, type UseSlideStateReturn, useSlideState };
|
package/dist/react/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { renderSlide, renderMermaidDiagrams } from '../chunk-NYLDRVHZ.js';
|
|
2
2
|
export { defineTheme, extractMaxClicks, generateClickCss, postprocessClicks, preprocessClicks, renderSlide, renderSlideAsync, resolveTheme } from '../chunk-NYLDRVHZ.js';
|
|
3
|
-
import { SLIDE_LAYOUT_PRESETS, updateSlideLayoutInMarkdown } from '../chunk-
|
|
4
|
-
import { useState, useRef, useMemo, useEffect, useCallback } from 'react';
|
|
3
|
+
import { SLIDE_LAYOUT_PRESETS, updateSlideLayoutInMarkdown, compileHtmlDeck } from '../chunk-3VGV5KYZ.js';
|
|
4
|
+
import React2, { useState, useRef, useMemo, useEffect, useCallback } from 'react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
function useSlideState(options) {
|
|
@@ -410,8 +410,45 @@ function DeckView({
|
|
|
410
410
|
themeCss,
|
|
411
411
|
layoutCss,
|
|
412
412
|
slideCount,
|
|
413
|
-
className
|
|
413
|
+
className,
|
|
414
|
+
notes,
|
|
415
|
+
showNotes = false
|
|
414
416
|
}) {
|
|
417
|
+
const hostRef = React2.useRef(null);
|
|
418
|
+
React2.useEffect(() => {
|
|
419
|
+
if (!hostRef.current) return;
|
|
420
|
+
hostRef.current.querySelectorAll(".deck-slide-note-item").forEach((el) => el.remove());
|
|
421
|
+
if (!showNotes || !notes || notes.length === 0) return;
|
|
422
|
+
const svgs = hostRef.current.querySelectorAll("svg[data-marpit-svg], svg");
|
|
423
|
+
svgs.forEach((svg, idx) => {
|
|
424
|
+
const slideNotes = notes[idx];
|
|
425
|
+
if (slideNotes && slideNotes.length > 0) {
|
|
426
|
+
const noteBox = document.createElement("div");
|
|
427
|
+
noteBox.className = "deck-slide-note-item";
|
|
428
|
+
noteBox.style.cssText = `
|
|
429
|
+
width: 100%;
|
|
430
|
+
max-width: 960px;
|
|
431
|
+
margin: -16px auto 32px auto;
|
|
432
|
+
background: rgba(24, 24, 32, 0.85);
|
|
433
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
434
|
+
border-left: 4px solid #0284c7;
|
|
435
|
+
border-radius: 8px;
|
|
436
|
+
padding: 14px 18px;
|
|
437
|
+
color: #e4e4e7;
|
|
438
|
+
font-size: 14px;
|
|
439
|
+
line-height: 1.6;
|
|
440
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
441
|
+
`;
|
|
442
|
+
noteBox.innerHTML = `
|
|
443
|
+
<div style="font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #38bdf8; margin-bottom: 4px; display: flex; align-items: center; gap: 6px;">
|
|
444
|
+
<span>\u{1F4DD}</span><span>Presenter Notes (Slide ${idx + 1})</span>
|
|
445
|
+
</div>
|
|
446
|
+
<div style="white-space: pre-wrap; font-size: 13px; line-height: 1.6; color: inherit;">${slideNotes.join("\n")}</div>
|
|
447
|
+
`;
|
|
448
|
+
svg.after(noteBox);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
}, [html, notes, showNotes]);
|
|
415
452
|
const deckCss = `
|
|
416
453
|
.slide-deck-host {
|
|
417
454
|
display: flex !important;
|
|
@@ -451,6 +488,46 @@ function DeckView({
|
|
|
451
488
|
transform: translateY(-2px);
|
|
452
489
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2) !important;
|
|
453
490
|
}
|
|
491
|
+
|
|
492
|
+
@media print {
|
|
493
|
+
@page {
|
|
494
|
+
size: landscape;
|
|
495
|
+
margin: 0;
|
|
496
|
+
}
|
|
497
|
+
body {
|
|
498
|
+
background: #ffffff !important;
|
|
499
|
+
color: #000000 !important;
|
|
500
|
+
}
|
|
501
|
+
.slide-deck-host {
|
|
502
|
+
padding: 0 !important;
|
|
503
|
+
}
|
|
504
|
+
.slide-deck-host #marp-container svg[data-marpit-svg],
|
|
505
|
+
.slide-deck-host #marp-container > svg,
|
|
506
|
+
.slide-deck-host > div > svg {
|
|
507
|
+
width: 100vw !important;
|
|
508
|
+
max-width: none !important;
|
|
509
|
+
height: 56.25vw !important;
|
|
510
|
+
page-break-inside: avoid !important;
|
|
511
|
+
break-inside: avoid !important;
|
|
512
|
+
page-break-after: always !important;
|
|
513
|
+
break-after: page !important;
|
|
514
|
+
margin: 0 auto !important;
|
|
515
|
+
box-shadow: none !important;
|
|
516
|
+
border-radius: 0 !important;
|
|
517
|
+
}
|
|
518
|
+
.deck-slide-note-item {
|
|
519
|
+
page-break-after: always !important;
|
|
520
|
+
break-after: page !important;
|
|
521
|
+
background: #f8fafc !important;
|
|
522
|
+
border: 1px solid #cbd5e1 !important;
|
|
523
|
+
border-left: 4px solid #2563eb !important;
|
|
524
|
+
color: #1e293b !important;
|
|
525
|
+
padding: 12px 18px !important;
|
|
526
|
+
margin: 12px auto 32px auto !important;
|
|
527
|
+
width: 90vw !important;
|
|
528
|
+
font-size: 11pt !important;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
454
531
|
`;
|
|
455
532
|
return /* @__PURE__ */ jsxs("div", { className, style: { width: "100%" }, children: [
|
|
456
533
|
/* @__PURE__ */ jsx("style", { children: css }),
|
|
@@ -460,6 +537,7 @@ function DeckView({
|
|
|
460
537
|
/* @__PURE__ */ jsx(
|
|
461
538
|
"div",
|
|
462
539
|
{
|
|
540
|
+
ref: hostRef,
|
|
463
541
|
className: "slide-deck-host",
|
|
464
542
|
dangerouslySetInnerHTML: { __html: html }
|
|
465
543
|
}
|
|
@@ -610,10 +688,12 @@ function SlideDesignOverlay({
|
|
|
610
688
|
setBoxes(layout?.boxes ?? []);
|
|
611
689
|
}, [layout, slideIndex]);
|
|
612
690
|
const selectedBox = boxes.find((b) => b.id === selectedId) ?? null;
|
|
691
|
+
const hasMovedRef = useRef(false);
|
|
613
692
|
const [dragging, setDragging] = useState(null);
|
|
614
693
|
const handleMouseDown = (e, box, type) => {
|
|
615
694
|
e.preventDefault();
|
|
616
695
|
e.stopPropagation();
|
|
696
|
+
hasMovedRef.current = false;
|
|
617
697
|
setSelectedId(box.id);
|
|
618
698
|
setDragging({
|
|
619
699
|
type,
|
|
@@ -630,6 +710,9 @@ function SlideDesignOverlay({
|
|
|
630
710
|
const scaleY = 720 / rect.height;
|
|
631
711
|
const dx = (e.clientX - dragging.startX) * scaleX;
|
|
632
712
|
const dy = (e.clientY - dragging.startY) * scaleY;
|
|
713
|
+
if (Math.abs(dx) > 1 || Math.abs(dy) > 1) {
|
|
714
|
+
hasMovedRef.current = true;
|
|
715
|
+
}
|
|
633
716
|
const [origX, origY, origW, origH] = dragging.startPos;
|
|
634
717
|
setBoxes((prev) => {
|
|
635
718
|
const updated = prev.map((b) => {
|
|
@@ -682,9 +765,10 @@ function SlideDesignOverlay({
|
|
|
682
765
|
});
|
|
683
766
|
}, [dragging, onLayoutChange]);
|
|
684
767
|
const handleMouseUp = useCallback(() => {
|
|
685
|
-
if (dragging && onSave) {
|
|
768
|
+
if (dragging && hasMovedRef.current && onSave) {
|
|
686
769
|
onSave({ boxes });
|
|
687
770
|
}
|
|
771
|
+
hasMovedRef.current = false;
|
|
688
772
|
setDragging(null);
|
|
689
773
|
}, [dragging, boxes, onSave]);
|
|
690
774
|
useEffect(() => {
|
|
@@ -913,8 +997,9 @@ function SlideDesignOverlay({
|
|
|
913
997
|
style: {
|
|
914
998
|
width: "100%",
|
|
915
999
|
height: "100%",
|
|
916
|
-
|
|
917
|
-
border: "
|
|
1000
|
+
backgroundColor: isLight ? "#ffffff" : isNavy ? "#0b132b" : "#181920",
|
|
1001
|
+
border: isLight ? "1px solid #0284c7" : "1px solid #38bdf8",
|
|
1002
|
+
borderRadius: "4px",
|
|
918
1003
|
outline: "none",
|
|
919
1004
|
resize: "none",
|
|
920
1005
|
fontSize: box.fontSize ?? (box.target === "h1" ? "2.2rem" : "1.1rem"),
|
|
@@ -923,8 +1008,9 @@ function SlideDesignOverlay({
|
|
|
923
1008
|
fontFamily: "Inter, sans-serif",
|
|
924
1009
|
fontWeight: box.target === "h1" ? 700 : 400,
|
|
925
1010
|
lineHeight: 1.25,
|
|
926
|
-
padding:
|
|
927
|
-
margin: 0
|
|
1011
|
+
padding: "4px 6px",
|
|
1012
|
+
margin: 0,
|
|
1013
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.25)"
|
|
928
1014
|
}
|
|
929
1015
|
}
|
|
930
1016
|
) : /* @__PURE__ */ jsx(
|
|
@@ -938,20 +1024,9 @@ function SlideDesignOverlay({
|
|
|
938
1024
|
style: {
|
|
939
1025
|
width: "100%",
|
|
940
1026
|
height: "100%",
|
|
941
|
-
|
|
942
|
-
color: box.color ?? (isLight ? "#0f172a" : "#f8fafc"),
|
|
943
|
-
textAlign: box.textAlign ?? "left",
|
|
944
|
-
fontFamily: "Inter, sans-serif",
|
|
945
|
-
fontWeight: box.target === "h1" ? 700 : 400,
|
|
946
|
-
lineHeight: 1.25,
|
|
947
|
-
wordBreak: "break-word",
|
|
948
|
-
userSelect: "none",
|
|
949
|
-
cursor: "pointer",
|
|
950
|
-
display: "flex",
|
|
951
|
-
alignItems: "center"
|
|
1027
|
+
cursor: "pointer"
|
|
952
1028
|
},
|
|
953
|
-
title: "Click \u0111\xFAp \u0111\u1EC3 s\u1EEDa ch\u1EEF"
|
|
954
|
-
children: box.content ? /* @__PURE__ */ jsx("span", { children: box.content }) : /* @__PURE__ */ jsx("span", { style: { opacity: 0.45, fontStyle: "italic", fontSize: "12px" }, children: box.target === "h1" ? "Ti\xEAu \u0111\u1EC1 (Click \u0111\xFAp \u0111\u1EC3 s\u1EEDa)..." : "N\u1ED9i dung (Click \u0111\xFAp \u0111\u1EC3 s\u1EEDa)..." })
|
|
1029
|
+
title: "Click \u0111\xFAp \u0111\u1EC3 s\u1EEDa ch\u1EEF"
|
|
955
1030
|
}
|
|
956
1031
|
)
|
|
957
1032
|
}
|
|
@@ -1222,6 +1297,13 @@ function SlideViewer({
|
|
|
1222
1297
|
setIsFullscreen((prev) => !prev);
|
|
1223
1298
|
}
|
|
1224
1299
|
break;
|
|
1300
|
+
case "p":
|
|
1301
|
+
case "P":
|
|
1302
|
+
if (showNotes) {
|
|
1303
|
+
e.preventDefault();
|
|
1304
|
+
setShowNotesDrawer((prev) => !prev);
|
|
1305
|
+
}
|
|
1306
|
+
break;
|
|
1225
1307
|
}
|
|
1226
1308
|
};
|
|
1227
1309
|
window.addEventListener("keydown", handleKey);
|
|
@@ -1443,45 +1525,62 @@ function SlideViewer({
|
|
|
1443
1525
|
transition: "width 0.2s ease"
|
|
1444
1526
|
} }) })
|
|
1445
1527
|
] }),
|
|
1446
|
-
/* @__PURE__ */ jsx(
|
|
1447
|
-
|
|
1448
|
-
PresentationView,
|
|
1449
|
-
{
|
|
1450
|
-
html: result.html,
|
|
1451
|
-
css: result.css,
|
|
1452
|
-
themeCss: result.themeCss,
|
|
1453
|
-
layoutCss: result.layoutCss,
|
|
1454
|
-
currentIndex,
|
|
1455
|
-
slideCount
|
|
1456
|
-
}
|
|
1457
|
-
),
|
|
1458
|
-
isDesignMode && /* @__PURE__ */ jsx(
|
|
1459
|
-
SlideDesignOverlay,
|
|
1460
|
-
{
|
|
1461
|
-
slideIndex: currentIndex,
|
|
1462
|
-
layout: liveLayout ?? result.layouts?.[currentIndex] ?? null,
|
|
1463
|
-
onLayoutChange: setLiveLayout,
|
|
1464
|
-
onSave: (layout) => {
|
|
1465
|
-
setLiveLayout(layout);
|
|
1466
|
-
if (onSaveMarkdown) {
|
|
1467
|
-
const updated = updateSlideLayoutInMarkdown(markdown, currentIndex, layout);
|
|
1468
|
-
onSaveMarkdown(updated);
|
|
1469
|
-
}
|
|
1470
|
-
},
|
|
1471
|
-
onClose: () => setIsDesignMode(false),
|
|
1472
|
-
isActive: isDesignMode
|
|
1473
|
-
}
|
|
1474
|
-
)
|
|
1475
|
-
] }) : /* @__PURE__ */ jsx(
|
|
1476
|
-
DeckView,
|
|
1528
|
+
/* @__PURE__ */ jsx(
|
|
1529
|
+
"div",
|
|
1477
1530
|
{
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1531
|
+
style: { position: "relative", width: "100%" },
|
|
1532
|
+
onClick: (e) => {
|
|
1533
|
+
if (mode !== "presentation" || isDesignMode) return;
|
|
1534
|
+
if (e.target.closest("button, a, input, select, textarea, [contenteditable], .slide-design-overlay")) return;
|
|
1535
|
+
if (enableClicks && currentClick < maxClicks) {
|
|
1536
|
+
nextClick();
|
|
1537
|
+
} else {
|
|
1538
|
+
nextSlide();
|
|
1539
|
+
}
|
|
1540
|
+
},
|
|
1541
|
+
children: mode === "presentation" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1542
|
+
/* @__PURE__ */ jsx(
|
|
1543
|
+
PresentationView,
|
|
1544
|
+
{
|
|
1545
|
+
html: result.html,
|
|
1546
|
+
css: result.css,
|
|
1547
|
+
themeCss: result.themeCss,
|
|
1548
|
+
layoutCss: result.layoutCss,
|
|
1549
|
+
currentIndex,
|
|
1550
|
+
slideCount
|
|
1551
|
+
}
|
|
1552
|
+
),
|
|
1553
|
+
isDesignMode && /* @__PURE__ */ jsx(
|
|
1554
|
+
SlideDesignOverlay,
|
|
1555
|
+
{
|
|
1556
|
+
slideIndex: currentIndex,
|
|
1557
|
+
layout: liveLayout ?? result.layouts?.[currentIndex] ?? null,
|
|
1558
|
+
onLayoutChange: setLiveLayout,
|
|
1559
|
+
onSave: (layout) => {
|
|
1560
|
+
setLiveLayout(layout);
|
|
1561
|
+
if (onSaveMarkdown) {
|
|
1562
|
+
const updated = updateSlideLayoutInMarkdown(markdown, currentIndex, layout);
|
|
1563
|
+
onSaveMarkdown(updated);
|
|
1564
|
+
}
|
|
1565
|
+
},
|
|
1566
|
+
onClose: () => setIsDesignMode(false),
|
|
1567
|
+
isActive: isDesignMode
|
|
1568
|
+
}
|
|
1569
|
+
)
|
|
1570
|
+
] }) : /* @__PURE__ */ jsx(
|
|
1571
|
+
DeckView,
|
|
1572
|
+
{
|
|
1573
|
+
html: result.html,
|
|
1574
|
+
css: result.css,
|
|
1575
|
+
themeCss: result.themeCss,
|
|
1576
|
+
layoutCss: result.layoutCss,
|
|
1577
|
+
slideCount,
|
|
1578
|
+
notes: result.notes,
|
|
1579
|
+
showNotes: showNotesDrawer
|
|
1580
|
+
}
|
|
1581
|
+
)
|
|
1483
1582
|
}
|
|
1484
|
-
)
|
|
1583
|
+
),
|
|
1485
1584
|
showNotes && /* @__PURE__ */ jsx(
|
|
1486
1585
|
PresenterNotesDrawer,
|
|
1487
1586
|
{
|
|
@@ -1497,7 +1596,161 @@ function SlideViewer({
|
|
|
1497
1596
|
}
|
|
1498
1597
|
);
|
|
1499
1598
|
}
|
|
1599
|
+
var HtmlSlideViewer = ({
|
|
1600
|
+
htmlContent: initialHtml,
|
|
1601
|
+
deckData,
|
|
1602
|
+
title: propTitle,
|
|
1603
|
+
className = "",
|
|
1604
|
+
onSlideChange,
|
|
1605
|
+
showTopBar = true
|
|
1606
|
+
}) => {
|
|
1607
|
+
const iframeRef = useRef(null);
|
|
1608
|
+
const containerRef = useRef(null);
|
|
1609
|
+
const [currentSlide, setCurrentSlide] = useState(0);
|
|
1610
|
+
const [totalSlides, setTotalSlides] = useState(deckData?.slides?.length || 1);
|
|
1611
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
1612
|
+
const fullHtml = useMemo(() => {
|
|
1613
|
+
if (initialHtml) return initialHtml;
|
|
1614
|
+
if (deckData) {
|
|
1615
|
+
return compileHtmlDeck(deckData).html;
|
|
1616
|
+
}
|
|
1617
|
+
return "";
|
|
1618
|
+
}, [initialHtml, deckData]);
|
|
1619
|
+
const deckTitle = propTitle || deckData?.title || "Presentation";
|
|
1620
|
+
useEffect(() => {
|
|
1621
|
+
const handleMessage = (e) => {
|
|
1622
|
+
if (!e.data || typeof e.data !== "object") return;
|
|
1623
|
+
if (e.data.type === "PRESENTATION_SLIDE_CHANGE") {
|
|
1624
|
+
const cur = Number(e.data.currentIndex) || 0;
|
|
1625
|
+
const tot = Number(e.data.totalSlides) || 1;
|
|
1626
|
+
setCurrentSlide(cur);
|
|
1627
|
+
setTotalSlides(tot);
|
|
1628
|
+
if (onSlideChange) {
|
|
1629
|
+
onSlideChange(cur, tot);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
window.addEventListener("message", handleMessage);
|
|
1634
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
1635
|
+
}, [onSlideChange]);
|
|
1636
|
+
useEffect(() => {
|
|
1637
|
+
const onFsChange = () => {
|
|
1638
|
+
setIsFullscreen(Boolean(document.fullscreenElement));
|
|
1639
|
+
};
|
|
1640
|
+
document.addEventListener("fullscreenchange", onFsChange);
|
|
1641
|
+
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
1642
|
+
}, []);
|
|
1643
|
+
const sendIframeMessage = useCallback((msg) => {
|
|
1644
|
+
if (iframeRef.current?.contentWindow) {
|
|
1645
|
+
iframeRef.current.contentWindow.postMessage(msg, "*");
|
|
1646
|
+
}
|
|
1647
|
+
}, []);
|
|
1648
|
+
const handleNext = () => sendIframeMessage({ type: "NEXT_SLIDE" });
|
|
1649
|
+
const handlePrev = () => sendIframeMessage({ type: "PREV_SLIDE" });
|
|
1650
|
+
const handleToggleFullscreen = () => {
|
|
1651
|
+
if (!containerRef.current) return;
|
|
1652
|
+
if (!document.fullscreenElement) {
|
|
1653
|
+
containerRef.current.requestFullscreen().catch(() => {
|
|
1654
|
+
});
|
|
1655
|
+
} else {
|
|
1656
|
+
document.exitFullscreen().catch(() => {
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
const handleDownloadHtml = () => {
|
|
1661
|
+
if (!fullHtml) return;
|
|
1662
|
+
const blob = new Blob([fullHtml], { type: "text/html;charset=utf-8" });
|
|
1663
|
+
const url = URL.createObjectURL(blob);
|
|
1664
|
+
const a = document.createElement("a");
|
|
1665
|
+
a.href = url;
|
|
1666
|
+
a.download = `${deckTitle.toLowerCase().replace(/[^a-z0-9]/g, "-") || "slide-deck"}.html`;
|
|
1667
|
+
document.body.appendChild(a);
|
|
1668
|
+
a.click();
|
|
1669
|
+
document.body.removeChild(a);
|
|
1670
|
+
URL.revokeObjectURL(url);
|
|
1671
|
+
};
|
|
1672
|
+
return /* @__PURE__ */ jsxs(
|
|
1673
|
+
"div",
|
|
1674
|
+
{
|
|
1675
|
+
ref: containerRef,
|
|
1676
|
+
className: `relative flex flex-col w-full h-full bg-neutral-950 text-neutral-100 rounded-xl overflow-hidden shadow-2xl ${className}`,
|
|
1677
|
+
style: { minHeight: "480px" },
|
|
1678
|
+
children: [
|
|
1679
|
+
showTopBar && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 bg-neutral-900/90 backdrop-blur border-b border-neutral-800 text-xs select-none z-20", children: [
|
|
1680
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium truncate max-w-md", children: [
|
|
1681
|
+
/* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
|
|
1682
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-neutral-200", children: deckTitle })
|
|
1683
|
+
] }),
|
|
1684
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1685
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 bg-neutral-800/80 px-2 py-1 rounded border border-neutral-700 font-mono text-[11px]", children: [
|
|
1686
|
+
/* @__PURE__ */ jsx(
|
|
1687
|
+
"button",
|
|
1688
|
+
{
|
|
1689
|
+
onClick: handlePrev,
|
|
1690
|
+
disabled: currentSlide <= 0,
|
|
1691
|
+
className: "hover:text-white disabled:opacity-40 p-0.5",
|
|
1692
|
+
title: "Previous Slide",
|
|
1693
|
+
children: "\u25C0"
|
|
1694
|
+
}
|
|
1695
|
+
),
|
|
1696
|
+
/* @__PURE__ */ jsxs("span", { className: "px-1 font-semibold text-neutral-200", children: [
|
|
1697
|
+
String(currentSlide + 1).padStart(2, "0"),
|
|
1698
|
+
" / ",
|
|
1699
|
+
String(totalSlides).padStart(2, "0")
|
|
1700
|
+
] }),
|
|
1701
|
+
/* @__PURE__ */ jsx(
|
|
1702
|
+
"button",
|
|
1703
|
+
{
|
|
1704
|
+
onClick: handleNext,
|
|
1705
|
+
disabled: currentSlide >= totalSlides - 1,
|
|
1706
|
+
className: "hover:text-white disabled:opacity-40 p-0.5",
|
|
1707
|
+
title: "Next Slide",
|
|
1708
|
+
children: "\u25B6"
|
|
1709
|
+
}
|
|
1710
|
+
)
|
|
1711
|
+
] }),
|
|
1712
|
+
/* @__PURE__ */ jsxs(
|
|
1713
|
+
"button",
|
|
1714
|
+
{
|
|
1715
|
+
onClick: handleDownloadHtml,
|
|
1716
|
+
className: "flex items-center gap-1 px-2.5 py-1 rounded bg-neutral-800 hover:bg-neutral-700 text-neutral-300 hover:text-white border border-neutral-700 transition-colors",
|
|
1717
|
+
title: "Download standalone offline HTML file",
|
|
1718
|
+
children: [
|
|
1719
|
+
/* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1720
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1721
|
+
/* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
|
|
1722
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
1723
|
+
] }),
|
|
1724
|
+
/* @__PURE__ */ jsx("span", { children: "Export HTML" })
|
|
1725
|
+
]
|
|
1726
|
+
}
|
|
1727
|
+
),
|
|
1728
|
+
/* @__PURE__ */ jsx(
|
|
1729
|
+
"button",
|
|
1730
|
+
{
|
|
1731
|
+
onClick: handleToggleFullscreen,
|
|
1732
|
+
className: "p-1 rounded bg-neutral-800 hover:bg-neutral-700 text-neutral-300 hover:text-white border border-neutral-700 transition-colors",
|
|
1733
|
+
title: "Toggle Fullscreen (F)",
|
|
1734
|
+
children: /* @__PURE__ */ jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: isFullscreen ? /* @__PURE__ */ jsx("path", { d: "M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3" }) : /* @__PURE__ */ jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" }) })
|
|
1735
|
+
}
|
|
1736
|
+
)
|
|
1737
|
+
] })
|
|
1738
|
+
] }),
|
|
1739
|
+
/* @__PURE__ */ jsx("div", { className: "relative flex-1 w-full h-full min-h-0 bg-black", children: fullHtml ? /* @__PURE__ */ jsx(
|
|
1740
|
+
"iframe",
|
|
1741
|
+
{
|
|
1742
|
+
ref: iframeRef,
|
|
1743
|
+
srcDoc: fullHtml,
|
|
1744
|
+
title: deckTitle,
|
|
1745
|
+
sandbox: "allow-scripts allow-same-origin allow-popups allow-forms",
|
|
1746
|
+
className: "w-full h-full border-0 block"
|
|
1747
|
+
}
|
|
1748
|
+
) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center text-neutral-500 text-sm", children: "No slide deck content loaded." }) })
|
|
1749
|
+
]
|
|
1750
|
+
}
|
|
1751
|
+
);
|
|
1752
|
+
};
|
|
1500
1753
|
|
|
1501
|
-
export { DeckView, NavigationBar, PresentationView, PresenterNotesDrawer, SlideDesignOverlay, SlideViewer, ThemeSwitcher, useSlideState };
|
|
1754
|
+
export { DeckView, HtmlSlideViewer, NavigationBar, PresentationView, PresenterNotesDrawer, SlideDesignOverlay, SlideViewer, ThemeSwitcher, useSlideState };
|
|
1502
1755
|
//# sourceMappingURL=index.js.map
|
|
1503
1756
|
//# sourceMappingURL=index.js.map
|