pxengine 0.1.74 → 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.cjs CHANGED
@@ -38894,6 +38894,38 @@ var FORMATS = [
38894
38894
  var ExportModal = ({ formats, title, onClose }) => {
38895
38895
  const available = FORMATS.filter((f) => formats[f.key]);
38896
38896
  const filename = title.replace(/[^a-z0-9]/gi, "-").toLowerCase();
38897
+ const [downloadingKey, setDownloadingKey] = (0, import_react74.useState)(null);
38898
+ const buildDownloadHref = (url, ext) => {
38899
+ const downloadName = `${filename}${ext}`;
38900
+ return `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(downloadName)}`;
38901
+ };
38902
+ const handleDownload = async (fmtKey, url, ext) => {
38903
+ if (downloadingKey) {
38904
+ return;
38905
+ }
38906
+ const downloadHref = buildDownloadHref(url, ext);
38907
+ const downloadName = `${filename}${ext}`;
38908
+ try {
38909
+ setDownloadingKey(fmtKey);
38910
+ const response = await fetch(downloadHref);
38911
+ if (!response.ok) {
38912
+ throw new Error(`Download failed with status ${response.status}`);
38913
+ }
38914
+ const blob = await response.blob();
38915
+ const objectUrl = window.URL.createObjectURL(blob);
38916
+ const anchor = document.createElement("a");
38917
+ anchor.href = objectUrl;
38918
+ anchor.download = downloadName;
38919
+ document.body.appendChild(anchor);
38920
+ anchor.click();
38921
+ anchor.remove();
38922
+ window.URL.revokeObjectURL(objectUrl);
38923
+ } catch {
38924
+ window.open(downloadHref, "_blank", "noopener,noreferrer");
38925
+ } finally {
38926
+ setDownloadingKey(null);
38927
+ }
38928
+ };
38897
38929
  return /* @__PURE__ */ (0, import_jsx_runtime146.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
38898
38930
  /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("div", { className: "absolute inset-0 bg-black/70 backdrop-blur-sm", onClick: onClose }),
38899
38931
  /* @__PURE__ */ (0, import_jsx_runtime146.jsxs)("div", { className: "relative z-10 bg-zinc-900 border border-zinc-800 rounded-2xl w-full max-w-sm p-6 shadow-2xl", children: [
@@ -38916,22 +38948,23 @@ var ExportModal = ({ formats, title, onClose }) => {
38916
38948
  available.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("p", { className: "text-sm text-zinc-500 text-center py-6", children: "No formats available yet" }),
38917
38949
  available.map((fmt) => {
38918
38950
  const url = formats[fmt.key];
38919
- const dlName = `${filename}${fmt.ext}`;
38951
+ const isDownloading = downloadingKey === fmt.key;
38920
38952
  return /* @__PURE__ */ (0, import_jsx_runtime146.jsxs)(
38921
- "a",
38953
+ "button",
38922
38954
  {
38923
- href: url,
38924
- download: dlName,
38955
+ type: "button",
38956
+ disabled: Boolean(downloadingKey),
38957
+ onClick: () => handleDownload(fmt.key, url, fmt.ext),
38925
38958
  className: cn(
38926
- "flex items-center gap-3.5 p-3.5 rounded-xl border transition-all",
38927
- "hover:brightness-110 cursor-pointer no-underline group",
38959
+ "flex w-full items-center gap-3.5 p-3.5 rounded-xl border transition-all text-left",
38960
+ "hover:brightness-110 disabled:opacity-60 disabled:cursor-not-allowed",
38928
38961
  fmt.accent.bg
38929
38962
  ),
38930
38963
  children: [
38931
38964
  /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("span", { className: "text-xl flex-shrink-0", children: fmt.emoji }),
38932
38965
  /* @__PURE__ */ (0, import_jsx_runtime146.jsxs)("div", { className: "flex-1 min-w-0", children: [
38933
- /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: fmt.label }),
38934
- /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("p", { className: "text-xs text-zinc-500 mt-0.5 leading-relaxed", children: fmt.desc })
38966
+ /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: isDownloading ? `Downloading ${fmt.label}...` : fmt.label }),
38967
+ /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("p", { className: "text-xs text-zinc-500 mt-0.5 leading-relaxed", children: isDownloading ? "Please wait while the file is being prepared." : fmt.desc })
38935
38968
  ] }),
38936
38969
  /* @__PURE__ */ (0, import_jsx_runtime146.jsx)("span", { className: cn("flex-shrink-0 transition-colors", fmt.accent.text), children: /* @__PURE__ */ (0, import_jsx_runtime146.jsx)(DownloadIcon, {}) })
38937
38970
  ]
@@ -39000,6 +39033,12 @@ var PresentationJobCard = ({
39000
39033
  iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: pendingSlide }, "*");
39001
39034
  setPendingSlide(null);
39002
39035
  }, [iframeReady, pendingSlide]);
39036
+ const sendSlideCommand = (command) => {
39037
+ if (!iframeReady) {
39038
+ return;
39039
+ }
39040
+ iframeRef.current?.contentWindow?.postMessage({ type: command }, "*");
39041
+ };
39003
39042
  const goToSlide = (n) => {
39004
39043
  const total2 = slideCount || 1;
39005
39044
  const target = (n - 1 + total2) % total2 + 1;
@@ -39139,8 +39178,14 @@ var PresentationJobCard = ({
39139
39178
  /* @__PURE__ */ (0, import_jsx_runtime146.jsx)(
39140
39179
  "button",
39141
39180
  {
39142
- onClick: () => goToSlide(currentSlide - 1),
39143
- disabled: total <= 1,
39181
+ onClick: () => {
39182
+ if (slideCount > 1) {
39183
+ goToSlide(currentSlide - 1);
39184
+ return;
39185
+ }
39186
+ sendSlideCommand("prevSlide");
39187
+ },
39188
+ disabled: !formats.html_url,
39144
39189
  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",
39145
39190
  "aria-label": "Previous slide",
39146
39191
  children: /* @__PURE__ */ (0, import_jsx_runtime146.jsx)(ChevronLeft2, {})
@@ -39154,8 +39199,14 @@ var PresentationJobCard = ({
39154
39199
  /* @__PURE__ */ (0, import_jsx_runtime146.jsx)(
39155
39200
  "button",
39156
39201
  {
39157
- onClick: () => goToSlide(currentSlide + 1),
39158
- disabled: total <= 1,
39202
+ onClick: () => {
39203
+ if (slideCount > 1) {
39204
+ goToSlide(currentSlide + 1);
39205
+ return;
39206
+ }
39207
+ sendSlideCommand("nextSlide");
39208
+ },
39209
+ disabled: !formats.html_url,
39159
39210
  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",
39160
39211
  "aria-label": "Next slide",
39161
39212
  children: /* @__PURE__ */ (0, import_jsx_runtime146.jsx)(ChevronRight2, {})