@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.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 import_react3 = require("react");
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/Carousel.tsx
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, import_react3.forwardRef)(
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, import_react3.useRef)(null);
532
- const [isFullscreen, setIsFullscreen] = (0, import_react3.useState)(false);
533
- const [touchStart, setTouchStart] = (0, import_react3.useState)(null);
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)(() => {
870
+ const exitFullscreen = (0, import_react4.useCallback)(() => {
562
871
  if (document.fullscreenElement) {
563
872
  document.exitFullscreen();
564
873
  }
565
874
  }, []);
566
- const toggleFullscreen = (0, import_react3.useCallback)(() => {
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, import_react3.useEffect)(() => {
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, import_react3.useEffect)(() => {
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, import_react3.useImperativeHandle)(ref, () => ({
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, import_jsx_runtime2.jsxs)(
991
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
683
992
  "div",
684
993
  {
685
- ref: containerRef,
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, import_jsx_runtime2.jsx)(
1000
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
699
1001
  "div",
700
1002
  {
701
- className: "qc-carousel__slides",
1003
+ ref: containerRef,
1004
+ className: `qc-carousel qc-carousel--${theme} ${isFullscreen ? "qc-carousel--fullscreen" : ""} ${className}`,
702
1005
  style: {
703
- display: transition === "slide" ? "flex" : "block",
704
- width: transition === "slide" ? `${totalSlides * 100}%` : "100%",
705
- height: "100%",
706
- ...getTransitionStyle()
1006
+ position: "relative",
1007
+ width: "100%",
1008
+ aspectRatio: isFullscreen ? "auto" : aspectRatio,
1009
+ overflow: "hidden",
1010
+ backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff"
707
1011
  },
708
- children: slides.map((slide, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
709
- "div",
710
- {
711
- className: `qc-carousel__slide ${index === currentIndex ? "qc-carousel__slide--active" : ""}`,
712
- style: {
713
- width: transition === "slide" ? `${100 / totalSlides}%` : "100%",
714
- height: "100%",
715
- position: transition === "slide" ? "relative" : "absolute",
716
- top: 0,
717
- left: 0,
718
- opacity: transition === "fade" ? index === currentIndex ? 1 : 0 : 1,
719
- transition: `opacity ${transitionDuration}ms ease-in-out`,
720
- pointerEvents: index === currentIndex ? "auto" : "none"
721
- },
722
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SlideRenderer, { slide, isActive: index === currentIndex, slideIndex: index })
723
- },
724
- slide.id
725
- ))
726
- }
727
- ),
728
- nav.arrows && totalSlides > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
729
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
730
- "button",
731
- {
732
- className: "qc-carousel__arrow qc-carousel__arrow--prev",
733
- onClick: () => {
734
- prev();
735
- handleInteraction();
736
- },
737
- disabled: !canGoPrev,
738
- "aria-label": "Previous slide",
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"
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
- index
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
- allowFullscreen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
831
- "button",
1266
+ nav.thumbnails && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1267
+ Thumbnails,
832
1268
  {
833
- className: "qc-carousel__fullscreen",
834
- onClick: toggleFullscreen,
835
- "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
836
- style: {
837
- position: "absolute",
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
- children: isFullscreen ? "\u22A0" : "\u229E"
1275
+ onReorder: onThumbnailReorder,
1276
+ onDelete: onThumbnailDelete,
1277
+ theme: theme === "auto" ? "light" : theme
854
1278
  }
855
1279
  ),
856
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1280
+ editingIndex !== null && ImageEditor && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
857
1281
  "div",
858
1282
  {
859
- className: "qc-carousel__counter",
1283
+ className: "qc-carousel__editor-overlay",
860
1284
  style: {
861
- position: "absolute",
862
- top: "16px",
863
- left: "16px",
864
- padding: "4px 12px",
865
- borderRadius: "4px",
866
- backgroundColor: "rgba(0,0,0,0.5)",
867
- color: "white",
868
- fontSize: "14px",
869
- zIndex: 10
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
- currentIndex + 1,
873
- " / ",
874
- totalSlides
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,