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