@orangecatai/adgen-canvas 0.0.15 → 0.0.17

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/dev/index.js CHANGED
@@ -67,10 +67,10 @@ import {
67
67
  serializeAsJSON,
68
68
  serializeLibraryAsJSON,
69
69
  strokeRectWithRotation_simple
70
- } from "./chunk-FGSZO5WI.js";
70
+ } from "./chunk-7JV3TYRQ.js";
71
71
  import {
72
72
  define_import_meta_env_default
73
- } from "./chunk-EL4HTLYE.js";
73
+ } from "./chunk-N5ZWSPF6.js";
74
74
  import {
75
75
  en_default
76
76
  } from "./chunk-IFMURN5W.js";
@@ -9770,7 +9770,7 @@ var exportCanvas = async (type, elements, appState, files, {
9770
9770
  let blob = canvasToBlob(tempCanvas);
9771
9771
  if (appState.exportEmbedScene) {
9772
9772
  blob = blob.then(
9773
- (blob2) => import("./data/image-AVR5GHYZ.js").then(
9773
+ (blob2) => import("./data/image-2XZ3M7M6.js").then(
9774
9774
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
9775
9775
  blob: blob2,
9776
9776
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -22300,7 +22300,13 @@ function notify2() {
22300
22300
  }
22301
22301
  var templateBuilderStore = {
22302
22302
  open(sourceFrameId) {
22303
- state2 = { ...state2, isOpen: true, templateName: "", campaignTag: "", sourceFrameId: sourceFrameId ?? null };
22303
+ state2 = {
22304
+ ...state2,
22305
+ isOpen: true,
22306
+ templateName: "",
22307
+ campaignTag: "",
22308
+ sourceFrameId: sourceFrameId ?? null
22309
+ };
22304
22310
  notify2();
22305
22311
  },
22306
22312
  close() {
@@ -22493,10 +22499,54 @@ var CheckIcon = () => /* @__PURE__ */ jsx83(
22493
22499
  }
22494
22500
  );
22495
22501
  var TemplateIcon = () => /* @__PURE__ */ jsxs45("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: [
22496
- /* @__PURE__ */ jsx83("rect", { x: "1", y: "1", width: "5", height: "5", rx: "1", stroke: "currentColor", strokeWidth: "1.4" }),
22497
- /* @__PURE__ */ jsx83("rect", { x: "8", y: "1", width: "5", height: "5", rx: "1", stroke: "currentColor", strokeWidth: "1.4" }),
22498
- /* @__PURE__ */ jsx83("rect", { x: "1", y: "8", width: "5", height: "5", rx: "1", stroke: "currentColor", strokeWidth: "1.4" }),
22499
- /* @__PURE__ */ jsx83("rect", { x: "8", y: "8", width: "5", height: "5", rx: "1", stroke: "currentColor", strokeWidth: "1.4" })
22502
+ /* @__PURE__ */ jsx83(
22503
+ "rect",
22504
+ {
22505
+ x: "1",
22506
+ y: "1",
22507
+ width: "5",
22508
+ height: "5",
22509
+ rx: "1",
22510
+ stroke: "currentColor",
22511
+ strokeWidth: "1.4"
22512
+ }
22513
+ ),
22514
+ /* @__PURE__ */ jsx83(
22515
+ "rect",
22516
+ {
22517
+ x: "8",
22518
+ y: "1",
22519
+ width: "5",
22520
+ height: "5",
22521
+ rx: "1",
22522
+ stroke: "currentColor",
22523
+ strokeWidth: "1.4"
22524
+ }
22525
+ ),
22526
+ /* @__PURE__ */ jsx83(
22527
+ "rect",
22528
+ {
22529
+ x: "1",
22530
+ y: "8",
22531
+ width: "5",
22532
+ height: "5",
22533
+ rx: "1",
22534
+ stroke: "currentColor",
22535
+ strokeWidth: "1.4"
22536
+ }
22537
+ ),
22538
+ /* @__PURE__ */ jsx83(
22539
+ "rect",
22540
+ {
22541
+ x: "8",
22542
+ y: "8",
22543
+ width: "5",
22544
+ height: "5",
22545
+ rx: "1",
22546
+ stroke: "currentColor",
22547
+ strokeWidth: "1.4"
22548
+ }
22549
+ )
22500
22550
  ] });
22501
22551
  var AutoResizeIcon = () => /* @__PURE__ */ jsxs45("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
22502
22552
  /* @__PURE__ */ jsx83(
@@ -22549,7 +22599,9 @@ var FrameToolbar = ({
22549
22599
  const [localWidth, setLocalWidth] = useState27(Math.round(element.width));
22550
22600
  const [localHeight, setLocalHeight] = useState27(Math.round(element.height));
22551
22601
  const [panelState, setPanelState] = useState27(autoResizePanelStore.getState());
22552
- const [builderState, setBuilderState] = useState27(templateBuilderStore.getState());
22602
+ const [builderState, setBuilderState] = useState27(
22603
+ templateBuilderStore.getState()
22604
+ );
22553
22605
  const dropdownRef = useRef24(null);
22554
22606
  useEffect29(() => {
22555
22607
  return autoResizePanelStore.subscribe(setPanelState);
@@ -22882,6 +22934,12 @@ import { useEffect as useEffect33, useRef as useRef28, useState as useState31 }
22882
22934
  import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords7 } from "@orangecatai/common";
22883
22935
  import { getElementAbsoluteCoords as getElementAbsoluteCoords10 } from "@orangecatai/element";
22884
22936
 
22937
+ // utils/openRouterApiKey.ts
22938
+ function resolveOpenRouterApiKey(propKey) {
22939
+ const normalizedPropKey = propKey?.trim();
22940
+ return (normalizedPropKey ? normalizedPropKey : void 0) ?? (typeof import.meta !== "undefined" && define_import_meta_env_default?.VITE_APP_OPENROUTER_API_KEY ? define_import_meta_env_default.VITE_APP_OPENROUTER_API_KEY : "") ?? "";
22941
+ }
22942
+
22885
22943
  // components/auto-resize/AutoResizePanel.tsx
22886
22944
  import { useCallback as useCallback16, useEffect as useEffect32, useRef as useRef27, useState as useState30 } from "react";
22887
22945
 
@@ -24674,11 +24732,19 @@ function extractFrameInfo(elements, frame, files) {
24674
24732
  if (el.type === "image") {
24675
24733
  const fileData = files[el.fileId];
24676
24734
  if (fileData?.dataURL) {
24677
- background = { type: "image", dataUrl: fileData.dataURL, elementId: el.id };
24735
+ background = {
24736
+ type: "image",
24737
+ dataUrl: fileData.dataURL,
24738
+ elementId: el.id
24739
+ };
24678
24740
  continue;
24679
24741
  }
24680
24742
  } else if (el.type === "rectangle" && el.backgroundColor && el.backgroundColor !== "transparent") {
24681
- background = { type: "solid", color: el.backgroundColor, elementId: el.id };
24743
+ background = {
24744
+ type: "solid",
24745
+ color: el.backgroundColor,
24746
+ elementId: el.id
24747
+ };
24682
24748
  continue;
24683
24749
  }
24684
24750
  }
@@ -24797,8 +24863,9 @@ function containImageInBbox(imgW, imgH, bboxW, bboxH) {
24797
24863
  async function captureFrameScreenshotFromApp(app, frameId) {
24798
24864
  const elements = app.getSceneElements();
24799
24865
  const frame = elements.find((el) => el.id === frameId);
24800
- if (!frame)
24866
+ if (!frame) {
24801
24867
  return null;
24868
+ }
24802
24869
  const children = getFrameChildren4(elements, frameId);
24803
24870
  try {
24804
24871
  const canvas = await exportToCanvas(
@@ -24910,8 +24977,9 @@ async function tagImageElementsWithVision(info, screenshotDataUrl, openRouterApi
24910
24977
  const imageEls = info.foreground.filter(
24911
24978
  (el) => el.kind === "image" && !el.slotType
24912
24979
  );
24913
- if (imageEls.length === 0)
24980
+ if (imageEls.length === 0) {
24914
24981
  return;
24982
+ }
24915
24983
  const srcW = info.frame.width;
24916
24984
  const srcH = info.frame.height;
24917
24985
  const elementList = imageEls.map((el, i) => {
@@ -24960,8 +25028,9 @@ Return ONLY a JSON object mapping the element number (string key) to its role. E
24960
25028
  })
24961
25029
  }
24962
25030
  );
24963
- if (!response.ok)
25031
+ if (!response.ok) {
24964
25032
  return;
25033
+ }
24965
25034
  const data = await response.json();
24966
25035
  const raw = data?.choices?.[0]?.message?.content ?? "";
24967
25036
  const parsed = JSON.parse(raw);
@@ -25325,13 +25394,15 @@ async function runAutoResizeForDimension(opts) {
25325
25394
  newEls.push({ ...el, frameId });
25326
25395
  } else if (pel.kind === "image") {
25327
25396
  const fileId2 = nanoid();
25328
- const { width: natW, height: natH } = await getImageNaturalDimensions(pel.dataUrl);
25329
- const { relX, relY, width: imgW, height: imgH } = containImageInBbox(
25330
- natW,
25331
- natH,
25332
- pel.width,
25333
- pel.height
25397
+ const { width: natW, height: natH } = await getImageNaturalDimensions(
25398
+ pel.dataUrl
25334
25399
  );
25400
+ const {
25401
+ relX,
25402
+ relY,
25403
+ width: imgW,
25404
+ height: imgH
25405
+ } = containImageInBbox(natW, natH, pel.width, pel.height);
25335
25406
  const el = newImageElement({
25336
25407
  type: "image",
25337
25408
  x: pel.x + relX,
@@ -25401,7 +25472,9 @@ async function runAutoResizeForDimension(opts) {
25401
25472
  }
25402
25473
  const screenshot = await captureFrameScreenshotFromApp(app, frameId);
25403
25474
  if (!screenshot) {
25404
- debug(`[AutoResize] ${debugLabel} \u2014 screenshot unavailable, skipping reviewer`);
25475
+ debug(
25476
+ `[AutoResize] ${debugLabel} \u2014 screenshot unavailable, skipping reviewer`
25477
+ );
25405
25478
  break;
25406
25479
  }
25407
25480
  onProgress?.("Reviewing layout\u2026");
@@ -25410,7 +25483,9 @@ async function runAutoResizeForDimension(opts) {
25410
25483
  screenshotDataUrl: screenshot,
25411
25484
  htmlSource: html,
25412
25485
  frame: { id: frameId, width: tgtW, height: tgtH },
25413
- userBrief: `Auto-resize ad from ${Math.round(srcFrame.width)}\xD7${Math.round(srcFrame.height)} to ${tgtW}\xD7${tgtH}`,
25486
+ userBrief: `Auto-resize ad from ${Math.round(
25487
+ srcFrame.width
25488
+ )}\xD7${Math.round(srcFrame.height)} to ${tgtW}\xD7${tgtH}`,
25414
25489
  apiKey: openRouterApiKey,
25415
25490
  reviewerModel: chatModel,
25416
25491
  signal,
@@ -25418,7 +25493,9 @@ async function runAutoResizeForDimension(opts) {
25418
25493
  });
25419
25494
  reviewRounds++;
25420
25495
  if (feedback.approved) {
25421
- debug(`[AutoResize] ${debugLabel} \u2014 reviewer approved (round ${reviewRounds})`);
25496
+ debug(
25497
+ `[AutoResize] ${debugLabel} \u2014 reviewer approved (round ${reviewRounds})`
25498
+ );
25422
25499
  break;
25423
25500
  }
25424
25501
  debug(
@@ -25494,7 +25571,10 @@ async function runAutoResize(opts) {
25494
25571
  }));
25495
25572
  }
25496
25573
  const info = extractFrameInfo(elements, sourceFrame, app.files);
25497
- const sourceScreenshot = await captureFrameScreenshotFromApp(app, sourceFrameId);
25574
+ const sourceScreenshot = await captureFrameScreenshotFromApp(
25575
+ app,
25576
+ sourceFrameId
25577
+ );
25498
25578
  if (sourceScreenshot) {
25499
25579
  await tagImageElementsWithVision(
25500
25580
  info,
@@ -25590,16 +25670,95 @@ var PRESETS = [
25590
25670
  { label: "160\xD7600", width: 160, height: 600, desc: "Wide Skyscraper" }
25591
25671
  ];
25592
25672
  var ResizeIcon = () => /* @__PURE__ */ jsxs48("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
25593
- /* @__PURE__ */ jsx89("rect", { x: "1.5", y: "1.5", width: "7", height: "7", rx: "1", stroke: "currentColor", strokeWidth: "1.4" }),
25594
- /* @__PURE__ */ jsx89("rect", { x: "7.5", y: "7.5", width: "7", height: "7", rx: "1", stroke: "currentColor", strokeWidth: "1.4", strokeDasharray: "2 1", opacity: "0.6" }),
25595
- /* @__PURE__ */ jsx89("path", { d: "M9.5 6.5L13.5 6.5M13.5 6.5L13.5 2.5M13.5 2.5L9.5 2.5", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" })
25673
+ /* @__PURE__ */ jsx89(
25674
+ "rect",
25675
+ {
25676
+ x: "1.5",
25677
+ y: "1.5",
25678
+ width: "7",
25679
+ height: "7",
25680
+ rx: "1",
25681
+ stroke: "currentColor",
25682
+ strokeWidth: "1.4"
25683
+ }
25684
+ ),
25685
+ /* @__PURE__ */ jsx89(
25686
+ "rect",
25687
+ {
25688
+ x: "7.5",
25689
+ y: "7.5",
25690
+ width: "7",
25691
+ height: "7",
25692
+ rx: "1",
25693
+ stroke: "currentColor",
25694
+ strokeWidth: "1.4",
25695
+ strokeDasharray: "2 1",
25696
+ opacity: "0.6"
25697
+ }
25698
+ ),
25699
+ /* @__PURE__ */ jsx89(
25700
+ "path",
25701
+ {
25702
+ d: "M9.5 6.5L13.5 6.5M13.5 6.5L13.5 2.5M13.5 2.5L9.5 2.5",
25703
+ stroke: "currentColor",
25704
+ strokeWidth: "1.3",
25705
+ strokeLinecap: "round",
25706
+ strokeLinejoin: "round"
25707
+ }
25708
+ )
25596
25709
  ] });
25597
- var CloseIcon2 = () => /* @__PURE__ */ jsx89("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89("path", { d: "M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
25598
- var CheckIcon3 = () => /* @__PURE__ */ jsx89("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89("path", { d: "M2 6.5L4.5 9L10 3", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
25599
- var SpinnerIcon2 = () => /* @__PURE__ */ jsx89("svg", { className: "arp-spinner", width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", children: /* @__PURE__ */ jsx89("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "20 14" }) });
25710
+ var CloseIcon2 = () => /* @__PURE__ */ jsx89("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89(
25711
+ "path",
25712
+ {
25713
+ d: "M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5",
25714
+ stroke: "currentColor",
25715
+ strokeWidth: "1.5",
25716
+ strokeLinecap: "round"
25717
+ }
25718
+ ) });
25719
+ var CheckIcon3 = () => /* @__PURE__ */ jsx89("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89(
25720
+ "path",
25721
+ {
25722
+ d: "M2 6.5L4.5 9L10 3",
25723
+ stroke: "currentColor",
25724
+ strokeWidth: "1.6",
25725
+ strokeLinecap: "round",
25726
+ strokeLinejoin: "round"
25727
+ }
25728
+ ) });
25729
+ var SpinnerIcon2 = () => /* @__PURE__ */ jsx89(
25730
+ "svg",
25731
+ {
25732
+ className: "arp-spinner",
25733
+ width: "13",
25734
+ height: "13",
25735
+ viewBox: "0 0 14 14",
25736
+ fill: "none",
25737
+ children: /* @__PURE__ */ jsx89(
25738
+ "circle",
25739
+ {
25740
+ cx: "7",
25741
+ cy: "7",
25742
+ r: "5.5",
25743
+ stroke: "currentColor",
25744
+ strokeWidth: "1.5",
25745
+ strokeLinecap: "round",
25746
+ strokeDasharray: "20 14"
25747
+ }
25748
+ )
25749
+ }
25750
+ );
25600
25751
  var ErrorIcon = () => /* @__PURE__ */ jsxs48("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", children: [
25601
25752
  /* @__PURE__ */ jsx89("circle", { cx: "6", cy: "6", r: "4.5", stroke: "currentColor", strokeWidth: "1.3" }),
25602
- /* @__PURE__ */ jsx89("path", { d: "M6 3.5V6.5", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round" }),
25753
+ /* @__PURE__ */ jsx89(
25754
+ "path",
25755
+ {
25756
+ d: "M6 3.5V6.5",
25757
+ stroke: "currentColor",
25758
+ strokeWidth: "1.4",
25759
+ strokeLinecap: "round"
25760
+ }
25761
+ ),
25603
25762
  /* @__PURE__ */ jsx89("circle", { cx: "6", cy: "8.5", r: "0.65", fill: "currentColor" })
25604
25763
  ] });
25605
25764
  var CustomDimInput = ({ onAdd }) => {
@@ -25615,10 +25774,41 @@ var CustomDimInput = ({ onAdd }) => {
25615
25774
  }
25616
25775
  };
25617
25776
  return /* @__PURE__ */ jsxs48("div", { className: "arp-custom-row", children: [
25618
- /* @__PURE__ */ jsx89("input", { className: "arp-custom-input", type: "number", placeholder: "W", value: w, min: 1, onChange: (e) => setW(e.target.value), onPointerDown: (e) => e.stopPropagation() }),
25777
+ /* @__PURE__ */ jsx89(
25778
+ "input",
25779
+ {
25780
+ className: "arp-custom-input",
25781
+ type: "number",
25782
+ placeholder: "W",
25783
+ value: w,
25784
+ min: 1,
25785
+ onChange: (e) => setW(e.target.value),
25786
+ onPointerDown: (e) => e.stopPropagation()
25787
+ }
25788
+ ),
25619
25789
  /* @__PURE__ */ jsx89("span", { className: "arp-custom-x", children: "\xD7" }),
25620
- /* @__PURE__ */ jsx89("input", { className: "arp-custom-input", type: "number", placeholder: "H", value: h, min: 1, onChange: (e) => setH(e.target.value), onPointerDown: (e) => e.stopPropagation() }),
25621
- /* @__PURE__ */ jsx89("button", { className: "arp-custom-add", onClick: handleAdd, disabled: !w || !h, title: "Add custom dimension", children: "+ Add" })
25790
+ /* @__PURE__ */ jsx89(
25791
+ "input",
25792
+ {
25793
+ className: "arp-custom-input",
25794
+ type: "number",
25795
+ placeholder: "H",
25796
+ value: h,
25797
+ min: 1,
25798
+ onChange: (e) => setH(e.target.value),
25799
+ onPointerDown: (e) => e.stopPropagation()
25800
+ }
25801
+ ),
25802
+ /* @__PURE__ */ jsx89(
25803
+ "button",
25804
+ {
25805
+ className: "arp-custom-add",
25806
+ onClick: handleAdd,
25807
+ disabled: !w || !h,
25808
+ title: "Add custom dimension",
25809
+ children: "+ Add"
25810
+ }
25811
+ )
25622
25812
  ] });
25623
25813
  };
25624
25814
  var AutoResizePanel = ({
@@ -25649,17 +25839,19 @@ var AutoResizePanel = ({
25649
25839
  const togglePreset = (label) => {
25650
25840
  setSelected((prev) => {
25651
25841
  const next = new Set(prev);
25652
- if (next.has(label))
25842
+ if (next.has(label)) {
25653
25843
  next.delete(label);
25654
- else
25844
+ } else {
25655
25845
  next.add(label);
25846
+ }
25656
25847
  return next;
25657
25848
  });
25658
25849
  };
25659
25850
  const addCustom = (dim) => {
25660
25851
  const key = dim.label;
25661
- if (selected.has(key))
25852
+ if (selected.has(key)) {
25662
25853
  return;
25854
+ }
25663
25855
  setExtras((prev) => [...prev, dim]);
25664
25856
  setSelected((prev) => /* @__PURE__ */ new Set([...prev, key]));
25665
25857
  };
@@ -25671,9 +25863,15 @@ var AutoResizePanel = ({
25671
25863
  return next;
25672
25864
  });
25673
25865
  };
25674
- const updateDimState = useCallback16((label, update) => {
25675
- setDimStates((prev) => ({ ...prev, [label]: { ...prev[label], ...update } }));
25676
- }, []);
25866
+ const updateDimState = useCallback16(
25867
+ (label, update) => {
25868
+ setDimStates((prev) => ({
25869
+ ...prev,
25870
+ [label]: { ...prev[label], ...update }
25871
+ }));
25872
+ },
25873
+ []
25874
+ );
25677
25875
  const cleanupShimmer = useCallback16(() => {
25678
25876
  autoResizeStore.clear();
25679
25877
  }, []);
@@ -25684,8 +25882,9 @@ var AutoResizePanel = ({
25684
25882
  };
25685
25883
  }, []);
25686
25884
  const handleGenerate = useCallback16(async () => {
25687
- if (allDimensions.length === 0)
25885
+ if (allDimensions.length === 0) {
25688
25886
  return;
25887
+ }
25689
25888
  setRunning(true);
25690
25889
  onRunningChange?.(true);
25691
25890
  setGlobalError(null);
@@ -25734,12 +25933,14 @@ var AutoResizePanel = ({
25734
25933
  const dimLabel = allDimensions[idx]?.label ?? label;
25735
25934
  if (phase === "done") {
25736
25935
  updateDimState(dimLabel, { status: "done" });
25737
- if (preCreatedFrames[idx])
25936
+ if (preCreatedFrames[idx]) {
25738
25937
  autoResizeStore.markComplete(preCreatedFrames[idx].frameId);
25938
+ }
25739
25939
  } else if (phase === "error") {
25740
25940
  updateDimState(dimLabel, { status: "error", error: label });
25741
- if (preCreatedFrames[idx])
25941
+ if (preCreatedFrames[idx]) {
25742
25942
  autoResizeStore.markComplete(preCreatedFrames[idx].frameId);
25943
+ }
25743
25944
  } else if (phase === "bg-regen") {
25744
25945
  updateDimState(dimLabel, { status: "bg-regen" });
25745
25946
  } else {
@@ -25751,7 +25952,9 @@ var AutoResizePanel = ({
25751
25952
  } catch (err) {
25752
25953
  if (err instanceof DOMException && err.name === "AbortError" || controller.signal.aborted) {
25753
25954
  } else {
25754
- setGlobalError(err instanceof Error ? err.message : "An unexpected error occurred");
25955
+ setGlobalError(
25956
+ err instanceof Error ? err.message : "An unexpected error occurred"
25957
+ );
25755
25958
  }
25756
25959
  } finally {
25757
25960
  setRunning(false);
@@ -25777,7 +25980,9 @@ var AutoResizePanel = ({
25777
25980
  onRunningChange?.(false);
25778
25981
  cleanupShimmer();
25779
25982
  };
25780
- const doneCount = Object.values(dimStates).filter((s) => s.status === "done").length;
25983
+ const doneCount = Object.values(dimStates).filter(
25984
+ (s) => s.status === "done"
25985
+ ).length;
25781
25986
  const totalCount = allDimensions.length;
25782
25987
  const hasResults = doneCount > 0;
25783
25988
  return /* @__PURE__ */ jsx89(Fragment13, { children: /* @__PURE__ */ jsxs48(
@@ -25798,7 +26003,9 @@ var AutoResizePanel = ({
25798
26003
  className: "arp-header__close",
25799
26004
  onClick: () => {
25800
26005
  if (running) {
25801
- if (window.confirm("This will cancel the generation. Are you sure?")) {
26006
+ if (window.confirm(
26007
+ "This will cancel the generation. Are you sure?"
26008
+ )) {
25802
26009
  handleCancel();
25803
26010
  onClose();
25804
26011
  }
@@ -25835,7 +26042,14 @@ var AutoResizePanel = ({
25835
26042
  state3.status === "waiting" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--waiting", children: "\u2026" }),
25836
26043
  (state3.status === "bg-regen" || state3.status === "layout" || state3.status === "inserting") && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--running", children: /* @__PURE__ */ jsx89(SpinnerIcon2, {}) }),
25837
26044
  state3.status === "done" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--done", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) }),
25838
- state3.status === "error" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--error", title: state3.error, children: /* @__PURE__ */ jsx89(ErrorIcon, {}) })
26045
+ state3.status === "error" && /* @__PURE__ */ jsx89(
26046
+ "span",
26047
+ {
26048
+ className: "arp-status arp-status--error",
26049
+ title: state3.error,
26050
+ children: /* @__PURE__ */ jsx89(ErrorIcon, {})
26051
+ }
26052
+ )
25839
26053
  ] })
25840
26054
  ]
25841
26055
  },
@@ -25847,9 +26061,23 @@ var AutoResizePanel = ({
25847
26061
  return /* @__PURE__ */ jsxs48("div", { className: "arp-extra-tag", children: [
25848
26062
  /* @__PURE__ */ jsx89("span", { children: d.label }),
25849
26063
  state3?.status === "done" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--done", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) }),
25850
- state3?.status === "error" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--error", title: state3.error, children: /* @__PURE__ */ jsx89(ErrorIcon, {}) }),
26064
+ state3?.status === "error" && /* @__PURE__ */ jsx89(
26065
+ "span",
26066
+ {
26067
+ className: "arp-status arp-status--error",
26068
+ title: state3.error,
26069
+ children: /* @__PURE__ */ jsx89(ErrorIcon, {})
26070
+ }
26071
+ ),
25851
26072
  (state3?.status === "bg-regen" || state3?.status === "layout") && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--running", children: /* @__PURE__ */ jsx89(SpinnerIcon2, {}) }),
25852
- !running && /* @__PURE__ */ jsx89("button", { className: "arp-extra-tag__remove", onClick: () => removeExtra(d.label), children: "\xD7" })
26073
+ !running && /* @__PURE__ */ jsx89(
26074
+ "button",
26075
+ {
26076
+ className: "arp-extra-tag__remove",
26077
+ onClick: () => removeExtra(d.label),
26078
+ children: "\xD7"
26079
+ }
26080
+ )
25853
26081
  ] }, d.label);
25854
26082
  }) }),
25855
26083
  !running && /* @__PURE__ */ jsxs48(Fragment13, { children: [
@@ -25858,7 +26086,13 @@ var AutoResizePanel = ({
25858
26086
  ] }),
25859
26087
  globalError && /* @__PURE__ */ jsx89("div", { className: "arp-error", children: globalError }),
25860
26088
  running && totalCount > 0 && /* @__PURE__ */ jsxs48("div", { className: "arp-progress", children: [
25861
- /* @__PURE__ */ jsx89("div", { className: "arp-progress__bar-bg", children: /* @__PURE__ */ jsx89("div", { className: "arp-progress__bar-fill", style: { width: `${doneCount / totalCount * 100}%` } }) }),
26089
+ /* @__PURE__ */ jsx89("div", { className: "arp-progress__bar-bg", children: /* @__PURE__ */ jsx89(
26090
+ "div",
26091
+ {
26092
+ className: "arp-progress__bar-fill",
26093
+ style: { width: `${doneCount / totalCount * 100}%` }
26094
+ }
26095
+ ) }),
25862
26096
  /* @__PURE__ */ jsxs48("span", { className: "arp-progress__text", children: [
25863
26097
  doneCount,
25864
26098
  "/",
@@ -25867,20 +26101,30 @@ var AutoResizePanel = ({
25867
26101
  ] })
25868
26102
  ] }),
25869
26103
  /* @__PURE__ */ jsx89("div", { className: "arp-actions", children: running ? /* @__PURE__ */ jsx89("button", { className: "arp-btn arp-btn--cancel", onClick: handleCancel, children: "Cancel" }) : hasResults ? /* @__PURE__ */ jsxs48(Fragment13, { children: [
25870
- /* @__PURE__ */ jsx89("button", { className: "arp-btn arp-btn--primary", onClick: handleGenerate, disabled: allDimensions.length === 0, children: "Generate more" }),
26104
+ /* @__PURE__ */ jsx89(
26105
+ "button",
26106
+ {
26107
+ className: "arp-btn arp-btn--primary",
26108
+ onClick: handleGenerate,
26109
+ disabled: allDimensions.length === 0,
26110
+ children: "Generate more"
26111
+ }
26112
+ ),
25871
26113
  /* @__PURE__ */ jsx89("button", { className: "arp-btn arp-btn--ghost", onClick: onClose, children: "Done" })
25872
- ] }) : /* @__PURE__ */ jsx89("button", { className: "arp-btn arp-btn--primary", onClick: handleGenerate, disabled: allDimensions.length === 0, children: allDimensions.length === 0 ? "Select sizes above" : `Generate ${allDimensions.length} size${allDimensions.length !== 1 ? "s" : ""}` }) })
26114
+ ] }) : /* @__PURE__ */ jsx89(
26115
+ "button",
26116
+ {
26117
+ className: "arp-btn arp-btn--primary",
26118
+ onClick: handleGenerate,
26119
+ disabled: allDimensions.length === 0,
26120
+ children: allDimensions.length === 0 ? "Select sizes above" : `Generate ${allDimensions.length} size${allDimensions.length !== 1 ? "s" : ""}`
26121
+ }
26122
+ ) })
25873
26123
  ]
25874
26124
  }
25875
26125
  ) });
25876
26126
  };
25877
26127
 
25878
- // utils/openRouterApiKey.ts
25879
- function resolveOpenRouterApiKey(propKey) {
25880
- const normalizedPropKey = propKey?.trim();
25881
- return (normalizedPropKey ? normalizedPropKey : void 0) ?? (typeof import.meta !== "undefined" && define_import_meta_env_default?.VITE_APP_OPENROUTER_API_KEY ? define_import_meta_env_default.VITE_APP_OPENROUTER_API_KEY : "") ?? "";
25882
- }
25883
-
25884
26128
  // components/auto-resize/AutoResizePanelHost.tsx
25885
26129
  import { jsx as jsx90 } from "react/jsx-runtime";
25886
26130
  var AutoResizePanelHost = ({ app }) => {
@@ -25970,12 +26214,22 @@ import { arrayToMap as arrayToMap23 } from "@orangecatai/common";
25970
26214
  var SLOT_TYPES = [
25971
26215
  { id: "background", label: "Background", color: "#94a3b8", kind: "rect" },
25972
26216
  { id: "logo", label: "Logo", color: "#f97316", kind: "image" },
25973
- { id: "product_image", label: "Product Image", color: "#22c55e", kind: "image" },
26217
+ {
26218
+ id: "product_image",
26219
+ label: "Product Image",
26220
+ color: "#22c55e",
26221
+ kind: "image"
26222
+ },
25974
26223
  { id: "headline", label: "Headline", color: "#3b82f6", kind: "text" },
25975
26224
  { id: "subhead", label: "Subhead", color: "#8b5cf6", kind: "text" },
25976
26225
  { id: "cta", label: "CTA", color: "#ef4444", kind: "text" },
25977
26226
  { id: "signoff", label: "Signoff", color: "#64748b", kind: "text" },
25978
- { id: "auxiliary_image", label: "Aux Image", color: "#14b8a6", kind: "image" }
26227
+ {
26228
+ id: "auxiliary_image",
26229
+ label: "Aux Image",
26230
+ color: "#14b8a6",
26231
+ kind: "image"
26232
+ }
25979
26233
  ];
25980
26234
 
25981
26235
  // components/template-builder/TemplateBuilderTray.tsx
@@ -26004,7 +26258,11 @@ var TemplateBuilderTray = ({ app }) => {
26004
26258
  strokeColor: "transparent",
26005
26259
  opacity: 60
26006
26260
  });
26007
- newEl = { ...base, frameId: frame.id, customData: { slotType: slot.id, isSlot: true } };
26261
+ newEl = {
26262
+ ...base,
26263
+ frameId: frame.id,
26264
+ customData: { slotType: slot.id, isSlot: true }
26265
+ };
26008
26266
  } else if (slot.kind === "text") {
26009
26267
  const base = newTextElement3({
26010
26268
  text: slot.label,
@@ -26013,7 +26271,11 @@ var TemplateBuilderTray = ({ app }) => {
26013
26271
  fontSize: 32,
26014
26272
  strokeColor: slot.color
26015
26273
  });
26016
- newEl = { ...base, frameId: frame.id, customData: { slotType: slot.id, isSlot: true } };
26274
+ newEl = {
26275
+ ...base,
26276
+ frameId: frame.id,
26277
+ customData: { slotType: slot.id, isSlot: true }
26278
+ };
26017
26279
  } else {
26018
26280
  const base = newElement5({
26019
26281
  type: "rectangle",
@@ -26026,7 +26288,11 @@ var TemplateBuilderTray = ({ app }) => {
26026
26288
  strokeColor: slot.color,
26027
26289
  opacity: 40
26028
26290
  });
26029
- newEl = { ...base, frameId: frame.id, customData: { slotType: slot.id, isSlot: true } };
26291
+ newEl = {
26292
+ ...base,
26293
+ frameId: frame.id,
26294
+ customData: { slotType: slot.id, isSlot: true }
26295
+ };
26030
26296
  }
26031
26297
  const elements = app.getSceneElements();
26032
26298
  const newElements = [...elements, newEl];
@@ -26132,14 +26398,19 @@ var TemplateBuilderPanelHost = ({
26132
26398
  }
26133
26399
  if (framesToSave.length === 0) {
26134
26400
  framesToSave = allElements.filter((el) => {
26135
- if (el.isDeleted || !isFrameLikeElement11(el))
26401
+ if (el.isDeleted || !isFrameLikeElement11(el)) {
26136
26402
  return false;
26403
+ }
26137
26404
  const children = getFrameChildren5(allElements, el.id);
26138
- return children.some((child) => child.customData?.isSlot === true);
26405
+ return children.some(
26406
+ (child) => child.customData?.isSlot === true
26407
+ );
26139
26408
  });
26140
26409
  }
26141
26410
  if (framesToSave.length === 0) {
26142
- alert("No frame found to save. Please select a frame on the canvas first.");
26411
+ alert(
26412
+ "No frame found to save. Please select a frame on the canvas first."
26413
+ );
26143
26414
  return;
26144
26415
  }
26145
26416
  const frame = framesToSave[0];
@@ -51045,8 +51316,15 @@ var BANNER_TOOLS = [
51045
51316
  parameters: {
51046
51317
  type: "object",
51047
51318
  properties: {
51048
- query: { type: "string", description: "Search query \u2014 name or tag keywords" },
51049
- type: { type: "string", enum: ["product", "logo", "lifestyle", "auxiliary"], description: "Optional filter by asset type" }
51319
+ query: {
51320
+ type: "string",
51321
+ description: "Search query \u2014 name or tag keywords"
51322
+ },
51323
+ type: {
51324
+ type: "string",
51325
+ enum: ["product", "logo", "lifestyle", "auxiliary"],
51326
+ description: "Optional filter by asset type"
51327
+ }
51050
51328
  },
51051
51329
  required: ["query"],
51052
51330
  additionalProperties: false
@@ -51057,11 +51335,29 @@ var BANNER_TOOLS = [
51057
51335
  type: "function",
51058
51336
  function: {
51059
51337
  name: "list_brand_templates",
51060
- description: "List available brand templates. Call this when the user mentions a campaign, template, or asks for multiple sizes.",
51338
+ description: `List available brand templates by keyword search across template names, campaign tags, and labels.
51339
+
51340
+ MANDATORY SEARCH PROTOCOL \u2014 follow exactly, no shortcuts:
51341
+
51342
+ ATTEMPT 1: Generate TWO sets of 10 keywords each from the user's request:
51343
+ - Set A (campaign tag variations): 10 synonyms/abbreviations/phrasings of the campaign topic (e.g. for "noida datacenter": ["datacenter", "data center", "dc", "noida dc", "noida datacenter", "data centre", "server farm", "cloud infra", "hyperscale", "colocation"])
51344
+ - Set B (template name variations): 10 different name keywords the template might have (e.g. ["noida", "datacenter campaign", "new datacenter", "dc launch", "infrastructure", "cloud", "enterprise", "b2b", "tech", "facility"])
51345
+ Merge all 20 into the keywords array. Call list_brand_templates with all 20.
51346
+
51347
+ IF templates returned is empty \u2192 ATTEMPT 2 (MANDATORY \u2014 do NOT skip):
51348
+ Generate a completely DIFFERENT set of 20 keywords \u2014 do not reuse any from attempt 1. Think laterally: different synonyms, related industry terms, the city name, brand-adjacent words, seasonal terms. Call list_brand_templates again with the new 20.
51349
+
51350
+ ONLY after both attempts return empty \u2192 tell the user no matching template was found.
51351
+
51352
+ If no search context exists, call with an empty keywords array to list all templates.`,
51061
51353
  parameters: {
51062
51354
  type: "object",
51063
51355
  properties: {
51064
- campaignTag: { type: "string", description: "Optional campaign tag to filter templates" }
51356
+ keywords: {
51357
+ type: "array",
51358
+ items: { type: "string" },
51359
+ description: "Up to 20 keyword variations to search across template names, campaign tags, and labels. All are OR-matched case-insensitively. Generate 10 tag synonyms + 10 name variations from the user's request."
51360
+ }
51065
51361
  },
51066
51362
  required: [],
51067
51363
  additionalProperties: false
@@ -51076,7 +51372,10 @@ var BANNER_TOOLS = [
51076
51372
  parameters: {
51077
51373
  type: "object",
51078
51374
  properties: {
51079
- variantId: { type: "string", description: "The template ID to fetch" }
51375
+ variantId: {
51376
+ type: "string",
51377
+ description: "The template ID to fetch"
51378
+ }
51080
51379
  },
51081
51380
  required: ["variantId"],
51082
51381
  additionalProperties: false
@@ -51091,8 +51390,14 @@ var BANNER_TOOLS = [
51091
51390
  parameters: {
51092
51391
  type: "object",
51093
51392
  properties: {
51094
- frameId: { type: "string", description: "The frame ID to load the template into" },
51095
- variantId: { type: "string", description: "The template ID to load (from list_brand_templates)" }
51393
+ frameId: {
51394
+ type: "string",
51395
+ description: "The frame ID to load the template into"
51396
+ },
51397
+ variantId: {
51398
+ type: "string",
51399
+ description: "The template ID to load (from list_brand_templates)"
51400
+ }
51096
51401
  },
51097
51402
  required: ["frameId", "variantId"],
51098
51403
  additionalProperties: false
@@ -51107,18 +51412,45 @@ var BANNER_TOOLS = [
51107
51412
  parameters: {
51108
51413
  type: "object",
51109
51414
  properties: {
51110
- frameId: { type: "string", description: "The frame ID containing slot elements" },
51111
- headline: { type: "string", description: "Text for the headline slot" },
51415
+ frameId: {
51416
+ type: "string",
51417
+ description: "The frame ID containing slot elements"
51418
+ },
51419
+ headline: {
51420
+ type: "string",
51421
+ description: "Text for the headline slot"
51422
+ },
51112
51423
  subhead: { type: "string", description: "Text for the subhead slot" },
51113
51424
  cta: { type: "string", description: "Text for the CTA slot" },
51114
51425
  signoff: { type: "string", description: "Text for the signoff slot" },
51115
- product_image_url: { type: "string", description: "URL for the product image slot (from search_brand_assets blobUrl, or a generated image data URL)" },
51116
- product_image_asset_id: { type: "string", description: "Asset ID for the product image (from search_brand_assets [id:...] field). Required when using a brand asset so the image can be swapped later." },
51117
- logo_url: { type: "string", description: "URL for the logo slot (from search_brand_assets blobUrl)" },
51118
- logo_asset_id: { type: "string", description: "Asset ID for the logo (from search_brand_assets [id:...] field). Required when using a brand asset." },
51119
- auxiliary_image_url: { type: "string", description: "URL for the auxiliary image slot" },
51120
- auxiliary_image_asset_id: { type: "string", description: "Asset ID for the auxiliary image (from search_brand_assets [id:...] field). Required when using a brand asset." },
51121
- background_color: { type: "string", description: "Hex color (e.g. #000000) for the background slot" }
51426
+ product_image_url: {
51427
+ type: "string",
51428
+ description: "URL for the product image slot (from search_brand_assets blobUrl, or a generated image data URL)"
51429
+ },
51430
+ product_image_asset_id: {
51431
+ type: "string",
51432
+ description: "Asset ID for the product image (from search_brand_assets [id:...] field). Required when using a brand asset so the image can be swapped later."
51433
+ },
51434
+ logo_url: {
51435
+ type: "string",
51436
+ description: "URL for the logo slot (from search_brand_assets blobUrl)"
51437
+ },
51438
+ logo_asset_id: {
51439
+ type: "string",
51440
+ description: "Asset ID for the logo (from search_brand_assets [id:...] field). Required when using a brand asset."
51441
+ },
51442
+ auxiliary_image_url: {
51443
+ type: "string",
51444
+ description: "URL for the auxiliary image slot"
51445
+ },
51446
+ auxiliary_image_asset_id: {
51447
+ type: "string",
51448
+ description: "Asset ID for the auxiliary image (from search_brand_assets [id:...] field). Required when using a brand asset."
51449
+ },
51450
+ background_color: {
51451
+ type: "string",
51452
+ description: "Hex color (e.g. #000000) for the background slot"
51453
+ }
51122
51454
  },
51123
51455
  required: ["frameId"],
51124
51456
  additionalProperties: false
@@ -51953,12 +52285,19 @@ async function execSearchBrandAssets(args, ctx) {
51953
52285
  const list = assets.map((a) => `- ${a.name} (${a.assetType}) [id:${a.id}]: ${a.blobUrl}`).join("\n");
51954
52286
  return {
51955
52287
  success: true,
51956
- data: { assets, summary: `Found ${assets.length} brand asset(s):
51957
- ${list}` },
52288
+ data: {
52289
+ assets,
52290
+ summary: `Found ${assets.length} brand asset(s):
52291
+ ${list}`
52292
+ },
51958
52293
  statusMessage: `Found ${assets.length} assets`
51959
52294
  };
51960
52295
  } catch {
51961
- return { success: false, error: "Failed to search brand assets.", statusMessage: "Asset search failed" };
52296
+ return {
52297
+ success: false,
52298
+ error: "Failed to search brand assets.",
52299
+ statusMessage: "Asset search failed"
52300
+ };
51962
52301
  }
51963
52302
  }
51964
52303
  async function execFinalizeAd(args, ctx) {
@@ -51972,14 +52311,23 @@ async function execFinalizeAd(args, ctx) {
51972
52311
  };
51973
52312
  }
51974
52313
  async function execListBrandTemplates(args, ctx) {
51975
- const campaignTag = args.campaignTag;
52314
+ let keywords;
52315
+ if (Array.isArray(args.keywords) && args.keywords.length > 0) {
52316
+ keywords = args.keywords;
52317
+ } else if (args.query || args.campaignTag) {
52318
+ keywords = [args.query ?? args.campaignTag];
52319
+ }
51976
52320
  if (!ctx.onListBrandTemplates) {
51977
52321
  return { success: true, statusMessage: "No template list configured" };
51978
52322
  }
51979
52323
  try {
51980
- const templates = await ctx.onListBrandTemplates(campaignTag);
52324
+ const templates = await ctx.onListBrandTemplates(keywords);
51981
52325
  if (templates.length === 0) {
51982
- return { success: true, data: { templates: [] }, statusMessage: "No templates found" };
52326
+ return {
52327
+ success: true,
52328
+ data: { templates: [] },
52329
+ statusMessage: "No templates found"
52330
+ };
51983
52331
  }
51984
52332
  const list = templates.map((t2) => {
51985
52333
  const dims = t2.width && t2.height ? ` (${t2.width}x${t2.height})` : "";
@@ -51991,13 +52339,21 @@ async function execListBrandTemplates(args, ctx) {
51991
52339
  statusMessage: `Found ${templates.length} template(s)`
51992
52340
  };
51993
52341
  } catch {
51994
- return { success: false, error: "Failed to list brand templates.", statusMessage: "Template list failed" };
52342
+ return {
52343
+ success: false,
52344
+ error: "Failed to list brand templates.",
52345
+ statusMessage: "Template list failed"
52346
+ };
51995
52347
  }
51996
52348
  }
51997
52349
  async function execGetTemplateVariant(args, ctx) {
51998
52350
  const templateId = args.variantId;
51999
52351
  if (!ctx.onGetTemplateVariant) {
52000
- return { success: false, error: "Template fetching not configured.", statusMessage: "No template fetch configured" };
52352
+ return {
52353
+ success: false,
52354
+ error: "Template fetching not configured.",
52355
+ statusMessage: "No template fetch configured"
52356
+ };
52001
52357
  }
52002
52358
  try {
52003
52359
  const { canvasJson } = await ctx.onGetTemplateVariant(templateId);
@@ -52011,14 +52367,22 @@ async function execGetTemplateVariant(args, ctx) {
52011
52367
  statusMessage: "Template fetched"
52012
52368
  };
52013
52369
  } catch {
52014
- return { success: false, error: "Failed to fetch template.", statusMessage: "Template fetch failed" };
52370
+ return {
52371
+ success: false,
52372
+ error: "Failed to fetch template.",
52373
+ statusMessage: "Template fetch failed"
52374
+ };
52015
52375
  }
52016
52376
  }
52017
52377
  async function execLoadTemplateIntoFrame(args, ctx) {
52018
52378
  const frameId = args.frameId;
52019
52379
  const templateId = args.variantId;
52020
52380
  if (!ctx.onGetTemplateVariant) {
52021
- return { success: false, error: "Template fetching not configured.", statusMessage: "No template fetch configured" };
52381
+ return {
52382
+ success: false,
52383
+ error: "Template fetching not configured.",
52384
+ statusMessage: "No template fetch configured"
52385
+ };
52022
52386
  }
52023
52387
  try {
52024
52388
  const cachedJson = ctx._templateJsonCache?.get(templateId);
@@ -52043,7 +52407,11 @@ async function execLoadTemplateIntoFrame(args, ctx) {
52043
52407
  const allElements = ctx.excalidrawAPI.getSceneElements();
52044
52408
  const targetFrame = allElements.find((el) => el.id === frameId);
52045
52409
  if (!targetFrame) {
52046
- return { success: false, error: `Frame ${frameId} not found.`, statusMessage: "Frame not found" };
52410
+ return {
52411
+ success: false,
52412
+ error: `Frame ${frameId} not found.`,
52413
+ statusMessage: "Frame not found"
52414
+ };
52047
52415
  }
52048
52416
  const withoutOldChildren = allElements.filter(
52049
52417
  (el) => el.frameId !== frameId
@@ -52092,7 +52460,11 @@ async function execLoadTemplateIntoFrame(args, ctx) {
52092
52460
  });
52093
52461
  }
52094
52462
  }
52095
- return { success: true, data: { frameId }, statusMessage: "Template loaded" };
52463
+ return {
52464
+ success: true,
52465
+ data: { frameId },
52466
+ statusMessage: "Template loaded"
52467
+ };
52096
52468
  } catch (e) {
52097
52469
  return {
52098
52470
  success: false,
@@ -52142,7 +52514,12 @@ function fitFontSize(text, slotEl) {
52142
52514
  }
52143
52515
  }
52144
52516
  if (bestFs !== -1) {
52145
- return { fontSize: bestFs, wrappedText: bestWrapped, height: bestHeight, autoResize: false };
52517
+ return {
52518
+ fontSize: bestFs,
52519
+ wrappedText: bestWrapped,
52520
+ height: bestHeight,
52521
+ autoResize: false
52522
+ };
52146
52523
  }
52147
52524
  const minCheck = testFit(MIN_FONT_SIZE3);
52148
52525
  return {
@@ -52182,8 +52559,9 @@ async function execFillTemplateSlots(args, ctx) {
52182
52559
  const imageJobs = [];
52183
52560
  allElements.forEach((el, index) => {
52184
52561
  const elAny = el;
52185
- if (elAny.frameId !== frameId)
52562
+ if (elAny.frameId !== frameId) {
52186
52563
  return;
52564
+ }
52187
52565
  const slotType = elAny.customData?.slotType;
52188
52566
  const url = slotType ? imageUrlBySlotType[slotType] : void 0;
52189
52567
  if (url) {
@@ -52202,8 +52580,9 @@ async function execFillTemplateSlots(args, ctx) {
52202
52580
  imageJobs.map(async (job) => {
52203
52581
  try {
52204
52582
  const res = await fetch(job.url);
52205
- if (!res.ok)
52583
+ if (!res.ok) {
52206
52584
  return;
52585
+ }
52207
52586
  const blob = await res.blob();
52208
52587
  const dataURL = await new Promise((resolve, reject) => {
52209
52588
  const reader = new FileReader();
@@ -52220,8 +52599,9 @@ async function execFillTemplateSlots(args, ctx) {
52220
52599
  await Promise.all(
52221
52600
  imageJobs.map(
52222
52601
  (job) => new Promise((resolve) => {
52223
- if (!job.dataURL)
52602
+ if (!job.dataURL) {
52224
52603
  return resolve();
52604
+ }
52225
52605
  const img = new Image();
52226
52606
  img.onload = () => {
52227
52607
  job.naturalWidth = img.naturalWidth;
@@ -52235,8 +52615,9 @@ async function execFillTemplateSlots(args, ctx) {
52235
52615
  );
52236
52616
  const imageReplacements = /* @__PURE__ */ new Map();
52237
52617
  for (const job of imageJobs) {
52238
- if (!job.fileId)
52618
+ if (!job.fileId) {
52239
52619
  continue;
52620
+ }
52240
52621
  const { x, y, width, height } = containFit(
52241
52622
  job.el.x,
52242
52623
  job.el.y,
@@ -52274,18 +52655,23 @@ async function execFillTemplateSlots(args, ctx) {
52274
52655
  let filledCount = 0;
52275
52656
  const updatedElements = allElements.map((el, index) => {
52276
52657
  const elWithFrame = el;
52277
- if (elWithFrame.frameId !== frameId)
52658
+ if (elWithFrame.frameId !== frameId) {
52278
52659
  return el;
52660
+ }
52279
52661
  const slotType = elWithFrame.customData?.slotType;
52280
- if (!slotType)
52662
+ if (!slotType) {
52281
52663
  return el;
52664
+ }
52282
52665
  if (imageReplacements.has(index)) {
52283
52666
  filledCount++;
52284
52667
  return imageReplacements.get(index);
52285
52668
  }
52286
52669
  let mutation = {};
52287
52670
  const makeTextMutation = (value, useHeadlineFont = false) => {
52288
- const { fontSize, wrappedText, height, autoResize } = fitFontSize(value, el);
52671
+ const { fontSize, wrappedText, height, autoResize } = fitFontSize(
52672
+ value,
52673
+ el
52674
+ );
52289
52675
  const brandFontId = useHeadlineFont ? ctx.brandHeadlineFontId ?? ctx.brandBodyFontId : ctx.brandBodyFontId;
52290
52676
  return {
52291
52677
  text: wrappedText,
@@ -52993,7 +53379,10 @@ ${f.textContent}`).join("\n\n")}`;
52993
53379
  statusMessage: error || "Insufficient credits for image generation"
52994
53380
  };
52995
53381
  const gatedAction = {
52996
- result: { success: gatedResult.success, statusMessage: gatedResult.statusMessage }
53382
+ result: {
53383
+ success: gatedResult.success,
53384
+ statusMessage: gatedResult.statusMessage
53385
+ }
52997
53386
  };
52998
53387
  toolActions.push(gatedAction);
52999
53388
  onUpdate({
@@ -53019,7 +53408,10 @@ ${f.textContent}`).join("\n\n")}`;
53019
53408
  statusMessage: "Blocked: template already provides text slots"
53020
53409
  };
53021
53410
  const blockedAction = {
53022
- result: { success: blockedResult.success, statusMessage: blockedResult.statusMessage }
53411
+ result: {
53412
+ success: blockedResult.success,
53413
+ statusMessage: blockedResult.statusMessage
53414
+ }
53023
53415
  };
53024
53416
  toolActions.push(blockedAction);
53025
53417
  onUpdate({
@@ -53030,7 +53422,10 @@ ${f.textContent}`).join("\n\n")}`;
53030
53422
  messages.push({
53031
53423
  role: "tool",
53032
53424
  tool_call_id: toolCall.id,
53033
- content: JSON.stringify({ success: false, error: blockedResult.error })
53425
+ content: JSON.stringify({
53426
+ success: false,
53427
+ error: blockedResult.error
53428
+ })
53034
53429
  });
53035
53430
  continue;
53036
53431
  }
@@ -53054,7 +53449,10 @@ ${f.textContent}`).join("\n\n")}`;
53054
53449
  }
53055
53450
  }
53056
53451
  const action = {
53057
- result: { success: result.success, statusMessage: result.statusMessage }
53452
+ result: {
53453
+ success: result.success,
53454
+ statusMessage: result.statusMessage
53455
+ }
53058
53456
  };
53059
53457
  toolActions.push(action);
53060
53458
  onUpdate({
@@ -54485,7 +54883,12 @@ var AIChatPanel = React63.forwardRef(
54485
54883
  actions: msg.toolActions
54486
54884
  }
54487
54885
  ),
54488
- msg.reviewFeedback && /* @__PURE__ */ jsx192(ReviewCritiqueCard, { feedback: msg.reviewFeedback }),
54886
+ msg.reviewFeedback && /* @__PURE__ */ jsx192(
54887
+ ReviewCritiqueCard,
54888
+ {
54889
+ feedback: msg.reviewFeedback
54890
+ }
54891
+ ),
54489
54892
  /* @__PURE__ */ jsx192(
54490
54893
  MessageContent,
54491
54894
  {
@@ -54779,44 +55182,65 @@ function ToolActionsDisplay({ actions: actions2 }) {
54779
55182
  function ReviewCritiqueCard({ feedback }) {
54780
55183
  const [expanded, setExpanded] = useState55(false);
54781
55184
  const severityClass = (severity) => {
54782
- if (severity === "critical")
55185
+ if (severity === "critical") {
54783
55186
  return "acp-review-issue--critical";
54784
- if (severity === "major")
55187
+ }
55188
+ if (severity === "major") {
54785
55189
  return "acp-review-issue--major";
55190
+ }
54786
55191
  return "acp-review-issue--minor";
54787
55192
  };
54788
55193
  const approved = feedback.approved;
54789
- return /* @__PURE__ */ jsxs106("div", { className: `acp-review-card ${approved ? "acp-review-card--ok" : "acp-review-card--issues"}`, children: [
54790
- /* @__PURE__ */ jsxs106(
54791
- "button",
54792
- {
54793
- className: "acp-review-toggle",
54794
- onClick: () => setExpanded((v) => !v),
54795
- children: [
54796
- /* @__PURE__ */ jsx192("span", { className: `acp-review-badge ${approved ? "acp-review-badge--ok" : "acp-review-badge--issues"}`, children: approved ? "\u2713 Design approved" : `${feedback.issues.length} issue${feedback.issues.length !== 1 ? "s" : ""} found` }),
54797
- /* @__PURE__ */ jsx192("span", { className: "acp-review-summary", children: feedback.summary }),
54798
- !approved && feedback.issues.length > 0 && /* @__PURE__ */ jsx192(
54799
- ChevronRight,
54800
- {
54801
- size: 12,
54802
- className: `acp-tool-chevron ${expanded ? "acp-tool-chevron--open" : ""}`
54803
- }
54804
- )
54805
- ]
54806
- }
54807
- ),
54808
- expanded && !approved && feedback.issues.length > 0 && /* @__PURE__ */ jsx192("div", { className: "acp-review-issues", children: feedback.issues.map((iss, i) => /* @__PURE__ */ jsxs106("div", { className: `acp-review-issue ${severityClass(iss.severity)}`, children: [
54809
- /* @__PURE__ */ jsxs106("div", { className: "acp-review-issue-header", children: [
54810
- /* @__PURE__ */ jsx192("span", { className: "acp-review-issue-severity", children: iss.severity }),
54811
- /* @__PURE__ */ jsx192("span", { className: "acp-review-issue-element", children: iss.element }),
54812
- /* @__PURE__ */ jsx192("span", { className: "acp-review-issue-problem", children: iss.problem })
54813
- ] }),
54814
- /* @__PURE__ */ jsxs106("div", { className: "acp-review-issue-fix", children: [
54815
- "\u2192 ",
54816
- iss.preciseInstruction
54817
- ] })
54818
- ] }, i)) })
54819
- ] });
55194
+ return /* @__PURE__ */ jsxs106(
55195
+ "div",
55196
+ {
55197
+ className: `acp-review-card ${approved ? "acp-review-card--ok" : "acp-review-card--issues"}`,
55198
+ children: [
55199
+ /* @__PURE__ */ jsxs106(
55200
+ "button",
55201
+ {
55202
+ className: "acp-review-toggle",
55203
+ onClick: () => setExpanded((v) => !v),
55204
+ children: [
55205
+ /* @__PURE__ */ jsx192(
55206
+ "span",
55207
+ {
55208
+ className: `acp-review-badge ${approved ? "acp-review-badge--ok" : "acp-review-badge--issues"}`,
55209
+ children: approved ? "\u2713 Design approved" : `${feedback.issues.length} issue${feedback.issues.length !== 1 ? "s" : ""} found`
55210
+ }
55211
+ ),
55212
+ /* @__PURE__ */ jsx192("span", { className: "acp-review-summary", children: feedback.summary }),
55213
+ !approved && feedback.issues.length > 0 && /* @__PURE__ */ jsx192(
55214
+ ChevronRight,
55215
+ {
55216
+ size: 12,
55217
+ className: `acp-tool-chevron ${expanded ? "acp-tool-chevron--open" : ""}`
55218
+ }
55219
+ )
55220
+ ]
55221
+ }
55222
+ ),
55223
+ expanded && !approved && feedback.issues.length > 0 && /* @__PURE__ */ jsx192("div", { className: "acp-review-issues", children: feedback.issues.map((iss, i) => /* @__PURE__ */ jsxs106(
55224
+ "div",
55225
+ {
55226
+ className: `acp-review-issue ${severityClass(iss.severity)}`,
55227
+ children: [
55228
+ /* @__PURE__ */ jsxs106("div", { className: "acp-review-issue-header", children: [
55229
+ /* @__PURE__ */ jsx192("span", { className: "acp-review-issue-severity", children: iss.severity }),
55230
+ /* @__PURE__ */ jsx192("span", { className: "acp-review-issue-element", children: iss.element }),
55231
+ /* @__PURE__ */ jsx192("span", { className: "acp-review-issue-problem", children: iss.problem })
55232
+ ] }),
55233
+ /* @__PURE__ */ jsxs106("div", { className: "acp-review-issue-fix", children: [
55234
+ "\u2192 ",
55235
+ iss.preciseInstruction
55236
+ ] })
55237
+ ]
55238
+ },
55239
+ i
55240
+ )) })
55241
+ ]
55242
+ }
55243
+ );
54820
55244
  }
54821
55245
  async function callPlainChatAPI(messages, apiKey, signal, opts) {
54822
55246
  const baseModel = opts?.chatModel || "google/gemini-3.1-flash-lite-preview";