@thanh01.pmt/presentation-kit 0.1.1 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkN4Q6GUAQ_cjs = require('../chunk-N4Q6GUAQ.cjs');
3
+ var chunkRJMPTRL3_cjs = require('../chunk-RJMPTRL3.cjs');
4
4
  var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
@@ -20,7 +20,7 @@ function useSlideState(options) {
20
20
  const result = react.useMemo(() => {
21
21
  if (!markdown || !markdown.trim()) return null;
22
22
  renderCountRef.current++;
23
- return chunkN4Q6GUAQ_cjs.renderSlide(markdown, {
23
+ return chunkRJMPTRL3_cjs.renderSlide(markdown, {
24
24
  theme,
25
25
  enableMermaid: true,
26
26
  enableClicks,
@@ -349,6 +349,7 @@ function PresentationView({
349
349
  html,
350
350
  css,
351
351
  themeCss,
352
+ layoutCss,
352
353
  currentIndex,
353
354
  slideCount,
354
355
  className
@@ -391,6 +392,7 @@ function PresentationView({
391
392
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { width: "100%" }, children: [
392
393
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: css }),
393
394
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: themeCss }),
395
+ layoutCss && /* @__PURE__ */ jsxRuntime.jsx("style", { children: layoutCss }),
394
396
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: presentationCss }),
395
397
  /* @__PURE__ */ jsxRuntime.jsx(
396
398
  "div",
@@ -406,6 +408,7 @@ function DeckView({
406
408
  html,
407
409
  css,
408
410
  themeCss,
411
+ layoutCss,
409
412
  slideCount,
410
413
  className
411
414
  }) {
@@ -452,6 +455,7 @@ function DeckView({
452
455
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { width: "100%" }, children: [
453
456
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: css }),
454
457
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: themeCss }),
458
+ layoutCss && /* @__PURE__ */ jsxRuntime.jsx("style", { children: layoutCss }),
455
459
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: deckCss }),
456
460
  /* @__PURE__ */ jsxRuntime.jsx(
457
461
  "div",
@@ -462,6 +466,619 @@ function DeckView({
462
466
  )
463
467
  ] });
464
468
  }
469
+ function PresenterNotesDrawer({
470
+ notes,
471
+ currentIndex,
472
+ slideCount,
473
+ isOpen,
474
+ onClose,
475
+ isDark = true
476
+ }) {
477
+ if (!isOpen) return null;
478
+ const bg = isDark ? "#181920" : "#ffffff";
479
+ const border = isDark ? "rgba(255, 255, 255, 0.12)" : "rgba(0, 0, 0, 0.12)";
480
+ const textColor = isDark ? "#f1f5f9" : "#1e293b";
481
+ const mutedColor = isDark ? "#94a3b8" : "#64748b";
482
+ return /* @__PURE__ */ jsxRuntime.jsxs(
483
+ "div",
484
+ {
485
+ style: {
486
+ marginTop: "12px",
487
+ padding: "16px 20px",
488
+ borderRadius: "10px",
489
+ backgroundColor: bg,
490
+ border: `1px solid ${border}`,
491
+ color: textColor,
492
+ boxShadow: isDark ? "0 4px 20px rgba(0, 0, 0, 0.4)" : "0 4px 20px rgba(0, 0, 0, 0.08)",
493
+ display: "flex",
494
+ flexDirection: "column",
495
+ gap: "10px",
496
+ transition: "all 0.2s ease"
497
+ },
498
+ children: [
499
+ /* @__PURE__ */ jsxRuntime.jsxs(
500
+ "div",
501
+ {
502
+ style: {
503
+ display: "flex",
504
+ alignItems: "center",
505
+ justifyContent: "space-between",
506
+ borderBottom: `1px solid ${border}`,
507
+ paddingBottom: "8px"
508
+ },
509
+ children: [
510
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
511
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "13px", letterSpacing: "0.02em" }, children: "Ghi ch\xFA Gi\u1EA3ng vi\xEAn" }),
512
+ /* @__PURE__ */ jsxRuntime.jsxs(
513
+ "span",
514
+ {
515
+ style: {
516
+ fontSize: "11px",
517
+ padding: "2px 8px",
518
+ borderRadius: "12px",
519
+ backgroundColor: isDark ? "rgba(56, 189, 248, 0.15)" : "rgba(2, 132, 199, 0.1)",
520
+ color: isDark ? "#38bdf8" : "#0284c7",
521
+ fontWeight: 500
522
+ },
523
+ children: [
524
+ "Slide ",
525
+ currentIndex + 1,
526
+ " / ",
527
+ slideCount
528
+ ]
529
+ }
530
+ )
531
+ ] }),
532
+ /* @__PURE__ */ jsxRuntime.jsx(
533
+ "button",
534
+ {
535
+ type: "button",
536
+ onClick: onClose,
537
+ style: {
538
+ background: "none",
539
+ border: "none",
540
+ color: mutedColor,
541
+ cursor: "pointer",
542
+ fontSize: "16px",
543
+ padding: "4px",
544
+ display: "flex",
545
+ alignItems: "center",
546
+ justifyContent: "center",
547
+ borderRadius: "4px"
548
+ },
549
+ title: "\u0110\xF3ng ghi ch\xFA",
550
+ children: "\u2715"
551
+ }
552
+ )
553
+ ]
554
+ }
555
+ ),
556
+ /* @__PURE__ */ jsxRuntime.jsx(
557
+ "div",
558
+ {
559
+ style: {
560
+ maxHeight: "180px",
561
+ overflowY: "auto",
562
+ fontSize: "13px",
563
+ lineHeight: "1.6"
564
+ },
565
+ children: notes.length > 0 ? notes.map((note, idx) => /* @__PURE__ */ jsxRuntime.jsx(
566
+ "div",
567
+ {
568
+ style: {
569
+ marginBottom: idx < notes.length - 1 ? "8px" : "0",
570
+ whiteSpace: "pre-wrap"
571
+ },
572
+ children: note
573
+ },
574
+ idx
575
+ )) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: mutedColor, fontStyle: "italic", fontSize: "12px" }, children: "Kh\xF4ng c\xF3 ghi ch\xFA cho slide n\xE0y." })
576
+ }
577
+ )
578
+ ]
579
+ }
580
+ );
581
+ }
582
+ function SlideDesignOverlay({
583
+ slideIndex,
584
+ layout,
585
+ onLayoutChange,
586
+ onSave,
587
+ onClose,
588
+ isActive
589
+ }) {
590
+ if (!isActive) return null;
591
+ const [boxes, setBoxes] = react.useState(layout?.boxes ?? []);
592
+ const [selectedId, setSelectedId] = react.useState(null);
593
+ const containerRef = react.useRef(null);
594
+ react.useEffect(() => {
595
+ setBoxes(layout?.boxes ?? []);
596
+ }, [layout, slideIndex]);
597
+ const selectedBox = boxes.find((b) => b.id === selectedId) ?? null;
598
+ const [dragging, setDragging] = react.useState(null);
599
+ const handleMouseDown = (e, box, type) => {
600
+ e.preventDefault();
601
+ e.stopPropagation();
602
+ setSelectedId(box.id);
603
+ setDragging({
604
+ type,
605
+ boxId: box.id,
606
+ startX: e.clientX,
607
+ startY: e.clientY,
608
+ startPos: [...box.pos]
609
+ });
610
+ };
611
+ const handleMouseMove = react.useCallback((e) => {
612
+ if (!dragging || !containerRef.current) return;
613
+ const rect = containerRef.current.getBoundingClientRect();
614
+ const scaleX = 1280 / rect.width;
615
+ const scaleY = 720 / rect.height;
616
+ const dx = (e.clientX - dragging.startX) * scaleX;
617
+ const dy = (e.clientY - dragging.startY) * scaleY;
618
+ const [origX, origY, origW, origH] = dragging.startPos;
619
+ setBoxes((prev) => {
620
+ const updated = prev.map((b) => {
621
+ if (b.id !== dragging.boxId) return b;
622
+ let [newX, newY, newW, newH] = [origX, origY, origW, origH];
623
+ switch (dragging.type) {
624
+ case "move":
625
+ newX = Math.max(0, Math.min(1280 - origW, origX + dx));
626
+ newY = Math.max(0, Math.min(720 - origH, origY + dy));
627
+ break;
628
+ case "se":
629
+ newW = Math.max(50, origW + dx);
630
+ newH = Math.max(30, origH + dy);
631
+ break;
632
+ case "e":
633
+ newW = Math.max(50, origW + dx);
634
+ break;
635
+ case "s":
636
+ newH = Math.max(30, origH + dy);
637
+ break;
638
+ case "sw":
639
+ newX = Math.min(origX + origW - 50, origX + dx);
640
+ newW = Math.max(50, origW - dx);
641
+ newH = Math.max(30, origH + dy);
642
+ break;
643
+ case "ne":
644
+ newY = Math.min(origY + origH - 30, origY + dy);
645
+ newW = Math.max(50, origW + dx);
646
+ newH = Math.max(30, origH - dy);
647
+ break;
648
+ case "nw":
649
+ newX = Math.min(origX + origW - 50, origX + dx);
650
+ newY = Math.min(origY + origH - 30, origY + dy);
651
+ newW = Math.max(50, origW - dx);
652
+ newH = Math.max(30, origH - dy);
653
+ break;
654
+ }
655
+ return {
656
+ ...b,
657
+ pos: [Math.round(newX), Math.round(newY), Math.round(newW), Math.round(newH)]
658
+ };
659
+ });
660
+ onLayoutChange({ boxes: updated });
661
+ return updated;
662
+ });
663
+ }, [dragging, onLayoutChange]);
664
+ const handleMouseUp = react.useCallback(() => {
665
+ setDragging(null);
666
+ }, []);
667
+ react.useEffect(() => {
668
+ if (dragging) {
669
+ window.addEventListener("mousemove", handleMouseMove);
670
+ window.addEventListener("mouseup", handleMouseUp);
671
+ return () => {
672
+ window.removeEventListener("mousemove", handleMouseMove);
673
+ window.removeEventListener("mouseup", handleMouseUp);
674
+ };
675
+ }
676
+ }, [dragging, handleMouseMove, handleMouseUp]);
677
+ const addNewBox = (targetTag) => {
678
+ const newBox = {
679
+ id: `box-${Date.now().toString(36)}`,
680
+ target: targetTag,
681
+ pos: [100, 120 + boxes.length * 80, 600, 100],
682
+ fontSize: targetTag === "h1" ? "2.5rem" : "1.2rem",
683
+ color: targetTag === "h1" ? "#38bdf8" : "#e2e8f0",
684
+ textAlign: "left"
685
+ };
686
+ const updated = [...boxes, newBox];
687
+ setBoxes(updated);
688
+ setSelectedId(newBox.id);
689
+ onLayoutChange({ boxes: updated });
690
+ };
691
+ const updateSelectedBox = (updates) => {
692
+ if (!selectedId) return;
693
+ setBoxes((prev) => {
694
+ const updated = prev.map((b) => b.id === selectedId ? { ...b, ...updates } : b);
695
+ onLayoutChange({ boxes: updated });
696
+ return updated;
697
+ });
698
+ };
699
+ const removeSelectedBox = () => {
700
+ if (!selectedId) return;
701
+ setBoxes((prev) => {
702
+ const updated = prev.filter((b) => b.id !== selectedId);
703
+ onLayoutChange({ boxes: updated });
704
+ return updated;
705
+ });
706
+ setSelectedId(null);
707
+ };
708
+ return /* @__PURE__ */ jsxRuntime.jsxs(
709
+ "div",
710
+ {
711
+ style: {
712
+ position: "absolute",
713
+ inset: 0,
714
+ zIndex: 50,
715
+ pointerEvents: "none"
716
+ // Allow passing through to children that have pointerEvents: 'auto'
717
+ },
718
+ children: [
719
+ /* @__PURE__ */ jsxRuntime.jsxs(
720
+ "div",
721
+ {
722
+ style: {
723
+ position: "absolute",
724
+ top: "12px",
725
+ left: "50%",
726
+ transform: "translateX(-50%)",
727
+ zIndex: 60,
728
+ pointerEvents: "auto",
729
+ display: "flex",
730
+ alignItems: "center",
731
+ gap: "8px",
732
+ padding: "6px 14px",
733
+ backgroundColor: "#1e1f29",
734
+ border: "1px solid rgba(56, 189, 248, 0.4)",
735
+ borderRadius: "24px",
736
+ boxShadow: "0 8px 30px rgba(0, 0, 0, 0.5)",
737
+ color: "#f8fafc",
738
+ fontSize: "12px",
739
+ fontFamily: "Inter, sans-serif"
740
+ },
741
+ children: [
742
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "#38bdf8" }, children: "Design Canvas:" }),
743
+ /* @__PURE__ */ jsxRuntime.jsx(
744
+ "button",
745
+ {
746
+ type: "button",
747
+ onClick: () => addNewBox("h1"),
748
+ style: toolbarButtonStyle,
749
+ title: "Th\xEAm khung v\u1ECB tr\xED Ti\xEAu \u0111\u1EC1",
750
+ children: "+ Ti\xEAu \u0111\u1EC1 (H1)"
751
+ }
752
+ ),
753
+ /* @__PURE__ */ jsxRuntime.jsx(
754
+ "button",
755
+ {
756
+ type: "button",
757
+ onClick: () => addNewBox("p"),
758
+ style: toolbarButtonStyle,
759
+ title: "Th\xEAm khung v\u1ECB tr\xED \u0110o\u1EA1n v\u0103n",
760
+ children: "+ \u0110o\u1EA1n v\u0103n (P)"
761
+ }
762
+ ),
763
+ /* @__PURE__ */ jsxRuntime.jsxs(
764
+ "select",
765
+ {
766
+ onChange: (e) => {
767
+ const preset = chunkRJMPTRL3_cjs.SLIDE_LAYOUT_PRESETS.find((p) => p.id === e.target.value);
768
+ if (preset) {
769
+ const clonedBoxes = JSON.parse(JSON.stringify(preset.layout.boxes));
770
+ setBoxes(clonedBoxes);
771
+ onLayoutChange({ boxes: clonedBoxes });
772
+ }
773
+ },
774
+ defaultValue: "",
775
+ style: {
776
+ ...toolbarButtonStyle,
777
+ cursor: "pointer",
778
+ outline: "none",
779
+ color: "#f8fafc",
780
+ border: "1px solid rgba(56, 189, 248, 0.3)"
781
+ },
782
+ title: "\xC1p d\u1EE5ng m\u1EABu b\u1ED1 c\u1EE5c c\xF3 s\u1EB5n",
783
+ children: [
784
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, style: { backgroundColor: "#1e1f29", color: "#94a3b8" }, children: "M\u1EABu b\u1ED1 c\u1EE5c (Presets)..." }),
785
+ chunkRJMPTRL3_cjs.SLIDE_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.id, style: { backgroundColor: "#1e1f29", color: "#f8fafc" }, children: p.name }, p.id))
786
+ ]
787
+ }
788
+ ),
789
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "1px", height: "16px", backgroundColor: "rgba(255,255,255,0.2)" } }),
790
+ onSave && /* @__PURE__ */ jsxRuntime.jsx(
791
+ "button",
792
+ {
793
+ type: "button",
794
+ onClick: () => onSave({ boxes }),
795
+ style: {
796
+ ...toolbarButtonStyle,
797
+ backgroundColor: "#0284c7",
798
+ color: "#ffffff",
799
+ fontWeight: 600
800
+ },
801
+ children: "L\u01B0u b\u1ED1 c\u1EE5c"
802
+ }
803
+ ),
804
+ onClose && /* @__PURE__ */ jsxRuntime.jsx(
805
+ "button",
806
+ {
807
+ type: "button",
808
+ onClick: onClose,
809
+ style: {
810
+ ...toolbarButtonStyle,
811
+ backgroundColor: "transparent",
812
+ color: "#94a3b8"
813
+ },
814
+ children: "\u0110\xF3ng"
815
+ }
816
+ )
817
+ ]
818
+ }
819
+ ),
820
+ /* @__PURE__ */ jsxRuntime.jsx(
821
+ "div",
822
+ {
823
+ ref: containerRef,
824
+ style: {
825
+ position: "absolute",
826
+ inset: 0,
827
+ pointerEvents: "auto"
828
+ },
829
+ onClick: () => setSelectedId(null),
830
+ children: boxes.map((box) => {
831
+ const [x, y, w, h] = box.pos;
832
+ const isSelected = box.id === selectedId;
833
+ const leftPercent = x / 1280 * 100;
834
+ const topPercent = y / 720 * 100;
835
+ const widthPercent = w / 1280 * 100;
836
+ const heightPercent = h / 720 * 100;
837
+ return /* @__PURE__ */ jsxRuntime.jsxs(
838
+ "div",
839
+ {
840
+ onClick: (e) => {
841
+ e.stopPropagation();
842
+ setSelectedId(box.id);
843
+ },
844
+ onMouseDown: (e) => handleMouseDown(e, box, "move"),
845
+ style: {
846
+ position: "absolute",
847
+ left: `${leftPercent}%`,
848
+ top: `${topPercent}%`,
849
+ width: `${widthPercent}%`,
850
+ height: `${heightPercent}%`,
851
+ border: isSelected ? "2px solid #38bdf8" : "1px dashed rgba(56, 189, 248, 0.5)",
852
+ backgroundColor: isSelected ? "rgba(56, 189, 248, 0.08)" : "rgba(56, 189, 248, 0.03)",
853
+ cursor: "move",
854
+ userSelect: "none",
855
+ boxSizing: "border-box",
856
+ zIndex: isSelected ? 40 : 20
857
+ },
858
+ children: [
859
+ /* @__PURE__ */ jsxRuntime.jsxs(
860
+ "div",
861
+ {
862
+ style: {
863
+ position: "absolute",
864
+ top: "-18px",
865
+ left: "0",
866
+ fontSize: "10px",
867
+ fontWeight: 600,
868
+ color: isSelected ? "#38bdf8" : "rgba(56, 189, 248, 0.7)",
869
+ backgroundColor: "rgba(0,0,0,0.8)",
870
+ padding: "1px 6px",
871
+ borderRadius: "3px",
872
+ whiteSpace: "nowrap"
873
+ },
874
+ children: [
875
+ box.target || box.id,
876
+ " (",
877
+ Math.round(x),
878
+ ", ",
879
+ Math.round(y),
880
+ ")"
881
+ ]
882
+ }
883
+ ),
884
+ isSelected && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
885
+ /* @__PURE__ */ jsxRuntime.jsx(
886
+ "div",
887
+ {
888
+ style: handleStyle("se"),
889
+ onMouseDown: (e) => handleMouseDown(e, box, "se")
890
+ }
891
+ ),
892
+ /* @__PURE__ */ jsxRuntime.jsx(
893
+ "div",
894
+ {
895
+ style: handleStyle("e"),
896
+ onMouseDown: (e) => handleMouseDown(e, box, "e")
897
+ }
898
+ ),
899
+ /* @__PURE__ */ jsxRuntime.jsx(
900
+ "div",
901
+ {
902
+ style: handleStyle("s"),
903
+ onMouseDown: (e) => handleMouseDown(e, box, "s")
904
+ }
905
+ ),
906
+ /* @__PURE__ */ jsxRuntime.jsx(
907
+ "div",
908
+ {
909
+ style: handleStyle("sw"),
910
+ onMouseDown: (e) => handleMouseDown(e, box, "sw")
911
+ }
912
+ ),
913
+ /* @__PURE__ */ jsxRuntime.jsx(
914
+ "div",
915
+ {
916
+ style: handleStyle("ne"),
917
+ onMouseDown: (e) => handleMouseDown(e, box, "ne")
918
+ }
919
+ ),
920
+ /* @__PURE__ */ jsxRuntime.jsx(
921
+ "div",
922
+ {
923
+ style: handleStyle("nw"),
924
+ onMouseDown: (e) => handleMouseDown(e, box, "nw")
925
+ }
926
+ )
927
+ ] })
928
+ ]
929
+ },
930
+ box.id
931
+ );
932
+ })
933
+ }
934
+ ),
935
+ selectedBox && /* @__PURE__ */ jsxRuntime.jsxs(
936
+ "div",
937
+ {
938
+ style: {
939
+ position: "absolute",
940
+ bottom: "24px",
941
+ left: "50%",
942
+ transform: "translateX(-50%)",
943
+ zIndex: 60,
944
+ pointerEvents: "auto",
945
+ display: "flex",
946
+ alignItems: "center",
947
+ gap: "12px",
948
+ padding: "8px 16px",
949
+ backgroundColor: "#181920",
950
+ border: "1px solid rgba(255,255,255,0.15)",
951
+ borderRadius: "12px",
952
+ boxShadow: "0 10px 30px rgba(0,0,0,0.6)",
953
+ color: "#f8fafc",
954
+ fontSize: "12px",
955
+ fontFamily: "Inter, sans-serif"
956
+ },
957
+ children: [
958
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: "#38bdf8" }, children: [
959
+ "Khung: ",
960
+ selectedBox.target
961
+ ] }),
962
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
963
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#94a3b8", fontSize: "11px" }, children: "Size:" }),
964
+ /* @__PURE__ */ jsxRuntime.jsx(
965
+ "input",
966
+ {
967
+ type: "text",
968
+ value: selectedBox.fontSize ?? "1.5rem",
969
+ onChange: (e) => updateSelectedBox({ fontSize: e.target.value }),
970
+ style: {
971
+ width: "60px",
972
+ padding: "2px 6px",
973
+ borderRadius: "4px",
974
+ border: "1px solid #334155",
975
+ backgroundColor: "#0f172a",
976
+ color: "#f8fafc",
977
+ fontSize: "11px"
978
+ }
979
+ }
980
+ )
981
+ ] }),
982
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
983
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#94a3b8", fontSize: "11px" }, children: "Color:" }),
984
+ /* @__PURE__ */ jsxRuntime.jsx(
985
+ "input",
986
+ {
987
+ type: "color",
988
+ value: selectedBox.color ?? "#38bdf8",
989
+ onChange: (e) => updateSelectedBox({ color: e.target.value }),
990
+ style: {
991
+ width: "24px",
992
+ height: "24px",
993
+ padding: "0",
994
+ border: "none",
995
+ borderRadius: "4px",
996
+ cursor: "pointer",
997
+ backgroundColor: "transparent"
998
+ }
999
+ }
1000
+ )
1001
+ ] }),
1002
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", gap: "2px" }, children: ["left", "center", "right"].map((align) => /* @__PURE__ */ jsxRuntime.jsx(
1003
+ "button",
1004
+ {
1005
+ type: "button",
1006
+ onClick: () => updateSelectedBox({ textAlign: align }),
1007
+ style: {
1008
+ ...toolbarButtonStyle,
1009
+ backgroundColor: selectedBox.textAlign === align ? "#0284c7" : "rgba(255,255,255,0.05)",
1010
+ textTransform: "capitalize",
1011
+ fontSize: "11px",
1012
+ padding: "2px 8px"
1013
+ },
1014
+ children: align
1015
+ },
1016
+ align
1017
+ )) }),
1018
+ /* @__PURE__ */ jsxRuntime.jsx(
1019
+ "button",
1020
+ {
1021
+ type: "button",
1022
+ onClick: removeSelectedBox,
1023
+ style: {
1024
+ ...toolbarButtonStyle,
1025
+ backgroundColor: "rgba(239, 68, 68, 0.2)",
1026
+ color: "#f87171",
1027
+ borderColor: "rgba(239, 68, 68, 0.4)"
1028
+ },
1029
+ title: "X\xF3a \u0111\u1ECBnh v\u1ECB t\u1EF1 do (tr\u1EDF v\u1EC1 lu\u1ED3ng b\xECnh th\u01B0\u1EDDng)",
1030
+ children: "Tr\u1EDF v\u1EC1 lu\u1ED3ng m\u1EB7c \u0111\u1ECBnh"
1031
+ }
1032
+ )
1033
+ ]
1034
+ }
1035
+ )
1036
+ ]
1037
+ }
1038
+ );
1039
+ }
1040
+ var toolbarButtonStyle = {
1041
+ height: "26px",
1042
+ padding: "0 10px",
1043
+ borderRadius: "14px",
1044
+ fontSize: "11px",
1045
+ fontFamily: "inherit",
1046
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1047
+ backgroundColor: "rgba(255, 255, 255, 0.08)",
1048
+ color: "#e2e8f0",
1049
+ cursor: "pointer",
1050
+ display: "flex",
1051
+ alignItems: "center",
1052
+ justifyContent: "center",
1053
+ transition: "all 0.15s ease"
1054
+ };
1055
+ function handleStyle(pos) {
1056
+ const size = 10;
1057
+ const base = {
1058
+ position: "absolute",
1059
+ width: `${size}px`,
1060
+ height: `${size}px`,
1061
+ backgroundColor: "#ffffff",
1062
+ border: "2px solid #0284c7",
1063
+ borderRadius: "2px",
1064
+ boxSizing: "border-box",
1065
+ zIndex: 50
1066
+ };
1067
+ switch (pos) {
1068
+ case "se":
1069
+ return { ...base, right: `-${size / 2}px`, bottom: `-${size / 2}px`, cursor: "se-resize" };
1070
+ case "e":
1071
+ return { ...base, right: `-${size / 2}px`, top: `calc(50% - ${size / 2}px)`, cursor: "e-resize" };
1072
+ case "s":
1073
+ return { ...base, bottom: `-${size / 2}px`, left: `calc(50% - ${size / 2}px)`, cursor: "s-resize" };
1074
+ case "sw":
1075
+ return { ...base, left: `-${size / 2}px`, bottom: `-${size / 2}px`, cursor: "sw-resize" };
1076
+ case "ne":
1077
+ return { ...base, right: `-${size / 2}px`, top: `-${size / 2}px`, cursor: "ne-resize" };
1078
+ case "nw":
1079
+ return { ...base, left: `-${size / 2}px`, top: `-${size / 2}px`, cursor: "nw-resize" };
1080
+ }
1081
+ }
465
1082
  var DEFAULT_THEME_OPTIONS = [
466
1083
  { id: "dark", label: "Dark" },
467
1084
  { id: "navy", label: "Navy" },
@@ -477,13 +1094,19 @@ function SlideViewer({
477
1094
  enableKeyboard = true,
478
1095
  enableClicks = false,
479
1096
  fullscreen = false,
1097
+ showNotes = true,
1098
+ showDesignMode = false,
480
1099
  themeOptions = DEFAULT_THEME_OPTIONS,
481
1100
  onThemeChange,
482
1101
  onSlideChange,
483
1102
  onModeChange,
484
- onRenderComplete
1103
+ onRenderComplete,
1104
+ onSaveMarkdown
485
1105
  }) {
486
1106
  const [isFullscreen, setIsFullscreen] = react.useState(false);
1107
+ const [showNotesDrawer, setShowNotesDrawer] = react.useState(false);
1108
+ const [isDesignMode, setIsDesignMode] = react.useState(false);
1109
+ const [liveLayout, setLiveLayout] = react.useState(null);
487
1110
  const state = useSlideState({
488
1111
  markdown,
489
1112
  initialTheme,
@@ -589,7 +1212,7 @@ function SlideViewer({
589
1212
  containers.forEach((container) => {
590
1213
  if (container instanceof HTMLElement) {
591
1214
  const themeName2 = typeof theme === "string" ? theme : "dark";
592
- chunkN4Q6GUAQ_cjs.renderMermaidDiagrams(container, themeName2).catch(() => {
1215
+ chunkRJMPTRL3_cjs.renderMermaidDiagrams(container, themeName2).catch(() => {
593
1216
  });
594
1217
  }
595
1218
  });
@@ -685,6 +1308,54 @@ function SlideViewer({
685
1308
  markdown
686
1309
  }
687
1310
  ),
1311
+ showNotes && /* @__PURE__ */ jsxRuntime.jsx(
1312
+ "button",
1313
+ {
1314
+ type: "button",
1315
+ onClick: () => setShowNotesDrawer((prev) => !prev),
1316
+ style: {
1317
+ height: "28px",
1318
+ padding: "0 10px",
1319
+ borderRadius: "6px",
1320
+ fontSize: "12px",
1321
+ fontFamily: "inherit",
1322
+ display: "flex",
1323
+ alignItems: "center",
1324
+ gap: "5px",
1325
+ border: showNotesDrawer ? "1px solid #0284c7" : "1px solid transparent",
1326
+ cursor: "pointer",
1327
+ backgroundColor: showNotesDrawer ? "rgba(2, 132, 199, 0.15)" : "transparent",
1328
+ color: showNotesDrawer ? "#38bdf8" : isFullscreen ? "#fff" : "rgba(128,128,128,0.7)",
1329
+ transition: "all 0.15s ease"
1330
+ },
1331
+ title: "Ghi ch\xFA cho Gi\u1EA3ng vi\xEAn",
1332
+ children: "Notes"
1333
+ }
1334
+ ),
1335
+ showDesignMode && mode === "presentation" && /* @__PURE__ */ jsxRuntime.jsx(
1336
+ "button",
1337
+ {
1338
+ type: "button",
1339
+ onClick: () => setIsDesignMode((prev) => !prev),
1340
+ style: {
1341
+ height: "28px",
1342
+ padding: "0 10px",
1343
+ borderRadius: "6px",
1344
+ fontSize: "12px",
1345
+ fontFamily: "inherit",
1346
+ display: "flex",
1347
+ alignItems: "center",
1348
+ gap: "5px",
1349
+ border: isDesignMode ? "1px solid #38bdf8" : "1px solid transparent",
1350
+ cursor: "pointer",
1351
+ backgroundColor: isDesignMode ? "rgba(56, 189, 248, 0.15)" : "transparent",
1352
+ color: isDesignMode ? "#38bdf8" : isFullscreen ? "#fff" : "rgba(128,128,128,0.7)",
1353
+ transition: "all 0.15s ease"
1354
+ },
1355
+ title: "Ch\u1EBF \u0111\u1ED9 ch\u1EC9nh s\u1EEDa b\u1ED1 c\u1EE5c (Google Slides-style)",
1356
+ children: "Design"
1357
+ }
1358
+ ),
688
1359
  fullscreen && /* @__PURE__ */ jsxRuntime.jsx(
689
1360
  "button",
690
1361
  {
@@ -737,22 +1408,54 @@ function SlideViewer({
737
1408
  transition: "width 0.2s ease"
738
1409
  } }) })
739
1410
  ] }),
740
- mode === "presentation" ? /* @__PURE__ */ jsxRuntime.jsx(
741
- PresentationView,
1411
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "relative", width: "100%" }, children: mode === "presentation" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1412
+ /* @__PURE__ */ jsxRuntime.jsx(
1413
+ PresentationView,
1414
+ {
1415
+ html: result.html,
1416
+ css: result.css,
1417
+ themeCss: result.themeCss,
1418
+ layoutCss: result.layoutCss,
1419
+ currentIndex,
1420
+ slideCount
1421
+ }
1422
+ ),
1423
+ isDesignMode && /* @__PURE__ */ jsxRuntime.jsx(
1424
+ SlideDesignOverlay,
1425
+ {
1426
+ slideIndex: currentIndex,
1427
+ layout: liveLayout ?? result.layouts?.[currentIndex] ?? null,
1428
+ onLayoutChange: setLiveLayout,
1429
+ onSave: (layout) => {
1430
+ setLiveLayout(layout);
1431
+ if (onSaveMarkdown) {
1432
+ const updated = chunkRJMPTRL3_cjs.updateSlideLayoutInMarkdown(markdown, currentIndex, layout);
1433
+ onSaveMarkdown(updated);
1434
+ }
1435
+ },
1436
+ onClose: () => setIsDesignMode(false),
1437
+ isActive: isDesignMode
1438
+ }
1439
+ )
1440
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
1441
+ DeckView,
742
1442
  {
743
1443
  html: result.html,
744
1444
  css: result.css,
745
1445
  themeCss: result.themeCss,
746
- currentIndex,
1446
+ layoutCss: result.layoutCss,
747
1447
  slideCount
748
1448
  }
749
- ) : /* @__PURE__ */ jsxRuntime.jsx(
750
- DeckView,
1449
+ ) }),
1450
+ showNotes && /* @__PURE__ */ jsxRuntime.jsx(
1451
+ PresenterNotesDrawer,
751
1452
  {
752
- html: result.html,
753
- css: result.css,
754
- themeCss: result.themeCss,
755
- slideCount
1453
+ notes: result.notes?.[currentIndex] ?? [],
1454
+ currentIndex,
1455
+ slideCount,
1456
+ isOpen: showNotesDrawer,
1457
+ onClose: () => setShowNotesDrawer(false),
1458
+ isDark: themeName !== "light"
756
1459
  }
757
1460
  )
758
1461
  ]
@@ -762,39 +1465,41 @@ function SlideViewer({
762
1465
 
763
1466
  Object.defineProperty(exports, "defineTheme", {
764
1467
  enumerable: true,
765
- get: function () { return chunkN4Q6GUAQ_cjs.defineTheme; }
1468
+ get: function () { return chunkRJMPTRL3_cjs.defineTheme; }
766
1469
  });
767
1470
  Object.defineProperty(exports, "extractMaxClicks", {
768
1471
  enumerable: true,
769
- get: function () { return chunkN4Q6GUAQ_cjs.extractMaxClicks; }
1472
+ get: function () { return chunkRJMPTRL3_cjs.extractMaxClicks; }
770
1473
  });
771
1474
  Object.defineProperty(exports, "generateClickCss", {
772
1475
  enumerable: true,
773
- get: function () { return chunkN4Q6GUAQ_cjs.generateClickCss; }
1476
+ get: function () { return chunkRJMPTRL3_cjs.generateClickCss; }
774
1477
  });
775
1478
  Object.defineProperty(exports, "postprocessClicks", {
776
1479
  enumerable: true,
777
- get: function () { return chunkN4Q6GUAQ_cjs.postprocessClicks; }
1480
+ get: function () { return chunkRJMPTRL3_cjs.postprocessClicks; }
778
1481
  });
779
1482
  Object.defineProperty(exports, "preprocessClicks", {
780
1483
  enumerable: true,
781
- get: function () { return chunkN4Q6GUAQ_cjs.preprocessClicks; }
1484
+ get: function () { return chunkRJMPTRL3_cjs.preprocessClicks; }
782
1485
  });
783
1486
  Object.defineProperty(exports, "renderSlide", {
784
1487
  enumerable: true,
785
- get: function () { return chunkN4Q6GUAQ_cjs.renderSlide; }
1488
+ get: function () { return chunkRJMPTRL3_cjs.renderSlide; }
786
1489
  });
787
1490
  Object.defineProperty(exports, "renderSlideAsync", {
788
1491
  enumerable: true,
789
- get: function () { return chunkN4Q6GUAQ_cjs.renderSlideAsync; }
1492
+ get: function () { return chunkRJMPTRL3_cjs.renderSlideAsync; }
790
1493
  });
791
1494
  Object.defineProperty(exports, "resolveTheme", {
792
1495
  enumerable: true,
793
- get: function () { return chunkN4Q6GUAQ_cjs.resolveTheme; }
1496
+ get: function () { return chunkRJMPTRL3_cjs.resolveTheme; }
794
1497
  });
795
1498
  exports.DeckView = DeckView;
796
1499
  exports.NavigationBar = NavigationBar;
797
1500
  exports.PresentationView = PresentationView;
1501
+ exports.PresenterNotesDrawer = PresenterNotesDrawer;
1502
+ exports.SlideDesignOverlay = SlideDesignOverlay;
798
1503
  exports.SlideViewer = SlideViewer;
799
1504
  exports.ThemeSwitcher = ThemeSwitcher;
800
1505
  exports.useSlideState = useSlideState;