pxengine 0.1.73 → 0.1.75

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.mjs CHANGED
@@ -38572,6 +38572,38 @@ var FORMATS = [
38572
38572
  var ExportModal = ({ formats, title, onClose }) => {
38573
38573
  const available = FORMATS.filter((f) => formats[f.key]);
38574
38574
  const filename = title.replace(/[^a-z0-9]/gi, "-").toLowerCase();
38575
+ 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
+ const handleDownload = async (fmtKey, url, ext) => {
38581
+ if (downloadingKey) {
38582
+ return;
38583
+ }
38584
+ const downloadHref = buildDownloadHref(url, ext);
38585
+ const downloadName = `${filename}${ext}`;
38586
+ try {
38587
+ setDownloadingKey(fmtKey);
38588
+ const response = await fetch(downloadHref);
38589
+ if (!response.ok) {
38590
+ throw new Error(`Download failed with status ${response.status}`);
38591
+ }
38592
+ const blob = await response.blob();
38593
+ const objectUrl = window.URL.createObjectURL(blob);
38594
+ const anchor = document.createElement("a");
38595
+ anchor.href = objectUrl;
38596
+ anchor.download = downloadName;
38597
+ document.body.appendChild(anchor);
38598
+ anchor.click();
38599
+ anchor.remove();
38600
+ window.URL.revokeObjectURL(objectUrl);
38601
+ } catch {
38602
+ window.open(downloadHref, "_blank", "noopener,noreferrer");
38603
+ } finally {
38604
+ setDownloadingKey(null);
38605
+ }
38606
+ };
38575
38607
  return /* @__PURE__ */ jsxs108("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
38576
38608
  /* @__PURE__ */ jsx146("div", { className: "absolute inset-0 bg-black/70 backdrop-blur-sm", onClick: onClose }),
38577
38609
  /* @__PURE__ */ jsxs108("div", { className: "relative z-10 bg-zinc-900 border border-zinc-800 rounded-2xl w-full max-w-sm p-6 shadow-2xl", children: [
@@ -38594,22 +38626,23 @@ var ExportModal = ({ formats, title, onClose }) => {
38594
38626
  available.length === 0 && /* @__PURE__ */ jsx146("p", { className: "text-sm text-zinc-500 text-center py-6", children: "No formats available yet" }),
38595
38627
  available.map((fmt) => {
38596
38628
  const url = formats[fmt.key];
38597
- const dlName = `${filename}${fmt.ext}`;
38629
+ const isDownloading = downloadingKey === fmt.key;
38598
38630
  return /* @__PURE__ */ jsxs108(
38599
- "a",
38631
+ "button",
38600
38632
  {
38601
- href: url,
38602
- download: dlName,
38633
+ type: "button",
38634
+ disabled: Boolean(downloadingKey),
38635
+ onClick: () => handleDownload(fmt.key, url, fmt.ext),
38603
38636
  className: cn(
38604
- "flex items-center gap-3.5 p-3.5 rounded-xl border transition-all",
38605
- "hover:brightness-110 cursor-pointer no-underline group",
38637
+ "flex w-full items-center gap-3.5 p-3.5 rounded-xl border transition-all text-left",
38638
+ "hover:brightness-110 disabled:opacity-60 disabled:cursor-not-allowed",
38606
38639
  fmt.accent.bg
38607
38640
  ),
38608
38641
  children: [
38609
38642
  /* @__PURE__ */ jsx146("span", { className: "text-xl flex-shrink-0", children: fmt.emoji }),
38610
38643
  /* @__PURE__ */ jsxs108("div", { className: "flex-1 min-w-0", children: [
38611
- /* @__PURE__ */ jsx146("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: fmt.label }),
38612
- /* @__PURE__ */ jsx146("p", { className: "text-xs text-zinc-500 mt-0.5 leading-relaxed", children: fmt.desc })
38644
+ /* @__PURE__ */ jsx146("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: isDownloading ? `Downloading ${fmt.label}...` : fmt.label }),
38645
+ /* @__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 })
38613
38646
  ] }),
38614
38647
  /* @__PURE__ */ jsx146("span", { className: cn("flex-shrink-0 transition-colors", fmt.accent.text), children: /* @__PURE__ */ jsx146(DownloadIcon, {}) })
38615
38648
  ]
@@ -38640,6 +38673,8 @@ var PresentationJobCard = ({
38640
38673
  const [showModal, setShowModal] = useState10(false);
38641
38674
  const [currentSlide, setCurrentSlide] = useState10(1);
38642
38675
  const [previewScale, setPreviewScale] = useState10(1);
38676
+ const [iframeReady, setIframeReady] = useState10(false);
38677
+ const [pendingSlide, setPendingSlide] = useState10(null);
38643
38678
  const intervalRef = useRef5(null);
38644
38679
  const previewRef = useRef5(null);
38645
38680
  const iframeRef = useRef5(null);
@@ -38655,6 +38690,10 @@ var PresentationJobCard = ({
38655
38690
  if (previewRef.current) ro.observe(previewRef.current);
38656
38691
  return () => ro.disconnect();
38657
38692
  }, [updateScale, formats.html_url]);
38693
+ useEffect6(() => {
38694
+ setIframeReady(false);
38695
+ setPendingSlide(null);
38696
+ }, [formats.html_url]);
38658
38697
  useEffect6(() => {
38659
38698
  const handler = (e) => {
38660
38699
  if (e.data?.type === "slideChanged") {
@@ -38667,11 +38706,26 @@ var PresentationJobCard = ({
38667
38706
  window.addEventListener("message", handler);
38668
38707
  return () => window.removeEventListener("message", handler);
38669
38708
  }, [slideCount]);
38709
+ useEffect6(() => {
38710
+ if (!iframeReady || pendingSlide === null) return;
38711
+ iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: pendingSlide }, "*");
38712
+ setPendingSlide(null);
38713
+ }, [iframeReady, pendingSlide]);
38714
+ const sendSlideCommand = (command) => {
38715
+ if (!iframeReady) {
38716
+ return;
38717
+ }
38718
+ iframeRef.current?.contentWindow?.postMessage({ type: command }, "*");
38719
+ };
38670
38720
  const goToSlide = (n) => {
38671
38721
  const total2 = slideCount || 1;
38672
38722
  const target = (n - 1 + total2) % total2 + 1;
38673
38723
  setCurrentSlide(target);
38674
- iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: target }, "*");
38724
+ if (iframeReady) {
38725
+ iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: target }, "*");
38726
+ return;
38727
+ }
38728
+ setPendingSlide(target);
38675
38729
  };
38676
38730
  const isTerminal = status === "complete" || status === "failed";
38677
38731
  useEffect6(() => {
@@ -38771,6 +38825,7 @@ var PresentationJobCard = ({
38771
38825
  ref: iframeRef,
38772
38826
  src: formats.html_url,
38773
38827
  title,
38828
+ onLoad: () => setIframeReady(true),
38774
38829
  sandbox: "allow-same-origin allow-scripts",
38775
38830
  style: {
38776
38831
  width: 1280,
@@ -38801,8 +38856,14 @@ var PresentationJobCard = ({
38801
38856
  /* @__PURE__ */ jsx146(
38802
38857
  "button",
38803
38858
  {
38804
- onClick: () => goToSlide(currentSlide - 1),
38805
- disabled: total <= 1,
38859
+ onClick: () => {
38860
+ if (slideCount > 1) {
38861
+ goToSlide(currentSlide - 1);
38862
+ return;
38863
+ }
38864
+ sendSlideCommand("prevSlide");
38865
+ },
38866
+ disabled: !formats.html_url,
38806
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",
38807
38868
  "aria-label": "Previous slide",
38808
38869
  children: /* @__PURE__ */ jsx146(ChevronLeft2, {})
@@ -38816,8 +38877,14 @@ var PresentationJobCard = ({
38816
38877
  /* @__PURE__ */ jsx146(
38817
38878
  "button",
38818
38879
  {
38819
- onClick: () => goToSlide(currentSlide + 1),
38820
- disabled: total <= 1,
38880
+ onClick: () => {
38881
+ if (slideCount > 1) {
38882
+ goToSlide(currentSlide + 1);
38883
+ return;
38884
+ }
38885
+ sendSlideCommand("nextSlide");
38886
+ },
38887
+ disabled: !formats.html_url,
38821
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",
38822
38889
  "aria-label": "Next slide",
38823
38890
  children: /* @__PURE__ */ jsx146(ChevronRight2, {})