pxengine 0.1.82 → 0.1.84

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
@@ -39096,8 +39096,9 @@ var ExportModal = ({ formats, title, onClose }) => {
39096
39096
  ] })
39097
39097
  ] });
39098
39098
  };
39099
- var FullscreenModal = ({ url, title, slideCount, onClose }) => {
39100
- const [currentSlide, setCurrentSlide] = (0, import_react75.useState)(1);
39099
+ var FullscreenModal = ({ url, title, slideCount, initialSlide = 1, onClose }) => {
39100
+ const [currentSlide, setCurrentSlide] = (0, import_react75.useState)(initialSlide);
39101
+ const [iframeReady, setIframeReady] = (0, import_react75.useState)(false);
39101
39102
  const iframeRef = (0, import_react75.useRef)(null);
39102
39103
  (0, import_react75.useEffect)(() => {
39103
39104
  const onKey = (e) => {
@@ -39105,7 +39106,10 @@ var FullscreenModal = ({ url, title, slideCount, onClose }) => {
39105
39106
  };
39106
39107
  const onMsg = (e) => {
39107
39108
  if (e.data?.type === "presentationExit") onClose();
39108
- if (e.data?.type === "slideChanged") setCurrentSlide(e.data.slide);
39109
+ if (e.data?.type === "slideChanged") {
39110
+ setCurrentSlide(e.data.slide);
39111
+ if (!iframeReady) setIframeReady(true);
39112
+ }
39109
39113
  };
39110
39114
  document.addEventListener("keydown", onKey);
39111
39115
  window.addEventListener("message", onMsg);
@@ -39113,14 +39117,26 @@ var FullscreenModal = ({ url, title, slideCount, onClose }) => {
39113
39117
  document.removeEventListener("keydown", onKey);
39114
39118
  window.removeEventListener("message", onMsg);
39115
39119
  };
39116
- }, [onClose]);
39120
+ }, [onClose, iframeReady]);
39117
39121
  (0, import_react75.useEffect)(() => {
39118
39122
  document.body.style.overflow = "hidden";
39119
39123
  return () => {
39120
39124
  document.body.style.overflow = "";
39121
39125
  };
39122
39126
  }, []);
39123
- const send = (type) => iframeRef.current?.contentWindow?.postMessage({ type }, "*");
39127
+ const sendSlideCommand = (command) => {
39128
+ const iframe = iframeRef.current;
39129
+ if (!iframe?.contentWindow) return;
39130
+ const totalSlides = slideCount || 1;
39131
+ let newSlide = currentSlide;
39132
+ if (command === "nextSlide") {
39133
+ newSlide = currentSlide >= totalSlides ? 1 : currentSlide + 1;
39134
+ } else {
39135
+ newSlide = currentSlide <= 1 ? totalSlides : currentSlide - 1;
39136
+ }
39137
+ setCurrentSlide(newSlide);
39138
+ iframe.contentWindow.postMessage({ type: command }, "*");
39139
+ };
39124
39140
  return /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "fixed inset-0 z-50 bg-black flex flex-col", children: [
39125
39141
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("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: [
39126
39142
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center gap-3 min-w-0", children: [
@@ -39136,8 +39152,9 @@ var FullscreenModal = ({ url, title, slideCount, onClose }) => {
39136
39152
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
39137
39153
  "button",
39138
39154
  {
39139
- onClick: () => send("prevSlide"),
39140
- 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",
39155
+ onClick: () => sendSlideCommand("prevSlide"),
39156
+ disabled: !iframeReady,
39157
+ 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",
39141
39158
  "aria-label": "Previous slide",
39142
39159
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronLeft2, {})
39143
39160
  }
@@ -39145,8 +39162,9 @@ var FullscreenModal = ({ url, title, slideCount, onClose }) => {
39145
39162
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
39146
39163
  "button",
39147
39164
  {
39148
- onClick: () => send("nextSlide"),
39149
- 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",
39165
+ onClick: () => sendSlideCommand("nextSlide"),
39166
+ disabled: !iframeReady,
39167
+ 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",
39150
39168
  "aria-label": "Next slide",
39151
39169
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronRight2, {})
39152
39170
  }
@@ -39170,7 +39188,10 @@ var FullscreenModal = ({ url, title, slideCount, onClose }) => {
39170
39188
  ref: iframeRef,
39171
39189
  src: url,
39172
39190
  title,
39173
- onLoad: () => iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: currentSlide }, "*"),
39191
+ onLoad: () => {
39192
+ setIframeReady(true);
39193
+ iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: initialSlide }, "*");
39194
+ },
39174
39195
  sandbox: "allow-same-origin allow-scripts allow-fullscreen",
39175
39196
  className: "absolute inset-0 w-full h-full border-0"
39176
39197
  }
@@ -39201,6 +39222,7 @@ var PresentationJobCard = ({
39201
39222
  const [copied, setCopied] = (0, import_react75.useState)(false);
39202
39223
  const [currentSlide, setCurrentSlide] = (0, import_react75.useState)(1);
39203
39224
  const [previewScale, setPreviewScale] = (0, import_react75.useState)(1);
39225
+ const [iframeReady, setIframeReady] = (0, import_react75.useState)(false);
39204
39226
  const intervalRef = (0, import_react75.useRef)(null);
39205
39227
  const previewRef = (0, import_react75.useRef)(null);
39206
39228
  const iframeRef = (0, import_react75.useRef)(null);
@@ -39209,6 +39231,7 @@ var PresentationJobCard = ({
39209
39231
  }, []);
39210
39232
  (0, import_react75.useEffect)(() => {
39211
39233
  updateScale();
39234
+ setIframeReady(false);
39212
39235
  if (typeof ResizeObserver === "undefined") return;
39213
39236
  const ro = new ResizeObserver(updateScale);
39214
39237
  if (previewRef.current) ro.observe(previewRef.current);
@@ -39219,13 +39242,24 @@ var PresentationJobCard = ({
39219
39242
  if (e.data?.type === "slideChanged") {
39220
39243
  setCurrentSlide(e.data.slide);
39221
39244
  if (e.data.total && !slideCount) setSlideCount(e.data.total);
39245
+ if (!iframeReady) setIframeReady(true);
39222
39246
  }
39223
39247
  };
39224
39248
  window.addEventListener("message", handler);
39225
39249
  return () => window.removeEventListener("message", handler);
39226
- }, [slideCount]);
39250
+ }, [slideCount, iframeReady]);
39227
39251
  const sendSlideCommand = (command) => {
39228
- iframeRef.current?.contentWindow?.postMessage({ type: command }, "*");
39252
+ const iframe = iframeRef.current;
39253
+ if (!iframe?.contentWindow) return;
39254
+ const totalSlides = slideCount || 1;
39255
+ let newSlide = currentSlide;
39256
+ if (command === "nextSlide") {
39257
+ newSlide = currentSlide >= totalSlides ? 1 : currentSlide + 1;
39258
+ } else {
39259
+ newSlide = currentSlide <= 1 ? totalSlides : currentSlide - 1;
39260
+ }
39261
+ setCurrentSlide(newSlide);
39262
+ iframe.contentWindow.postMessage({ type: command }, "*");
39229
39263
  };
39230
39264
  const isTerminal = status === "complete" || status === "failed";
39231
39265
  const onCompleteRef = (0, import_react75.useRef)(onComplete);
@@ -39388,6 +39422,7 @@ var PresentationJobCard = ({
39388
39422
  src: formats.html_url,
39389
39423
  title,
39390
39424
  sandbox: "allow-same-origin allow-scripts",
39425
+ onLoad: () => setIframeReady(true),
39391
39426
  style: {
39392
39427
  width: 1280,
39393
39428
  height: 720,
@@ -39414,7 +39449,7 @@ var PresentationJobCard = ({
39414
39449
  e.stopPropagation();
39415
39450
  sendSlideCommand("prevSlide");
39416
39451
  },
39417
- disabled: !hasHtml,
39452
+ disabled: !hasHtml || !iframeReady,
39418
39453
  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",
39419
39454
  "aria-label": "Previous slide",
39420
39455
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronLeft2, {})
@@ -39432,7 +39467,7 @@ var PresentationJobCard = ({
39432
39467
  e.stopPropagation();
39433
39468
  sendSlideCommand("nextSlide");
39434
39469
  },
39435
- disabled: !hasHtml,
39470
+ disabled: !hasHtml || !iframeReady,
39436
39471
  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",
39437
39472
  "aria-label": "Next slide",
39438
39473
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronRight2, {})
@@ -39449,6 +39484,7 @@ var PresentationJobCard = ({
39449
39484
  url: formats.html_url,
39450
39485
  title,
39451
39486
  slideCount,
39487
+ initialSlide: currentSlide,
39452
39488
  onClose: () => setShowFullscreen(false)
39453
39489
  }
39454
39490
  )
@@ -39485,94 +39521,6 @@ var ExpandIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("svg", {
39485
39521
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
39486
39522
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
39487
39523
  ] });
39488
- var FORMATS2 = [
39489
- {
39490
- key: "pdf_url",
39491
- label: "PDF",
39492
- ext: ".pdf",
39493
- emoji: "\u{1F4C4}",
39494
- desc: "Professional formatted report \u2014 open in any PDF viewer",
39495
- accent: { text: "text-red-400", bg: "bg-red-500/10 border-red-500/20" }
39496
- },
39497
- {
39498
- key: "html_url",
39499
- label: "HTML",
39500
- ext: ".html",
39501
- emoji: "\u{1F310}",
39502
- desc: "Interactive web version \u2014 open in any browser",
39503
- accent: { text: "text-blue-400", bg: "bg-blue-500/10 border-blue-500/20" }
39504
- }
39505
- ];
39506
- var ExportModal2 = ({ formats, title, onClose }) => {
39507
- const available = FORMATS2.filter((f) => formats[f.key]);
39508
- const filename = title.replace(/[^a-z0-9]/gi, "-").toLowerCase();
39509
- const [downloadingKey, setDownloadingKey] = (0, import_react76.useState)(null);
39510
- const handleDownload = async (fmtKey, url, ext) => {
39511
- if (downloadingKey) return;
39512
- const downloadName = `${filename}${ext}`;
39513
- const href = `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(downloadName)}`;
39514
- try {
39515
- setDownloadingKey(fmtKey);
39516
- const response = await fetch(href);
39517
- if (!response.ok) throw new Error(`status ${response.status}`);
39518
- const blob = await response.blob();
39519
- const objectUrl = window.URL.createObjectURL(blob);
39520
- const anchor = document.createElement("a");
39521
- anchor.href = objectUrl;
39522
- anchor.download = downloadName;
39523
- document.body.appendChild(anchor);
39524
- anchor.click();
39525
- anchor.remove();
39526
- window.URL.revokeObjectURL(objectUrl);
39527
- } catch {
39528
- window.open(href, "_blank", "noopener,noreferrer");
39529
- } finally {
39530
- setDownloadingKey(null);
39531
- }
39532
- };
39533
- return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
39534
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "absolute inset-0 bg-black/70 backdrop-blur-sm", onClick: onClose }),
39535
- /* @__PURE__ */ (0, import_jsx_runtime148.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: [
39536
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-start justify-between mb-5", children: [
39537
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "min-w-0 pr-3", children: [
39538
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("h3", { className: "text-sm font-semibold text-zinc-100", children: "Download Report" }),
39539
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-xs text-zinc-500 mt-0.5 truncate", children: title })
39540
- ] }),
39541
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("button", { onClick: onClose, className: "text-zinc-500 hover:text-zinc-200 transition-colors flex-shrink-0 mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CloseIcon2, {}) })
39542
- ] }),
39543
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "space-y-2.5", children: [
39544
- available.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-sm text-zinc-500 text-center py-6", children: "No formats available yet" }),
39545
- available.map((fmt) => {
39546
- const url = formats[fmt.key];
39547
- const isDownloading = downloadingKey === fmt.key;
39548
- return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
39549
- "button",
39550
- {
39551
- type: "button",
39552
- disabled: Boolean(downloadingKey),
39553
- onClick: () => handleDownload(fmt.key, url, fmt.ext),
39554
- className: cn(
39555
- "flex w-full items-center gap-3.5 p-3.5 rounded-xl border transition-all text-left",
39556
- "hover:brightness-110 disabled:opacity-60 disabled:cursor-not-allowed",
39557
- fmt.accent.bg
39558
- ),
39559
- children: [
39560
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-xl flex-shrink-0", children: fmt.emoji }),
39561
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex-1 min-w-0", children: [
39562
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: isDownloading ? `Downloading ${fmt.label}...` : fmt.label }),
39563
- /* @__PURE__ */ (0, import_jsx_runtime148.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 })
39564
- ] }),
39565
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: cn("flex-shrink-0", fmt.accent.text), children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DownloadIcon2, {}) })
39566
- ]
39567
- },
39568
- fmt.key
39569
- );
39570
- })
39571
- ] }),
39572
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-xs text-zinc-600 mt-4 text-center", children: "Download links expire in 7 days" })
39573
- ] })
39574
- ] });
39575
- };
39576
39524
  var FullscreenPreviewModal = ({ url, title, onClose }) => {
39577
39525
  (0, import_react76.useEffect)(() => {
39578
39526
  const onKey = (e) => {
@@ -39627,7 +39575,7 @@ var ResearchReportJobCard = ({
39627
39575
  word_count: initialWordCount,
39628
39576
  executive_summary: initialSummary,
39629
39577
  key_findings: _initialFindings,
39630
- formats: initialFormats = {},
39578
+ html_url: initialHtmlUrl,
39631
39579
  theme: initialTheme,
39632
39580
  error: initialError,
39633
39581
  pollUrl,
@@ -39643,10 +39591,9 @@ var ResearchReportJobCard = ({
39643
39591
  const [sourceCount, setSourceCount] = (0, import_react76.useState)(initialSourceCount ?? 0);
39644
39592
  const [wordCount, setWordCount] = (0, import_react76.useState)(initialWordCount ?? 0);
39645
39593
  const [summary, setSummary] = (0, import_react76.useState)(initialSummary || "");
39646
- const [formats, setFormats] = (0, import_react76.useState)(initialFormats);
39594
+ const [htmlUrl, setHtmlUrl] = (0, import_react76.useState)(initialHtmlUrl || "");
39647
39595
  const [theme, setTheme] = (0, import_react76.useState)(initialTheme || DEFAULT_THEME);
39648
39596
  const [error, setError] = (0, import_react76.useState)(initialError);
39649
- const [showExport, setShowExport] = (0, import_react76.useState)(false);
39650
39597
  const [showPreview, setShowPreview] = (0, import_react76.useState)(false);
39651
39598
  const [previewScale, setPreviewScale] = (0, import_react76.useState)(1);
39652
39599
  const previewRef = (0, import_react76.useRef)(null);
@@ -39656,9 +39603,39 @@ var ResearchReportJobCard = ({
39656
39603
  const hasNotifiedRef = (0, import_react76.useRef)(false);
39657
39604
  onCompleteRef.current = onComplete;
39658
39605
  onFailedRef.current = onFailed;
39606
+ (0, import_react76.useEffect)(() => {
39607
+ setStatus(initialStatus);
39608
+ }, [initialStatus]);
39609
+ (0, import_react76.useEffect)(() => {
39610
+ if (initialTitle) setTitle(initialTitle);
39611
+ }, [initialTitle]);
39612
+ (0, import_react76.useEffect)(() => {
39613
+ if (initialHtmlUrl) setHtmlUrl(initialHtmlUrl);
39614
+ }, [initialHtmlUrl]);
39615
+ (0, import_react76.useEffect)(() => {
39616
+ if (initialDepth) setDepth(initialDepth);
39617
+ }, [initialDepth]);
39618
+ (0, import_react76.useEffect)(() => {
39619
+ if (initialSectionCount !== void 0) setSectionCount(initialSectionCount);
39620
+ }, [initialSectionCount]);
39621
+ (0, import_react76.useEffect)(() => {
39622
+ if (initialSourceCount !== void 0) setSourceCount(initialSourceCount);
39623
+ }, [initialSourceCount]);
39624
+ (0, import_react76.useEffect)(() => {
39625
+ if (initialWordCount !== void 0) setWordCount(initialWordCount);
39626
+ }, [initialWordCount]);
39627
+ (0, import_react76.useEffect)(() => {
39628
+ if (initialSummary) setSummary(initialSummary);
39629
+ }, [initialSummary]);
39630
+ (0, import_react76.useEffect)(() => {
39631
+ if (initialTheme) setTheme(initialTheme);
39632
+ }, [initialTheme]);
39633
+ (0, import_react76.useEffect)(() => {
39634
+ if (initialError) setError(initialError);
39635
+ }, [initialError]);
39659
39636
  const isTerminal = status === "complete" || status === "failed";
39660
39637
  const primaryColor = theme?.primary || DEFAULT_THEME.primary;
39661
- const hasHTML = Boolean(formats.html_url);
39638
+ const hasHTML = Boolean(htmlUrl);
39662
39639
  const updateScale = (0, import_react76.useCallback)(() => {
39663
39640
  if (previewRef.current) {
39664
39641
  setPreviewScale(previewRef.current.offsetWidth / 800);
@@ -39670,7 +39647,7 @@ var ResearchReportJobCard = ({
39670
39647
  const ro = new ResizeObserver(updateScale);
39671
39648
  if (previewRef.current) ro.observe(previewRef.current);
39672
39649
  return () => ro.disconnect();
39673
- }, [updateScale, formats.html_url]);
39650
+ }, [updateScale, htmlUrl]);
39674
39651
  (0, import_react76.useEffect)(() => {
39675
39652
  if (isTerminal || !pollUrl) return;
39676
39653
  const poll = async () => {
@@ -39692,7 +39669,7 @@ var ResearchReportJobCard = ({
39692
39669
  setSourceCount(output.source_count || 0);
39693
39670
  setWordCount(output.word_count || 0);
39694
39671
  setSummary(output.executive_summary || "");
39695
- setFormats(output.formats || {});
39672
+ setHtmlUrl(output.html_url || "");
39696
39673
  if (output.theme) {
39697
39674
  setTheme(output.theme);
39698
39675
  }
@@ -39753,6 +39730,26 @@ var ResearchReportJobCard = ({
39753
39730
  ] })
39754
39731
  ] }) }) });
39755
39732
  }
39733
+ const handleDownload = async () => {
39734
+ if (!htmlUrl) return;
39735
+ const filename = `${title.replace(/[^a-z0-9]/gi, "-").toLowerCase()}.html`;
39736
+ const href = `/api/download?url=${encodeURIComponent(htmlUrl)}&filename=${encodeURIComponent(filename)}`;
39737
+ try {
39738
+ const response = await fetch(href);
39739
+ if (!response.ok) throw new Error(`status ${response.status}`);
39740
+ const blob = await response.blob();
39741
+ const objectUrl = window.URL.createObjectURL(blob);
39742
+ const anchor = document.createElement("a");
39743
+ anchor.href = objectUrl;
39744
+ anchor.download = filename;
39745
+ document.body.appendChild(anchor);
39746
+ anchor.click();
39747
+ anchor.remove();
39748
+ window.URL.revokeObjectURL(objectUrl);
39749
+ } catch {
39750
+ window.open(htmlUrl, "_blank", "noopener,noreferrer");
39751
+ }
39752
+ };
39756
39753
  return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(import_jsx_runtime148.Fragment, { children: [
39757
39754
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: cn("w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", children: [
39758
39755
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
@@ -39806,14 +39803,15 @@ var ResearchReportJobCard = ({
39806
39803
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
39807
39804
  "button",
39808
39805
  {
39809
- onClick: () => setShowExport(true),
39810
- className: "flex items-center gap-1.5 px-2.5 h-7 text-white text-xs font-medium rounded-lg transition-colors",
39806
+ onClick: handleDownload,
39807
+ disabled: !hasHTML,
39808
+ className: "flex items-center gap-1.5 px-2.5 h-7 text-white text-xs font-medium rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
39811
39809
  style: { backgroundColor: primaryColor },
39812
39810
  onMouseEnter: (e) => e.currentTarget.style.filter = "brightness(1.15)",
39813
39811
  onMouseLeave: (e) => e.currentTarget.style.filter = "brightness(1)",
39814
39812
  children: [
39815
39813
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DownloadIcon2, {}),
39816
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: "Export" })
39814
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: "Download" })
39817
39815
  ]
39818
39816
  }
39819
39817
  )
@@ -39831,7 +39829,7 @@ var ResearchReportJobCard = ({
39831
39829
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
39832
39830
  "iframe",
39833
39831
  {
39834
- src: formats.html_url,
39832
+ src: htmlUrl,
39835
39833
  title,
39836
39834
  sandbox: "allow-same-origin",
39837
39835
  style: {
@@ -39855,11 +39853,10 @@ var ResearchReportJobCard = ({
39855
39853
  !hasHTML && summary && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "mt-4 pt-4 border-t border-zinc-800/60", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-sm text-zinc-400 leading-relaxed line-clamp-3", children: summary }) })
39856
39854
  ] })
39857
39855
  ] }) }),
39858
- showExport && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(ExportModal2, { formats, title, onClose: () => setShowExport(false) }),
39859
39856
  showPreview && hasHTML && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
39860
39857
  FullscreenPreviewModal,
39861
39858
  {
39862
- url: formats.html_url,
39859
+ url: htmlUrl,
39863
39860
  title,
39864
39861
  onClose: () => setShowPreview(false)
39865
39862
  }