@thanh01.pmt/presentation-kit 0.2.10 → 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 +351 -90
- 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 +297 -41
- 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-3Q4RMZVQ.cjs +0 -867
- package/dist/chunk-3Q4RMZVQ.cjs.map +0 -1
- package/dist/chunk-V6X7D44H.js +0 -854
- package/dist/chunk-V6X7D44H.js.map +0 -1
package/dist/react/index.cjs
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkTGI6YSZP_cjs = require('../chunk-TGI6YSZP.cjs');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chunk53GLUCYC_cjs = require('../chunk-53GLUCYC.cjs');
|
|
5
|
+
var React2 = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
11
|
+
|
|
8
12
|
function useSlideState(options) {
|
|
9
13
|
const {
|
|
10
14
|
markdown,
|
|
@@ -13,12 +17,12 @@ function useSlideState(options) {
|
|
|
13
17
|
containerId,
|
|
14
18
|
enableClicks = false
|
|
15
19
|
} = options;
|
|
16
|
-
const [currentIndex, setCurrentIndex] =
|
|
17
|
-
const [mode, setMode] =
|
|
18
|
-
const [theme, setTheme] =
|
|
19
|
-
const [currentClick, setCurrentClick] =
|
|
20
|
-
const renderCountRef =
|
|
21
|
-
const result =
|
|
20
|
+
const [currentIndex, setCurrentIndex] = React2.useState(0);
|
|
21
|
+
const [mode, setMode] = React2.useState(initialMode);
|
|
22
|
+
const [theme, setTheme] = React2.useState(initialTheme);
|
|
23
|
+
const [currentClick, setCurrentClick] = React2.useState(0);
|
|
24
|
+
const renderCountRef = React2.useRef(0);
|
|
25
|
+
const result = React2.useMemo(() => {
|
|
22
26
|
if (!markdown || !markdown.trim()) return null;
|
|
23
27
|
renderCountRef.current++;
|
|
24
28
|
return chunkTGI6YSZP_cjs.renderSlide(markdown, {
|
|
@@ -31,49 +35,49 @@ function useSlideState(options) {
|
|
|
31
35
|
const slideCount = result?.slideCount ?? 1;
|
|
32
36
|
const maxClicks = result?.maxClicks ?? 0;
|
|
33
37
|
const isReady = result !== null;
|
|
34
|
-
|
|
38
|
+
React2.useEffect(() => {
|
|
35
39
|
if (result && currentIndex >= result.slideCount) {
|
|
36
40
|
setCurrentIndex(Math.max(0, result.slideCount - 1));
|
|
37
41
|
}
|
|
38
42
|
}, [result?.slideCount, currentIndex]);
|
|
39
|
-
|
|
43
|
+
React2.useEffect(() => {
|
|
40
44
|
setCurrentClick(0);
|
|
41
45
|
}, [currentIndex]);
|
|
42
|
-
|
|
46
|
+
React2.useCallback(
|
|
43
47
|
(index) => {
|
|
44
48
|
setCurrentIndex(Math.max(0, Math.min(index, slideCount - 1)));
|
|
45
49
|
},
|
|
46
50
|
[slideCount]
|
|
47
51
|
);
|
|
48
|
-
|
|
52
|
+
React2.useCallback(() => {
|
|
49
53
|
setCurrentIndex((prev) => Math.min(prev + 1, slideCount - 1));
|
|
50
54
|
}, [slideCount]);
|
|
51
|
-
|
|
55
|
+
React2.useCallback(() => {
|
|
52
56
|
setCurrentIndex((prev) => Math.max(prev - 1, 0));
|
|
53
57
|
}, []);
|
|
54
|
-
const nextClick =
|
|
58
|
+
const nextClick = React2.useCallback(() => {
|
|
55
59
|
setCurrentClick((prev) => Math.min(prev + 1, maxClicks));
|
|
56
60
|
}, [maxClicks]);
|
|
57
|
-
const prevClick =
|
|
61
|
+
const prevClick = React2.useCallback(() => {
|
|
58
62
|
setCurrentClick((prev) => Math.max(prev - 1, 0));
|
|
59
63
|
}, []);
|
|
60
|
-
const resetClicks =
|
|
64
|
+
const resetClicks = React2.useCallback(() => {
|
|
61
65
|
setCurrentClick(0);
|
|
62
66
|
}, []);
|
|
63
|
-
const setClickIndex =
|
|
67
|
+
const setClickIndex = React2.useCallback(
|
|
64
68
|
(index) => {
|
|
65
69
|
setCurrentClick(Math.max(0, Math.min(index, maxClicks)));
|
|
66
70
|
},
|
|
67
71
|
[maxClicks]
|
|
68
72
|
);
|
|
69
|
-
const goToSlideWithReset =
|
|
73
|
+
const goToSlideWithReset = React2.useCallback(
|
|
70
74
|
(index) => {
|
|
71
75
|
setCurrentClick(0);
|
|
72
76
|
setCurrentIndex(Math.max(0, Math.min(index, slideCount - 1)));
|
|
73
77
|
},
|
|
74
78
|
[slideCount]
|
|
75
79
|
);
|
|
76
|
-
const nextWithClick =
|
|
80
|
+
const nextWithClick = React2.useCallback(() => {
|
|
77
81
|
if (currentClick < maxClicks) {
|
|
78
82
|
setCurrentClick((prev) => prev + 1);
|
|
79
83
|
} else {
|
|
@@ -81,14 +85,14 @@ function useSlideState(options) {
|
|
|
81
85
|
setCurrentIndex((prev) => Math.min(prev + 1, slideCount - 1));
|
|
82
86
|
}
|
|
83
87
|
}, [currentClick, maxClicks, slideCount]);
|
|
84
|
-
const prevWithClick =
|
|
88
|
+
const prevWithClick = React2.useCallback(() => {
|
|
85
89
|
if (currentClick > 0) {
|
|
86
90
|
setCurrentClick((prev) => prev - 1);
|
|
87
91
|
} else {
|
|
88
92
|
setCurrentIndex((prev) => Math.max(prev - 1, 0));
|
|
89
93
|
}
|
|
90
94
|
}, [currentClick]);
|
|
91
|
-
const rerender =
|
|
95
|
+
const rerender = React2.useCallback(() => {
|
|
92
96
|
setCurrentIndex((prev) => prev);
|
|
93
97
|
}, []);
|
|
94
98
|
return {
|
|
@@ -228,8 +232,8 @@ function NavigationBar({
|
|
|
228
232
|
showCopy = true,
|
|
229
233
|
markdown
|
|
230
234
|
}) {
|
|
231
|
-
const [copied, setCopied] =
|
|
232
|
-
const handleCopy =
|
|
235
|
+
const [copied, setCopied] = React2.useState(false);
|
|
236
|
+
const handleCopy = React2.useCallback(async () => {
|
|
233
237
|
if (!markdown) return;
|
|
234
238
|
try {
|
|
235
239
|
await navigator.clipboard.writeText(markdown);
|
|
@@ -411,8 +415,45 @@ function DeckView({
|
|
|
411
415
|
themeCss,
|
|
412
416
|
layoutCss,
|
|
413
417
|
slideCount,
|
|
414
|
-
className
|
|
418
|
+
className,
|
|
419
|
+
notes,
|
|
420
|
+
showNotes = false
|
|
415
421
|
}) {
|
|
422
|
+
const hostRef = React2__default.default.useRef(null);
|
|
423
|
+
React2__default.default.useEffect(() => {
|
|
424
|
+
if (!hostRef.current) return;
|
|
425
|
+
hostRef.current.querySelectorAll(".deck-slide-note-item").forEach((el) => el.remove());
|
|
426
|
+
if (!showNotes || !notes || notes.length === 0) return;
|
|
427
|
+
const svgs = hostRef.current.querySelectorAll("svg[data-marpit-svg], svg");
|
|
428
|
+
svgs.forEach((svg, idx) => {
|
|
429
|
+
const slideNotes = notes[idx];
|
|
430
|
+
if (slideNotes && slideNotes.length > 0) {
|
|
431
|
+
const noteBox = document.createElement("div");
|
|
432
|
+
noteBox.className = "deck-slide-note-item";
|
|
433
|
+
noteBox.style.cssText = `
|
|
434
|
+
width: 100%;
|
|
435
|
+
max-width: 960px;
|
|
436
|
+
margin: -16px auto 32px auto;
|
|
437
|
+
background: rgba(24, 24, 32, 0.85);
|
|
438
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
439
|
+
border-left: 4px solid #0284c7;
|
|
440
|
+
border-radius: 8px;
|
|
441
|
+
padding: 14px 18px;
|
|
442
|
+
color: #e4e4e7;
|
|
443
|
+
font-size: 14px;
|
|
444
|
+
line-height: 1.6;
|
|
445
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
446
|
+
`;
|
|
447
|
+
noteBox.innerHTML = `
|
|
448
|
+
<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;">
|
|
449
|
+
<span>\u{1F4DD}</span><span>Presenter Notes (Slide ${idx + 1})</span>
|
|
450
|
+
</div>
|
|
451
|
+
<div style="white-space: pre-wrap; font-size: 13px; line-height: 1.6; color: inherit;">${slideNotes.join("\n")}</div>
|
|
452
|
+
`;
|
|
453
|
+
svg.after(noteBox);
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}, [html, notes, showNotes]);
|
|
416
457
|
const deckCss = `
|
|
417
458
|
.slide-deck-host {
|
|
418
459
|
display: flex !important;
|
|
@@ -452,6 +493,46 @@ function DeckView({
|
|
|
452
493
|
transform: translateY(-2px);
|
|
453
494
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2) !important;
|
|
454
495
|
}
|
|
496
|
+
|
|
497
|
+
@media print {
|
|
498
|
+
@page {
|
|
499
|
+
size: landscape;
|
|
500
|
+
margin: 0;
|
|
501
|
+
}
|
|
502
|
+
body {
|
|
503
|
+
background: #ffffff !important;
|
|
504
|
+
color: #000000 !important;
|
|
505
|
+
}
|
|
506
|
+
.slide-deck-host {
|
|
507
|
+
padding: 0 !important;
|
|
508
|
+
}
|
|
509
|
+
.slide-deck-host #marp-container svg[data-marpit-svg],
|
|
510
|
+
.slide-deck-host #marp-container > svg,
|
|
511
|
+
.slide-deck-host > div > svg {
|
|
512
|
+
width: 100vw !important;
|
|
513
|
+
max-width: none !important;
|
|
514
|
+
height: 56.25vw !important;
|
|
515
|
+
page-break-inside: avoid !important;
|
|
516
|
+
break-inside: avoid !important;
|
|
517
|
+
page-break-after: always !important;
|
|
518
|
+
break-after: page !important;
|
|
519
|
+
margin: 0 auto !important;
|
|
520
|
+
box-shadow: none !important;
|
|
521
|
+
border-radius: 0 !important;
|
|
522
|
+
}
|
|
523
|
+
.deck-slide-note-item {
|
|
524
|
+
page-break-after: always !important;
|
|
525
|
+
break-after: page !important;
|
|
526
|
+
background: #f8fafc !important;
|
|
527
|
+
border: 1px solid #cbd5e1 !important;
|
|
528
|
+
border-left: 4px solid #2563eb !important;
|
|
529
|
+
color: #1e293b !important;
|
|
530
|
+
padding: 12px 18px !important;
|
|
531
|
+
margin: 12px auto 32px auto !important;
|
|
532
|
+
width: 90vw !important;
|
|
533
|
+
font-size: 11pt !important;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
455
536
|
`;
|
|
456
537
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { width: "100%" }, children: [
|
|
457
538
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: css }),
|
|
@@ -461,6 +542,7 @@ function DeckView({
|
|
|
461
542
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
462
543
|
"div",
|
|
463
544
|
{
|
|
545
|
+
ref: hostRef,
|
|
464
546
|
className: "slide-deck-host",
|
|
465
547
|
dangerouslySetInnerHTML: { __html: html }
|
|
466
548
|
}
|
|
@@ -594,25 +676,25 @@ function SlideDesignOverlay({
|
|
|
594
676
|
onSelectBoxId
|
|
595
677
|
}) {
|
|
596
678
|
if (!isActive) return null;
|
|
597
|
-
const [boxes, setBoxes] =
|
|
598
|
-
const [selectedId, setSelectedIdState] =
|
|
599
|
-
const [editingId, setEditingId] =
|
|
600
|
-
const containerRef =
|
|
601
|
-
const setSelectedId =
|
|
679
|
+
const [boxes, setBoxes] = React2.useState(layout?.boxes ?? []);
|
|
680
|
+
const [selectedId, setSelectedIdState] = React2.useState(selectedBoxId ?? null);
|
|
681
|
+
const [editingId, setEditingId] = React2.useState(null);
|
|
682
|
+
const containerRef = React2.useRef(null);
|
|
683
|
+
const setSelectedId = React2.useCallback((id) => {
|
|
602
684
|
setSelectedIdState(id);
|
|
603
685
|
if (onSelectBoxId) onSelectBoxId(id);
|
|
604
686
|
}, [onSelectBoxId]);
|
|
605
|
-
|
|
687
|
+
React2.useEffect(() => {
|
|
606
688
|
if (selectedBoxId !== void 0) {
|
|
607
689
|
setSelectedIdState(selectedBoxId);
|
|
608
690
|
}
|
|
609
691
|
}, [selectedBoxId]);
|
|
610
|
-
|
|
692
|
+
React2.useEffect(() => {
|
|
611
693
|
setBoxes(layout?.boxes ?? []);
|
|
612
694
|
}, [layout, slideIndex]);
|
|
613
695
|
const selectedBox = boxes.find((b) => b.id === selectedId) ?? null;
|
|
614
|
-
const hasMovedRef =
|
|
615
|
-
const [dragging, setDragging] =
|
|
696
|
+
const hasMovedRef = React2.useRef(false);
|
|
697
|
+
const [dragging, setDragging] = React2.useState(null);
|
|
616
698
|
const handleMouseDown = (e, box, type) => {
|
|
617
699
|
e.preventDefault();
|
|
618
700
|
e.stopPropagation();
|
|
@@ -626,7 +708,7 @@ function SlideDesignOverlay({
|
|
|
626
708
|
startPos: [...box.pos]
|
|
627
709
|
});
|
|
628
710
|
};
|
|
629
|
-
const handleMouseMove =
|
|
711
|
+
const handleMouseMove = React2.useCallback((e) => {
|
|
630
712
|
if (!dragging || !containerRef.current) return;
|
|
631
713
|
const rect = containerRef.current.getBoundingClientRect();
|
|
632
714
|
const scaleX = 1280 / rect.width;
|
|
@@ -687,14 +769,14 @@ function SlideDesignOverlay({
|
|
|
687
769
|
return updated;
|
|
688
770
|
});
|
|
689
771
|
}, [dragging, onLayoutChange]);
|
|
690
|
-
const handleMouseUp =
|
|
772
|
+
const handleMouseUp = React2.useCallback(() => {
|
|
691
773
|
if (dragging && hasMovedRef.current && onSave) {
|
|
692
774
|
onSave({ boxes });
|
|
693
775
|
}
|
|
694
776
|
hasMovedRef.current = false;
|
|
695
777
|
setDragging(null);
|
|
696
778
|
}, [dragging, boxes, onSave]);
|
|
697
|
-
|
|
779
|
+
React2.useEffect(() => {
|
|
698
780
|
if (dragging) {
|
|
699
781
|
window.addEventListener("mousemove", handleMouseMove);
|
|
700
782
|
window.addEventListener("mouseup", handleMouseUp);
|
|
@@ -704,7 +786,7 @@ function SlideDesignOverlay({
|
|
|
704
786
|
};
|
|
705
787
|
}
|
|
706
788
|
}, [dragging, handleMouseMove, handleMouseUp]);
|
|
707
|
-
const removeSelectedBox =
|
|
789
|
+
const removeSelectedBox = React2.useCallback(() => {
|
|
708
790
|
if (!selectedId) return;
|
|
709
791
|
const boxToRemove = boxes.find((b) => b.id === selectedId);
|
|
710
792
|
setBoxes((prev) => {
|
|
@@ -718,7 +800,7 @@ function SlideDesignOverlay({
|
|
|
718
800
|
onDeleteBox(boxToRemove);
|
|
719
801
|
}
|
|
720
802
|
}, [selectedId, boxes, onLayoutChange, onSave, onDeleteBox, setSelectedId]);
|
|
721
|
-
|
|
803
|
+
React2.useEffect(() => {
|
|
722
804
|
const handleKeyDown = (e) => {
|
|
723
805
|
if (editingId) return;
|
|
724
806
|
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
|
|
@@ -829,7 +911,7 @@ function SlideDesignOverlay({
|
|
|
829
911
|
"select",
|
|
830
912
|
{
|
|
831
913
|
onChange: (e) => {
|
|
832
|
-
const preset =
|
|
914
|
+
const preset = chunk53GLUCYC_cjs.SLIDE_LAYOUT_PRESETS.find((p) => p.id === e.target.value);
|
|
833
915
|
if (preset) {
|
|
834
916
|
const clonedBoxes = JSON.parse(JSON.stringify(preset.layout.boxes));
|
|
835
917
|
setBoxes(clonedBoxes);
|
|
@@ -849,7 +931,7 @@ function SlideDesignOverlay({
|
|
|
849
931
|
title: "\xC1p d\u1EE5ng m\u1EABu b\u1ED1 c\u1EE5c c\xF3 s\u1EB5n",
|
|
850
932
|
children: [
|
|
851
933
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, style: { backgroundColor: isLight ? "#ffffff" : "#1e1f29", color: subtextColor }, children: "M\u1EABu b\u1ED1 c\u1EE5c (Presets)..." }),
|
|
852
|
-
|
|
934
|
+
chunk53GLUCYC_cjs.SLIDE_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.id, style: { backgroundColor: isLight ? "#ffffff" : "#1e1f29", color: isLight ? "#0f172a" : "#f8fafc" }, children: p.name }, p.id))
|
|
853
935
|
]
|
|
854
936
|
}
|
|
855
937
|
),
|
|
@@ -1136,10 +1218,10 @@ function SlideViewer({
|
|
|
1136
1218
|
onRenderComplete,
|
|
1137
1219
|
onSaveMarkdown
|
|
1138
1220
|
}) {
|
|
1139
|
-
const [isFullscreen, setIsFullscreen] =
|
|
1140
|
-
const [showNotesDrawer, setShowNotesDrawer] =
|
|
1141
|
-
const [isDesignMode, setIsDesignMode] =
|
|
1142
|
-
const [liveLayout, setLiveLayout] =
|
|
1221
|
+
const [isFullscreen, setIsFullscreen] = React2.useState(false);
|
|
1222
|
+
const [showNotesDrawer, setShowNotesDrawer] = React2.useState(false);
|
|
1223
|
+
const [isDesignMode, setIsDesignMode] = React2.useState(false);
|
|
1224
|
+
const [liveLayout, setLiveLayout] = React2.useState(null);
|
|
1143
1225
|
const state = useSlideState({
|
|
1144
1226
|
markdown,
|
|
1145
1227
|
initialTheme,
|
|
@@ -1163,19 +1245,19 @@ function SlideViewer({
|
|
|
1163
1245
|
prevClick,
|
|
1164
1246
|
resetClicks
|
|
1165
1247
|
} = state;
|
|
1166
|
-
|
|
1248
|
+
React2.useEffect(() => {
|
|
1167
1249
|
onThemeChange?.(theme);
|
|
1168
1250
|
}, [theme, onThemeChange]);
|
|
1169
|
-
|
|
1251
|
+
React2.useEffect(() => {
|
|
1170
1252
|
onSlideChange?.(currentIndex);
|
|
1171
1253
|
}, [currentIndex, onSlideChange]);
|
|
1172
|
-
|
|
1254
|
+
React2.useEffect(() => {
|
|
1173
1255
|
onModeChange?.(mode);
|
|
1174
1256
|
}, [mode, onModeChange]);
|
|
1175
|
-
|
|
1257
|
+
React2.useEffect(() => {
|
|
1176
1258
|
if (result) onRenderComplete?.(result);
|
|
1177
1259
|
}, [result, onRenderComplete]);
|
|
1178
|
-
|
|
1260
|
+
React2.useEffect(() => {
|
|
1179
1261
|
if (!enableKeyboard) return;
|
|
1180
1262
|
const handleKey = (e) => {
|
|
1181
1263
|
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
|
|
@@ -1220,12 +1302,19 @@ function SlideViewer({
|
|
|
1220
1302
|
setIsFullscreen((prev) => !prev);
|
|
1221
1303
|
}
|
|
1222
1304
|
break;
|
|
1305
|
+
case "p":
|
|
1306
|
+
case "P":
|
|
1307
|
+
if (showNotes) {
|
|
1308
|
+
e.preventDefault();
|
|
1309
|
+
setShowNotesDrawer((prev) => !prev);
|
|
1310
|
+
}
|
|
1311
|
+
break;
|
|
1223
1312
|
}
|
|
1224
1313
|
};
|
|
1225
1314
|
window.addEventListener("keydown", handleKey);
|
|
1226
1315
|
return () => window.removeEventListener("keydown", handleKey);
|
|
1227
1316
|
}, [enableKeyboard, mode, fullscreen, isFullscreen, enableClicks, currentClick, maxClicks, nextClick, prevClick, nextSlide, prevSlide, goToSlide, slideCount]);
|
|
1228
|
-
|
|
1317
|
+
React2.useEffect(() => {
|
|
1229
1318
|
if (!enableClicks || !result || mode !== "presentation") return;
|
|
1230
1319
|
const timer = setTimeout(() => {
|
|
1231
1320
|
const container = document.querySelector(".slide-presentation-host > div");
|
|
@@ -1238,7 +1327,7 @@ function SlideViewer({
|
|
|
1238
1327
|
}, 50);
|
|
1239
1328
|
return () => clearTimeout(timer);
|
|
1240
1329
|
}, [enableClicks, currentClick, result, currentIndex, mode]);
|
|
1241
|
-
|
|
1330
|
+
React2.useEffect(() => {
|
|
1242
1331
|
if (!result || result.mermaidBlocks.length === 0) return;
|
|
1243
1332
|
const timer = setTimeout(() => {
|
|
1244
1333
|
const containers = document.querySelectorAll(".slide-presentation-host > div, .slide-deck-host > div");
|
|
@@ -1252,13 +1341,13 @@ function SlideViewer({
|
|
|
1252
1341
|
}, 100);
|
|
1253
1342
|
return () => clearTimeout(timer);
|
|
1254
1343
|
}, [result, theme, currentIndex, mode]);
|
|
1255
|
-
const handleThemeChange =
|
|
1344
|
+
const handleThemeChange = React2.useCallback(
|
|
1256
1345
|
(themeId) => {
|
|
1257
1346
|
setTheme(themeId);
|
|
1258
1347
|
},
|
|
1259
1348
|
[setTheme]
|
|
1260
1349
|
);
|
|
1261
|
-
const toggleFullscreen =
|
|
1350
|
+
const toggleFullscreen = React2.useCallback(() => {
|
|
1262
1351
|
setIsFullscreen((prev) => !prev);
|
|
1263
1352
|
}, []);
|
|
1264
1353
|
if (!result) {
|
|
@@ -1441,45 +1530,62 @@ function SlideViewer({
|
|
|
1441
1530
|
transition: "width 0.2s ease"
|
|
1442
1531
|
} }) })
|
|
1443
1532
|
] }),
|
|
1444
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1445
|
-
|
|
1446
|
-
PresentationView,
|
|
1447
|
-
{
|
|
1448
|
-
html: result.html,
|
|
1449
|
-
css: result.css,
|
|
1450
|
-
themeCss: result.themeCss,
|
|
1451
|
-
layoutCss: result.layoutCss,
|
|
1452
|
-
currentIndex,
|
|
1453
|
-
slideCount
|
|
1454
|
-
}
|
|
1455
|
-
),
|
|
1456
|
-
isDesignMode && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1457
|
-
SlideDesignOverlay,
|
|
1458
|
-
{
|
|
1459
|
-
slideIndex: currentIndex,
|
|
1460
|
-
layout: liveLayout ?? result.layouts?.[currentIndex] ?? null,
|
|
1461
|
-
onLayoutChange: setLiveLayout,
|
|
1462
|
-
onSave: (layout) => {
|
|
1463
|
-
setLiveLayout(layout);
|
|
1464
|
-
if (onSaveMarkdown) {
|
|
1465
|
-
const updated = chunk3Q4RMZVQ_cjs.updateSlideLayoutInMarkdown(markdown, currentIndex, layout);
|
|
1466
|
-
onSaveMarkdown(updated);
|
|
1467
|
-
}
|
|
1468
|
-
},
|
|
1469
|
-
onClose: () => setIsDesignMode(false),
|
|
1470
|
-
isActive: isDesignMode
|
|
1471
|
-
}
|
|
1472
|
-
)
|
|
1473
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1474
|
-
DeckView,
|
|
1533
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1534
|
+
"div",
|
|
1475
1535
|
{
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1536
|
+
style: { position: "relative", width: "100%" },
|
|
1537
|
+
onClick: (e) => {
|
|
1538
|
+
if (mode !== "presentation" || isDesignMode) return;
|
|
1539
|
+
if (e.target.closest("button, a, input, select, textarea, [contenteditable], .slide-design-overlay")) return;
|
|
1540
|
+
if (enableClicks && currentClick < maxClicks) {
|
|
1541
|
+
nextClick();
|
|
1542
|
+
} else {
|
|
1543
|
+
nextSlide();
|
|
1544
|
+
}
|
|
1545
|
+
},
|
|
1546
|
+
children: mode === "presentation" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1547
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1548
|
+
PresentationView,
|
|
1549
|
+
{
|
|
1550
|
+
html: result.html,
|
|
1551
|
+
css: result.css,
|
|
1552
|
+
themeCss: result.themeCss,
|
|
1553
|
+
layoutCss: result.layoutCss,
|
|
1554
|
+
currentIndex,
|
|
1555
|
+
slideCount
|
|
1556
|
+
}
|
|
1557
|
+
),
|
|
1558
|
+
isDesignMode && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1559
|
+
SlideDesignOverlay,
|
|
1560
|
+
{
|
|
1561
|
+
slideIndex: currentIndex,
|
|
1562
|
+
layout: liveLayout ?? result.layouts?.[currentIndex] ?? null,
|
|
1563
|
+
onLayoutChange: setLiveLayout,
|
|
1564
|
+
onSave: (layout) => {
|
|
1565
|
+
setLiveLayout(layout);
|
|
1566
|
+
if (onSaveMarkdown) {
|
|
1567
|
+
const updated = chunk53GLUCYC_cjs.updateSlideLayoutInMarkdown(markdown, currentIndex, layout);
|
|
1568
|
+
onSaveMarkdown(updated);
|
|
1569
|
+
}
|
|
1570
|
+
},
|
|
1571
|
+
onClose: () => setIsDesignMode(false),
|
|
1572
|
+
isActive: isDesignMode
|
|
1573
|
+
}
|
|
1574
|
+
)
|
|
1575
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1576
|
+
DeckView,
|
|
1577
|
+
{
|
|
1578
|
+
html: result.html,
|
|
1579
|
+
css: result.css,
|
|
1580
|
+
themeCss: result.themeCss,
|
|
1581
|
+
layoutCss: result.layoutCss,
|
|
1582
|
+
slideCount,
|
|
1583
|
+
notes: result.notes,
|
|
1584
|
+
showNotes: showNotesDrawer
|
|
1585
|
+
}
|
|
1586
|
+
)
|
|
1481
1587
|
}
|
|
1482
|
-
)
|
|
1588
|
+
),
|
|
1483
1589
|
showNotes && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1484
1590
|
PresenterNotesDrawer,
|
|
1485
1591
|
{
|
|
@@ -1495,6 +1601,160 @@ function SlideViewer({
|
|
|
1495
1601
|
}
|
|
1496
1602
|
);
|
|
1497
1603
|
}
|
|
1604
|
+
var HtmlSlideViewer = ({
|
|
1605
|
+
htmlContent: initialHtml,
|
|
1606
|
+
deckData,
|
|
1607
|
+
title: propTitle,
|
|
1608
|
+
className = "",
|
|
1609
|
+
onSlideChange,
|
|
1610
|
+
showTopBar = true
|
|
1611
|
+
}) => {
|
|
1612
|
+
const iframeRef = React2.useRef(null);
|
|
1613
|
+
const containerRef = React2.useRef(null);
|
|
1614
|
+
const [currentSlide, setCurrentSlide] = React2.useState(0);
|
|
1615
|
+
const [totalSlides, setTotalSlides] = React2.useState(deckData?.slides?.length || 1);
|
|
1616
|
+
const [isFullscreen, setIsFullscreen] = React2.useState(false);
|
|
1617
|
+
const fullHtml = React2.useMemo(() => {
|
|
1618
|
+
if (initialHtml) return initialHtml;
|
|
1619
|
+
if (deckData) {
|
|
1620
|
+
return chunk53GLUCYC_cjs.compileHtmlDeck(deckData).html;
|
|
1621
|
+
}
|
|
1622
|
+
return "";
|
|
1623
|
+
}, [initialHtml, deckData]);
|
|
1624
|
+
const deckTitle = propTitle || deckData?.title || "Presentation";
|
|
1625
|
+
React2.useEffect(() => {
|
|
1626
|
+
const handleMessage = (e) => {
|
|
1627
|
+
if (!e.data || typeof e.data !== "object") return;
|
|
1628
|
+
if (e.data.type === "PRESENTATION_SLIDE_CHANGE") {
|
|
1629
|
+
const cur = Number(e.data.currentIndex) || 0;
|
|
1630
|
+
const tot = Number(e.data.totalSlides) || 1;
|
|
1631
|
+
setCurrentSlide(cur);
|
|
1632
|
+
setTotalSlides(tot);
|
|
1633
|
+
if (onSlideChange) {
|
|
1634
|
+
onSlideChange(cur, tot);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
window.addEventListener("message", handleMessage);
|
|
1639
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
1640
|
+
}, [onSlideChange]);
|
|
1641
|
+
React2.useEffect(() => {
|
|
1642
|
+
const onFsChange = () => {
|
|
1643
|
+
setIsFullscreen(Boolean(document.fullscreenElement));
|
|
1644
|
+
};
|
|
1645
|
+
document.addEventListener("fullscreenchange", onFsChange);
|
|
1646
|
+
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
1647
|
+
}, []);
|
|
1648
|
+
const sendIframeMessage = React2.useCallback((msg) => {
|
|
1649
|
+
if (iframeRef.current?.contentWindow) {
|
|
1650
|
+
iframeRef.current.contentWindow.postMessage(msg, "*");
|
|
1651
|
+
}
|
|
1652
|
+
}, []);
|
|
1653
|
+
const handleNext = () => sendIframeMessage({ type: "NEXT_SLIDE" });
|
|
1654
|
+
const handlePrev = () => sendIframeMessage({ type: "PREV_SLIDE" });
|
|
1655
|
+
const handleToggleFullscreen = () => {
|
|
1656
|
+
if (!containerRef.current) return;
|
|
1657
|
+
if (!document.fullscreenElement) {
|
|
1658
|
+
containerRef.current.requestFullscreen().catch(() => {
|
|
1659
|
+
});
|
|
1660
|
+
} else {
|
|
1661
|
+
document.exitFullscreen().catch(() => {
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
const handleDownloadHtml = () => {
|
|
1666
|
+
if (!fullHtml) return;
|
|
1667
|
+
const blob = new Blob([fullHtml], { type: "text/html;charset=utf-8" });
|
|
1668
|
+
const url = URL.createObjectURL(blob);
|
|
1669
|
+
const a = document.createElement("a");
|
|
1670
|
+
a.href = url;
|
|
1671
|
+
a.download = `${deckTitle.toLowerCase().replace(/[^a-z0-9]/g, "-") || "slide-deck"}.html`;
|
|
1672
|
+
document.body.appendChild(a);
|
|
1673
|
+
a.click();
|
|
1674
|
+
document.body.removeChild(a);
|
|
1675
|
+
URL.revokeObjectURL(url);
|
|
1676
|
+
};
|
|
1677
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1678
|
+
"div",
|
|
1679
|
+
{
|
|
1680
|
+
ref: containerRef,
|
|
1681
|
+
className: `relative flex flex-col w-full h-full bg-neutral-950 text-neutral-100 rounded-xl overflow-hidden shadow-2xl ${className}`,
|
|
1682
|
+
style: { minHeight: "480px" },
|
|
1683
|
+
children: [
|
|
1684
|
+
showTopBar && /* @__PURE__ */ jsxRuntime.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: [
|
|
1685
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 font-medium truncate max-w-md", children: [
|
|
1686
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
|
|
1687
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-neutral-200", children: deckTitle })
|
|
1688
|
+
] }),
|
|
1689
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1690
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
1691
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1692
|
+
"button",
|
|
1693
|
+
{
|
|
1694
|
+
onClick: handlePrev,
|
|
1695
|
+
disabled: currentSlide <= 0,
|
|
1696
|
+
className: "hover:text-white disabled:opacity-40 p-0.5",
|
|
1697
|
+
title: "Previous Slide",
|
|
1698
|
+
children: "\u25C0"
|
|
1699
|
+
}
|
|
1700
|
+
),
|
|
1701
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 font-semibold text-neutral-200", children: [
|
|
1702
|
+
String(currentSlide + 1).padStart(2, "0"),
|
|
1703
|
+
" / ",
|
|
1704
|
+
String(totalSlides).padStart(2, "0")
|
|
1705
|
+
] }),
|
|
1706
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1707
|
+
"button",
|
|
1708
|
+
{
|
|
1709
|
+
onClick: handleNext,
|
|
1710
|
+
disabled: currentSlide >= totalSlides - 1,
|
|
1711
|
+
className: "hover:text-white disabled:opacity-40 p-0.5",
|
|
1712
|
+
title: "Next Slide",
|
|
1713
|
+
children: "\u25B6"
|
|
1714
|
+
}
|
|
1715
|
+
)
|
|
1716
|
+
] }),
|
|
1717
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1718
|
+
"button",
|
|
1719
|
+
{
|
|
1720
|
+
onClick: handleDownloadHtml,
|
|
1721
|
+
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",
|
|
1722
|
+
title: "Download standalone offline HTML file",
|
|
1723
|
+
children: [
|
|
1724
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1725
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1726
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "7 10 12 15 17 10" }),
|
|
1727
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
1728
|
+
] }),
|
|
1729
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Export HTML" })
|
|
1730
|
+
]
|
|
1731
|
+
}
|
|
1732
|
+
),
|
|
1733
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1734
|
+
"button",
|
|
1735
|
+
{
|
|
1736
|
+
onClick: handleToggleFullscreen,
|
|
1737
|
+
className: "p-1 rounded bg-neutral-800 hover:bg-neutral-700 text-neutral-300 hover:text-white border border-neutral-700 transition-colors",
|
|
1738
|
+
title: "Toggle Fullscreen (F)",
|
|
1739
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: isFullscreen ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.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" }) })
|
|
1740
|
+
}
|
|
1741
|
+
)
|
|
1742
|
+
] })
|
|
1743
|
+
] }),
|
|
1744
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 w-full h-full min-h-0 bg-black", children: fullHtml ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1745
|
+
"iframe",
|
|
1746
|
+
{
|
|
1747
|
+
ref: iframeRef,
|
|
1748
|
+
srcDoc: fullHtml,
|
|
1749
|
+
title: deckTitle,
|
|
1750
|
+
sandbox: "allow-scripts allow-same-origin allow-popups allow-forms",
|
|
1751
|
+
className: "w-full h-full border-0 block"
|
|
1752
|
+
}
|
|
1753
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-neutral-500 text-sm", children: "No slide deck content loaded." }) })
|
|
1754
|
+
]
|
|
1755
|
+
}
|
|
1756
|
+
);
|
|
1757
|
+
};
|
|
1498
1758
|
|
|
1499
1759
|
Object.defineProperty(exports, "defineTheme", {
|
|
1500
1760
|
enumerable: true,
|
|
@@ -1529,6 +1789,7 @@ Object.defineProperty(exports, "resolveTheme", {
|
|
|
1529
1789
|
get: function () { return chunkTGI6YSZP_cjs.resolveTheme; }
|
|
1530
1790
|
});
|
|
1531
1791
|
exports.DeckView = DeckView;
|
|
1792
|
+
exports.HtmlSlideViewer = HtmlSlideViewer;
|
|
1532
1793
|
exports.NavigationBar = NavigationBar;
|
|
1533
1794
|
exports.PresentationView = PresentationView;
|
|
1534
1795
|
exports.PresenterNotesDrawer = PresenterNotesDrawer;
|