@thanh01.pmt/presentation-kit 0.1.0

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.
@@ -0,0 +1,788 @@
1
+ 'use strict';
2
+
3
+ var chunkN4Q6GUAQ_cjs = require('../chunk-N4Q6GUAQ.cjs');
4
+ var react = require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ function useSlideState(options) {
8
+ const {
9
+ markdown,
10
+ initialTheme = "dark",
11
+ initialMode = "presentation",
12
+ containerId,
13
+ enableClicks = false
14
+ } = options;
15
+ const [currentIndex, setCurrentIndex] = react.useState(0);
16
+ const [mode, setMode] = react.useState(initialMode);
17
+ const [theme, setTheme] = react.useState(initialTheme);
18
+ const [currentClick, setCurrentClick] = react.useState(0);
19
+ const renderCountRef = react.useRef(0);
20
+ const result = react.useMemo(() => {
21
+ if (!markdown || !markdown.trim()) return null;
22
+ renderCountRef.current++;
23
+ return chunkN4Q6GUAQ_cjs.renderSlide(markdown, {
24
+ theme,
25
+ enableMermaid: true,
26
+ enableClicks,
27
+ containerId: containerId ?? `slide-container-${renderCountRef.current}`
28
+ });
29
+ }, [markdown, theme, containerId, enableClicks]);
30
+ const slideCount = result?.slideCount ?? 1;
31
+ const maxClicks = result?.maxClicks ?? 0;
32
+ const isReady = result !== null;
33
+ react.useEffect(() => {
34
+ if (result && currentIndex >= result.slideCount) {
35
+ setCurrentIndex(Math.max(0, result.slideCount - 1));
36
+ }
37
+ }, [result?.slideCount, currentIndex]);
38
+ react.useEffect(() => {
39
+ setCurrentClick(0);
40
+ }, [currentIndex]);
41
+ react.useCallback(
42
+ (index) => {
43
+ setCurrentIndex(Math.max(0, Math.min(index, slideCount - 1)));
44
+ },
45
+ [slideCount]
46
+ );
47
+ react.useCallback(() => {
48
+ setCurrentIndex((prev) => Math.min(prev + 1, slideCount - 1));
49
+ }, [slideCount]);
50
+ react.useCallback(() => {
51
+ setCurrentIndex((prev) => Math.max(prev - 1, 0));
52
+ }, []);
53
+ const nextClick = react.useCallback(() => {
54
+ setCurrentClick((prev) => Math.min(prev + 1, maxClicks));
55
+ }, [maxClicks]);
56
+ const prevClick = react.useCallback(() => {
57
+ setCurrentClick((prev) => Math.max(prev - 1, 0));
58
+ }, []);
59
+ const resetClicks = react.useCallback(() => {
60
+ setCurrentClick(0);
61
+ }, []);
62
+ const setClickIndex = react.useCallback(
63
+ (index) => {
64
+ setCurrentClick(Math.max(0, Math.min(index, maxClicks)));
65
+ },
66
+ [maxClicks]
67
+ );
68
+ const goToSlideWithReset = react.useCallback(
69
+ (index) => {
70
+ setCurrentClick(0);
71
+ setCurrentIndex(Math.max(0, Math.min(index, slideCount - 1)));
72
+ },
73
+ [slideCount]
74
+ );
75
+ const nextWithClick = react.useCallback(() => {
76
+ if (currentClick < maxClicks) {
77
+ setCurrentClick((prev) => prev + 1);
78
+ } else {
79
+ setCurrentClick(0);
80
+ setCurrentIndex((prev) => Math.min(prev + 1, slideCount - 1));
81
+ }
82
+ }, [currentClick, maxClicks, slideCount]);
83
+ const prevWithClick = react.useCallback(() => {
84
+ if (currentClick > 0) {
85
+ setCurrentClick((prev) => prev - 1);
86
+ } else {
87
+ setCurrentIndex((prev) => Math.max(prev - 1, 0));
88
+ }
89
+ }, [currentClick]);
90
+ const rerender = react.useCallback(() => {
91
+ setCurrentIndex((prev) => prev);
92
+ }, []);
93
+ return {
94
+ // Render
95
+ result,
96
+ isReady,
97
+ // Slide
98
+ currentIndex,
99
+ slideCount,
100
+ mode,
101
+ theme,
102
+ // Click
103
+ currentClick,
104
+ maxClicks,
105
+ // Slide actions
106
+ goToSlide: goToSlideWithReset,
107
+ nextSlide: nextWithClick,
108
+ prevSlide: prevWithClick,
109
+ setMode,
110
+ setTheme,
111
+ rerender,
112
+ // Click actions
113
+ nextClick,
114
+ prevClick,
115
+ resetClicks,
116
+ setClickIndex
117
+ };
118
+ }
119
+ var DEFAULT_THEMES = [
120
+ { id: "dark", label: "Dark" },
121
+ { id: "navy", label: "Navy" },
122
+ { id: "light", label: "Light" }
123
+ ];
124
+ function ThemeSwitcher({
125
+ currentTheme,
126
+ onThemeChange,
127
+ themes = DEFAULT_THEMES,
128
+ className
129
+ }) {
130
+ const currentId = typeof currentTheme === "object" && currentTheme !== null && "name" in currentTheme ? currentTheme.name : String(currentTheme);
131
+ return /* @__PURE__ */ jsxRuntime.jsx(
132
+ "div",
133
+ {
134
+ className,
135
+ style: {
136
+ display: "inline-flex",
137
+ alignItems: "center",
138
+ gap: "2px",
139
+ padding: "2px",
140
+ borderRadius: "8px",
141
+ border: "1px solid rgba(128, 128, 128, 0.2)",
142
+ backgroundColor: "rgba(128, 128, 128, 0.05)"
143
+ },
144
+ children: themes.map((theme) => {
145
+ const isActive = currentId === theme.id;
146
+ return /* @__PURE__ */ jsxRuntime.jsxs(
147
+ "button",
148
+ {
149
+ type: "button",
150
+ onClick: () => onThemeChange(theme.id),
151
+ title: `Theme: ${theme.label}`,
152
+ style: {
153
+ height: "28px",
154
+ padding: "0 10px",
155
+ borderRadius: "6px",
156
+ fontSize: "12px",
157
+ fontFamily: "inherit",
158
+ fontWeight: isActive ? 600 : 400,
159
+ display: "flex",
160
+ alignItems: "center",
161
+ gap: "5px",
162
+ transition: "all 0.15s ease",
163
+ cursor: "pointer",
164
+ border: "none",
165
+ lineHeight: 1,
166
+ whiteSpace: "nowrap",
167
+ backgroundColor: isActive ? "rgba(128, 128, 128, 0.15)" : "transparent",
168
+ color: isActive ? "currentColor" : "rgba(128, 128, 128, 0.7)"
169
+ },
170
+ children: [
171
+ theme.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "13px" }, children: theme.icon }),
172
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: theme.label })
173
+ ]
174
+ },
175
+ theme.id
176
+ );
177
+ })
178
+ }
179
+ );
180
+ }
181
+ var btnBase = {
182
+ height: "28px",
183
+ borderRadius: "6px",
184
+ fontSize: "12px",
185
+ fontFamily: "inherit",
186
+ display: "flex",
187
+ alignItems: "center",
188
+ justifyContent: "center",
189
+ gap: "5px",
190
+ transition: "all 0.15s ease",
191
+ cursor: "pointer",
192
+ border: "none",
193
+ lineHeight: 1,
194
+ whiteSpace: "nowrap"
195
+ };
196
+ var btnSecondary = {
197
+ ...btnBase,
198
+ padding: "0 10px",
199
+ backgroundColor: "transparent",
200
+ color: "rgba(128, 128, 128, 0.7)"
201
+ };
202
+ var btnActive = {
203
+ ...btnBase,
204
+ padding: "0 10px",
205
+ fontWeight: 600,
206
+ backgroundColor: "rgba(128, 128, 128, 0.15)",
207
+ color: "currentColor"
208
+ };
209
+ var iconBtn = {
210
+ ...btnBase,
211
+ width: "28px",
212
+ padding: 0,
213
+ backgroundColor: "transparent",
214
+ color: "rgba(128, 128, 128, 0.7)"
215
+ };
216
+ var disabledStyle = {
217
+ opacity: 0.3,
218
+ cursor: "not-allowed"
219
+ };
220
+ function NavigationBar({
221
+ currentIndex,
222
+ slideCount,
223
+ onNavigate,
224
+ mode,
225
+ onModeChange,
226
+ className,
227
+ showCopy = true,
228
+ markdown
229
+ }) {
230
+ const [copied, setCopied] = react.useState(false);
231
+ const handleCopy = react.useCallback(async () => {
232
+ if (!markdown) return;
233
+ try {
234
+ await navigator.clipboard.writeText(markdown);
235
+ setCopied(true);
236
+ setTimeout(() => setCopied(false), 2e3);
237
+ } catch {
238
+ }
239
+ }, [markdown]);
240
+ const isFirst = currentIndex === 0;
241
+ const isLast = currentIndex >= slideCount - 1;
242
+ return /* @__PURE__ */ jsxRuntime.jsxs(
243
+ "div",
244
+ {
245
+ className,
246
+ style: {
247
+ display: "flex",
248
+ alignItems: "center",
249
+ justifyContent: "space-between",
250
+ gap: "8px",
251
+ padding: "8px 0",
252
+ borderBottom: "1px solid rgba(128, 128, 128, 0.12)",
253
+ flexWrap: "wrap"
254
+ },
255
+ children: [
256
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
257
+ /* @__PURE__ */ jsxRuntime.jsx(
258
+ "button",
259
+ {
260
+ type: "button",
261
+ onClick: () => onModeChange("presentation"),
262
+ style: mode === "presentation" ? btnActive : btnSecondary,
263
+ title: "Presentation mode (1 slide)",
264
+ children: "\u25B6 Presentation"
265
+ }
266
+ ),
267
+ /* @__PURE__ */ jsxRuntime.jsx(
268
+ "button",
269
+ {
270
+ type: "button",
271
+ onClick: () => onModeChange("deck"),
272
+ style: mode === "deck" ? btnActive : btnSecondary,
273
+ title: "Deck mode (all slides)",
274
+ children: "\u2630 Deck"
275
+ }
276
+ )
277
+ ] }),
278
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
279
+ mode === "presentation" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
280
+ /* @__PURE__ */ jsxRuntime.jsx(
281
+ "button",
282
+ {
283
+ type: "button",
284
+ onClick: () => onNavigate(currentIndex - 1),
285
+ disabled: isFirst,
286
+ style: { ...iconBtn, ...isFirst ? disabledStyle : {} },
287
+ title: "Previous slide (\u2190)",
288
+ children: "\u2039"
289
+ }
290
+ ),
291
+ /* @__PURE__ */ jsxRuntime.jsx(
292
+ "select",
293
+ {
294
+ value: currentIndex,
295
+ onChange: (e) => onNavigate(Number(e.target.value)),
296
+ style: {
297
+ height: "28px",
298
+ padding: "0 6px",
299
+ borderRadius: "6px",
300
+ fontSize: "12px",
301
+ fontFamily: "inherit",
302
+ border: "none",
303
+ backgroundColor: "transparent",
304
+ color: "currentColor",
305
+ cursor: "pointer",
306
+ outline: "none"
307
+ },
308
+ title: "Jump to slide",
309
+ children: Array.from({ length: slideCount }, (_, i) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: i, children: [
310
+ "Slide ",
311
+ i + 1,
312
+ " / ",
313
+ slideCount
314
+ ] }, i))
315
+ }
316
+ ),
317
+ /* @__PURE__ */ jsxRuntime.jsx(
318
+ "button",
319
+ {
320
+ type: "button",
321
+ onClick: () => onNavigate(currentIndex + 1),
322
+ disabled: isLast,
323
+ style: { ...iconBtn, ...isLast ? disabledStyle : {} },
324
+ title: "Next slide (\u2192)",
325
+ children: "\u203A"
326
+ }
327
+ )
328
+ ] }),
329
+ mode === "deck" && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: "12px", color: "rgba(128, 128, 128, 0.6)", padding: "0 8px" }, children: [
330
+ slideCount,
331
+ " slides"
332
+ ] }),
333
+ showCopy && markdown && /* @__PURE__ */ jsxRuntime.jsx(
334
+ "button",
335
+ {
336
+ type: "button",
337
+ onClick: handleCopy,
338
+ style: btnSecondary,
339
+ title: "Copy markdown source",
340
+ children: copied ? "\u2713 Copied" : "\u29C9 Copy"
341
+ }
342
+ )
343
+ ] })
344
+ ]
345
+ }
346
+ );
347
+ }
348
+ function PresentationView({
349
+ html,
350
+ css,
351
+ themeCss,
352
+ currentIndex,
353
+ slideCount,
354
+ className
355
+ }) {
356
+ const presentationCss = `
357
+ .slide-presentation-host {
358
+ display: flex;
359
+ align-items: center;
360
+ justify-content: center;
361
+ width: 100%;
362
+ }
363
+ .slide-presentation-host > div {
364
+ position: relative;
365
+ display: flex;
366
+ align-items: center;
367
+ justify-content: center;
368
+ width: 100%;
369
+ }
370
+ .slide-presentation-host > div > svg {
371
+ position: absolute;
372
+ visibility: hidden;
373
+ opacity: 0;
374
+ pointer-events: none;
375
+ width: min(100%, calc((100vh - 120px) * (16 / 9)));
376
+ max-width: 1400px;
377
+ height: auto;
378
+ max-height: calc(100vh - 120px);
379
+ aspect-ratio: 16 / 9;
380
+ margin: 0 auto;
381
+ }
382
+ .slide-presentation-host > div > svg:nth-child(${currentIndex + 1}) {
383
+ position: relative;
384
+ visibility: visible;
385
+ opacity: 1;
386
+ pointer-events: auto;
387
+ display: block;
388
+ }
389
+ `;
390
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { width: "100%" }, children: [
391
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: css }),
392
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: themeCss }),
393
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: presentationCss }),
394
+ /* @__PURE__ */ jsxRuntime.jsx(
395
+ "div",
396
+ {
397
+ className: "slide-presentation-host",
398
+ style: { padding: "16px 0" },
399
+ dangerouslySetInnerHTML: { __html: html }
400
+ }
401
+ )
402
+ ] });
403
+ }
404
+ function DeckView({
405
+ html,
406
+ css,
407
+ themeCss,
408
+ slideCount,
409
+ className
410
+ }) {
411
+ const deckCss = `
412
+ .slide-deck-host {
413
+ display: flex;
414
+ flex-direction: column;
415
+ align-items: center;
416
+ gap: 24px;
417
+ padding: 16px 0;
418
+ }
419
+ .slide-deck-host > div {
420
+ display: flex;
421
+ flex-direction: column;
422
+ align-items: center;
423
+ gap: 24px;
424
+ }
425
+ .slide-deck-host > div > svg {
426
+ display: block !important;
427
+ width: 100% !important;
428
+ max-width: 960px;
429
+ height: auto !important;
430
+ aspect-ratio: 16 / 9;
431
+ border-radius: 12px;
432
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
433
+ }
434
+ .slide-deck-host > div > svg:hover {
435
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
436
+ }
437
+ `;
438
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { width: "100%" }, children: [
439
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: css }),
440
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: themeCss }),
441
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: deckCss }),
442
+ /* @__PURE__ */ jsxRuntime.jsx(
443
+ "div",
444
+ {
445
+ className: "slide-deck-host",
446
+ dangerouslySetInnerHTML: { __html: html }
447
+ }
448
+ )
449
+ ] });
450
+ }
451
+ var DEFAULT_THEME_OPTIONS = [
452
+ { id: "dark", label: "Dark" },
453
+ { id: "navy", label: "Navy" },
454
+ { id: "light", label: "Light" }
455
+ ];
456
+ function SlideViewer({
457
+ markdown,
458
+ initialTheme = "dark",
459
+ initialMode = "presentation",
460
+ className,
461
+ showThemeSwitcher = true,
462
+ showNavigation = true,
463
+ enableKeyboard = true,
464
+ enableClicks = false,
465
+ fullscreen = false,
466
+ themeOptions = DEFAULT_THEME_OPTIONS,
467
+ onThemeChange,
468
+ onSlideChange,
469
+ onModeChange,
470
+ onRenderComplete
471
+ }) {
472
+ const [isFullscreen, setIsFullscreen] = react.useState(false);
473
+ const state = useSlideState({
474
+ markdown,
475
+ initialTheme,
476
+ initialMode,
477
+ enableClicks
478
+ });
479
+ const {
480
+ currentIndex,
481
+ mode,
482
+ theme,
483
+ result,
484
+ slideCount,
485
+ currentClick,
486
+ maxClicks,
487
+ goToSlide,
488
+ nextSlide,
489
+ prevSlide,
490
+ setMode,
491
+ setTheme,
492
+ nextClick,
493
+ prevClick,
494
+ resetClicks
495
+ } = state;
496
+ react.useEffect(() => {
497
+ onThemeChange?.(theme);
498
+ }, [theme, onThemeChange]);
499
+ react.useEffect(() => {
500
+ onSlideChange?.(currentIndex);
501
+ }, [currentIndex, onSlideChange]);
502
+ react.useEffect(() => {
503
+ onModeChange?.(mode);
504
+ }, [mode, onModeChange]);
505
+ react.useEffect(() => {
506
+ if (result) onRenderComplete?.(result);
507
+ }, [result, onRenderComplete]);
508
+ react.useEffect(() => {
509
+ if (!enableKeyboard) return;
510
+ const handleKey = (e) => {
511
+ if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
512
+ if (e.key === "Escape" && fullscreen && isFullscreen) {
513
+ e.preventDefault();
514
+ setIsFullscreen(false);
515
+ return;
516
+ }
517
+ if (mode !== "presentation") return;
518
+ switch (e.key) {
519
+ case "ArrowRight":
520
+ case "PageDown":
521
+ case " ":
522
+ e.preventDefault();
523
+ if (enableClicks && currentClick < maxClicks) {
524
+ nextClick();
525
+ } else {
526
+ nextSlide();
527
+ }
528
+ break;
529
+ case "ArrowLeft":
530
+ case "PageUp":
531
+ e.preventDefault();
532
+ if (enableClicks && currentClick > 0) {
533
+ prevClick();
534
+ } else {
535
+ prevSlide();
536
+ }
537
+ break;
538
+ case "Home":
539
+ e.preventDefault();
540
+ goToSlide(0);
541
+ break;
542
+ case "End":
543
+ e.preventDefault();
544
+ goToSlide(slideCount - 1);
545
+ break;
546
+ case "f":
547
+ case "F":
548
+ if (fullscreen) {
549
+ e.preventDefault();
550
+ setIsFullscreen((prev) => !prev);
551
+ }
552
+ break;
553
+ }
554
+ };
555
+ window.addEventListener("keydown", handleKey);
556
+ return () => window.removeEventListener("keydown", handleKey);
557
+ }, [enableKeyboard, mode, fullscreen, isFullscreen, enableClicks, currentClick, maxClicks, nextClick, prevClick, nextSlide, prevSlide, goToSlide, slideCount]);
558
+ react.useEffect(() => {
559
+ if (!enableClicks || !result || mode !== "presentation") return;
560
+ const timer = setTimeout(() => {
561
+ const container = document.querySelector(".slide-presentation-host > div");
562
+ if (!container) return;
563
+ container.querySelectorAll("[data-click-group]").forEach((el) => {
564
+ const group = parseInt(el.getAttribute("data-click-group") ?? "0", 10);
565
+ const isVisible = group <= currentClick;
566
+ el.classList.toggle("visible", isVisible);
567
+ });
568
+ }, 50);
569
+ return () => clearTimeout(timer);
570
+ }, [enableClicks, currentClick, result, currentIndex, mode]);
571
+ react.useEffect(() => {
572
+ if (!result || result.mermaidBlocks.length === 0) return;
573
+ const timer = setTimeout(() => {
574
+ const containers = document.querySelectorAll(".slide-presentation-host > div, .slide-deck-host > div");
575
+ containers.forEach((container) => {
576
+ if (container instanceof HTMLElement) {
577
+ const themeName2 = typeof theme === "string" ? theme : "dark";
578
+ chunkN4Q6GUAQ_cjs.renderMermaidDiagrams(container, themeName2).catch(() => {
579
+ });
580
+ }
581
+ });
582
+ }, 100);
583
+ return () => clearTimeout(timer);
584
+ }, [result, theme, currentIndex, mode]);
585
+ const handleThemeChange = react.useCallback(
586
+ (themeId) => {
587
+ setTheme(themeId);
588
+ },
589
+ [setTheme]
590
+ );
591
+ const toggleFullscreen = react.useCallback(() => {
592
+ setIsFullscreen((prev) => !prev);
593
+ }, []);
594
+ if (!result) {
595
+ return /* @__PURE__ */ jsxRuntime.jsx(
596
+ "div",
597
+ {
598
+ className,
599
+ style: {
600
+ display: "flex",
601
+ alignItems: "center",
602
+ justifyContent: "center",
603
+ padding: "80px 0",
604
+ color: "rgba(128, 128, 128, 0.5)",
605
+ fontSize: "13px",
606
+ fontFamily: "inherit"
607
+ },
608
+ children: "No slide content"
609
+ }
610
+ );
611
+ }
612
+ const themeName = typeof theme === "string" ? theme : theme.name;
613
+ const fullscreenCss = fullscreen ? `
614
+ .slide-viewer-fullscreen {
615
+ position: fixed !important;
616
+ inset: 0 !important;
617
+ z-index: 9999 !important;
618
+ background: #000 !important;
619
+ padding: 24px !important;
620
+ overflow-y: auto !important;
621
+ display: flex !important;
622
+ flex-direction: column !important;
623
+ }
624
+ .slide-viewer-fullscreen .slide-presentation-host {
625
+ flex: 1 !important;
626
+ display: flex !important;
627
+ align-items: center !important;
628
+ justify-content: center !important;
629
+ }
630
+ ` : "";
631
+ return /* @__PURE__ */ jsxRuntime.jsxs(
632
+ "div",
633
+ {
634
+ className: `${className ?? ""} ${isFullscreen ? "slide-viewer-fullscreen" : ""}`.trim(),
635
+ style: {
636
+ display: "flex",
637
+ flexDirection: "column",
638
+ width: "100%",
639
+ gap: "12px",
640
+ fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
641
+ ...isFullscreen ? { background: "#000", color: "#fff" } : {}
642
+ },
643
+ children: [
644
+ fullscreen && /* @__PURE__ */ jsxRuntime.jsx("style", { children: fullscreenCss }),
645
+ enableClicks && mode === "presentation" && result.clickCss && /* @__PURE__ */ jsxRuntime.jsx("style", { children: result.clickCss }),
646
+ (showThemeSwitcher || showNavigation || fullscreen) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
647
+ display: "flex",
648
+ alignItems: "center",
649
+ justifyContent: "space-between",
650
+ gap: "12px",
651
+ flexWrap: "wrap",
652
+ ...isFullscreen ? { borderBottom: "1px solid rgba(255,255,255,0.1)", paddingBottom: "8px" } : {}
653
+ }, children: [
654
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: showThemeSwitcher && /* @__PURE__ */ jsxRuntime.jsx(
655
+ ThemeSwitcher,
656
+ {
657
+ currentTheme: themeName,
658
+ onThemeChange: handleThemeChange,
659
+ themes: themeOptions
660
+ }
661
+ ) }),
662
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
663
+ showNavigation && /* @__PURE__ */ jsxRuntime.jsx(
664
+ NavigationBar,
665
+ {
666
+ currentIndex,
667
+ slideCount,
668
+ onNavigate: goToSlide,
669
+ mode,
670
+ onModeChange: setMode,
671
+ markdown
672
+ }
673
+ ),
674
+ fullscreen && /* @__PURE__ */ jsxRuntime.jsx(
675
+ "button",
676
+ {
677
+ type: "button",
678
+ onClick: toggleFullscreen,
679
+ style: {
680
+ height: "28px",
681
+ padding: "0 10px",
682
+ borderRadius: "6px",
683
+ fontSize: "12px",
684
+ fontFamily: "inherit",
685
+ display: "flex",
686
+ alignItems: "center",
687
+ gap: "5px",
688
+ border: "none",
689
+ cursor: "pointer",
690
+ backgroundColor: "transparent",
691
+ color: isFullscreen ? "#fff" : "rgba(128,128,128,0.7)",
692
+ transition: "all 0.15s ease"
693
+ },
694
+ title: isFullscreen ? "Exit fullscreen (ESC)" : "Fullscreen (F)",
695
+ children: isFullscreen ? "\u22A1 Exit" : "\u229E Fullscreen"
696
+ }
697
+ )
698
+ ] })
699
+ ] }),
700
+ enableClicks && maxClicks > 0 && mode === "presentation" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
701
+ display: "flex",
702
+ alignItems: "center",
703
+ gap: "8px",
704
+ fontSize: "11px",
705
+ color: isFullscreen ? "rgba(255,255,255,0.5)" : "rgba(128,128,128,0.5)"
706
+ }, children: [
707
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
708
+ "Click ",
709
+ currentClick,
710
+ " / ",
711
+ maxClicks
712
+ ] }),
713
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
714
+ flex: 1,
715
+ height: "2px",
716
+ borderRadius: "1px",
717
+ backgroundColor: isFullscreen ? "rgba(255,255,255,0.1)" : "rgba(128,128,128,0.1)"
718
+ }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
719
+ height: "100%",
720
+ borderRadius: "1px",
721
+ backgroundColor: isFullscreen ? "rgba(255,255,255,0.3)" : "rgba(128,128,128,0.3)",
722
+ width: `${maxClicks > 0 ? currentClick / maxClicks * 100 : 0}%`,
723
+ transition: "width 0.2s ease"
724
+ } }) })
725
+ ] }),
726
+ mode === "presentation" ? /* @__PURE__ */ jsxRuntime.jsx(
727
+ PresentationView,
728
+ {
729
+ html: result.html,
730
+ css: result.css,
731
+ themeCss: result.themeCss,
732
+ currentIndex,
733
+ slideCount
734
+ }
735
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
736
+ DeckView,
737
+ {
738
+ html: result.html,
739
+ css: result.css,
740
+ themeCss: result.themeCss,
741
+ slideCount
742
+ }
743
+ )
744
+ ]
745
+ }
746
+ );
747
+ }
748
+
749
+ Object.defineProperty(exports, "defineTheme", {
750
+ enumerable: true,
751
+ get: function () { return chunkN4Q6GUAQ_cjs.defineTheme; }
752
+ });
753
+ Object.defineProperty(exports, "extractMaxClicks", {
754
+ enumerable: true,
755
+ get: function () { return chunkN4Q6GUAQ_cjs.extractMaxClicks; }
756
+ });
757
+ Object.defineProperty(exports, "generateClickCss", {
758
+ enumerable: true,
759
+ get: function () { return chunkN4Q6GUAQ_cjs.generateClickCss; }
760
+ });
761
+ Object.defineProperty(exports, "postprocessClicks", {
762
+ enumerable: true,
763
+ get: function () { return chunkN4Q6GUAQ_cjs.postprocessClicks; }
764
+ });
765
+ Object.defineProperty(exports, "preprocessClicks", {
766
+ enumerable: true,
767
+ get: function () { return chunkN4Q6GUAQ_cjs.preprocessClicks; }
768
+ });
769
+ Object.defineProperty(exports, "renderSlide", {
770
+ enumerable: true,
771
+ get: function () { return chunkN4Q6GUAQ_cjs.renderSlide; }
772
+ });
773
+ Object.defineProperty(exports, "renderSlideAsync", {
774
+ enumerable: true,
775
+ get: function () { return chunkN4Q6GUAQ_cjs.renderSlideAsync; }
776
+ });
777
+ Object.defineProperty(exports, "resolveTheme", {
778
+ enumerable: true,
779
+ get: function () { return chunkN4Q6GUAQ_cjs.resolveTheme; }
780
+ });
781
+ exports.DeckView = DeckView;
782
+ exports.NavigationBar = NavigationBar;
783
+ exports.PresentationView = PresentationView;
784
+ exports.SlideViewer = SlideViewer;
785
+ exports.ThemeSwitcher = ThemeSwitcher;
786
+ exports.useSlideState = useSlideState;
787
+ //# sourceMappingURL=index.cjs.map
788
+ //# sourceMappingURL=index.cjs.map