pxengine 0.1.118 → 0.1.119

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
@@ -15811,6 +15811,7 @@ function formatTemplateLabel(templateId) {
15811
15811
  if (!templateId) return null;
15812
15812
  return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
15813
15813
  }
15814
+ var Chip = ({ children }) => /* @__PURE__ */ jsx147("span", { className: "inline-flex items-center px-2 h-[22px] rounded-md bg-zinc-800/70 border border-zinc-700/50 text-[11px] font-medium text-zinc-400 whitespace-nowrap", children });
15814
15815
  function deriveJobStatusUrl(newJobId, pollUrl, regenerateUrl) {
15815
15816
  const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/presentations\/[^/]+\/regenerate.*$/, "") ?? "";
15816
15817
  return `${base}/api/jobs/${newJobId}/status`;
@@ -16789,12 +16790,22 @@ var PresentationJobCard = ({
16789
16790
  ),
16790
16791
  /* @__PURE__ */ jsxs108("div", { className: "flex-1 min-w-0", children: [
16791
16792
  /* @__PURE__ */ jsx147("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", style: t.text, children: title }),
16792
- /* @__PURE__ */ jsxs108("p", { className: "text-xs text-zinc-500 mt-0.5", style: t.muted, children: [
16793
- slideCount ? `${slideCount} slides` : "Presentation",
16794
- " \xB7 Ready to export",
16795
- templateLabel && ` \xB7 ${templateLabel}`
16793
+ /* @__PURE__ */ jsxs108("div", { className: "flex flex-wrap items-center gap-1.5 mt-1.5", children: [
16794
+ /* @__PURE__ */ jsx147(Chip, { children: slideCount ? `${slideCount} slides` : "Presentation" }),
16795
+ templateLabel && /* @__PURE__ */ jsx147(Chip, { children: templateLabel })
16796
16796
  ] }),
16797
- generationMode === "template" && /* @__PURE__ */ jsx147("p", { className: "text-xs mt-1", children: isApproved ? /* @__PURE__ */ jsx147("span", { className: "text-emerald-400/90", children: "Approved \u2014 future decks use this format" }) : reviewStatus === "pending_review" ? /* @__PURE__ */ jsx147("span", { className: "text-amber-400/90", children: "Review this deck, then approve to lock the format" }) : null })
16797
+ generationMode === "template" && (isApproved || reviewStatus === "pending_review") && /* @__PURE__ */ jsxs108("p", { className: "flex items-center gap-1.5 text-xs mt-2", children: [
16798
+ /* @__PURE__ */ jsx147(
16799
+ "span",
16800
+ {
16801
+ className: cn(
16802
+ "w-1.5 h-1.5 rounded-full flex-shrink-0",
16803
+ isApproved ? "bg-emerald-400" : "bg-amber-400"
16804
+ )
16805
+ }
16806
+ ),
16807
+ isApproved ? /* @__PURE__ */ jsx147("span", { className: "text-emerald-400/90", children: "Approved \u2014 future decks use this format" }) : /* @__PURE__ */ jsx147("span", { className: "text-amber-400/90", children: "Review this deck, then approve to lock the format" })
16808
+ ] })
16798
16809
  ] }),
16799
16810
  /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-1.5 flex-shrink-0 flex-wrap justify-end", children: [
16800
16811
  /* @__PURE__ */ jsxs108("div", { className: "flex items-center rounded-lg border border-zinc-700 bg-zinc-800 overflow-hidden divide-x divide-zinc-700", children: [
@@ -17079,6 +17090,102 @@ var FullscreenPreviewModal = ({ url, title, onClose }) => {
17079
17090
  ) })
17080
17091
  ] });
17081
17092
  };
17093
+ var Chip2 = ({ children }) => /* @__PURE__ */ jsx148("span", { className: "inline-flex items-center px-2 h-[22px] rounded-md bg-zinc-800/70 border border-zinc-700/50 text-[11px] font-medium text-zinc-400 whitespace-nowrap capitalize", children });
17094
+ var REPORT_FORMATS = [
17095
+ {
17096
+ key: "pdf",
17097
+ label: "PDF",
17098
+ ext: ".pdf",
17099
+ emoji: "\u{1F4C4}",
17100
+ desc: "Print-ready, fixed layout \u2014 open in any PDF viewer",
17101
+ accent: { text: "text-red-400", bg: "bg-red-500/10 border-red-500/20" }
17102
+ },
17103
+ {
17104
+ key: "html",
17105
+ label: "HTML",
17106
+ ext: ".html",
17107
+ emoji: "\u{1F310}",
17108
+ desc: "Interactive web page \u2014 download and open in a browser",
17109
+ accent: { text: "text-sky-400", bg: "bg-sky-500/10 border-sky-500/20" }
17110
+ }
17111
+ ];
17112
+ var ReportExportModal = ({ htmlUrl, pdfUrl, title, onClose }) => {
17113
+ const urls = { pdf: pdfUrl, html: htmlUrl };
17114
+ const available = REPORT_FORMATS.filter((f) => urls[f.key]);
17115
+ const filename = (title ?? "").replace(/[^a-z0-9]/gi, "-").toLowerCase();
17116
+ const [downloadingKey, setDownloadingKey] = useState11(null);
17117
+ useEffect8(() => {
17118
+ const onKey = (e) => {
17119
+ if (e.key === "Escape") onClose();
17120
+ };
17121
+ document.addEventListener("keydown", onKey);
17122
+ return () => document.removeEventListener("keydown", onKey);
17123
+ }, [onClose]);
17124
+ const handleDownload = async (key, url, ext) => {
17125
+ if (downloadingKey) return;
17126
+ const downloadName = `${filename}${ext}`;
17127
+ const href = `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(downloadName)}`;
17128
+ try {
17129
+ setDownloadingKey(key);
17130
+ const response = await fetch(href);
17131
+ if (!response.ok) throw new Error(`status ${response.status}`);
17132
+ const blob = await response.blob();
17133
+ const objectUrl = window.URL.createObjectURL(blob);
17134
+ const anchor = document.createElement("a");
17135
+ anchor.href = objectUrl;
17136
+ anchor.download = downloadName;
17137
+ document.body.appendChild(anchor);
17138
+ anchor.click();
17139
+ anchor.remove();
17140
+ window.URL.revokeObjectURL(objectUrl);
17141
+ } catch {
17142
+ window.open(url, "_blank", "noopener,noreferrer");
17143
+ } finally {
17144
+ setDownloadingKey(null);
17145
+ }
17146
+ };
17147
+ return /* @__PURE__ */ jsxs109("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
17148
+ /* @__PURE__ */ jsx148("div", { className: "absolute inset-0 bg-black/70 backdrop-blur-sm", onClick: onClose }),
17149
+ /* @__PURE__ */ jsxs109("div", { className: "relative z-10 bg-zinc-900 border border-zinc-800 rounded-2xl w-full max-w-sm p-6 shadow-2xl", children: [
17150
+ /* @__PURE__ */ jsxs109("div", { className: "flex items-start justify-between mb-5", children: [
17151
+ /* @__PURE__ */ jsxs109("div", { className: "min-w-0 pr-3", children: [
17152
+ /* @__PURE__ */ jsx148("h3", { className: "text-sm font-semibold text-zinc-100", children: "Download report" }),
17153
+ /* @__PURE__ */ jsx148("p", { className: "text-xs text-zinc-500 mt-0.5 truncate", children: title })
17154
+ ] }),
17155
+ /* @__PURE__ */ jsx148("button", { onClick: onClose, className: "text-zinc-500 hover:text-zinc-200 transition-colors flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx148(CloseIcon2, {}) })
17156
+ ] }),
17157
+ /* @__PURE__ */ jsxs109("div", { className: "space-y-2.5", children: [
17158
+ available.length === 0 && /* @__PURE__ */ jsx148("p", { className: "text-sm text-zinc-500 text-center py-6", children: "No formats available yet" }),
17159
+ available.map((fmt) => {
17160
+ const url = urls[fmt.key];
17161
+ const isDownloading = downloadingKey === fmt.key;
17162
+ return /* @__PURE__ */ jsxs109(
17163
+ "button",
17164
+ {
17165
+ type: "button",
17166
+ disabled: Boolean(downloadingKey),
17167
+ onClick: () => handleDownload(fmt.key, url, fmt.ext),
17168
+ className: cn(
17169
+ "flex w-full items-center gap-3.5 p-3.5 rounded-xl border transition-all text-left",
17170
+ "hover:brightness-110 disabled:opacity-60 disabled:cursor-not-allowed",
17171
+ fmt.accent.bg
17172
+ ),
17173
+ children: [
17174
+ /* @__PURE__ */ jsx148("span", { className: "text-xl flex-shrink-0", children: fmt.emoji }),
17175
+ /* @__PURE__ */ jsxs109("div", { className: "flex-1 min-w-0", children: [
17176
+ /* @__PURE__ */ jsx148("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: isDownloading ? `Downloading ${fmt.label}...` : fmt.label }),
17177
+ /* @__PURE__ */ jsx148("p", { className: "text-xs text-zinc-500 mt-0.5 leading-relaxed", children: isDownloading ? "Please wait while the file is being prepared." : fmt.desc })
17178
+ ] }),
17179
+ /* @__PURE__ */ jsx148("span", { className: cn("flex-shrink-0", fmt.accent.text), children: /* @__PURE__ */ jsx148(DownloadIcon2, {}) })
17180
+ ]
17181
+ },
17182
+ fmt.key
17183
+ );
17184
+ })
17185
+ ] })
17186
+ ] })
17187
+ ] });
17188
+ };
17082
17189
  function deriveJobStatusUrl2(newJobId, pollUrl, regenerateUrl) {
17083
17190
  const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/reports\/[^/]+\/regenerate.*$/, "") ?? "";
17084
17191
  return `${base}/api/jobs/${newJobId}/status`;
@@ -17142,6 +17249,7 @@ var ResearchReportJobCard = (props) => {
17142
17249
  const [error, setError] = useState11(initialError);
17143
17250
  const [progress, setProgress] = useState11(initialProgress);
17144
17251
  const [showPreview, setShowPreview] = useState11(false);
17252
+ const [showExport, setShowExport] = useState11(false);
17145
17253
  const [previewScale, setPreviewScale] = useState11(1);
17146
17254
  const [copied, setCopied] = useState11(false);
17147
17255
  const [approving, setApproving] = useState11(false);
@@ -17732,46 +17840,6 @@ var ResearchReportJobCard = (props) => {
17732
17840
  ] }) })
17733
17841
  ] }) });
17734
17842
  }
17735
- const handleDownload = async () => {
17736
- if (!htmlUrl) return;
17737
- const filename = `${(title ?? "").replace(/[^a-z0-9]/gi, "-").toLowerCase()}.html`;
17738
- const href = `/api/download?url=${encodeURIComponent(htmlUrl)}&filename=${encodeURIComponent(filename)}`;
17739
- try {
17740
- const response = await fetch(href);
17741
- if (!response.ok) throw new Error(`status ${response.status}`);
17742
- const blob = await response.blob();
17743
- const objectUrl = window.URL.createObjectURL(blob);
17744
- const anchor = document.createElement("a");
17745
- anchor.href = objectUrl;
17746
- anchor.download = filename;
17747
- document.body.appendChild(anchor);
17748
- anchor.click();
17749
- anchor.remove();
17750
- window.URL.revokeObjectURL(objectUrl);
17751
- } catch {
17752
- window.open(htmlUrl, "_blank", "noopener,noreferrer");
17753
- }
17754
- };
17755
- const handleDownloadPdf = async () => {
17756
- if (!pdfUrl) return;
17757
- const filename = `${(title ?? "").replace(/[^a-z0-9]/gi, "-").toLowerCase()}.pdf`;
17758
- const href = `/api/download?url=${encodeURIComponent(pdfUrl)}&filename=${encodeURIComponent(filename)}`;
17759
- try {
17760
- const response = await fetch(href);
17761
- if (!response.ok) throw new Error(`status ${response.status}`);
17762
- const blob = await response.blob();
17763
- const objectUrl = window.URL.createObjectURL(blob);
17764
- const anchor = document.createElement("a");
17765
- anchor.href = objectUrl;
17766
- anchor.download = filename;
17767
- document.body.appendChild(anchor);
17768
- anchor.click();
17769
- anchor.remove();
17770
- window.URL.revokeObjectURL(objectUrl);
17771
- } catch {
17772
- window.open(pdfUrl, "_blank", "noopener,noreferrer");
17773
- }
17774
- };
17775
17843
  const resolveShareLink = () => {
17776
17844
  if (shareUrl) return shareUrl;
17777
17845
  if (typeof window !== "undefined" && job_id) {
@@ -17897,15 +17965,34 @@ var ResearchReportJobCard = (props) => {
17897
17965
  ),
17898
17966
  /* @__PURE__ */ jsxs109("div", { className: "flex-1 min-w-0", children: [
17899
17967
  /* @__PURE__ */ jsx148("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", children: title }),
17900
- /* @__PURE__ */ jsxs109("p", { className: "text-xs text-zinc-500 mt-0.5", children: [
17901
- depth && /* @__PURE__ */ jsx148("span", { className: "capitalize", children: depth }),
17902
- depth && sectionCount > 0 && " \xB7 ",
17903
- sectionCount > 0 && `${sectionCount} sections`,
17904
- sourceCount > 0 && ` \xB7 ${sourceCount} sources`,
17905
- wordCount > 0 && ` \xB7 ${formatWordCount(wordCount)} words`,
17906
- templateLabel && ` \xB7 ${templateLabel}`
17968
+ (depth || sectionCount > 0 || sourceCount > 0 || wordCount > 0 || templateLabel) && /* @__PURE__ */ jsxs109("div", { className: "flex flex-wrap items-center gap-1.5 mt-1.5", children: [
17969
+ depth && /* @__PURE__ */ jsx148(Chip2, { children: depth }),
17970
+ sectionCount > 0 && /* @__PURE__ */ jsxs109(Chip2, { children: [
17971
+ sectionCount,
17972
+ " sections"
17973
+ ] }),
17974
+ sourceCount > 0 && /* @__PURE__ */ jsxs109(Chip2, { children: [
17975
+ sourceCount,
17976
+ " sources"
17977
+ ] }),
17978
+ wordCount > 0 && /* @__PURE__ */ jsxs109(Chip2, { children: [
17979
+ formatWordCount(wordCount),
17980
+ " words"
17981
+ ] }),
17982
+ templateLabel && /* @__PURE__ */ jsx148(Chip2, { children: templateLabel })
17907
17983
  ] }),
17908
- generationMode === "template" && /* @__PURE__ */ jsx148("p", { className: "text-xs mt-1", children: isApproved ? /* @__PURE__ */ jsx148("span", { className: "text-emerald-400/90", children: "Approved \u2014 future reports use this format" }) : reviewStatus === "pending_review" ? /* @__PURE__ */ jsx148("span", { className: "text-amber-400/90", children: "Review this report, then approve to lock the layout" }) : null })
17984
+ generationMode === "template" && (isApproved || reviewStatus === "pending_review") && /* @__PURE__ */ jsxs109("p", { className: "flex items-center gap-1.5 text-xs mt-2", children: [
17985
+ /* @__PURE__ */ jsx148(
17986
+ "span",
17987
+ {
17988
+ className: cn(
17989
+ "w-1.5 h-1.5 rounded-full flex-shrink-0",
17990
+ isApproved ? "bg-emerald-400" : "bg-amber-400"
17991
+ )
17992
+ }
17993
+ ),
17994
+ isApproved ? /* @__PURE__ */ jsx148("span", { className: "text-emerald-400/90", children: "Approved \u2014 future reports use this format" }) : /* @__PURE__ */ jsx148("span", { className: "text-amber-400/90", children: "Review this report, then approve to lock the layout" })
17995
+ ] })
17909
17996
  ] }),
17910
17997
  /* @__PURE__ */ jsxs109("div", { className: "flex items-center gap-1.5 flex-shrink-0 flex-wrap justify-end", children: [
17911
17998
  /* @__PURE__ */ jsxs109("div", { className: "flex items-center rounded-lg border border-zinc-700 bg-zinc-800 overflow-hidden divide-x divide-zinc-700", children: [
@@ -17963,18 +18050,6 @@ var ResearchReportJobCard = (props) => {
17963
18050
  ),
17964
18051
  children: copied ? /* @__PURE__ */ jsx148(CheckIcon2, {}) : /* @__PURE__ */ jsx148(ShareIcon2, {})
17965
18052
  }
17966
- ),
17967
- pdfUrl && /* @__PURE__ */ jsxs109(
17968
- "button",
17969
- {
17970
- onClick: handleDownloadPdf,
17971
- title: "Download PDF",
17972
- className: "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors",
17973
- children: [
17974
- /* @__PURE__ */ jsx148(DownloadIcon2, {}),
17975
- /* @__PURE__ */ jsx148("span", { children: "PDF" })
17976
- ]
17977
- }
17978
18053
  )
17979
18054
  ] }),
17980
18055
  canApprove && /* @__PURE__ */ jsxs109(
@@ -17994,8 +18069,9 @@ var ResearchReportJobCard = (props) => {
17994
18069
  /* @__PURE__ */ jsxs109(
17995
18070
  "button",
17996
18071
  {
17997
- onClick: handleDownload,
17998
- disabled: !hasHTML,
18072
+ onClick: () => setShowExport(true),
18073
+ disabled: !hasHTML && !pdfUrl,
18074
+ title: "Download this report (PDF or HTML)",
17999
18075
  className: "flex items-center gap-1.5 px-3 h-7 text-xs font-semibold rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
18000
18076
  style: { backgroundImage: GOLD_GRADIENT, color: readableOn(primaryColor) },
18001
18077
  onMouseEnter: (e) => e.currentTarget.style.filter = "brightness(1.1)",
@@ -18052,6 +18128,15 @@ var ResearchReportJobCard = (props) => {
18052
18128
  title,
18053
18129
  onClose: () => setShowPreview(false)
18054
18130
  }
18131
+ ),
18132
+ showExport && /* @__PURE__ */ jsx148(
18133
+ ReportExportModal,
18134
+ {
18135
+ htmlUrl,
18136
+ pdfUrl,
18137
+ title,
18138
+ onClose: () => setShowExport(false)
18139
+ }
18055
18140
  )
18056
18141
  ] });
18057
18142
  };