pxengine 0.1.75 → 0.1.76

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.cts CHANGED
@@ -3078,6 +3078,12 @@ interface PresentationJobCardProps {
3078
3078
  * e.g. /api/agents-proxy/jobs/{job_id}/status
3079
3079
  */
3080
3080
  pollUrl?: string;
3081
+ /**
3082
+ * Shareable link copied when the user clicks Share.
3083
+ * Falls back to formats.html_url if not provided.
3084
+ * Pass a /p/{id} permanent URL once that route exists.
3085
+ */
3086
+ shareUrl?: string;
3081
3087
  className?: string;
3082
3088
  onAction?: (action: string, payload?: any) => void;
3083
3089
  sendMessage?: (message: string) => void;
package/dist/index.d.ts CHANGED
@@ -3078,6 +3078,12 @@ interface PresentationJobCardProps {
3078
3078
  * e.g. /api/agents-proxy/jobs/{job_id}/status
3079
3079
  */
3080
3080
  pollUrl?: string;
3081
+ /**
3082
+ * Shareable link copied when the user clicks Share.
3083
+ * Falls back to formats.html_url if not provided.
3084
+ * Pass a /p/{id} permanent URL once that route exists.
3085
+ */
3086
+ shareUrl?: string;
3081
3087
  className?: string;
3082
3088
  onAction?: (action: string, payload?: any) => void;
3083
3089
  sendMessage?: (message: string) => void;
package/dist/index.mjs CHANGED
@@ -38525,7 +38525,7 @@ var NextStepCard = ({
38525
38525
  ] });
38526
38526
 
38527
38527
  // src/molecules/generic/PresentationJobCard/PresentationJobCard.tsx
38528
- import { useEffect as useEffect6, useRef as useRef5, useState as useState10, useCallback as useCallback4 } from "react";
38528
+ import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef5, useState as useState10 } from "react";
38529
38529
  import { Fragment as Fragment5, jsx as jsx146, jsxs as jsxs108 } from "react/jsx-runtime";
38530
38530
  var DownloadIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
38531
38531
  /* @__PURE__ */ jsx146("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
@@ -38542,23 +38542,26 @@ var CloseIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "16", height: "16"
38542
38542
  ] });
38543
38543
  var ChevronLeft2 = () => /* @__PURE__ */ jsx146("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx146("polyline", { points: "15 18 9 12 15 6" }) });
38544
38544
  var ChevronRight2 = () => /* @__PURE__ */ jsx146("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx146("polyline", { points: "9 18 15 12 9 6" }) });
38545
+ var ExpandIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
38546
+ /* @__PURE__ */ jsx146("polyline", { points: "15 3 21 3 21 9" }),
38547
+ /* @__PURE__ */ jsx146("polyline", { points: "9 21 3 21 3 15" }),
38548
+ /* @__PURE__ */ jsx146("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
38549
+ /* @__PURE__ */ jsx146("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
38550
+ ] });
38551
+ var ShareIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
38552
+ /* @__PURE__ */ jsx146("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
38553
+ /* @__PURE__ */ jsx146("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
38554
+ ] });
38555
+ var CheckIcon = () => /* @__PURE__ */ jsx146("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx146("polyline", { points: "20 6 9 17 4 12" }) });
38545
38556
  var Skel = ({ className, style }) => /* @__PURE__ */ jsx146("div", { className: cn("animate-pulse rounded-md bg-zinc-800/60", className), style });
38546
38557
  var FORMATS = [
38547
- {
38548
- key: "pptx_url",
38549
- label: "PowerPoint",
38550
- ext: ".pptx",
38551
- emoji: "\u{1F4CA}",
38552
- desc: "Editable slides \u2014 open in Microsoft PowerPoint or Google Slides",
38553
- accent: { text: "text-orange-400", bg: "bg-orange-500/10 border-orange-500/20", pill: "bg-orange-500/15 text-orange-400 border-orange-500/25" }
38554
- },
38555
38558
  {
38556
38559
  key: "pdf_url",
38557
38560
  label: "PDF",
38558
38561
  ext: ".pdf",
38559
38562
  emoji: "\u{1F4C4}",
38560
38563
  desc: "Print-ready, fixed layout \u2014 open in any PDF viewer",
38561
- accent: { text: "text-red-400", bg: "bg-red-500/10 border-red-500/20", pill: "bg-red-500/15 text-red-400 border-red-500/25" }
38564
+ accent: { text: "text-red-400", bg: "bg-red-500/10 border-red-500/20" }
38562
38565
  },
38563
38566
  {
38564
38567
  key: "html_url",
@@ -38566,29 +38569,21 @@ var FORMATS = [
38566
38569
  ext: ".html",
38567
38570
  emoji: "\u{1F310}",
38568
38571
  desc: "Interactive web presentation \u2014 download and open in browser",
38569
- accent: { text: "text-indigo-400", bg: "bg-indigo-500/10 border-indigo-500/20", pill: "bg-indigo-500/15 text-indigo-400 border-indigo-500/25" }
38572
+ accent: { text: "text-indigo-400", bg: "bg-indigo-500/10 border-indigo-500/20" }
38570
38573
  }
38571
38574
  ];
38572
38575
  var ExportModal = ({ formats, title, onClose }) => {
38573
38576
  const available = FORMATS.filter((f) => formats[f.key]);
38574
38577
  const filename = title.replace(/[^a-z0-9]/gi, "-").toLowerCase();
38575
38578
  const [downloadingKey, setDownloadingKey] = useState10(null);
38576
- const buildDownloadHref = (url, ext) => {
38577
- const downloadName = `${filename}${ext}`;
38578
- return `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(downloadName)}`;
38579
- };
38580
38579
  const handleDownload = async (fmtKey, url, ext) => {
38581
- if (downloadingKey) {
38582
- return;
38583
- }
38584
- const downloadHref = buildDownloadHref(url, ext);
38580
+ if (downloadingKey) return;
38585
38581
  const downloadName = `${filename}${ext}`;
38582
+ const href = `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(downloadName)}`;
38586
38583
  try {
38587
38584
  setDownloadingKey(fmtKey);
38588
- const response = await fetch(downloadHref);
38589
- if (!response.ok) {
38590
- throw new Error(`Download failed with status ${response.status}`);
38591
- }
38585
+ const response = await fetch(href);
38586
+ if (!response.ok) throw new Error(`status ${response.status}`);
38592
38587
  const blob = await response.blob();
38593
38588
  const objectUrl = window.URL.createObjectURL(blob);
38594
38589
  const anchor = document.createElement("a");
@@ -38599,7 +38594,7 @@ var ExportModal = ({ formats, title, onClose }) => {
38599
38594
  anchor.remove();
38600
38595
  window.URL.revokeObjectURL(objectUrl);
38601
38596
  } catch {
38602
- window.open(downloadHref, "_blank", "noopener,noreferrer");
38597
+ window.open(href, "_blank", "noopener,noreferrer");
38603
38598
  } finally {
38604
38599
  setDownloadingKey(null);
38605
38600
  }
@@ -38612,15 +38607,7 @@ var ExportModal = ({ formats, title, onClose }) => {
38612
38607
  /* @__PURE__ */ jsx146("h3", { className: "text-sm font-semibold text-zinc-100", children: "Export Presentation" }),
38613
38608
  /* @__PURE__ */ jsx146("p", { className: "text-xs text-zinc-500 mt-0.5 truncate", children: title })
38614
38609
  ] }),
38615
- /* @__PURE__ */ jsx146(
38616
- "button",
38617
- {
38618
- onClick: onClose,
38619
- className: "text-zinc-500 hover:text-zinc-200 transition-colors flex-shrink-0 mt-0.5",
38620
- "aria-label": "Close",
38621
- children: /* @__PURE__ */ jsx146(CloseIcon, {})
38622
- }
38623
- )
38610
+ /* @__PURE__ */ jsx146("button", { onClick: onClose, className: "text-zinc-500 hover:text-zinc-200 transition-colors flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx146(CloseIcon, {}) })
38624
38611
  ] }),
38625
38612
  /* @__PURE__ */ jsxs108("div", { className: "space-y-2.5", children: [
38626
38613
  available.length === 0 && /* @__PURE__ */ jsx146("p", { className: "text-sm text-zinc-500 text-center py-6", children: "No formats available yet" }),
@@ -38644,7 +38631,7 @@ var ExportModal = ({ formats, title, onClose }) => {
38644
38631
  /* @__PURE__ */ jsx146("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: isDownloading ? `Downloading ${fmt.label}...` : fmt.label }),
38645
38632
  /* @__PURE__ */ jsx146("p", { className: "text-xs text-zinc-500 mt-0.5 leading-relaxed", children: isDownloading ? "Please wait while the file is being prepared." : fmt.desc })
38646
38633
  ] }),
38647
- /* @__PURE__ */ jsx146("span", { className: cn("flex-shrink-0 transition-colors", fmt.accent.text), children: /* @__PURE__ */ jsx146(DownloadIcon, {}) })
38634
+ /* @__PURE__ */ jsx146("span", { className: cn("flex-shrink-0", fmt.accent.text), children: /* @__PURE__ */ jsx146(DownloadIcon, {}) })
38648
38635
  ]
38649
38636
  },
38650
38637
  fmt.key
@@ -38655,6 +38642,87 @@ var ExportModal = ({ formats, title, onClose }) => {
38655
38642
  ] })
38656
38643
  ] });
38657
38644
  };
38645
+ var FullscreenModal = ({ url, title, slideCount, onClose }) => {
38646
+ const [currentSlide, setCurrentSlide] = useState10(1);
38647
+ const iframeRef = useRef5(null);
38648
+ useEffect6(() => {
38649
+ const onKey = (e) => {
38650
+ if (e.key === "Escape") onClose();
38651
+ };
38652
+ const onMsg = (e) => {
38653
+ if (e.data?.type === "presentationExit") onClose();
38654
+ if (e.data?.type === "slideChanged") setCurrentSlide(e.data.slide);
38655
+ };
38656
+ document.addEventListener("keydown", onKey);
38657
+ window.addEventListener("message", onMsg);
38658
+ return () => {
38659
+ document.removeEventListener("keydown", onKey);
38660
+ window.removeEventListener("message", onMsg);
38661
+ };
38662
+ }, [onClose]);
38663
+ useEffect6(() => {
38664
+ document.body.style.overflow = "hidden";
38665
+ return () => {
38666
+ document.body.style.overflow = "";
38667
+ };
38668
+ }, []);
38669
+ const send = (type) => iframeRef.current?.contentWindow?.postMessage({ type }, "*");
38670
+ return /* @__PURE__ */ jsxs108("div", { className: "fixed inset-0 z-50 bg-black flex flex-col", children: [
38671
+ /* @__PURE__ */ jsxs108("div", { className: "flex items-center justify-between gap-4 px-4 h-11 bg-zinc-950/90 border-b border-zinc-800/60 flex-shrink-0", children: [
38672
+ /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-3 min-w-0", children: [
38673
+ /* @__PURE__ */ jsx146("span", { className: "text-indigo-400 flex-shrink-0", children: /* @__PURE__ */ jsx146(SlidesIcon, {}) }),
38674
+ /* @__PURE__ */ jsx146("span", { className: "text-sm font-medium text-zinc-300 truncate", children: title }),
38675
+ slideCount > 0 && /* @__PURE__ */ jsxs108("span", { className: "text-xs text-zinc-600 flex-shrink-0", children: [
38676
+ currentSlide,
38677
+ " / ",
38678
+ slideCount
38679
+ ] })
38680
+ ] }),
38681
+ /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
38682
+ /* @__PURE__ */ jsx146(
38683
+ "button",
38684
+ {
38685
+ onClick: () => send("prevSlide"),
38686
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors",
38687
+ "aria-label": "Previous slide",
38688
+ children: /* @__PURE__ */ jsx146(ChevronLeft2, {})
38689
+ }
38690
+ ),
38691
+ /* @__PURE__ */ jsx146(
38692
+ "button",
38693
+ {
38694
+ onClick: () => send("nextSlide"),
38695
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors",
38696
+ "aria-label": "Next slide",
38697
+ children: /* @__PURE__ */ jsx146(ChevronRight2, {})
38698
+ }
38699
+ ),
38700
+ /* @__PURE__ */ jsxs108(
38701
+ "button",
38702
+ {
38703
+ onClick: onClose,
38704
+ className: "flex items-center gap-1.5 px-3 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-400 hover:text-zinc-200 text-xs transition-colors",
38705
+ children: [
38706
+ /* @__PURE__ */ jsx146(CloseIcon, {}),
38707
+ /* @__PURE__ */ jsx146("span", { children: "ESC" })
38708
+ ]
38709
+ }
38710
+ )
38711
+ ] })
38712
+ ] }),
38713
+ /* @__PURE__ */ jsx146("div", { className: "flex-1 relative", children: /* @__PURE__ */ jsx146(
38714
+ "iframe",
38715
+ {
38716
+ ref: iframeRef,
38717
+ src: url,
38718
+ title,
38719
+ onLoad: () => iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: currentSlide }, "*"),
38720
+ sandbox: "allow-same-origin allow-scripts allow-fullscreen",
38721
+ className: "absolute inset-0 w-full h-full border-0"
38722
+ }
38723
+ ) })
38724
+ ] });
38725
+ };
38658
38726
  var PresentationJobCard = ({
38659
38727
  job_id: _job_id,
38660
38728
  title: initialTitle,
@@ -38663,6 +38731,7 @@ var PresentationJobCard = ({
38663
38731
  formats: initialFormats = {},
38664
38732
  error: initialError,
38665
38733
  pollUrl,
38734
+ shareUrl,
38666
38735
  className
38667
38736
  }) => {
38668
38737
  const [status, setStatus] = useState10(initialStatus);
@@ -38670,7 +38739,9 @@ var PresentationJobCard = ({
38670
38739
  const [slideCount, setSlideCount] = useState10(initialSlideCount ?? 0);
38671
38740
  const [formats, setFormats] = useState10(initialFormats);
38672
38741
  const [error, setError] = useState10(initialError);
38673
- const [showModal, setShowModal] = useState10(false);
38742
+ const [showExport, setShowExport] = useState10(false);
38743
+ const [showFullscreen, setShowFullscreen] = useState10(false);
38744
+ const [copied, setCopied] = useState10(false);
38674
38745
  const [currentSlide, setCurrentSlide] = useState10(1);
38675
38746
  const [previewScale, setPreviewScale] = useState10(1);
38676
38747
  const [iframeReady, setIframeReady] = useState10(false);
@@ -38679,9 +38750,7 @@ var PresentationJobCard = ({
38679
38750
  const previewRef = useRef5(null);
38680
38751
  const iframeRef = useRef5(null);
38681
38752
  const updateScale = useCallback4(() => {
38682
- if (previewRef.current) {
38683
- setPreviewScale(previewRef.current.offsetWidth / 1280);
38684
- }
38753
+ if (previewRef.current) setPreviewScale(previewRef.current.offsetWidth / 1280);
38685
38754
  }, []);
38686
38755
  useEffect6(() => {
38687
38756
  updateScale();
@@ -38698,9 +38767,7 @@ var PresentationJobCard = ({
38698
38767
  const handler = (e) => {
38699
38768
  if (e.data?.type === "slideChanged") {
38700
38769
  setCurrentSlide(e.data.slide);
38701
- if (e.data.total && !slideCount) {
38702
- setSlideCount(e.data.total);
38703
- }
38770
+ if (e.data.total && !slideCount) setSlideCount(e.data.total);
38704
38771
  }
38705
38772
  };
38706
38773
  window.addEventListener("message", handler);
@@ -38712,9 +38779,7 @@ var PresentationJobCard = ({
38712
38779
  setPendingSlide(null);
38713
38780
  }, [iframeReady, pendingSlide]);
38714
38781
  const sendSlideCommand = (command) => {
38715
- if (!iframeReady) {
38716
- return;
38717
- }
38782
+ if (!iframeReady) return;
38718
38783
  iframeRef.current?.contentWindow?.postMessage({ type: command }, "*");
38719
38784
  };
38720
38785
  const goToSlide = (n) => {
@@ -38742,9 +38807,7 @@ var PresentationJobCard = ({
38742
38807
  if (data.output.slide_count) setSlideCount(data.output.slide_count);
38743
38808
  if (data.output.formats) setFormats(data.output.formats);
38744
38809
  }
38745
- if (newStatus === "failed" && data.error) {
38746
- setError(data.error);
38747
- }
38810
+ if (newStatus === "failed" && data.error) setError(data.error);
38748
38811
  } catch {
38749
38812
  }
38750
38813
  };
@@ -38760,6 +38823,17 @@ var PresentationJobCard = ({
38760
38823
  intervalRef.current = null;
38761
38824
  }
38762
38825
  }, [isTerminal]);
38826
+ const handleShare = async () => {
38827
+ const link = shareUrl ?? formats.html_url;
38828
+ if (!link) return;
38829
+ try {
38830
+ await navigator.clipboard.writeText(link);
38831
+ setCopied(true);
38832
+ setTimeout(() => setCopied(false), 2e3);
38833
+ } catch {
38834
+ window.open(link, "_blank", "noopener,noreferrer");
38835
+ }
38836
+ };
38763
38837
  if (status === "pending" || status === "running") {
38764
38838
  return /* @__PURE__ */ jsx146("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs108("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl p-5", children: [
38765
38839
  /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-3 mb-5", children: [
@@ -38785,8 +38859,8 @@ var PresentationJobCard = ({
38785
38859
  ] })
38786
38860
  ] }) }) });
38787
38861
  }
38788
- const availablePills = FORMATS.filter((f) => formats[f.key]);
38789
38862
  const total = slideCount || 1;
38863
+ const hasHtml = Boolean(formats.html_url);
38790
38864
  return /* @__PURE__ */ jsxs108(Fragment5, { children: [
38791
38865
  /* @__PURE__ */ jsx146("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs108("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", children: [
38792
38866
  /* @__PURE__ */ jsx146("div", { className: "h-[3px] bg-gradient-to-r from-indigo-600 via-violet-500 to-purple-600" }),
@@ -38800,118 +38874,127 @@ var PresentationJobCard = ({
38800
38874
  " \xB7 Ready to export"
38801
38875
  ] })
38802
38876
  ] }),
38803
- /* @__PURE__ */ jsxs108(
38804
- "button",
38805
- {
38806
- onClick: () => setShowModal(true),
38807
- className: "flex items-center gap-1.5 px-3 py-1.5 bg-indigo-600 hover:bg-indigo-500 active:bg-indigo-700 text-white text-xs font-medium rounded-lg transition-colors flex-shrink-0",
38808
- children: [
38809
- /* @__PURE__ */ jsx146(DownloadIcon, {}),
38810
- "Export"
38811
- ]
38812
- }
38813
- )
38877
+ /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: [
38878
+ /* @__PURE__ */ jsx146(
38879
+ "button",
38880
+ {
38881
+ onClick: handleShare,
38882
+ disabled: !hasHtml,
38883
+ title: copied ? "Copied!" : "Copy shareable link",
38884
+ className: cn(
38885
+ "w-7 h-7 rounded-lg border flex items-center justify-center transition-all",
38886
+ copied ? "border-green-500/40 bg-green-500/10 text-green-400" : "border-zinc-700 bg-zinc-800 text-zinc-400 hover:border-zinc-500 hover:text-zinc-200",
38887
+ "disabled:opacity-30 disabled:cursor-not-allowed"
38888
+ ),
38889
+ children: copied ? /* @__PURE__ */ jsx146(CheckIcon, {}) : /* @__PURE__ */ jsx146(ShareIcon, {})
38890
+ }
38891
+ ),
38892
+ /* @__PURE__ */ jsxs108(
38893
+ "button",
38894
+ {
38895
+ onClick: () => setShowFullscreen(true),
38896
+ disabled: !hasHtml,
38897
+ title: "Open fullscreen preview",
38898
+ className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-400 hover:text-zinc-200 text-xs font-medium transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
38899
+ children: [
38900
+ /* @__PURE__ */ jsx146(ExpandIcon, {}),
38901
+ /* @__PURE__ */ jsx146("span", { children: "Preview" })
38902
+ ]
38903
+ }
38904
+ ),
38905
+ /* @__PURE__ */ jsxs108(
38906
+ "button",
38907
+ {
38908
+ onClick: () => setShowExport(true),
38909
+ className: "flex items-center gap-1.5 px-2.5 h-7 bg-indigo-600 hover:bg-indigo-500 active:bg-indigo-700 text-white text-xs font-medium rounded-lg transition-colors",
38910
+ children: [
38911
+ /* @__PURE__ */ jsx146(DownloadIcon, {}),
38912
+ /* @__PURE__ */ jsx146("span", { children: "Export" })
38913
+ ]
38914
+ }
38915
+ )
38916
+ ] })
38814
38917
  ] }),
38815
- formats.html_url && /* @__PURE__ */ jsxs108("div", { className: "mt-4", children: [
38816
- /* @__PURE__ */ jsx146(
38918
+ hasHtml && /* @__PURE__ */ jsxs108("div", { className: "mt-4", children: [
38919
+ /* @__PURE__ */ jsxs108(
38817
38920
  "div",
38818
38921
  {
38819
38922
  ref: previewRef,
38820
- className: "relative overflow-hidden rounded-xl bg-zinc-950 border border-zinc-800/50",
38923
+ onClick: () => setShowFullscreen(true),
38924
+ className: "group relative overflow-hidden rounded-xl bg-zinc-950 border border-zinc-800/50 cursor-pointer",
38821
38925
  style: { height: Math.round(previewScale * 720) },
38822
- children: /* @__PURE__ */ jsx146(
38823
- "iframe",
38824
- {
38825
- ref: iframeRef,
38826
- src: formats.html_url,
38827
- title,
38828
- onLoad: () => setIframeReady(true),
38829
- sandbox: "allow-same-origin allow-scripts",
38830
- style: {
38831
- width: 1280,
38832
- height: 720,
38833
- transform: `scale(${previewScale})`,
38834
- transformOrigin: "top left",
38835
- border: "none",
38836
- pointerEvents: "none",
38837
- display: "block"
38926
+ title: "Click to open fullscreen",
38927
+ children: [
38928
+ /* @__PURE__ */ jsx146(
38929
+ "iframe",
38930
+ {
38931
+ ref: iframeRef,
38932
+ src: formats.html_url,
38933
+ title,
38934
+ onLoad: () => setIframeReady(true),
38935
+ sandbox: "allow-same-origin allow-scripts",
38936
+ style: {
38937
+ width: 1280,
38938
+ height: 720,
38939
+ transform: `scale(${previewScale})`,
38940
+ transformOrigin: "top left",
38941
+ border: "none",
38942
+ pointerEvents: "none",
38943
+ display: "block"
38944
+ }
38838
38945
  }
38839
- }
38840
- )
38946
+ ),
38947
+ /* @__PURE__ */ jsx146("div", { className: "absolute inset-0 flex items-center justify-center bg-black/0 group-hover:bg-black/30 transition-colors", children: /* @__PURE__ */ jsxs108("span", { className: "opacity-0 group-hover:opacity-100 transition-opacity flex items-center gap-2 bg-zinc-900/80 backdrop-blur-sm border border-zinc-700 rounded-lg px-3 py-1.5 text-xs text-zinc-200 font-medium", children: [
38948
+ /* @__PURE__ */ jsx146(ExpandIcon, {}),
38949
+ "Open fullscreen"
38950
+ ] }) })
38951
+ ]
38841
38952
  }
38842
38953
  ),
38843
- /* @__PURE__ */ jsxs108("div", { className: "flex items-center justify-between mt-3", children: [
38844
- /* @__PURE__ */ jsx146("div", { className: "flex items-center gap-2", children: availablePills.map((fmt) => /* @__PURE__ */ jsx146(
38845
- "span",
38954
+ /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-2 mt-3", children: [
38955
+ /* @__PURE__ */ jsx146(
38956
+ "button",
38846
38957
  {
38847
- className: cn(
38848
- "text-xs px-2.5 py-0.5 rounded-md border font-medium",
38849
- fmt.accent.pill
38850
- ),
38851
- children: fmt.label
38852
- },
38853
- fmt.key
38854
- )) }),
38855
- /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-2", children: [
38856
- /* @__PURE__ */ jsx146(
38857
- "button",
38858
- {
38859
- onClick: () => {
38860
- if (slideCount > 1) {
38861
- goToSlide(currentSlide - 1);
38862
- return;
38863
- }
38864
- sendSlideCommand("prevSlide");
38865
- },
38866
- disabled: !formats.html_url,
38867
- className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
38868
- "aria-label": "Previous slide",
38869
- children: /* @__PURE__ */ jsx146(ChevronLeft2, {})
38870
- }
38871
- ),
38872
- /* @__PURE__ */ jsxs108("span", { className: "text-xs text-zinc-500 font-medium tabular-nums min-w-[3rem] text-center", children: [
38873
- currentSlide,
38874
- " / ",
38875
- total
38876
- ] }),
38877
- /* @__PURE__ */ jsx146(
38878
- "button",
38879
- {
38880
- onClick: () => {
38881
- if (slideCount > 1) {
38882
- goToSlide(currentSlide + 1);
38883
- return;
38884
- }
38885
- sendSlideCommand("nextSlide");
38886
- },
38887
- disabled: !formats.html_url,
38888
- className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
38889
- "aria-label": "Next slide",
38890
- children: /* @__PURE__ */ jsx146(ChevronRight2, {})
38891
- }
38892
- )
38893
- ] })
38894
- ] })
38895
- ] }),
38896
- !formats.html_url && availablePills.length > 0 && /* @__PURE__ */ jsx146("div", { className: "flex items-center gap-2 mt-4", children: availablePills.map((fmt) => /* @__PURE__ */ jsx146(
38897
- "span",
38898
- {
38899
- className: cn(
38900
- "text-xs px-2.5 py-0.5 rounded-md border font-medium",
38901
- fmt.accent.pill
38958
+ onClick: (e) => {
38959
+ e.stopPropagation();
38960
+ slideCount > 1 ? goToSlide(currentSlide - 1) : sendSlideCommand("prevSlide");
38961
+ },
38962
+ disabled: !hasHtml,
38963
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
38964
+ "aria-label": "Previous slide",
38965
+ children: /* @__PURE__ */ jsx146(ChevronLeft2, {})
38966
+ }
38902
38967
  ),
38903
- children: fmt.label
38904
- },
38905
- fmt.key
38906
- )) })
38968
+ /* @__PURE__ */ jsxs108("span", { className: "text-xs text-zinc-500 font-medium tabular-nums min-w-[3rem] text-center", children: [
38969
+ currentSlide,
38970
+ " / ",
38971
+ total
38972
+ ] }),
38973
+ /* @__PURE__ */ jsx146(
38974
+ "button",
38975
+ {
38976
+ onClick: (e) => {
38977
+ e.stopPropagation();
38978
+ slideCount > 1 ? goToSlide(currentSlide + 1) : sendSlideCommand("nextSlide");
38979
+ },
38980
+ disabled: !hasHtml,
38981
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
38982
+ "aria-label": "Next slide",
38983
+ children: /* @__PURE__ */ jsx146(ChevronRight2, {})
38984
+ }
38985
+ )
38986
+ ] })
38987
+ ] })
38907
38988
  ] })
38908
38989
  ] }) }),
38909
- showModal && /* @__PURE__ */ jsx146(
38910
- ExportModal,
38990
+ showExport && /* @__PURE__ */ jsx146(ExportModal, { formats, title, onClose: () => setShowExport(false) }),
38991
+ showFullscreen && hasHtml && /* @__PURE__ */ jsx146(
38992
+ FullscreenModal,
38911
38993
  {
38912
- formats,
38994
+ url: formats.html_url,
38913
38995
  title,
38914
- onClose: () => setShowModal(false)
38996
+ slideCount,
38997
+ onClose: () => setShowFullscreen(false)
38915
38998
  }
38916
38999
  )
38917
39000
  ] });