@thanh01.pmt/presentation-kit 0.1.0 → 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,47 +348,50 @@ function PresentationView({
348
348
  html,
349
349
  css,
350
350
  themeCss,
351
+ layoutCss,
351
352
  currentIndex,
352
353
  slideCount,
353
354
  className
354
355
  }) {
355
356
  const presentationCss = `
356
357
  .slide-presentation-host {
357
- display: flex;
358
- align-items: center;
359
- justify-content: center;
360
- width: 100%;
358
+ display: flex !important;
359
+ align-items: center !important;
360
+ justify-content: center !important;
361
+ width: 100% !important;
361
362
  }
362
363
  .slide-presentation-host > div {
363
- position: relative;
364
- display: flex;
365
- align-items: center;
366
- justify-content: center;
367
- width: 100%;
364
+ position: relative !important;
365
+ display: flex !important;
366
+ align-items: center !important;
367
+ justify-content: center !important;
368
+ width: 100% !important;
368
369
  }
370
+ .slide-presentation-host #marp-container svg[data-marpit-svg],
371
+ .slide-presentation-host #marp-container > svg,
369
372
  .slide-presentation-host > div > svg {
370
- position: absolute;
371
- visibility: hidden;
372
- opacity: 0;
373
- pointer-events: none;
374
- width: min(100%, calc((100vh - 120px) * (16 / 9)));
375
- max-width: 1400px;
376
- height: auto;
377
- max-height: calc(100vh - 120px);
378
- aspect-ratio: 16 / 9;
379
- margin: 0 auto;
373
+ display: none !important;
380
374
  }
381
- .slide-presentation-host > div > svg:nth-child(${currentIndex + 1}) {
382
- position: relative;
383
- visibility: visible;
384
- opacity: 1;
385
- pointer-events: auto;
386
- display: block;
375
+ .slide-presentation-host #marp-container svg[data-marpit-svg]:nth-of-type(${currentIndex + 1}),
376
+ .slide-presentation-host #marp-container > svg:nth-of-type(${currentIndex + 1}),
377
+ .slide-presentation-host > div > svg:nth-of-type(${currentIndex + 1}) {
378
+ display: block !important;
379
+ position: relative !important;
380
+ visibility: visible !important;
381
+ opacity: 1 !important;
382
+ pointer-events: auto !important;
383
+ width: min(100%, calc((100vh - 120px) * 16 / 9)) !important;
384
+ max-width: 1400px !important;
385
+ height: auto !important;
386
+ max-height: calc(100vh - 120px) !important;
387
+ aspect-ratio: 16 / 9 !important;
388
+ margin: 0 auto !important;
387
389
  }
388
390
  `;
389
391
  return /* @__PURE__ */ jsxs("div", { className, style: { width: "100%" }, children: [
390
392
  /* @__PURE__ */ jsx("style", { children: css }),
391
393
  /* @__PURE__ */ jsx("style", { children: themeCss }),
394
+ layoutCss && /* @__PURE__ */ jsx("style", { children: layoutCss }),
392
395
  /* @__PURE__ */ jsx("style", { children: presentationCss }),
393
396
  /* @__PURE__ */ jsx(
394
397
  "div",
@@ -404,39 +407,54 @@ function DeckView({
404
407
  html,
405
408
  css,
406
409
  themeCss,
410
+ layoutCss,
407
411
  slideCount,
408
412
  className
409
413
  }) {
410
414
  const deckCss = `
411
415
  .slide-deck-host {
412
- display: flex;
413
- flex-direction: column;
414
- align-items: center;
415
- gap: 24px;
416
- padding: 16px 0;
416
+ display: flex !important;
417
+ flex-direction: column !important;
418
+ align-items: center !important;
419
+ width: 100% !important;
420
+ padding: 16px 0 !important;
417
421
  }
418
- .slide-deck-host > div {
419
- display: flex;
420
- flex-direction: column;
421
- align-items: center;
422
- gap: 24px;
422
+ .slide-deck-host > div,
423
+ .slide-deck-host #marp-container {
424
+ display: flex !important;
425
+ flex-direction: column !important;
426
+ align-items: center !important;
427
+ width: 100% !important;
423
428
  }
429
+ .slide-deck-host #marp-container svg[data-marpit-svg],
430
+ .slide-deck-host #marp-container > svg,
424
431
  .slide-deck-host > div > svg {
425
432
  display: block !important;
426
433
  width: 100% !important;
427
- max-width: 960px;
434
+ max-width: 960px !important;
428
435
  height: auto !important;
429
- aspect-ratio: 16 / 9;
430
- border-radius: 12px;
431
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
436
+ aspect-ratio: 16 / 9 !important;
437
+ margin: 0 auto 32px auto !important;
438
+ border-radius: 12px !important;
439
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12) !important;
440
+ transition: transform 0.2s ease, box-shadow 0.2s ease !important;
441
+ }
442
+ .slide-deck-host #marp-container svg[data-marpit-svg]:last-of-type,
443
+ .slide-deck-host #marp-container > svg:last-of-type,
444
+ .slide-deck-host > div > svg:last-of-type {
445
+ margin-bottom: 0 !important;
432
446
  }
447
+ .slide-deck-host #marp-container svg[data-marpit-svg]:hover,
448
+ .slide-deck-host #marp-container > svg:hover,
433
449
  .slide-deck-host > div > svg:hover {
434
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
450
+ transform: translateY(-2px);
451
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2) !important;
435
452
  }
436
453
  `;
437
454
  return /* @__PURE__ */ jsxs("div", { className, style: { width: "100%" }, children: [
438
455
  /* @__PURE__ */ jsx("style", { children: css }),
439
456
  /* @__PURE__ */ jsx("style", { children: themeCss }),
457
+ layoutCss && /* @__PURE__ */ jsx("style", { children: layoutCss }),
440
458
  /* @__PURE__ */ jsx("style", { children: deckCss }),
441
459
  /* @__PURE__ */ jsx(
442
460
  "div",
@@ -447,6 +465,593 @@ function DeckView({
447
465
  )
448
466
  ] });
449
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
+ }
450
1055
  var DEFAULT_THEME_OPTIONS = [
451
1056
  { id: "dark", label: "Dark" },
452
1057
  { id: "navy", label: "Navy" },
@@ -462,13 +1067,19 @@ function SlideViewer({
462
1067
  enableKeyboard = true,
463
1068
  enableClicks = false,
464
1069
  fullscreen = false,
1070
+ showNotes = true,
1071
+ showDesignMode = false,
465
1072
  themeOptions = DEFAULT_THEME_OPTIONS,
466
1073
  onThemeChange,
467
1074
  onSlideChange,
468
1075
  onModeChange,
469
- onRenderComplete
1076
+ onRenderComplete,
1077
+ onSaveMarkdown
470
1078
  }) {
471
1079
  const [isFullscreen, setIsFullscreen] = useState(false);
1080
+ const [showNotesDrawer, setShowNotesDrawer] = useState(false);
1081
+ const [isDesignMode, setIsDesignMode] = useState(false);
1082
+ const [liveLayout, setLiveLayout] = useState(null);
472
1083
  const state = useSlideState({
473
1084
  markdown,
474
1085
  initialTheme,
@@ -670,6 +1281,54 @@ function SlideViewer({
670
1281
  markdown
671
1282
  }
672
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
+ ),
673
1332
  fullscreen && /* @__PURE__ */ jsx(
674
1333
  "button",
675
1334
  {
@@ -722,22 +1381,54 @@ function SlideViewer({
722
1381
  transition: "width 0.2s ease"
723
1382
  } }) })
724
1383
  ] }),
725
- mode === "presentation" ? /* @__PURE__ */ jsx(
726
- 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,
727
1415
  {
728
1416
  html: result.html,
729
1417
  css: result.css,
730
1418
  themeCss: result.themeCss,
731
- currentIndex,
1419
+ layoutCss: result.layoutCss,
732
1420
  slideCount
733
1421
  }
734
- ) : /* @__PURE__ */ jsx(
735
- DeckView,
1422
+ ) }),
1423
+ showNotes && /* @__PURE__ */ jsx(
1424
+ PresenterNotesDrawer,
736
1425
  {
737
- html: result.html,
738
- css: result.css,
739
- themeCss: result.themeCss,
740
- slideCount
1426
+ notes: result.notes?.[currentIndex] ?? [],
1427
+ currentIndex,
1428
+ slideCount,
1429
+ isOpen: showNotesDrawer,
1430
+ onClose: () => setShowNotesDrawer(false),
1431
+ isDark: themeName !== "light"
741
1432
  }
742
1433
  )
743
1434
  ]
@@ -745,6 +1436,6 @@ function SlideViewer({
745
1436
  );
746
1437
  }
747
1438
 
748
- export { DeckView, NavigationBar, PresentationView, SlideViewer, ThemeSwitcher, useSlideState };
1439
+ export { DeckView, NavigationBar, PresentationView, PresenterNotesDrawer, SlideDesignOverlay, SlideViewer, ThemeSwitcher, useSlideState };
749
1440
  //# sourceMappingURL=index.js.map
750
1441
  //# sourceMappingURL=index.js.map