@qwanyx/carousel 0.1.0 → 0.1.3
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 +52 -6
- package/dist/index.d.ts +52 -6
- package/dist/index.js +803 -308
- package/dist/index.mjs +785 -300
- package/package.json +9 -3
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,66 @@ 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,
|
|
792
|
+
// Image editing
|
|
793
|
+
onImageEdit,
|
|
794
|
+
editorAspectRatio = "4/3",
|
|
795
|
+
ImageEditor
|
|
530
796
|
}, ref) => {
|
|
531
|
-
const containerRef = (0,
|
|
532
|
-
const [isFullscreen, setIsFullscreen] = (0,
|
|
533
|
-
const [touchStart, setTouchStart] = (0,
|
|
797
|
+
const containerRef = (0, import_react4.useRef)(null);
|
|
798
|
+
const [isFullscreen, setIsFullscreen] = (0, import_react4.useState)(false);
|
|
799
|
+
const [touchStart, setTouchStart] = (0, import_react4.useState)(null);
|
|
800
|
+
const [copiedState, setCopiedState] = (0, import_react4.useState)(null);
|
|
801
|
+
const [editingIndex, setEditingIndex] = (0, import_react4.useState)(null);
|
|
802
|
+
const canEdit = ImageEditor !== void 0 && onImageEdit !== void 0;
|
|
803
|
+
const handleSlideDoubleClick = (0, import_react4.useCallback)((index) => {
|
|
804
|
+
if (!canEdit) return;
|
|
805
|
+
setEditingIndex(index);
|
|
806
|
+
}, [canEdit]);
|
|
807
|
+
const handleImageSave = (0, import_react4.useCallback)((blob) => {
|
|
808
|
+
if (editingIndex !== null && onImageEdit) {
|
|
809
|
+
onImageEdit(editingIndex, blob);
|
|
810
|
+
}
|
|
811
|
+
setEditingIndex(null);
|
|
812
|
+
}, [editingIndex, onImageEdit]);
|
|
813
|
+
const handleEditorCancel = (0, import_react4.useCallback)(() => {
|
|
814
|
+
setEditingIndex(null);
|
|
815
|
+
}, []);
|
|
816
|
+
const getEditingImageUrl = (0, import_react4.useCallback)(() => {
|
|
817
|
+
if (editingIndex === null) return void 0;
|
|
818
|
+
const slide = slides[editingIndex];
|
|
819
|
+
if (!slide) return void 0;
|
|
820
|
+
return getSlideUrl ? getSlideUrl(slide) : extractSlideUrl(slide);
|
|
821
|
+
}, [editingIndex, slides, getSlideUrl]);
|
|
822
|
+
const copyToClipboard = (0, import_react4.useCallback)(async (text, type) => {
|
|
823
|
+
try {
|
|
824
|
+
await navigator.clipboard.writeText(text);
|
|
825
|
+
setCopiedState(type);
|
|
826
|
+
setTimeout(() => setCopiedState(null), 2e3);
|
|
827
|
+
} catch (err) {
|
|
828
|
+
console.error("Failed to copy:", err);
|
|
829
|
+
}
|
|
830
|
+
}, []);
|
|
831
|
+
const handleCopyCarousel = (0, import_react4.useCallback)(() => {
|
|
832
|
+
if (!carouselInfo) return;
|
|
833
|
+
const jsonStr = JSON.stringify(carouselInfo);
|
|
834
|
+
copyToClipboard(jsonStr, "carousel");
|
|
835
|
+
onCopyCarousel?.(carouselInfo);
|
|
836
|
+
}, [carouselInfo, copyToClipboard, onCopyCarousel]);
|
|
837
|
+
const handleCopySlide = (0, import_react4.useCallback)((slide) => {
|
|
838
|
+
const url = getSlideUrl ? getSlideUrl(slide) : extractSlideUrl(slide);
|
|
839
|
+
if (!url) return;
|
|
840
|
+
copyToClipboard(url, "slide");
|
|
841
|
+
onCopySlide?.(slide, url);
|
|
842
|
+
}, [getSlideUrl, copyToClipboard, onCopySlide]);
|
|
534
843
|
const nav = typeof navigation === "boolean" ? navigation ? defaultNavigation : {} : { ...defaultNavigation, ...navigation };
|
|
535
844
|
const {
|
|
536
845
|
currentIndex,
|
|
@@ -553,24 +862,24 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
553
862
|
autoplay,
|
|
554
863
|
onSlideChange
|
|
555
864
|
});
|
|
556
|
-
const enterFullscreen = (0,
|
|
865
|
+
const enterFullscreen = (0, import_react4.useCallback)(() => {
|
|
557
866
|
if (containerRef.current?.requestFullscreen) {
|
|
558
867
|
containerRef.current.requestFullscreen();
|
|
559
868
|
}
|
|
560
869
|
}, []);
|
|
561
|
-
const exitFullscreen = (0,
|
|
870
|
+
const exitFullscreen = (0, import_react4.useCallback)(() => {
|
|
562
871
|
if (document.fullscreenElement) {
|
|
563
872
|
document.exitFullscreen();
|
|
564
873
|
}
|
|
565
874
|
}, []);
|
|
566
|
-
const toggleFullscreen = (0,
|
|
875
|
+
const toggleFullscreen = (0, import_react4.useCallback)(() => {
|
|
567
876
|
if (isFullscreen) {
|
|
568
877
|
exitFullscreen();
|
|
569
878
|
} else {
|
|
570
879
|
enterFullscreen();
|
|
571
880
|
}
|
|
572
881
|
}, [isFullscreen, enterFullscreen, exitFullscreen]);
|
|
573
|
-
(0,
|
|
882
|
+
(0, import_react4.useEffect)(() => {
|
|
574
883
|
const handleFullscreenChange = () => {
|
|
575
884
|
const fs = document.fullscreenElement === containerRef.current;
|
|
576
885
|
setIsFullscreen(fs);
|
|
@@ -581,7 +890,7 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
581
890
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
582
891
|
};
|
|
583
892
|
}, [onFullscreenChange]);
|
|
584
|
-
(0,
|
|
893
|
+
(0, import_react4.useEffect)(() => {
|
|
585
894
|
if (!nav.keyboard) return;
|
|
586
895
|
const handleKeyDown = (e) => {
|
|
587
896
|
switch (e.key) {
|
|
@@ -651,7 +960,7 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
651
960
|
}
|
|
652
961
|
setTouchStart(null);
|
|
653
962
|
};
|
|
654
|
-
(0,
|
|
963
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({
|
|
655
964
|
next,
|
|
656
965
|
prev,
|
|
657
966
|
goTo,
|
|
@@ -679,199 +988,366 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
679
988
|
return base;
|
|
680
989
|
}
|
|
681
990
|
};
|
|
682
|
-
return /* @__PURE__ */ (0,
|
|
991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
683
992
|
"div",
|
|
684
993
|
{
|
|
685
|
-
|
|
686
|
-
className: `qc-carousel qc-carousel--${theme} ${isFullscreen ? "qc-carousel--fullscreen" : ""} ${className}`,
|
|
994
|
+
className: "qc-carousel-wrapper",
|
|
687
995
|
style: {
|
|
688
|
-
position: "relative",
|
|
689
996
|
width: "100%",
|
|
690
|
-
aspectRatio: isFullscreen ? "auto" : aspectRatio,
|
|
691
|
-
overflow: "hidden",
|
|
692
|
-
backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff",
|
|
693
997
|
...style
|
|
694
998
|
},
|
|
695
|
-
onTouchStart: handleTouchStart,
|
|
696
|
-
onTouchEnd: handleTouchEnd,
|
|
697
999
|
children: [
|
|
698
|
-
/* @__PURE__ */ (0,
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
699
1001
|
"div",
|
|
700
1002
|
{
|
|
701
|
-
|
|
1003
|
+
ref: containerRef,
|
|
1004
|
+
className: `qc-carousel qc-carousel--${theme} ${isFullscreen ? "qc-carousel--fullscreen" : ""} ${className}`,
|
|
702
1005
|
style: {
|
|
703
|
-
|
|
704
|
-
width:
|
|
705
|
-
|
|
706
|
-
|
|
1006
|
+
position: "relative",
|
|
1007
|
+
width: "100%",
|
|
1008
|
+
aspectRatio: isFullscreen ? "auto" : aspectRatio,
|
|
1009
|
+
overflow: "hidden",
|
|
1010
|
+
backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff"
|
|
707
1011
|
},
|
|
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
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1012
|
+
onTouchStart: handleTouchStart,
|
|
1013
|
+
onTouchEnd: handleTouchEnd,
|
|
1014
|
+
children: [
|
|
1015
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1016
|
+
"div",
|
|
1017
|
+
{
|
|
1018
|
+
className: "qc-carousel__slides",
|
|
1019
|
+
style: {
|
|
1020
|
+
display: transition === "slide" ? "flex" : "block",
|
|
1021
|
+
width: transition === "slide" ? `${totalSlides * 100}%` : "100%",
|
|
1022
|
+
height: "100%",
|
|
1023
|
+
...getTransitionStyle()
|
|
1024
|
+
},
|
|
1025
|
+
children: slides.map((slide, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1026
|
+
"div",
|
|
1027
|
+
{
|
|
1028
|
+
className: `qc-carousel__slide ${index === currentIndex ? "qc-carousel__slide--active" : ""}`,
|
|
1029
|
+
style: {
|
|
1030
|
+
width: transition === "slide" ? `${100 / totalSlides}%` : "100%",
|
|
1031
|
+
height: "100%",
|
|
1032
|
+
position: transition === "slide" ? "relative" : "absolute",
|
|
1033
|
+
top: 0,
|
|
1034
|
+
left: 0,
|
|
1035
|
+
opacity: transition === "fade" ? index === currentIndex ? 1 : 0 : 1,
|
|
1036
|
+
transition: `opacity ${transitionDuration}ms ease-in-out`,
|
|
1037
|
+
pointerEvents: index === currentIndex ? "auto" : "none",
|
|
1038
|
+
cursor: canEdit ? "pointer" : "default"
|
|
1039
|
+
},
|
|
1040
|
+
onDoubleClick: () => handleSlideDoubleClick(index),
|
|
1041
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SlideRenderer, { slide, isActive: index === currentIndex, slideIndex: index })
|
|
1042
|
+
},
|
|
1043
|
+
slide.id
|
|
1044
|
+
))
|
|
1045
|
+
}
|
|
1046
|
+
),
|
|
1047
|
+
nav.arrows && totalSlides > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1048
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1049
|
+
"button",
|
|
1050
|
+
{
|
|
1051
|
+
className: "qc-carousel__arrow qc-carousel__arrow--prev",
|
|
1052
|
+
onClick: () => {
|
|
1053
|
+
prev();
|
|
1054
|
+
handleInteraction();
|
|
1055
|
+
},
|
|
1056
|
+
disabled: !canGoPrev,
|
|
1057
|
+
"aria-label": "Previous slide",
|
|
1058
|
+
style: {
|
|
1059
|
+
position: "absolute",
|
|
1060
|
+
left: "16px",
|
|
1061
|
+
top: "50%",
|
|
1062
|
+
transform: "translateY(-50%)",
|
|
1063
|
+
width: "48px",
|
|
1064
|
+
height: "48px",
|
|
1065
|
+
borderRadius: "50%",
|
|
1066
|
+
border: "none",
|
|
1067
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1068
|
+
color: "white",
|
|
1069
|
+
cursor: canGoPrev ? "pointer" : "not-allowed",
|
|
1070
|
+
opacity: canGoPrev ? 1 : 0.3,
|
|
1071
|
+
display: "flex",
|
|
1072
|
+
alignItems: "center",
|
|
1073
|
+
justifyContent: "center",
|
|
1074
|
+
fontSize: "24px",
|
|
1075
|
+
zIndex: 10
|
|
1076
|
+
},
|
|
1077
|
+
children: "\u2039"
|
|
1078
|
+
}
|
|
1079
|
+
),
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1081
|
+
"button",
|
|
1082
|
+
{
|
|
1083
|
+
className: "qc-carousel__arrow qc-carousel__arrow--next",
|
|
1084
|
+
onClick: () => {
|
|
1085
|
+
next();
|
|
1086
|
+
handleInteraction();
|
|
1087
|
+
},
|
|
1088
|
+
disabled: !canGoNext,
|
|
1089
|
+
"aria-label": "Next slide",
|
|
1090
|
+
style: {
|
|
1091
|
+
position: "absolute",
|
|
1092
|
+
right: "16px",
|
|
1093
|
+
top: "50%",
|
|
1094
|
+
transform: "translateY(-50%)",
|
|
1095
|
+
width: "48px",
|
|
1096
|
+
height: "48px",
|
|
1097
|
+
borderRadius: "50%",
|
|
1098
|
+
border: "none",
|
|
1099
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1100
|
+
color: "white",
|
|
1101
|
+
cursor: canGoNext ? "pointer" : "not-allowed",
|
|
1102
|
+
opacity: canGoNext ? 1 : 0.3,
|
|
1103
|
+
display: "flex",
|
|
1104
|
+
alignItems: "center",
|
|
1105
|
+
justifyContent: "center",
|
|
1106
|
+
fontSize: "24px",
|
|
1107
|
+
zIndex: 10
|
|
1108
|
+
},
|
|
1109
|
+
children: "\u203A"
|
|
1110
|
+
}
|
|
1111
|
+
)
|
|
1112
|
+
] }),
|
|
1113
|
+
nav.dots && totalSlides > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1114
|
+
"div",
|
|
1115
|
+
{
|
|
1116
|
+
className: "qc-carousel__dots",
|
|
1117
|
+
style: {
|
|
1118
|
+
position: "absolute",
|
|
1119
|
+
bottom: "16px",
|
|
1120
|
+
left: "50%",
|
|
1121
|
+
transform: "translateX(-50%)",
|
|
1122
|
+
display: "flex",
|
|
1123
|
+
gap: "8px",
|
|
1124
|
+
zIndex: 10
|
|
1125
|
+
},
|
|
1126
|
+
children: slides.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1127
|
+
"button",
|
|
1128
|
+
{
|
|
1129
|
+
className: `qc-carousel__dot ${index === currentIndex ? "qc-carousel__dot--active" : ""}`,
|
|
1130
|
+
onClick: () => {
|
|
1131
|
+
goTo(index);
|
|
1132
|
+
handleInteraction();
|
|
1133
|
+
},
|
|
1134
|
+
"aria-label": `Go to slide ${index + 1}`,
|
|
1135
|
+
style: {
|
|
1136
|
+
width: "10px",
|
|
1137
|
+
height: "10px",
|
|
1138
|
+
borderRadius: "50%",
|
|
1139
|
+
border: "none",
|
|
1140
|
+
backgroundColor: index === currentIndex ? "#E67E22" : "rgba(255,255,255,0.5)",
|
|
1141
|
+
cursor: "pointer",
|
|
1142
|
+
transition: "all 0.2s ease"
|
|
1143
|
+
}
|
|
1144
|
+
},
|
|
1145
|
+
index
|
|
1146
|
+
))
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1150
|
+
"div",
|
|
1151
|
+
{
|
|
1152
|
+
className: "qc-carousel__top-right-buttons",
|
|
1153
|
+
style: {
|
|
1154
|
+
position: "absolute",
|
|
1155
|
+
top: "16px",
|
|
1156
|
+
right: "16px",
|
|
1157
|
+
display: "flex",
|
|
1158
|
+
flexDirection: "column",
|
|
1159
|
+
alignItems: "center",
|
|
1160
|
+
gap: "8px",
|
|
1161
|
+
zIndex: 10
|
|
1162
|
+
},
|
|
1163
|
+
children: [
|
|
1164
|
+
allowFullscreen && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1165
|
+
"button",
|
|
1166
|
+
{
|
|
1167
|
+
className: "qc-carousel__fullscreen",
|
|
1168
|
+
onClick: toggleFullscreen,
|
|
1169
|
+
"aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
|
|
1170
|
+
style: {
|
|
1171
|
+
width: "40px",
|
|
1172
|
+
height: "40px",
|
|
1173
|
+
borderRadius: "8px",
|
|
1174
|
+
border: "none",
|
|
1175
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1176
|
+
color: "white",
|
|
1177
|
+
cursor: "pointer",
|
|
1178
|
+
display: "flex",
|
|
1179
|
+
alignItems: "center",
|
|
1180
|
+
justifyContent: "center",
|
|
1181
|
+
fontSize: "18px"
|
|
1182
|
+
},
|
|
1183
|
+
children: isFullscreen ? "\u22A0" : "\u229E"
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
currentSlide && (getSlideUrl || extractSlideUrl(currentSlide)) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1187
|
+
"button",
|
|
1188
|
+
{
|
|
1189
|
+
className: "qc-carousel__copy-slide",
|
|
1190
|
+
onClick: () => handleCopySlide(currentSlide),
|
|
1191
|
+
"aria-label": "Copy image URL",
|
|
1192
|
+
title: "Copy image URL",
|
|
1193
|
+
style: {
|
|
1194
|
+
width: "40px",
|
|
1195
|
+
height: "40px",
|
|
1196
|
+
borderRadius: "8px",
|
|
1197
|
+
border: "none",
|
|
1198
|
+
backgroundColor: copiedState === "slide" ? "rgba(34,197,94,0.8)" : "rgba(0,0,0,0.5)",
|
|
1199
|
+
color: "white",
|
|
1200
|
+
cursor: "pointer",
|
|
1201
|
+
display: "flex",
|
|
1202
|
+
alignItems: "center",
|
|
1203
|
+
justifyContent: "center",
|
|
1204
|
+
fontSize: "16px",
|
|
1205
|
+
transition: "background-color 0.2s ease"
|
|
1206
|
+
},
|
|
1207
|
+
children: copiedState === "slide" ? "\u2713" : "\u{1F517}"
|
|
1208
|
+
}
|
|
1209
|
+
)
|
|
1210
|
+
]
|
|
824
1211
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1212
|
+
),
|
|
1213
|
+
carouselInfo && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1214
|
+
"button",
|
|
1215
|
+
{
|
|
1216
|
+
className: "qc-carousel__copy-carousel",
|
|
1217
|
+
onClick: handleCopyCarousel,
|
|
1218
|
+
"aria-label": "Copy carousel link",
|
|
1219
|
+
title: "Copy carousel link",
|
|
1220
|
+
style: {
|
|
1221
|
+
position: "absolute",
|
|
1222
|
+
top: "16px",
|
|
1223
|
+
right: allowFullscreen ? "72px" : "16px",
|
|
1224
|
+
width: "40px",
|
|
1225
|
+
height: "40px",
|
|
1226
|
+
borderRadius: "8px",
|
|
1227
|
+
border: "none",
|
|
1228
|
+
backgroundColor: copiedState === "carousel" ? "rgba(34,197,94,0.8)" : "rgba(0,0,0,0.5)",
|
|
1229
|
+
color: "white",
|
|
1230
|
+
cursor: "pointer",
|
|
1231
|
+
display: "flex",
|
|
1232
|
+
alignItems: "center",
|
|
1233
|
+
justifyContent: "center",
|
|
1234
|
+
fontSize: "16px",
|
|
1235
|
+
transition: "background-color 0.2s ease",
|
|
1236
|
+
zIndex: 10
|
|
1237
|
+
},
|
|
1238
|
+
children: copiedState === "carousel" ? "\u2713" : "\u{1F4CB}"
|
|
1239
|
+
}
|
|
1240
|
+
),
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1242
|
+
"div",
|
|
1243
|
+
{
|
|
1244
|
+
className: "qc-carousel__counter",
|
|
1245
|
+
style: {
|
|
1246
|
+
position: "absolute",
|
|
1247
|
+
top: "16px",
|
|
1248
|
+
left: "16px",
|
|
1249
|
+
padding: "4px 12px",
|
|
1250
|
+
borderRadius: "4px",
|
|
1251
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1252
|
+
color: "white",
|
|
1253
|
+
fontSize: "14px",
|
|
1254
|
+
zIndex: 10
|
|
1255
|
+
},
|
|
1256
|
+
children: [
|
|
1257
|
+
currentIndex + 1,
|
|
1258
|
+
" / ",
|
|
1259
|
+
totalSlides
|
|
1260
|
+
]
|
|
1261
|
+
}
|
|
1262
|
+
)
|
|
1263
|
+
]
|
|
828
1264
|
}
|
|
829
1265
|
),
|
|
830
|
-
|
|
831
|
-
|
|
1266
|
+
nav.thumbnails && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1267
|
+
Thumbnails,
|
|
832
1268
|
{
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
top: "16px",
|
|
839
|
-
right: "16px",
|
|
840
|
-
width: "40px",
|
|
841
|
-
height: "40px",
|
|
842
|
-
borderRadius: "8px",
|
|
843
|
-
border: "none",
|
|
844
|
-
backgroundColor: "rgba(0,0,0,0.5)",
|
|
845
|
-
color: "white",
|
|
846
|
-
cursor: "pointer",
|
|
847
|
-
display: "flex",
|
|
848
|
-
alignItems: "center",
|
|
849
|
-
justifyContent: "center",
|
|
850
|
-
fontSize: "18px",
|
|
851
|
-
zIndex: 10
|
|
1269
|
+
slides,
|
|
1270
|
+
currentIndex,
|
|
1271
|
+
onSelect: (index) => {
|
|
1272
|
+
goTo(index);
|
|
1273
|
+
handleInteraction();
|
|
852
1274
|
},
|
|
853
|
-
|
|
1275
|
+
onReorder: onThumbnailReorder,
|
|
1276
|
+
onDelete: onThumbnailDelete,
|
|
1277
|
+
theme: theme === "auto" ? "light" : theme
|
|
854
1278
|
}
|
|
855
1279
|
),
|
|
856
|
-
/* @__PURE__ */ (0,
|
|
1280
|
+
editingIndex !== null && ImageEditor && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
857
1281
|
"div",
|
|
858
1282
|
{
|
|
859
|
-
className: "qc-
|
|
1283
|
+
className: "qc-carousel__editor-overlay",
|
|
860
1284
|
style: {
|
|
861
|
-
position: "
|
|
862
|
-
top:
|
|
863
|
-
left:
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1285
|
+
position: "fixed",
|
|
1286
|
+
top: 0,
|
|
1287
|
+
left: 0,
|
|
1288
|
+
right: 0,
|
|
1289
|
+
bottom: 0,
|
|
1290
|
+
zIndex: 9999,
|
|
1291
|
+
backgroundColor: theme === "dark" ? "#1a1a1a" : "#f5f5f5",
|
|
1292
|
+
display: "flex",
|
|
1293
|
+
flexDirection: "column"
|
|
870
1294
|
},
|
|
871
1295
|
children: [
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1296
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1297
|
+
"div",
|
|
1298
|
+
{
|
|
1299
|
+
style: {
|
|
1300
|
+
padding: "12px 16px",
|
|
1301
|
+
display: "flex",
|
|
1302
|
+
alignItems: "center",
|
|
1303
|
+
justifyContent: "space-between",
|
|
1304
|
+
borderBottom: `1px solid ${theme === "dark" ? "#333" : "#ddd"}`,
|
|
1305
|
+
backgroundColor: theme === "dark" ? "#242424" : "#fff"
|
|
1306
|
+
},
|
|
1307
|
+
children: [
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: {
|
|
1309
|
+
color: theme === "dark" ? "#fff" : "#333",
|
|
1310
|
+
fontWeight: 500,
|
|
1311
|
+
fontSize: "16px"
|
|
1312
|
+
}, children: [
|
|
1313
|
+
"Edit Image ",
|
|
1314
|
+
editingIndex + 1,
|
|
1315
|
+
" / ",
|
|
1316
|
+
totalSlides
|
|
1317
|
+
] }),
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1319
|
+
"button",
|
|
1320
|
+
{
|
|
1321
|
+
onClick: handleEditorCancel,
|
|
1322
|
+
style: {
|
|
1323
|
+
background: "none",
|
|
1324
|
+
border: "none",
|
|
1325
|
+
color: theme === "dark" ? "#aaa" : "#666",
|
|
1326
|
+
cursor: "pointer",
|
|
1327
|
+
fontSize: "24px",
|
|
1328
|
+
lineHeight: 1,
|
|
1329
|
+
padding: "4px"
|
|
1330
|
+
},
|
|
1331
|
+
children: "\xD7"
|
|
1332
|
+
}
|
|
1333
|
+
)
|
|
1334
|
+
]
|
|
1335
|
+
}
|
|
1336
|
+
),
|
|
1337
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: (() => {
|
|
1338
|
+
const imageUrl = getEditingImageUrl();
|
|
1339
|
+
if (!imageUrl) return null;
|
|
1340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1341
|
+
ImageEditor,
|
|
1342
|
+
{
|
|
1343
|
+
src: imageUrl,
|
|
1344
|
+
onSave: handleImageSave,
|
|
1345
|
+
onCancel: handleEditorCancel,
|
|
1346
|
+
aspectRatio: editorAspectRatio,
|
|
1347
|
+
theme: theme === "auto" ? "dark" : theme
|
|
1348
|
+
}
|
|
1349
|
+
);
|
|
1350
|
+
})() })
|
|
875
1351
|
]
|
|
876
1352
|
}
|
|
877
1353
|
)
|
|
@@ -882,131 +1358,6 @@ var Carousel = (0, import_react3.forwardRef)(
|
|
|
882
1358
|
);
|
|
883
1359
|
Carousel.displayName = "Carousel";
|
|
884
1360
|
|
|
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
1361
|
// src/types.ts
|
|
1011
1362
|
function createSimpleSlide(id, objects, options) {
|
|
1012
1363
|
return {
|
|
@@ -1049,6 +1400,81 @@ function createImageSlide(id, src, options) {
|
|
|
1049
1400
|
}
|
|
1050
1401
|
|
|
1051
1402
|
// src/index.ts
|
|
1403
|
+
var import_react5 = __toESM(require("react"));
|
|
1404
|
+
function MarkdownContent({ url, filename }) {
|
|
1405
|
+
const [content, setContent] = (0, import_react5.useState)("");
|
|
1406
|
+
const [loading, setLoading] = (0, import_react5.useState)(true);
|
|
1407
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
1408
|
+
(0, import_react5.useEffect)(() => {
|
|
1409
|
+
fetch(url).then((res) => {
|
|
1410
|
+
if (!res.ok) throw new Error("Failed to load");
|
|
1411
|
+
return res.text();
|
|
1412
|
+
}).then((text) => {
|
|
1413
|
+
setContent(text);
|
|
1414
|
+
setLoading(false);
|
|
1415
|
+
}).catch((err) => {
|
|
1416
|
+
setError(err.message);
|
|
1417
|
+
setLoading(false);
|
|
1418
|
+
});
|
|
1419
|
+
}, [url]);
|
|
1420
|
+
const containerStyle = {
|
|
1421
|
+
width: "100%",
|
|
1422
|
+
height: "100%",
|
|
1423
|
+
display: "flex",
|
|
1424
|
+
flexDirection: "column",
|
|
1425
|
+
backgroundColor: "#f0f9ff",
|
|
1426
|
+
padding: "16px",
|
|
1427
|
+
overflow: "auto"
|
|
1428
|
+
};
|
|
1429
|
+
const centeredStyle = {
|
|
1430
|
+
...containerStyle,
|
|
1431
|
+
alignItems: "center",
|
|
1432
|
+
justifyContent: "center"
|
|
1433
|
+
};
|
|
1434
|
+
const headerStyle = {
|
|
1435
|
+
display: "flex",
|
|
1436
|
+
alignItems: "center",
|
|
1437
|
+
gap: "8px",
|
|
1438
|
+
marginBottom: "12px",
|
|
1439
|
+
paddingBottom: "8px",
|
|
1440
|
+
borderBottom: "1px solid #bae6fd"
|
|
1441
|
+
};
|
|
1442
|
+
const preStyle = {
|
|
1443
|
+
flex: 1,
|
|
1444
|
+
fontSize: "14px",
|
|
1445
|
+
color: "#374151",
|
|
1446
|
+
whiteSpace: "pre-wrap",
|
|
1447
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
1448
|
+
overflow: "auto",
|
|
1449
|
+
margin: 0
|
|
1450
|
+
};
|
|
1451
|
+
if (loading) {
|
|
1452
|
+
return import_react5.default.createElement(
|
|
1453
|
+
"div",
|
|
1454
|
+
{ style: centeredStyle },
|
|
1455
|
+
import_react5.default.createElement("span", { style: { color: "#9ca3af" } }, "Loading...")
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
if (error) {
|
|
1459
|
+
return import_react5.default.createElement(
|
|
1460
|
+
"div",
|
|
1461
|
+
{ style: centeredStyle },
|
|
1462
|
+
import_react5.default.createElement("span", { style: { color: "#ef4444" } }, "Failed to load markdown")
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1465
|
+
const children = [];
|
|
1466
|
+
if (filename) {
|
|
1467
|
+
children.push(
|
|
1468
|
+
import_react5.default.createElement(
|
|
1469
|
+
"div",
|
|
1470
|
+
{ key: "header", style: headerStyle },
|
|
1471
|
+
import_react5.default.createElement("span", { style: { color: "#0284c7", fontWeight: 500, fontSize: "14px" } }, "\u{1F4C4} " + filename)
|
|
1472
|
+
)
|
|
1473
|
+
);
|
|
1474
|
+
}
|
|
1475
|
+
children.push(import_react5.default.createElement("pre", { key: "content", style: preStyle }, content));
|
|
1476
|
+
return import_react5.default.createElement("div", { style: containerStyle }, ...children);
|
|
1477
|
+
}
|
|
1052
1478
|
var createSlide = {
|
|
1053
1479
|
/**
|
|
1054
1480
|
* Create a simple image slide (single image, full slide)
|
|
@@ -1091,8 +1517,77 @@ var createSlide = {
|
|
|
1091
1517
|
position: { x: 0, y: 0 },
|
|
1092
1518
|
size: { width: 100, height: 100, unit: "percent" }
|
|
1093
1519
|
}], options);
|
|
1520
|
+
},
|
|
1521
|
+
/**
|
|
1522
|
+
* Create a slide to display a markdown file
|
|
1523
|
+
*/
|
|
1524
|
+
markdown: (id, url, options) => {
|
|
1525
|
+
const thumbnail = options?.thumbnail ?? markdownThumbnailSvg;
|
|
1526
|
+
return createSimpleSlide(id, [{
|
|
1527
|
+
id: `${id}-markdown`,
|
|
1528
|
+
type: "component",
|
|
1529
|
+
render: () => import_react5.default.createElement(MarkdownContent, { url, filename: options?.filename }),
|
|
1530
|
+
position: { x: 0, y: 0 },
|
|
1531
|
+
size: { width: 100, height: 100, unit: "percent" }
|
|
1532
|
+
}], { thumbnail });
|
|
1533
|
+
},
|
|
1534
|
+
/**
|
|
1535
|
+
* Create a slide to display an audio file
|
|
1536
|
+
*/
|
|
1537
|
+
audio: (id, url, options) => {
|
|
1538
|
+
const thumbnail = options?.thumbnail ?? audioThumbnailSvg;
|
|
1539
|
+
return createSimpleSlide(id, [{
|
|
1540
|
+
id: `${id}-audio`,
|
|
1541
|
+
type: "component",
|
|
1542
|
+
render: () => import_react5.default.createElement(AudioContent, { url, filename: options?.filename }),
|
|
1543
|
+
position: { x: 0, y: 0 },
|
|
1544
|
+
size: { width: 100, height: 100, unit: "percent" }
|
|
1545
|
+
}], { thumbnail });
|
|
1094
1546
|
}
|
|
1095
1547
|
};
|
|
1548
|
+
var markdownThumbnailSvg = "data:image/svg+xml," + encodeURIComponent(
|
|
1549
|
+
'<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>'
|
|
1550
|
+
);
|
|
1551
|
+
var audioThumbnailSvg = "data:image/svg+xml," + encodeURIComponent(
|
|
1552
|
+
'<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>'
|
|
1553
|
+
);
|
|
1554
|
+
function AudioContent({ url, filename }) {
|
|
1555
|
+
const containerStyle = {
|
|
1556
|
+
width: "100%",
|
|
1557
|
+
height: "100%",
|
|
1558
|
+
display: "flex",
|
|
1559
|
+
flexDirection: "column",
|
|
1560
|
+
alignItems: "center",
|
|
1561
|
+
justifyContent: "center",
|
|
1562
|
+
backgroundColor: "#171717",
|
|
1563
|
+
padding: "16px"
|
|
1564
|
+
};
|
|
1565
|
+
const iconStyle = {
|
|
1566
|
+
width: "48px",
|
|
1567
|
+
height: "48px",
|
|
1568
|
+
color: "#34d399",
|
|
1569
|
+
marginBottom: "12px"
|
|
1570
|
+
};
|
|
1571
|
+
const filenameStyle = {
|
|
1572
|
+
color: "#d1d5db",
|
|
1573
|
+
fontSize: "14px",
|
|
1574
|
+
marginBottom: "16px"
|
|
1575
|
+
};
|
|
1576
|
+
const children = [
|
|
1577
|
+
import_react5.default.createElement(
|
|
1578
|
+
"svg",
|
|
1579
|
+
{ key: "icon", style: iconStyle, viewBox: "0 0 24 24", fill: "currentColor" },
|
|
1580
|
+
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" })
|
|
1581
|
+
)
|
|
1582
|
+
];
|
|
1583
|
+
if (filename) {
|
|
1584
|
+
children.push(import_react5.default.createElement("span", { key: "filename", style: filenameStyle }, filename));
|
|
1585
|
+
}
|
|
1586
|
+
children.push(
|
|
1587
|
+
import_react5.default.createElement("audio", { key: "audio", src: url, controls: true, style: { width: "100%", maxWidth: "280px" } })
|
|
1588
|
+
);
|
|
1589
|
+
return import_react5.default.createElement("div", { style: containerStyle }, ...children);
|
|
1590
|
+
}
|
|
1096
1591
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1097
1592
|
0 && (module.exports = {
|
|
1098
1593
|
Carousel,
|