pxengine 0.1.134 → 0.1.135

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
@@ -16376,6 +16376,40 @@ function formatTemplateLabel(templateId) {
16376
16376
  if (!templateId) return null;
16377
16377
  return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
16378
16378
  }
16379
+ var DECK_CANVAS = { w: 1280, h: 720 };
16380
+ function useDeckFitScale(canvasW = DECK_CANVAS.w, canvasH = DECK_CANVAS.h) {
16381
+ const containerRef = (0, import_react80.useRef)(null);
16382
+ const [scale, setScale] = (0, import_react80.useState)(1);
16383
+ (0, import_react80.useLayoutEffect)(() => {
16384
+ const el = containerRef.current;
16385
+ if (!el) return;
16386
+ const update = () => {
16387
+ const w = el.clientWidth;
16388
+ const h = el.clientHeight;
16389
+ if (w <= 0 || h <= 0) return;
16390
+ setScale(Math.min(w / canvasW, h / canvasH));
16391
+ };
16392
+ update();
16393
+ const ro = new ResizeObserver(update);
16394
+ ro.observe(el);
16395
+ return () => ro.disconnect();
16396
+ }, [canvasW, canvasH]);
16397
+ return { containerRef, scale, canvasW, canvasH };
16398
+ }
16399
+ function hideDeckChrome(iframe) {
16400
+ try {
16401
+ const doc = iframe?.contentDocument;
16402
+ if (!doc) return;
16403
+ let style = doc.getElementById("pxe-embed-chrome");
16404
+ if (!style) {
16405
+ style = doc.createElement("style");
16406
+ style.id = "pxe-embed-chrome";
16407
+ (doc.head || doc.documentElement).appendChild(style);
16408
+ }
16409
+ style.textContent = ".nav,.progress-bar,.dots{display:none!important}";
16410
+ } catch {
16411
+ }
16412
+ }
16379
16413
  function deriveJobStatusUrl(newJobId, pollUrl, regenerateUrl) {
16380
16414
  const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/presentations\/[^/]+\/regenerate.*$/, "") ?? "";
16381
16415
  return `${base}/api/jobs/${newJobId}/status`;
@@ -16480,6 +16514,7 @@ var FullscreenModal = ({ url, title, slideCount, initialSlide = 1, onClose }) =>
16480
16514
  const [currentSlide, setCurrentSlide] = (0, import_react80.useState)(initialSlide);
16481
16515
  const [iframeReady, setIframeReady] = (0, import_react80.useState)(false);
16482
16516
  const iframeRef = (0, import_react80.useRef)(null);
16517
+ const { containerRef, scale, canvasW, canvasH } = useDeckFitScale();
16483
16518
  (0, import_react80.useEffect)(() => {
16484
16519
  const onKey = (e) => {
16485
16520
  if (e.key === "Escape") onClose();
@@ -16562,19 +16597,33 @@ var FullscreenModal = ({ url, title, slideCount, initialSlide = 1, onClose }) =>
16562
16597
  )
16563
16598
  ] })
16564
16599
  ] }),
16565
- /* @__PURE__ */ (0, import_jsx_runtime151.jsx)("div", { className: "flex-1 relative", children: /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
16566
- "iframe",
16600
+ /* @__PURE__ */ (0, import_jsx_runtime151.jsx)("div", { ref: containerRef, className: "flex-1 relative flex items-center justify-center overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
16601
+ "div",
16567
16602
  {
16568
- ref: iframeRef,
16569
- src: url,
16570
- title,
16571
- onLoad: () => {
16572
- setIframeReady(true);
16573
- iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: initialSlide }, "*");
16574
- },
16575
- sandbox: "allow-same-origin allow-scripts",
16576
- allow: "fullscreen",
16577
- className: "absolute inset-0 w-full h-full border-0"
16603
+ className: "relative",
16604
+ style: { width: canvasW * scale, height: canvasH * scale },
16605
+ children: /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
16606
+ "iframe",
16607
+ {
16608
+ ref: iframeRef,
16609
+ src: url,
16610
+ title,
16611
+ onLoad: () => {
16612
+ setIframeReady(true);
16613
+ hideDeckChrome(iframeRef.current);
16614
+ iframeRef.current?.contentWindow?.postMessage({ type: "goToSlide", slide: initialSlide }, "*");
16615
+ },
16616
+ sandbox: "allow-same-origin allow-scripts",
16617
+ allow: "fullscreen",
16618
+ className: "absolute top-0 left-0 border-0",
16619
+ style: {
16620
+ width: canvasW,
16621
+ height: canvasH,
16622
+ transform: `scale(${scale})`,
16623
+ transformOrigin: "top left"
16624
+ }
16625
+ }
16626
+ )
16578
16627
  }
16579
16628
  ) })
16580
16629
  ] });
@@ -16639,6 +16688,7 @@ var PresentationJobCard = ({
16639
16688
  const [currentSlide, setCurrentSlide] = (0, import_react80.useState)(1);
16640
16689
  const [iframeReady, setIframeReady] = (0, import_react80.useState)(false);
16641
16690
  const iframeRef = (0, import_react80.useRef)(null);
16691
+ const { containerRef: previewFitRef, scale: previewScale, canvasW, canvasH } = useDeckFitScale();
16642
16692
  (0, import_react80.useEffect)(() => {
16643
16693
  setStatus(initialStatus);
16644
16694
  }, [initialStatus]);
@@ -17499,19 +17549,36 @@ var PresentationJobCard = ({
17499
17549
  /* @__PURE__ */ (0, import_jsx_runtime151.jsxs)(
17500
17550
  "div",
17501
17551
  {
17552
+ ref: previewFitRef,
17502
17553
  onClick: () => setShowFullscreen(true),
17503
- className: "group relative aspect-video w-full overflow-hidden rounded-xl bg-zinc-950 border border-zinc-800/50 cursor-pointer",
17554
+ className: "group relative aspect-video w-full overflow-hidden rounded-xl bg-zinc-950 border border-zinc-800/50 cursor-pointer flex items-center justify-center",
17504
17555
  title: "Click to open fullscreen",
17505
17556
  children: [
17506
17557
  /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
17507
- "iframe",
17558
+ "div",
17508
17559
  {
17509
- ref: iframeRef,
17510
- src: formats.html_url,
17511
- title,
17512
- sandbox: "allow-same-origin allow-scripts",
17513
- onLoad: () => setIframeReady(true),
17514
- className: "absolute inset-0 block h-full w-full border-0 pointer-events-none"
17560
+ className: "relative",
17561
+ style: { width: canvasW * previewScale, height: canvasH * previewScale },
17562
+ children: /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
17563
+ "iframe",
17564
+ {
17565
+ ref: iframeRef,
17566
+ src: formats.html_url,
17567
+ title,
17568
+ sandbox: "allow-same-origin allow-scripts",
17569
+ onLoad: () => {
17570
+ setIframeReady(true);
17571
+ hideDeckChrome(iframeRef.current);
17572
+ },
17573
+ className: "absolute top-0 left-0 border-0 pointer-events-none",
17574
+ style: {
17575
+ width: canvasW,
17576
+ height: canvasH,
17577
+ transform: `scale(${previewScale})`,
17578
+ transformOrigin: "top left"
17579
+ }
17580
+ }
17581
+ )
17515
17582
  }
17516
17583
  ),
17517
17584
  /* @__PURE__ */ (0, import_jsx_runtime151.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-black/0 group-hover:bg-black/30 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime151.jsxs)("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: [