@qwanyx/carousel 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +710 -316
- package/dist/index.mjs +692 -308
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -31,7 +41,7 @@ __export(index_exports, {
|
|
|
31
41
|
module.exports = __toCommonJS(index_exports);
|
|
32
42
|
|
|
33
43
|
// src/components/Carousel.tsx
|
|
34
|
-
var
|
|
44
|
+
var import_react4 = require("react");
|
|
35
45
|
|
|
36
46
|
// src/hooks/useCarousel.ts
|
|
37
47
|
var import_react = require("react");
|
|
@@ -501,8 +511,252 @@ function SlideRenderer({ slide, isActive, slideIndex }) {
|
|
|
501
511
|
);
|
|
502
512
|
}
|
|
503
513
|
|
|
504
|
-
// src/components/
|
|
514
|
+
// src/components/Thumbnails.tsx
|
|
515
|
+
var import_react3 = require("react");
|
|
505
516
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
517
|
+
function getThumbnail(slide) {
|
|
518
|
+
if (slide.thumbnail) return slide.thumbnail;
|
|
519
|
+
for (const layer of slide.layers) {
|
|
520
|
+
for (const obj of layer.objects) {
|
|
521
|
+
if (obj.type === "image") {
|
|
522
|
+
return obj.src;
|
|
523
|
+
}
|
|
524
|
+
if (obj.type === "video" && obj.poster) {
|
|
525
|
+
return obj.poster || null;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (slide.background?.type === "image") {
|
|
530
|
+
return slide.background.value;
|
|
531
|
+
}
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
function getSlideIcon(slide) {
|
|
535
|
+
for (const layer of slide.layers) {
|
|
536
|
+
for (const obj of layer.objects) {
|
|
537
|
+
switch (obj.type) {
|
|
538
|
+
case "video":
|
|
539
|
+
return "\u25B6";
|
|
540
|
+
case "audio":
|
|
541
|
+
return "\u{1F3B5}";
|
|
542
|
+
case "text":
|
|
543
|
+
return "\u{1F4DD}";
|
|
544
|
+
case "component":
|
|
545
|
+
return "\u26A1";
|
|
546
|
+
case "shape":
|
|
547
|
+
return "\u25FC";
|
|
548
|
+
case "group":
|
|
549
|
+
return "\u{1F4C1}";
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return "\u{1F5BC}";
|
|
554
|
+
}
|
|
555
|
+
function Thumbnails({
|
|
556
|
+
slides,
|
|
557
|
+
currentIndex,
|
|
558
|
+
onSelect,
|
|
559
|
+
onReorder,
|
|
560
|
+
onDelete,
|
|
561
|
+
position = "bottom",
|
|
562
|
+
size = "medium",
|
|
563
|
+
theme = "light"
|
|
564
|
+
}) {
|
|
565
|
+
const isVertical = position === "left" || position === "right";
|
|
566
|
+
const [draggedIndex, setDraggedIndex] = (0, import_react3.useState)(null);
|
|
567
|
+
const [dragOverIndex, setDragOverIndex] = (0, import_react3.useState)(null);
|
|
568
|
+
const sizeMap = {
|
|
569
|
+
small: { width: 48, height: 48 },
|
|
570
|
+
medium: { width: 64, height: 64 },
|
|
571
|
+
large: { width: 80, height: 80 }
|
|
572
|
+
};
|
|
573
|
+
const { width, height } = sizeMap[size];
|
|
574
|
+
const handleDragStart = (e, index, thumbnailUrl) => {
|
|
575
|
+
setDraggedIndex(index);
|
|
576
|
+
e.dataTransfer.effectAllowed = "copyMove";
|
|
577
|
+
e.dataTransfer.setData("text/plain", index.toString());
|
|
578
|
+
if (thumbnailUrl) {
|
|
579
|
+
e.dataTransfer.setData("text/uri-list", thumbnailUrl);
|
|
580
|
+
e.dataTransfer.setData("application/x-thumbnail-url", thumbnailUrl);
|
|
581
|
+
}
|
|
582
|
+
const target = e.target;
|
|
583
|
+
requestAnimationFrame(() => {
|
|
584
|
+
target.style.opacity = "0.5";
|
|
585
|
+
});
|
|
586
|
+
};
|
|
587
|
+
const handleDragEnd = (e) => {
|
|
588
|
+
const target = e.target;
|
|
589
|
+
target.style.opacity = "1";
|
|
590
|
+
setDraggedIndex(null);
|
|
591
|
+
setDragOverIndex(null);
|
|
592
|
+
};
|
|
593
|
+
const handleDragOver = (e, index) => {
|
|
594
|
+
if (!onReorder || draggedIndex === null) return;
|
|
595
|
+
e.preventDefault();
|
|
596
|
+
e.dataTransfer.dropEffect = "move";
|
|
597
|
+
if (index !== draggedIndex) {
|
|
598
|
+
setDragOverIndex(index);
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
const handleDragLeave = () => {
|
|
602
|
+
setDragOverIndex(null);
|
|
603
|
+
};
|
|
604
|
+
const handleDrop = (e, toIndex) => {
|
|
605
|
+
e.preventDefault();
|
|
606
|
+
if (!onReorder || draggedIndex === null || draggedIndex === toIndex) return;
|
|
607
|
+
onReorder(draggedIndex, toIndex);
|
|
608
|
+
setDraggedIndex(null);
|
|
609
|
+
setDragOverIndex(null);
|
|
610
|
+
};
|
|
611
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
612
|
+
"div",
|
|
613
|
+
{
|
|
614
|
+
className: `qc-thumbnails qc-thumbnails--${position} qc-thumbnails--${theme}`,
|
|
615
|
+
style: {
|
|
616
|
+
display: "flex",
|
|
617
|
+
flexDirection: isVertical ? "column" : "row",
|
|
618
|
+
flexWrap: "wrap",
|
|
619
|
+
gap: "8px",
|
|
620
|
+
marginTop: "8px"
|
|
621
|
+
},
|
|
622
|
+
children: slides.map((slide, index) => {
|
|
623
|
+
const thumbnailUrl = getThumbnail(slide);
|
|
624
|
+
const isActive = index === currentIndex;
|
|
625
|
+
const isDragging = draggedIndex === index;
|
|
626
|
+
const isDragOver = dragOverIndex === index;
|
|
627
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
628
|
+
"div",
|
|
629
|
+
{
|
|
630
|
+
className: "qc-thumbnail-wrapper",
|
|
631
|
+
style: {
|
|
632
|
+
position: "relative"
|
|
633
|
+
},
|
|
634
|
+
onDragOver: (e) => handleDragOver(e, index),
|
|
635
|
+
onDragLeave: handleDragLeave,
|
|
636
|
+
onDrop: (e) => handleDrop(e, index),
|
|
637
|
+
children: [
|
|
638
|
+
isDragOver && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
639
|
+
"div",
|
|
640
|
+
{
|
|
641
|
+
style: {
|
|
642
|
+
position: "absolute",
|
|
643
|
+
left: "-4px",
|
|
644
|
+
top: 0,
|
|
645
|
+
bottom: 0,
|
|
646
|
+
width: "3px",
|
|
647
|
+
backgroundColor: "#3B82F6",
|
|
648
|
+
borderRadius: "2px"
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
),
|
|
652
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
653
|
+
"button",
|
|
654
|
+
{
|
|
655
|
+
className: `qc-thumbnail ${isActive ? "qc-thumbnail--active" : ""}`,
|
|
656
|
+
draggable: true,
|
|
657
|
+
onDragStart: (e) => handleDragStart(e, index, thumbnailUrl),
|
|
658
|
+
onDragEnd: handleDragEnd,
|
|
659
|
+
onClick: () => onSelect(index),
|
|
660
|
+
style: {
|
|
661
|
+
position: "relative",
|
|
662
|
+
width: `${width}px`,
|
|
663
|
+
height: `${height}px`,
|
|
664
|
+
minWidth: `${width}px`,
|
|
665
|
+
minHeight: `${height}px`,
|
|
666
|
+
border: "none",
|
|
667
|
+
borderRadius: "5px",
|
|
668
|
+
overflow: "visible",
|
|
669
|
+
cursor: onReorder ? "grab" : "pointer",
|
|
670
|
+
opacity: isDragging ? 0.5 : 1,
|
|
671
|
+
transform: isActive ? "scale(1)" : "scale(0.95)",
|
|
672
|
+
transition: "all 0.2s ease",
|
|
673
|
+
backgroundColor: theme === "dark" ? "#333" : "#f5f5f5",
|
|
674
|
+
padding: 0,
|
|
675
|
+
boxShadow: isActive ? "0 0 0 2px #3B82F6, 0 2px 8px rgba(0,0,0,0.15)" : "0 1px 3px rgba(0,0,0,0.1)"
|
|
676
|
+
},
|
|
677
|
+
"aria-label": `Go to slide ${index + 1}: ${slide.name || ""}`,
|
|
678
|
+
children: [
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: "100%", height: "100%", borderRadius: "5px", overflow: "hidden" }, children: thumbnailUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
680
|
+
"img",
|
|
681
|
+
{
|
|
682
|
+
src: thumbnailUrl,
|
|
683
|
+
alt: slide.name || `Slide ${index + 1}`,
|
|
684
|
+
draggable: false,
|
|
685
|
+
style: {
|
|
686
|
+
width: "100%",
|
|
687
|
+
height: "100%",
|
|
688
|
+
objectFit: "cover"
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
692
|
+
"div",
|
|
693
|
+
{
|
|
694
|
+
style: {
|
|
695
|
+
width: "100%",
|
|
696
|
+
height: "100%",
|
|
697
|
+
display: "flex",
|
|
698
|
+
alignItems: "center",
|
|
699
|
+
justifyContent: "center",
|
|
700
|
+
color: theme === "dark" ? "#888" : "#666",
|
|
701
|
+
fontSize: "20px"
|
|
702
|
+
},
|
|
703
|
+
children: getSlideIcon(slide)
|
|
704
|
+
}
|
|
705
|
+
) }),
|
|
706
|
+
onDelete && isActive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
707
|
+
"div",
|
|
708
|
+
{
|
|
709
|
+
onClick: (e) => {
|
|
710
|
+
e.stopPropagation();
|
|
711
|
+
onDelete(index);
|
|
712
|
+
},
|
|
713
|
+
style: {
|
|
714
|
+
position: "absolute",
|
|
715
|
+
top: "-6px",
|
|
716
|
+
right: "-6px",
|
|
717
|
+
width: "20px",
|
|
718
|
+
height: "20px",
|
|
719
|
+
borderRadius: "50%",
|
|
720
|
+
backgroundColor: "#EF4444",
|
|
721
|
+
color: "white",
|
|
722
|
+
display: "flex",
|
|
723
|
+
alignItems: "center",
|
|
724
|
+
justifyContent: "center",
|
|
725
|
+
fontSize: "14px",
|
|
726
|
+
fontWeight: "bold",
|
|
727
|
+
cursor: "pointer",
|
|
728
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.3)",
|
|
729
|
+
transition: "transform 0.15s ease"
|
|
730
|
+
},
|
|
731
|
+
onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.1)",
|
|
732
|
+
onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
|
|
733
|
+
title: "Delete",
|
|
734
|
+
children: "\xD7"
|
|
735
|
+
}
|
|
736
|
+
)
|
|
737
|
+
]
|
|
738
|
+
}
|
|
739
|
+
)
|
|
740
|
+
]
|
|
741
|
+
},
|
|
742
|
+
slide.id
|
|
743
|
+
);
|
|
744
|
+
})
|
|
745
|
+
}
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/components/Carousel.tsx
|
|
750
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
751
|
+
function extractSlideUrl(slide) {
|
|
752
|
+
const layer = slide.layers?.[0];
|
|
753
|
+
if (!layer) return void 0;
|
|
754
|
+
const imageObj = layer.objects?.find((obj) => obj.type === "image");
|
|
755
|
+
if (imageObj && "src" in imageObj) {
|
|
756
|
+
return imageObj.src;
|
|
757
|
+
}
|
|
758
|
+
return void 0;
|
|
759
|
+
}
|
|
506
760
|
var defaultNavigation = {
|
|
507
761
|
arrows: true,
|
|
508
762
|
dots: true,
|
|
@@ -511,7 +765,7 @@ var defaultNavigation = {
|
|
|
511
765
|
touch: true,
|
|
512
766
|
mouseWheel: false
|
|
513
767
|
};
|
|
514
|
-
var Carousel = (0,
|
|
768
|
+
var Carousel = (0, import_react4.forwardRef)(
|
|
515
769
|
({
|
|
516
770
|
slides,
|
|
517
771
|
initialIndex = 0,
|
|
@@ -526,11 +780,41 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
526
780
|
style,
|
|
527
781
|
onSlideChange,
|
|
528
782
|
onFullscreenChange,
|
|
529
|
-
theme = "dark"
|
|
783
|
+
theme = "dark",
|
|
784
|
+
// Copy functionality
|
|
785
|
+
carouselInfo,
|
|
786
|
+
getSlideUrl,
|
|
787
|
+
onCopyCarousel,
|
|
788
|
+
onCopySlide,
|
|
789
|
+
// Thumbnail callbacks
|
|
790
|
+
onThumbnailReorder,
|
|
791
|
+
onThumbnailDelete
|
|
530
792
|
}, ref) => {
|
|
531
|
-
const containerRef = (0,
|
|
532
|
-
const [isFullscreen, setIsFullscreen] = (0,
|
|
533
|
-
const [touchStart, setTouchStart] = (0,
|
|
793
|
+
const containerRef = (0, import_react4.useRef)(null);
|
|
794
|
+
const [isFullscreen, setIsFullscreen] = (0, import_react4.useState)(false);
|
|
795
|
+
const [touchStart, setTouchStart] = (0, import_react4.useState)(null);
|
|
796
|
+
const [copiedState, setCopiedState] = (0, import_react4.useState)(null);
|
|
797
|
+
const copyToClipboard = (0, import_react4.useCallback)(async (text, type) => {
|
|
798
|
+
try {
|
|
799
|
+
await navigator.clipboard.writeText(text);
|
|
800
|
+
setCopiedState(type);
|
|
801
|
+
setTimeout(() => setCopiedState(null), 2e3);
|
|
802
|
+
} catch (err) {
|
|
803
|
+
console.error("Failed to copy:", err);
|
|
804
|
+
}
|
|
805
|
+
}, []);
|
|
806
|
+
const handleCopyCarousel = (0, import_react4.useCallback)(() => {
|
|
807
|
+
if (!carouselInfo) return;
|
|
808
|
+
const jsonStr = JSON.stringify(carouselInfo);
|
|
809
|
+
copyToClipboard(jsonStr, "carousel");
|
|
810
|
+
onCopyCarousel?.(carouselInfo);
|
|
811
|
+
}, [carouselInfo, copyToClipboard, onCopyCarousel]);
|
|
812
|
+
const handleCopySlide = (0, import_react4.useCallback)((slide) => {
|
|
813
|
+
const url = getSlideUrl ? getSlideUrl(slide) : extractSlideUrl(slide);
|
|
814
|
+
if (!url) return;
|
|
815
|
+
copyToClipboard(url, "slide");
|
|
816
|
+
onCopySlide?.(slide, url);
|
|
817
|
+
}, [getSlideUrl, copyToClipboard, onCopySlide]);
|
|
534
818
|
const nav = typeof navigation === "boolean" ? navigation ? defaultNavigation : {} : { ...defaultNavigation, ...navigation };
|
|
535
819
|
const {
|
|
536
820
|
currentIndex,
|
|
@@ -553,24 +837,24 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
553
837
|
autoplay,
|
|
554
838
|
onSlideChange
|
|
555
839
|
});
|
|
556
|
-
const enterFullscreen = (0,
|
|
840
|
+
const enterFullscreen = (0, import_react4.useCallback)(() => {
|
|
557
841
|
if (containerRef.current?.requestFullscreen) {
|
|
558
842
|
containerRef.current.requestFullscreen();
|
|
559
843
|
}
|
|
560
844
|
}, []);
|
|
561
|
-
const exitFullscreen = (0,
|
|
845
|
+
const exitFullscreen = (0, import_react4.useCallback)(() => {
|
|
562
846
|
if (document.fullscreenElement) {
|
|
563
847
|
document.exitFullscreen();
|
|
564
848
|
}
|
|
565
849
|
}, []);
|
|
566
|
-
const toggleFullscreen = (0,
|
|
850
|
+
const toggleFullscreen = (0, import_react4.useCallback)(() => {
|
|
567
851
|
if (isFullscreen) {
|
|
568
852
|
exitFullscreen();
|
|
569
853
|
} else {
|
|
570
854
|
enterFullscreen();
|
|
571
855
|
}
|
|
572
856
|
}, [isFullscreen, enterFullscreen, exitFullscreen]);
|
|
573
|
-
(0,
|
|
857
|
+
(0, import_react4.useEffect)(() => {
|
|
574
858
|
const handleFullscreenChange = () => {
|
|
575
859
|
const fs = document.fullscreenElement === containerRef.current;
|
|
576
860
|
setIsFullscreen(fs);
|
|
@@ -581,7 +865,7 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
581
865
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
582
866
|
};
|
|
583
867
|
}, [onFullscreenChange]);
|
|
584
|
-
(0,
|
|
868
|
+
(0, import_react4.useEffect)(() => {
|
|
585
869
|
if (!nav.keyboard) return;
|
|
586
870
|
const handleKeyDown = (e) => {
|
|
587
871
|
switch (e.key) {
|
|
@@ -651,7 +935,7 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
651
935
|
}
|
|
652
936
|
setTouchStart(null);
|
|
653
937
|
};
|
|
654
|
-
(0,
|
|
938
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({
|
|
655
939
|
next,
|
|
656
940
|
prev,
|
|
657
941
|
goTo,
|
|
@@ -679,200 +963,291 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
679
963
|
return base;
|
|
680
964
|
}
|
|
681
965
|
};
|
|
682
|
-
return /* @__PURE__ */ (0,
|
|
966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
683
967
|
"div",
|
|
684
968
|
{
|
|
685
|
-
|
|
686
|
-
className: `qc-carousel qc-carousel--${theme} ${isFullscreen ? "qc-carousel--fullscreen" : ""} ${className}`,
|
|
969
|
+
className: "qc-carousel-wrapper",
|
|
687
970
|
style: {
|
|
688
|
-
position: "relative",
|
|
689
971
|
width: "100%",
|
|
690
|
-
aspectRatio: isFullscreen ? "auto" : aspectRatio,
|
|
691
|
-
overflow: "hidden",
|
|
692
|
-
backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff",
|
|
693
972
|
...style
|
|
694
973
|
},
|
|
695
|
-
onTouchStart: handleTouchStart,
|
|
696
|
-
onTouchEnd: handleTouchEnd,
|
|
697
974
|
children: [
|
|
698
|
-
/* @__PURE__ */ (0,
|
|
975
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
699
976
|
"div",
|
|
700
977
|
{
|
|
701
|
-
|
|
978
|
+
ref: containerRef,
|
|
979
|
+
className: `qc-carousel qc-carousel--${theme} ${isFullscreen ? "qc-carousel--fullscreen" : ""} ${className}`,
|
|
702
980
|
style: {
|
|
703
|
-
|
|
704
|
-
width:
|
|
705
|
-
|
|
706
|
-
|
|
981
|
+
position: "relative",
|
|
982
|
+
width: "100%",
|
|
983
|
+
aspectRatio: isFullscreen ? "auto" : aspectRatio,
|
|
984
|
+
overflow: "hidden",
|
|
985
|
+
backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff"
|
|
707
986
|
},
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
style: {
|
|
740
|
-
position: "absolute",
|
|
741
|
-
left: "16px",
|
|
742
|
-
top: "50%",
|
|
743
|
-
transform: "translateY(-50%)",
|
|
744
|
-
width: "48px",
|
|
745
|
-
height: "48px",
|
|
746
|
-
borderRadius: "50%",
|
|
747
|
-
border: "none",
|
|
748
|
-
backgroundColor: "rgba(0,0,0,0.5)",
|
|
749
|
-
color: "white",
|
|
750
|
-
cursor: canGoPrev ? "pointer" : "not-allowed",
|
|
751
|
-
opacity: canGoPrev ? 1 : 0.3,
|
|
752
|
-
display: "flex",
|
|
753
|
-
alignItems: "center",
|
|
754
|
-
justifyContent: "center",
|
|
755
|
-
fontSize: "24px",
|
|
756
|
-
zIndex: 10
|
|
757
|
-
},
|
|
758
|
-
children: "\u2039"
|
|
759
|
-
}
|
|
760
|
-
),
|
|
761
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
762
|
-
"button",
|
|
763
|
-
{
|
|
764
|
-
className: "qc-carousel__arrow qc-carousel__arrow--next",
|
|
765
|
-
onClick: () => {
|
|
766
|
-
next();
|
|
767
|
-
handleInteraction();
|
|
768
|
-
},
|
|
769
|
-
disabled: !canGoNext,
|
|
770
|
-
"aria-label": "Next slide",
|
|
771
|
-
style: {
|
|
772
|
-
position: "absolute",
|
|
773
|
-
right: "16px",
|
|
774
|
-
top: "50%",
|
|
775
|
-
transform: "translateY(-50%)",
|
|
776
|
-
width: "48px",
|
|
777
|
-
height: "48px",
|
|
778
|
-
borderRadius: "50%",
|
|
779
|
-
border: "none",
|
|
780
|
-
backgroundColor: "rgba(0,0,0,0.5)",
|
|
781
|
-
color: "white",
|
|
782
|
-
cursor: canGoNext ? "pointer" : "not-allowed",
|
|
783
|
-
opacity: canGoNext ? 1 : 0.3,
|
|
784
|
-
display: "flex",
|
|
785
|
-
alignItems: "center",
|
|
786
|
-
justifyContent: "center",
|
|
787
|
-
fontSize: "24px",
|
|
788
|
-
zIndex: 10
|
|
789
|
-
},
|
|
790
|
-
children: "\u203A"
|
|
791
|
-
}
|
|
792
|
-
)
|
|
793
|
-
] }),
|
|
794
|
-
nav.dots && totalSlides > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
795
|
-
"div",
|
|
796
|
-
{
|
|
797
|
-
className: "qc-carousel__dots",
|
|
798
|
-
style: {
|
|
799
|
-
position: "absolute",
|
|
800
|
-
bottom: "16px",
|
|
801
|
-
left: "50%",
|
|
802
|
-
transform: "translateX(-50%)",
|
|
803
|
-
display: "flex",
|
|
804
|
-
gap: "8px",
|
|
805
|
-
zIndex: 10
|
|
806
|
-
},
|
|
807
|
-
children: slides.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
808
|
-
"button",
|
|
809
|
-
{
|
|
810
|
-
className: `qc-carousel__dot ${index === currentIndex ? "qc-carousel__dot--active" : ""}`,
|
|
811
|
-
onClick: () => {
|
|
812
|
-
goTo(index);
|
|
813
|
-
handleInteraction();
|
|
814
|
-
},
|
|
815
|
-
"aria-label": `Go to slide ${index + 1}`,
|
|
816
|
-
style: {
|
|
817
|
-
width: "10px",
|
|
818
|
-
height: "10px",
|
|
819
|
-
borderRadius: "50%",
|
|
820
|
-
border: "none",
|
|
821
|
-
backgroundColor: index === currentIndex ? "#E67E22" : "rgba(255,255,255,0.5)",
|
|
822
|
-
cursor: "pointer",
|
|
823
|
-
transition: "all 0.2s ease"
|
|
987
|
+
onTouchStart: handleTouchStart,
|
|
988
|
+
onTouchEnd: handleTouchEnd,
|
|
989
|
+
children: [
|
|
990
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
991
|
+
"div",
|
|
992
|
+
{
|
|
993
|
+
className: "qc-carousel__slides",
|
|
994
|
+
style: {
|
|
995
|
+
display: transition === "slide" ? "flex" : "block",
|
|
996
|
+
width: transition === "slide" ? `${totalSlides * 100}%` : "100%",
|
|
997
|
+
height: "100%",
|
|
998
|
+
...getTransitionStyle()
|
|
999
|
+
},
|
|
1000
|
+
children: slides.map((slide, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1001
|
+
"div",
|
|
1002
|
+
{
|
|
1003
|
+
className: `qc-carousel__slide ${index === currentIndex ? "qc-carousel__slide--active" : ""}`,
|
|
1004
|
+
style: {
|
|
1005
|
+
width: transition === "slide" ? `${100 / totalSlides}%` : "100%",
|
|
1006
|
+
height: "100%",
|
|
1007
|
+
position: transition === "slide" ? "relative" : "absolute",
|
|
1008
|
+
top: 0,
|
|
1009
|
+
left: 0,
|
|
1010
|
+
opacity: transition === "fade" ? index === currentIndex ? 1 : 0 : 1,
|
|
1011
|
+
transition: `opacity ${transitionDuration}ms ease-in-out`,
|
|
1012
|
+
pointerEvents: index === currentIndex ? "auto" : "none"
|
|
1013
|
+
},
|
|
1014
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SlideRenderer, { slide, isActive: index === currentIndex, slideIndex: index })
|
|
1015
|
+
},
|
|
1016
|
+
slide.id
|
|
1017
|
+
))
|
|
824
1018
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1019
|
+
),
|
|
1020
|
+
nav.arrows && totalSlides > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1021
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1022
|
+
"button",
|
|
1023
|
+
{
|
|
1024
|
+
className: "qc-carousel__arrow qc-carousel__arrow--prev",
|
|
1025
|
+
onClick: () => {
|
|
1026
|
+
prev();
|
|
1027
|
+
handleInteraction();
|
|
1028
|
+
},
|
|
1029
|
+
disabled: !canGoPrev,
|
|
1030
|
+
"aria-label": "Previous slide",
|
|
1031
|
+
style: {
|
|
1032
|
+
position: "absolute",
|
|
1033
|
+
left: "16px",
|
|
1034
|
+
top: "50%",
|
|
1035
|
+
transform: "translateY(-50%)",
|
|
1036
|
+
width: "48px",
|
|
1037
|
+
height: "48px",
|
|
1038
|
+
borderRadius: "50%",
|
|
1039
|
+
border: "none",
|
|
1040
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1041
|
+
color: "white",
|
|
1042
|
+
cursor: canGoPrev ? "pointer" : "not-allowed",
|
|
1043
|
+
opacity: canGoPrev ? 1 : 0.3,
|
|
1044
|
+
display: "flex",
|
|
1045
|
+
alignItems: "center",
|
|
1046
|
+
justifyContent: "center",
|
|
1047
|
+
fontSize: "24px",
|
|
1048
|
+
zIndex: 10
|
|
1049
|
+
},
|
|
1050
|
+
children: "\u2039"
|
|
1051
|
+
}
|
|
1052
|
+
),
|
|
1053
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1054
|
+
"button",
|
|
1055
|
+
{
|
|
1056
|
+
className: "qc-carousel__arrow qc-carousel__arrow--next",
|
|
1057
|
+
onClick: () => {
|
|
1058
|
+
next();
|
|
1059
|
+
handleInteraction();
|
|
1060
|
+
},
|
|
1061
|
+
disabled: !canGoNext,
|
|
1062
|
+
"aria-label": "Next slide",
|
|
1063
|
+
style: {
|
|
1064
|
+
position: "absolute",
|
|
1065
|
+
right: "16px",
|
|
1066
|
+
top: "50%",
|
|
1067
|
+
transform: "translateY(-50%)",
|
|
1068
|
+
width: "48px",
|
|
1069
|
+
height: "48px",
|
|
1070
|
+
borderRadius: "50%",
|
|
1071
|
+
border: "none",
|
|
1072
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1073
|
+
color: "white",
|
|
1074
|
+
cursor: canGoNext ? "pointer" : "not-allowed",
|
|
1075
|
+
opacity: canGoNext ? 1 : 0.3,
|
|
1076
|
+
display: "flex",
|
|
1077
|
+
alignItems: "center",
|
|
1078
|
+
justifyContent: "center",
|
|
1079
|
+
fontSize: "24px",
|
|
1080
|
+
zIndex: 10
|
|
1081
|
+
},
|
|
1082
|
+
children: "\u203A"
|
|
1083
|
+
}
|
|
1084
|
+
)
|
|
1085
|
+
] }),
|
|
1086
|
+
nav.dots && totalSlides > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1087
|
+
"div",
|
|
1088
|
+
{
|
|
1089
|
+
className: "qc-carousel__dots",
|
|
1090
|
+
style: {
|
|
1091
|
+
position: "absolute",
|
|
1092
|
+
bottom: "16px",
|
|
1093
|
+
left: "50%",
|
|
1094
|
+
transform: "translateX(-50%)",
|
|
1095
|
+
display: "flex",
|
|
1096
|
+
gap: "8px",
|
|
1097
|
+
zIndex: 10
|
|
1098
|
+
},
|
|
1099
|
+
children: slides.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1100
|
+
"button",
|
|
1101
|
+
{
|
|
1102
|
+
className: `qc-carousel__dot ${index === currentIndex ? "qc-carousel__dot--active" : ""}`,
|
|
1103
|
+
onClick: () => {
|
|
1104
|
+
goTo(index);
|
|
1105
|
+
handleInteraction();
|
|
1106
|
+
},
|
|
1107
|
+
"aria-label": `Go to slide ${index + 1}`,
|
|
1108
|
+
style: {
|
|
1109
|
+
width: "10px",
|
|
1110
|
+
height: "10px",
|
|
1111
|
+
borderRadius: "50%",
|
|
1112
|
+
border: "none",
|
|
1113
|
+
backgroundColor: index === currentIndex ? "#E67E22" : "rgba(255,255,255,0.5)",
|
|
1114
|
+
cursor: "pointer",
|
|
1115
|
+
transition: "all 0.2s ease"
|
|
1116
|
+
}
|
|
1117
|
+
},
|
|
1118
|
+
index
|
|
1119
|
+
))
|
|
1120
|
+
}
|
|
1121
|
+
),
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1123
|
+
"div",
|
|
1124
|
+
{
|
|
1125
|
+
className: "qc-carousel__top-right-buttons",
|
|
1126
|
+
style: {
|
|
1127
|
+
position: "absolute",
|
|
1128
|
+
top: "16px",
|
|
1129
|
+
right: "16px",
|
|
1130
|
+
display: "flex",
|
|
1131
|
+
flexDirection: "column",
|
|
1132
|
+
alignItems: "center",
|
|
1133
|
+
gap: "8px",
|
|
1134
|
+
zIndex: 10
|
|
1135
|
+
},
|
|
1136
|
+
children: [
|
|
1137
|
+
allowFullscreen && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1138
|
+
"button",
|
|
1139
|
+
{
|
|
1140
|
+
className: "qc-carousel__fullscreen",
|
|
1141
|
+
onClick: toggleFullscreen,
|
|
1142
|
+
"aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
|
|
1143
|
+
style: {
|
|
1144
|
+
width: "40px",
|
|
1145
|
+
height: "40px",
|
|
1146
|
+
borderRadius: "8px",
|
|
1147
|
+
border: "none",
|
|
1148
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1149
|
+
color: "white",
|
|
1150
|
+
cursor: "pointer",
|
|
1151
|
+
display: "flex",
|
|
1152
|
+
alignItems: "center",
|
|
1153
|
+
justifyContent: "center",
|
|
1154
|
+
fontSize: "18px"
|
|
1155
|
+
},
|
|
1156
|
+
children: isFullscreen ? "\u22A0" : "\u229E"
|
|
1157
|
+
}
|
|
1158
|
+
),
|
|
1159
|
+
currentSlide && (getSlideUrl || extractSlideUrl(currentSlide)) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1160
|
+
"button",
|
|
1161
|
+
{
|
|
1162
|
+
className: "qc-carousel__copy-slide",
|
|
1163
|
+
onClick: () => handleCopySlide(currentSlide),
|
|
1164
|
+
"aria-label": "Copy image URL",
|
|
1165
|
+
title: "Copy image URL",
|
|
1166
|
+
style: {
|
|
1167
|
+
width: "40px",
|
|
1168
|
+
height: "40px",
|
|
1169
|
+
borderRadius: "8px",
|
|
1170
|
+
border: "none",
|
|
1171
|
+
backgroundColor: copiedState === "slide" ? "rgba(34,197,94,0.8)" : "rgba(0,0,0,0.5)",
|
|
1172
|
+
color: "white",
|
|
1173
|
+
cursor: "pointer",
|
|
1174
|
+
display: "flex",
|
|
1175
|
+
alignItems: "center",
|
|
1176
|
+
justifyContent: "center",
|
|
1177
|
+
fontSize: "16px",
|
|
1178
|
+
transition: "background-color 0.2s ease"
|
|
1179
|
+
},
|
|
1180
|
+
children: copiedState === "slide" ? "\u2713" : "\u{1F517}"
|
|
1181
|
+
}
|
|
1182
|
+
)
|
|
1183
|
+
]
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
carouselInfo && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1187
|
+
"button",
|
|
1188
|
+
{
|
|
1189
|
+
className: "qc-carousel__copy-carousel",
|
|
1190
|
+
onClick: handleCopyCarousel,
|
|
1191
|
+
"aria-label": "Copy carousel link",
|
|
1192
|
+
title: "Copy carousel link",
|
|
1193
|
+
style: {
|
|
1194
|
+
position: "absolute",
|
|
1195
|
+
top: "16px",
|
|
1196
|
+
right: allowFullscreen ? "72px" : "16px",
|
|
1197
|
+
width: "40px",
|
|
1198
|
+
height: "40px",
|
|
1199
|
+
borderRadius: "8px",
|
|
1200
|
+
border: "none",
|
|
1201
|
+
backgroundColor: copiedState === "carousel" ? "rgba(34,197,94,0.8)" : "rgba(0,0,0,0.5)",
|
|
1202
|
+
color: "white",
|
|
1203
|
+
cursor: "pointer",
|
|
1204
|
+
display: "flex",
|
|
1205
|
+
alignItems: "center",
|
|
1206
|
+
justifyContent: "center",
|
|
1207
|
+
fontSize: "16px",
|
|
1208
|
+
transition: "background-color 0.2s ease",
|
|
1209
|
+
zIndex: 10
|
|
1210
|
+
},
|
|
1211
|
+
children: copiedState === "carousel" ? "\u2713" : "\u{1F4CB}"
|
|
1212
|
+
}
|
|
1213
|
+
),
|
|
1214
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1215
|
+
"div",
|
|
1216
|
+
{
|
|
1217
|
+
className: "qc-carousel__counter",
|
|
1218
|
+
style: {
|
|
1219
|
+
position: "absolute",
|
|
1220
|
+
top: "16px",
|
|
1221
|
+
left: "16px",
|
|
1222
|
+
padding: "4px 12px",
|
|
1223
|
+
borderRadius: "4px",
|
|
1224
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1225
|
+
color: "white",
|
|
1226
|
+
fontSize: "14px",
|
|
1227
|
+
zIndex: 10
|
|
1228
|
+
},
|
|
1229
|
+
children: [
|
|
1230
|
+
currentIndex + 1,
|
|
1231
|
+
" / ",
|
|
1232
|
+
totalSlides
|
|
1233
|
+
]
|
|
1234
|
+
}
|
|
1235
|
+
)
|
|
1236
|
+
]
|
|
854
1237
|
}
|
|
855
1238
|
),
|
|
856
|
-
/* @__PURE__ */ (0,
|
|
857
|
-
|
|
1239
|
+
nav.thumbnails && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1240
|
+
Thumbnails,
|
|
858
1241
|
{
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
padding: "4px 12px",
|
|
865
|
-
borderRadius: "4px",
|
|
866
|
-
backgroundColor: "rgba(0,0,0,0.5)",
|
|
867
|
-
color: "white",
|
|
868
|
-
fontSize: "14px",
|
|
869
|
-
zIndex: 10
|
|
1242
|
+
slides,
|
|
1243
|
+
currentIndex,
|
|
1244
|
+
onSelect: (index) => {
|
|
1245
|
+
goTo(index);
|
|
1246
|
+
handleInteraction();
|
|
870
1247
|
},
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
totalSlides
|
|
875
|
-
]
|
|
1248
|
+
onReorder: onThumbnailReorder,
|
|
1249
|
+
onDelete: onThumbnailDelete,
|
|
1250
|
+
theme: theme === "auto" ? "light" : theme
|
|
876
1251
|
}
|
|
877
1252
|
)
|
|
878
1253
|
]
|
|
@@ -882,131 +1257,6 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
882
1257
|
);
|
|
883
1258
|
Carousel.displayName = "Carousel";
|
|
884
1259
|
|
|
885
|
-
// src/components/Thumbnails.tsx
|
|
886
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
887
|
-
function getThumbnail(slide) {
|
|
888
|
-
if (slide.thumbnail) return slide.thumbnail;
|
|
889
|
-
for (const layer of slide.layers) {
|
|
890
|
-
for (const obj of layer.objects) {
|
|
891
|
-
if (obj.type === "image") {
|
|
892
|
-
return obj.src;
|
|
893
|
-
}
|
|
894
|
-
if (obj.type === "video" && obj.poster) {
|
|
895
|
-
return obj.poster || null;
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
if (slide.background?.type === "image") {
|
|
900
|
-
return slide.background.value;
|
|
901
|
-
}
|
|
902
|
-
return null;
|
|
903
|
-
}
|
|
904
|
-
function getSlideIcon(slide) {
|
|
905
|
-
for (const layer of slide.layers) {
|
|
906
|
-
for (const obj of layer.objects) {
|
|
907
|
-
switch (obj.type) {
|
|
908
|
-
case "video":
|
|
909
|
-
return "\u25B6";
|
|
910
|
-
case "audio":
|
|
911
|
-
return "\u{1F3B5}";
|
|
912
|
-
case "text":
|
|
913
|
-
return "\u{1F4DD}";
|
|
914
|
-
case "component":
|
|
915
|
-
return "\u26A1";
|
|
916
|
-
case "shape":
|
|
917
|
-
return "\u25FC";
|
|
918
|
-
case "group":
|
|
919
|
-
return "\u{1F4C1}";
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
return "\u{1F5BC}";
|
|
924
|
-
}
|
|
925
|
-
function Thumbnails({
|
|
926
|
-
slides,
|
|
927
|
-
currentIndex,
|
|
928
|
-
onSelect,
|
|
929
|
-
position = "bottom",
|
|
930
|
-
size = "medium",
|
|
931
|
-
theme = "dark"
|
|
932
|
-
}) {
|
|
933
|
-
const isVertical = position === "left" || position === "right";
|
|
934
|
-
const sizeMap = {
|
|
935
|
-
small: { width: 48, height: 36 },
|
|
936
|
-
medium: { width: 80, height: 60 },
|
|
937
|
-
large: { width: 120, height: 90 }
|
|
938
|
-
};
|
|
939
|
-
const { width, height } = sizeMap[size];
|
|
940
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
941
|
-
"div",
|
|
942
|
-
{
|
|
943
|
-
className: `qc-thumbnails qc-thumbnails--${position} qc-thumbnails--${theme}`,
|
|
944
|
-
style: {
|
|
945
|
-
display: "flex",
|
|
946
|
-
flexDirection: isVertical ? "column" : "row",
|
|
947
|
-
gap: "8px",
|
|
948
|
-
padding: "8px",
|
|
949
|
-
overflowX: isVertical ? "hidden" : "auto",
|
|
950
|
-
overflowY: isVertical ? "auto" : "hidden",
|
|
951
|
-
backgroundColor: theme === "dark" ? "rgba(0,0,0,0.8)" : "rgba(255,255,255,0.9)"
|
|
952
|
-
},
|
|
953
|
-
children: slides.map((slide, index) => {
|
|
954
|
-
const thumbnailUrl = getThumbnail(slide);
|
|
955
|
-
const isActive = index === currentIndex;
|
|
956
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
957
|
-
"button",
|
|
958
|
-
{
|
|
959
|
-
className: `qc-thumbnail ${isActive ? "qc-thumbnail--active" : ""}`,
|
|
960
|
-
onClick: () => onSelect(index),
|
|
961
|
-
style: {
|
|
962
|
-
width: `${width}px`,
|
|
963
|
-
height: `${height}px`,
|
|
964
|
-
minWidth: `${width}px`,
|
|
965
|
-
minHeight: `${height}px`,
|
|
966
|
-
border: isActive ? "2px solid #E67E22" : "2px solid transparent",
|
|
967
|
-
borderRadius: "4px",
|
|
968
|
-
overflow: "hidden",
|
|
969
|
-
cursor: "pointer",
|
|
970
|
-
opacity: isActive ? 1 : 0.6,
|
|
971
|
-
transition: "all 0.2s ease",
|
|
972
|
-
backgroundColor: theme === "dark" ? "#333" : "#eee",
|
|
973
|
-
padding: 0
|
|
974
|
-
},
|
|
975
|
-
"aria-label": `Go to slide ${index + 1}: ${slide.name || ""}`,
|
|
976
|
-
children: thumbnailUrl ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
977
|
-
"img",
|
|
978
|
-
{
|
|
979
|
-
src: thumbnailUrl,
|
|
980
|
-
alt: slide.name || `Slide ${index + 1}`,
|
|
981
|
-
style: {
|
|
982
|
-
width: "100%",
|
|
983
|
-
height: "100%",
|
|
984
|
-
objectFit: "cover"
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
988
|
-
"div",
|
|
989
|
-
{
|
|
990
|
-
style: {
|
|
991
|
-
width: "100%",
|
|
992
|
-
height: "100%",
|
|
993
|
-
display: "flex",
|
|
994
|
-
alignItems: "center",
|
|
995
|
-
justifyContent: "center",
|
|
996
|
-
color: theme === "dark" ? "#888" : "#666",
|
|
997
|
-
fontSize: "12px"
|
|
998
|
-
},
|
|
999
|
-
children: getSlideIcon(slide)
|
|
1000
|
-
}
|
|
1001
|
-
)
|
|
1002
|
-
},
|
|
1003
|
-
slide.id
|
|
1004
|
-
);
|
|
1005
|
-
})
|
|
1006
|
-
}
|
|
1007
|
-
);
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
1260
|
// src/types.ts
|
|
1011
1261
|
function createSimpleSlide(id, objects, options) {
|
|
1012
1262
|
return {
|
|
@@ -1049,6 +1299,81 @@ function createImageSlide(id, src, options) {
|
|
|
1049
1299
|
}
|
|
1050
1300
|
|
|
1051
1301
|
// src/index.ts
|
|
1302
|
+
var import_react5 = __toESM(require("react"));
|
|
1303
|
+
function MarkdownContent({ url, filename }) {
|
|
1304
|
+
const [content, setContent] = (0, import_react5.useState)("");
|
|
1305
|
+
const [loading, setLoading] = (0, import_react5.useState)(true);
|
|
1306
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
1307
|
+
(0, import_react5.useEffect)(() => {
|
|
1308
|
+
fetch(url).then((res) => {
|
|
1309
|
+
if (!res.ok) throw new Error("Failed to load");
|
|
1310
|
+
return res.text();
|
|
1311
|
+
}).then((text) => {
|
|
1312
|
+
setContent(text);
|
|
1313
|
+
setLoading(false);
|
|
1314
|
+
}).catch((err) => {
|
|
1315
|
+
setError(err.message);
|
|
1316
|
+
setLoading(false);
|
|
1317
|
+
});
|
|
1318
|
+
}, [url]);
|
|
1319
|
+
const containerStyle = {
|
|
1320
|
+
width: "100%",
|
|
1321
|
+
height: "100%",
|
|
1322
|
+
display: "flex",
|
|
1323
|
+
flexDirection: "column",
|
|
1324
|
+
backgroundColor: "#f0f9ff",
|
|
1325
|
+
padding: "16px",
|
|
1326
|
+
overflow: "auto"
|
|
1327
|
+
};
|
|
1328
|
+
const centeredStyle = {
|
|
1329
|
+
...containerStyle,
|
|
1330
|
+
alignItems: "center",
|
|
1331
|
+
justifyContent: "center"
|
|
1332
|
+
};
|
|
1333
|
+
const headerStyle = {
|
|
1334
|
+
display: "flex",
|
|
1335
|
+
alignItems: "center",
|
|
1336
|
+
gap: "8px",
|
|
1337
|
+
marginBottom: "12px",
|
|
1338
|
+
paddingBottom: "8px",
|
|
1339
|
+
borderBottom: "1px solid #bae6fd"
|
|
1340
|
+
};
|
|
1341
|
+
const preStyle = {
|
|
1342
|
+
flex: 1,
|
|
1343
|
+
fontSize: "14px",
|
|
1344
|
+
color: "#374151",
|
|
1345
|
+
whiteSpace: "pre-wrap",
|
|
1346
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
1347
|
+
overflow: "auto",
|
|
1348
|
+
margin: 0
|
|
1349
|
+
};
|
|
1350
|
+
if (loading) {
|
|
1351
|
+
return import_react5.default.createElement(
|
|
1352
|
+
"div",
|
|
1353
|
+
{ style: centeredStyle },
|
|
1354
|
+
import_react5.default.createElement("span", { style: { color: "#9ca3af" } }, "Loading...")
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
if (error) {
|
|
1358
|
+
return import_react5.default.createElement(
|
|
1359
|
+
"div",
|
|
1360
|
+
{ style: centeredStyle },
|
|
1361
|
+
import_react5.default.createElement("span", { style: { color: "#ef4444" } }, "Failed to load markdown")
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
const children = [];
|
|
1365
|
+
if (filename) {
|
|
1366
|
+
children.push(
|
|
1367
|
+
import_react5.default.createElement(
|
|
1368
|
+
"div",
|
|
1369
|
+
{ key: "header", style: headerStyle },
|
|
1370
|
+
import_react5.default.createElement("span", { style: { color: "#0284c7", fontWeight: 500, fontSize: "14px" } }, "\u{1F4C4} " + filename)
|
|
1371
|
+
)
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
children.push(import_react5.default.createElement("pre", { key: "content", style: preStyle }, content));
|
|
1375
|
+
return import_react5.default.createElement("div", { style: containerStyle }, ...children);
|
|
1376
|
+
}
|
|
1052
1377
|
var createSlide = {
|
|
1053
1378
|
/**
|
|
1054
1379
|
* Create a simple image slide (single image, full slide)
|
|
@@ -1091,8 +1416,77 @@ var createSlide = {
|
|
|
1091
1416
|
position: { x: 0, y: 0 },
|
|
1092
1417
|
size: { width: 100, height: 100, unit: "percent" }
|
|
1093
1418
|
}], options);
|
|
1419
|
+
},
|
|
1420
|
+
/**
|
|
1421
|
+
* Create a slide to display a markdown file
|
|
1422
|
+
*/
|
|
1423
|
+
markdown: (id, url, options) => {
|
|
1424
|
+
const thumbnail = options?.thumbnail ?? markdownThumbnailSvg;
|
|
1425
|
+
return createSimpleSlide(id, [{
|
|
1426
|
+
id: `${id}-markdown`,
|
|
1427
|
+
type: "component",
|
|
1428
|
+
render: () => import_react5.default.createElement(MarkdownContent, { url, filename: options?.filename }),
|
|
1429
|
+
position: { x: 0, y: 0 },
|
|
1430
|
+
size: { width: 100, height: 100, unit: "percent" }
|
|
1431
|
+
}], { thumbnail });
|
|
1432
|
+
},
|
|
1433
|
+
/**
|
|
1434
|
+
* Create a slide to display an audio file
|
|
1435
|
+
*/
|
|
1436
|
+
audio: (id, url, options) => {
|
|
1437
|
+
const thumbnail = options?.thumbnail ?? audioThumbnailSvg;
|
|
1438
|
+
return createSimpleSlide(id, [{
|
|
1439
|
+
id: `${id}-audio`,
|
|
1440
|
+
type: "component",
|
|
1441
|
+
render: () => import_react5.default.createElement(AudioContent, { url, filename: options?.filename }),
|
|
1442
|
+
position: { x: 0, y: 0 },
|
|
1443
|
+
size: { width: 100, height: 100, unit: "percent" }
|
|
1444
|
+
}], { thumbnail });
|
|
1094
1445
|
}
|
|
1095
1446
|
};
|
|
1447
|
+
var markdownThumbnailSvg = "data:image/svg+xml," + encodeURIComponent(
|
|
1448
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect fill="#e0f2fe" width="64" height="64"/><path fill="#0284c7" d="M12 20v24h40V20H12zm4 20V24h4l4 6 4-6h4v16h-4v-9l-4 6-4-6v9h-4zm24-8v8h-4l6 8 6-8h-4v-8h-4z"/></svg>'
|
|
1449
|
+
);
|
|
1450
|
+
var audioThumbnailSvg = "data:image/svg+xml," + encodeURIComponent(
|
|
1451
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect fill="#171717" width="64" height="64"/><path fill="#34d399" d="M20 24v16h4V24zm8-4v24h4V20zm8 8v8h4v-8zm8-4v16h4V24z"/></svg>'
|
|
1452
|
+
);
|
|
1453
|
+
function AudioContent({ url, filename }) {
|
|
1454
|
+
const containerStyle = {
|
|
1455
|
+
width: "100%",
|
|
1456
|
+
height: "100%",
|
|
1457
|
+
display: "flex",
|
|
1458
|
+
flexDirection: "column",
|
|
1459
|
+
alignItems: "center",
|
|
1460
|
+
justifyContent: "center",
|
|
1461
|
+
backgroundColor: "#171717",
|
|
1462
|
+
padding: "16px"
|
|
1463
|
+
};
|
|
1464
|
+
const iconStyle = {
|
|
1465
|
+
width: "48px",
|
|
1466
|
+
height: "48px",
|
|
1467
|
+
color: "#34d399",
|
|
1468
|
+
marginBottom: "12px"
|
|
1469
|
+
};
|
|
1470
|
+
const filenameStyle = {
|
|
1471
|
+
color: "#d1d5db",
|
|
1472
|
+
fontSize: "14px",
|
|
1473
|
+
marginBottom: "16px"
|
|
1474
|
+
};
|
|
1475
|
+
const children = [
|
|
1476
|
+
import_react5.default.createElement(
|
|
1477
|
+
"svg",
|
|
1478
|
+
{ key: "icon", style: iconStyle, viewBox: "0 0 24 24", fill: "currentColor" },
|
|
1479
|
+
import_react5.default.createElement("path", { d: "M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z" })
|
|
1480
|
+
)
|
|
1481
|
+
];
|
|
1482
|
+
if (filename) {
|
|
1483
|
+
children.push(import_react5.default.createElement("span", { key: "filename", style: filenameStyle }, filename));
|
|
1484
|
+
}
|
|
1485
|
+
children.push(
|
|
1486
|
+
import_react5.default.createElement("audio", { key: "audio", src: url, controls: true, style: { width: "100%", maxWidth: "280px" } })
|
|
1487
|
+
);
|
|
1488
|
+
return import_react5.default.createElement("div", { style: containerStyle }, ...children);
|
|
1489
|
+
}
|
|
1096
1490
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1097
1491
|
0 && (module.exports = {
|
|
1098
1492
|
Carousel,
|