pxengine 0.1.28 → 0.1.30

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
@@ -352,6 +352,10 @@ __export(atoms_exports, {
352
352
  VideoAtom: () => VideoAtom
353
353
  });
354
354
 
355
+ // src/atoms/TextAtom.tsx
356
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
357
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
358
+
355
359
  // src/lib/utils.ts
356
360
  var import_clsx = require("clsx");
357
361
  var import_tailwind_merge = require("tailwind-merge");
@@ -366,7 +370,8 @@ var TextAtom = ({
366
370
  variant = "p",
367
371
  className,
368
372
  style,
369
- backgroundColor
373
+ backgroundColor,
374
+ markdown = false
370
375
  }) => {
371
376
  const baseStyles = {
372
377
  h1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-gray900",
@@ -379,14 +384,25 @@ var TextAtom = ({
379
384
  label: "text-[10px] font-bold text-gray400 uppercase tracking-widest pl-1"
380
385
  };
381
386
  const Component2 = variant === "small" || variant === "muted" || variant === "label" ? "p" : variant;
387
+ const wrapperStyles = {
388
+ ...style,
389
+ ...backgroundColor && { backgroundColor }
390
+ };
391
+ if (markdown) {
392
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
393
+ "div",
394
+ {
395
+ className: cn(baseStyles[variant], "prose prose-sm max-w-none", className),
396
+ style: wrapperStyles,
397
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], children: content })
398
+ }
399
+ );
400
+ }
382
401
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
383
402
  Component2,
384
403
  {
385
404
  className: cn(baseStyles[variant], className),
386
- style: {
387
- ...style,
388
- ...backgroundColor && { backgroundColor }
389
- },
405
+ style: wrapperStyles,
390
406
  children: content
391
407
  }
392
408
  );
@@ -25545,7 +25561,7 @@ var InputAtom = ({
25545
25561
  var import_class_variance_authority3 = require("class-variance-authority");
25546
25562
  var import_jsx_runtime18 = require("react/jsx-runtime");
25547
25563
  var badgeVariants = (0, import_class_variance_authority3.cva)(
25548
- "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
25564
+ "inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
25549
25565
  {
25550
25566
  variants: {
25551
25567
  variant: {
@@ -34040,7 +34056,7 @@ var EditableField = import_react54.default.memo(
34040
34056
  "div",
34041
34057
  {
34042
34058
  className: cn(
34043
- "relative z-10 group flex flex-col gap-2 p-3 bg-background dark:bg-gray700 rounded-md mb-8",
34059
+ "relative z-10 group flex flex-col gap-2 p-3 bg-paperBackground rounded-md mb-8",
34044
34060
  className
34045
34061
  ),
34046
34062
  children: [
@@ -34052,13 +34068,14 @@ var EditableField = import_react54.default.memo(
34052
34068
  children: label
34053
34069
  }
34054
34070
  ),
34055
- !isEditingProp && /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "inline-flex items-center gap-1 text-[10px] font-medium text-green-500 dark:text-green-500", children: [
34071
+ !isEditingProp && /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "inline-flex items-center gap-1.5 text-[0.75rem] font-medium text-green-600 dark:text-green-500 bg-green-500/5 px-2 py-0.5 rounded-full ", children: [
34056
34072
  "Suggested by an Agent",
34057
34073
  /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
34058
- Pencil,
34074
+ "span",
34059
34075
  {
34060
- className: "h-3 w-3 hover:text-green-700 cursor-pointer",
34061
- onClick: onEdit
34076
+ className: "flex items-center gap-1 cursor-pointer text-foreground hover:text-green-700 transition-colors ml-1 pl-1.5 ",
34077
+ onClick: onEdit,
34078
+ children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(SquarePen, { className: "h-5 w-5" })
34062
34079
  }
34063
34080
  )
34064
34081
  ] })
@@ -34071,7 +34088,7 @@ var EditableField = import_react54.default.memo(
34071
34088
  {
34072
34089
  size: "icon",
34073
34090
  variant: "outline",
34074
- className: "h-8 w-8 text-destructive border-destructive/20 hover:bg-destructive/10 rounded-lg",
34091
+ className: "h-8 w-8 text-foreground rounded-lg",
34075
34092
  onClick: onCancel,
34076
34093
  disabled: isSaving,
34077
34094
  children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(X, { className: "h-4 w-4" })
@@ -34081,10 +34098,10 @@ var EditableField = import_react54.default.memo(
34081
34098
  Button,
34082
34099
  {
34083
34100
  size: "icon",
34084
- className: "h-8 w-8 bg-purpleLight text-purpleText2 hover:bg-purpleText1 rounded-lg border border-purpleText1 shadow-none",
34101
+ className: "h-8 w-8 text-foreground rounded-lg shadow-none",
34085
34102
  onClick: handleSave,
34086
34103
  disabled: isSaving,
34087
- children: isSaving ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(LoaderCircle, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(Check, { className: "h-4 w-4" })
34104
+ children: isSaving ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(LoaderCircle, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(Save, { className: "h-4 w-4" })
34088
34105
  }
34089
34106
  )
34090
34107
  ] })
@@ -34092,9 +34109,10 @@ var EditableField = import_react54.default.memo(
34092
34109
  "div",
34093
34110
  {
34094
34111
  className: cn(
34095
- "relative flex items-center justify-between rounded-lg px-3 py-2",
34096
- "text-[14px] text-foreground font-normal leading-relaxed"
34112
+ "relative flex items-start justify-between rounded-lg px-3 py-2",
34113
+ "text-base text-foreground/90 font-medium leading-relaxed"
34097
34114
  ),
34115
+ style: { fontFamily: "Noto Sans, sans-serif" },
34098
34116
  children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { className: "flex-1", children: formattedValue() })
34099
34117
  }
34100
34118
  )
@@ -34202,47 +34220,109 @@ var import_react56 = __toESM(require("react"), 1);
34202
34220
  var import_jsx_runtime96 = require("react/jsx-runtime");
34203
34221
  var FormCard = import_react56.default.memo(
34204
34222
  ({
34205
- // title,
34223
+ title,
34206
34224
  fields,
34207
34225
  data,
34208
- editingFields = {},
34226
+ editingFields: externalEditingFields,
34209
34227
  changedFields = {},
34210
34228
  savingFields = {},
34211
- onFieldEdit,
34212
- onFieldSave,
34213
- onFieldCancel,
34229
+ onFieldEdit: externalOnFieldEdit,
34230
+ onFieldSave: externalOnFieldSave,
34231
+ onFieldCancel: externalOnFieldCancel,
34214
34232
  showTimeline = true,
34215
34233
  proceedLabel,
34216
34234
  onProceed,
34217
34235
  isLatestMessage = true,
34236
+ hideTitle = false,
34237
+ hideCopyButton = false,
34218
34238
  className,
34219
34239
  footer
34220
34240
  }) => {
34241
+ const [copied, setCopied] = (0, import_react56.useState)(false);
34242
+ const [internalEditingFields, setInternalEditingFields] = (0, import_react56.useState)({});
34243
+ const [internalData, setInternalData] = (0, import_react56.useState)(data);
34244
+ import_react56.default.useEffect(() => {
34245
+ setInternalData(data);
34246
+ }, [data]);
34247
+ const isExternallyControlled = !!(externalOnFieldEdit || externalOnFieldSave || externalOnFieldCancel);
34248
+ const editingFields = isExternallyControlled ? externalEditingFields || {} : internalEditingFields;
34249
+ const activeData = isExternallyControlled ? data : internalData;
34250
+ const handleFieldEdit = (key) => {
34251
+ if (isExternallyControlled) {
34252
+ externalOnFieldEdit?.(key);
34253
+ } else {
34254
+ setInternalEditingFields((prev) => ({ ...prev, [key]: true }));
34255
+ }
34256
+ };
34257
+ const handleFieldSave = (key, newValue) => {
34258
+ if (isExternallyControlled) {
34259
+ externalOnFieldSave?.(key, newValue);
34260
+ } else {
34261
+ setInternalData((prev) => ({ ...prev, [key]: newValue }));
34262
+ setInternalEditingFields((prev) => ({ ...prev, [key]: false }));
34263
+ }
34264
+ };
34265
+ const handleFieldCancel = (key) => {
34266
+ if (isExternallyControlled) {
34267
+ externalOnFieldCancel?.(key);
34268
+ } else {
34269
+ setInternalEditingFields((prev) => ({ ...prev, [key]: false }));
34270
+ }
34271
+ };
34221
34272
  const handleCopyAll = () => {
34222
- const text = fields.map((field) => {
34223
- const value = data[field.key];
34224
- return `${field.label}: ${typeof value === "object" ? JSON.stringify(value) : value}`;
34225
- }).join("\n");
34226
- navigator.clipboard.writeText(text);
34273
+ const flattenValue = (val) => {
34274
+ if (val === null || val === void 0) return "-";
34275
+ if (Array.isArray(val)) {
34276
+ return val.map((item) => {
34277
+ if (typeof item === "object" && item !== null) {
34278
+ return item.label || item.value || item.name || JSON.stringify(item);
34279
+ }
34280
+ return String(item);
34281
+ }).join(", ");
34282
+ }
34283
+ if (typeof val === "object") {
34284
+ return Object.entries(val).map(([k, v]) => `${k.replace(/_/g, " ")}: ${v}`).join(", ");
34285
+ }
34286
+ return String(val);
34287
+ };
34288
+ const text = [
34289
+ title,
34290
+ "",
34291
+ ...fields.map((field) => {
34292
+ const value = activeData[field.key];
34293
+ return `${field.label}: ${flattenValue(value)}`;
34294
+ })
34295
+ ].join("\n");
34296
+ navigator.clipboard.writeText(text).then(() => {
34297
+ setCopied(true);
34298
+ setTimeout(() => setCopied(false), 2e3);
34299
+ });
34227
34300
  };
34228
34301
  return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)(
34229
34302
  "div",
34230
34303
  {
34231
34304
  className: cn(
34232
- "relative w-full rounded-[20px] bg-background dark:bg-gray100 border border-gray400 shadow-lg overflow-hidden mb-6 font-noto",
34305
+ "relative w-full rounded-[20px] bg-paperBackground dark:bg-gray100 border border-gray400 shadow-lg overflow-hidden mb-6 font-noto",
34233
34306
  className
34234
34307
  ),
34235
34308
  children: [
34236
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
34309
+ !hideCopyButton && /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
34237
34310
  "button",
34238
34311
  {
34239
34312
  onClick: handleCopyAll,
34240
34313
  title: "Copy all details",
34241
- className: "absolute top-4 right-4 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray200 text-gray-400 hover:text-gray-600 dark:hover:text-gray300 transition-all active:scale-95 z-10",
34242
- children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(Copy, { className: "h-4 w-4" })
34314
+ className: "absolute top-4 right-4 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-200 text-gray-400 hover:text-gray-600 dark:hover:text-gray300 transition-all active:scale-95 z-10",
34315
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(Check, { className: "h-4 w-4 text-green-500" }) : /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(Copy, { className: "h-4 w-4" })
34243
34316
  }
34244
34317
  ),
34245
34318
  /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "p-6 relative", children: [
34319
+ !hideTitle && title && /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
34320
+ "h3",
34321
+ {
34322
+ className: "text-gray900 dark:text-white mb-12 text-[1rem] font-bold",
34323
+ children: title
34324
+ }
34325
+ ),
34246
34326
  showTimeline && /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
34247
34327
  "div",
34248
34328
  {
@@ -34259,16 +34339,16 @@ var FormCard = import_react56.default.memo(
34259
34339
  EditableField,
34260
34340
  {
34261
34341
  label: field.label,
34262
- value: data[field.key],
34342
+ value: activeData[field.key],
34263
34343
  type: field.type,
34264
34344
  config: field,
34265
34345
  isEditing: editingFields[field.key],
34266
34346
  isChanged: changedFields[field.key],
34267
34347
  isSaving: savingFields[field.key],
34268
34348
  isLatestMessage,
34269
- onEdit: () => onFieldEdit?.(field.key),
34270
- onSave: (val) => onFieldSave?.(field.key, val),
34271
- onCancel: () => onFieldCancel?.(field.key),
34349
+ onEdit: () => handleFieldEdit(field.key),
34350
+ onSave: (val) => handleFieldSave(field.key, val),
34351
+ onCancel: () => handleFieldCancel(field.key),
34272
34352
  renderDisplay: field.renderDisplay,
34273
34353
  renderEdit: field.renderEdit,
34274
34354
  showIndex: showTimeline,
@@ -35129,7 +35209,7 @@ var CountrySelectDisplay = ({ value }) => {
35129
35209
  Badge2,
35130
35210
  {
35131
35211
  variant: "outline",
35132
- className: "bg-gray-50 text-gray-700 border-gray-200",
35212
+ className: "text-foreground border-gray-200 py-1",
35133
35213
  children: countryCode
35134
35214
  },
35135
35215
  countryCode
@@ -35149,7 +35229,7 @@ var KeywordBundlesEdit = ({
35149
35229
  const sortedPriorities = Object.keys(groups).map((n) => parseInt(n)).sort((a, b) => a - b);
35150
35230
  return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "space-y-6 pt-2", children: sortedPriorities.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "space-y-3", children: [
35151
35231
  /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center gap-2", children: [
35152
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(Badge2, { className: "bg-purple500 hover:bg-purple500", children: [
35232
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(Badge2, { className: "bg-purple500 hover:bg-purple500 py-1", children: [
35153
35233
  "Priority ",
35154
35234
  priority
35155
35235
  ] }),
@@ -35165,7 +35245,7 @@ var KeywordBundlesEdit = ({
35165
35245
  /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "flex flex-wrap gap-1.5", children: Array.isArray(bundle.keywords) && bundle.keywords.map((keyword, kIndex) => /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
35166
35246
  Badge2,
35167
35247
  {
35168
- className: "bg-white border-gray-200 text-gray-700 hover:bg-red-50 hover:text-red-600 hover:border-red-100 transition-all cursor-pointer group",
35248
+ className: "bg-white py-1 border-gray-200 text-gray-700 hover:bg-red-50 hover:text-red-600 hover:border-red-100 transition-all cursor-pointer group",
35169
35249
  onClick: () => {
35170
35250
  const updatedBundles = [...bundles];
35171
35251
  updatedBundles[bundleIndex] = {
@@ -35259,7 +35339,7 @@ var KeywordBundlesDisplay = ({ value }) => {
35259
35339
  /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "flex flex-wrap gap-2", children: deduped.map((keyword) => /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
35260
35340
  "div",
35261
35341
  {
35262
- className: "px-2 py-1 rounded bg-background bg-gray400 border border-white/10 text-gray-300 text-xs font-medium",
35342
+ className: "px-2 py-1 rounded bg-background border text-gray-300 text-sm font-medium py-1",
35263
35343
  children: keyword
35264
35344
  },
35265
35345
  keyword
@@ -35283,7 +35363,7 @@ var ObjectDisplay = ({ value }) => {
35283
35363
  var StringArrayDisplay = ({ value }) => {
35284
35364
  if (!Array.isArray(value) || value.length === 0)
35285
35365
  return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "text-muted-foreground italic text-sm", children: "Not specified" });
35286
- return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "flex flex-wrap gap-1.5 pt-1", children: value.map((item) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Badge2, { variant: "outline", className: "text-xs", children: item }, item)) });
35366
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "flex flex-wrap gap-1.5 pt-1", children: value.map((item) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Badge2, { variant: "outline", className: "text-sm border-gray-200 py-1", children: item }, item)) });
35287
35367
  };
35288
35368
  function buildCampaignSeedFields(data) {
35289
35369
  if (!data || typeof data !== "object") return [];
@@ -35294,7 +35374,32 @@ function buildCampaignSeedFields(data) {
35294
35374
  key,
35295
35375
  label: "Keyword Bundles",
35296
35376
  type: "custom",
35297
- renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(KeywordBundlesDisplay, { value: v })
35377
+ renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(KeywordBundlesDisplay, { value: v }),
35378
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
35379
+ Textarea,
35380
+ {
35381
+ value: Array.isArray(v) ? v.map((b) => `${(b.keywords || []).join(", ")} (Priority: ${b.priority || 1})`).join("\n") : String(v || ""),
35382
+ onChange: (e) => {
35383
+ const lines = e.target.value.split("\n").filter(Boolean);
35384
+ const bundles = lines.map((line) => {
35385
+ const match2 = line.match(/(.*?)\s*\(Priority:\s*(\d+)\)/i);
35386
+ if (match2) {
35387
+ return {
35388
+ keywords: match2[1].split(",").map((s) => s.trim()).filter(Boolean),
35389
+ priority: parseInt(match2[2]) || 1
35390
+ };
35391
+ }
35392
+ return {
35393
+ keywords: line.split(",").map((s) => s.trim()).filter(Boolean),
35394
+ priority: 1
35395
+ };
35396
+ });
35397
+ onChange(bundles);
35398
+ },
35399
+ placeholder: "Keyword 1, Keyword 2 (Priority: 1)...",
35400
+ className: "min-h-[120px] bg-background border-gray-300"
35401
+ }
35402
+ )
35298
35403
  };
35299
35404
  }
35300
35405
  if (key === "geography") {
@@ -35302,7 +35407,19 @@ function buildCampaignSeedFields(data) {
35302
35407
  key,
35303
35408
  label: "Geography",
35304
35409
  type: "custom",
35305
- renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(CountrySelectDisplay, { value: v })
35410
+ renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(CountrySelectDisplay, { value: v }),
35411
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
35412
+ Textarea,
35413
+ {
35414
+ value: Array.isArray(v) ? v.join(", ") : String(v || ""),
35415
+ onChange: (e) => {
35416
+ const items = e.target.value.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean);
35417
+ onChange(items);
35418
+ },
35419
+ placeholder: "Enter country codes (US, GB, PK) separated by commas...",
35420
+ className: "min-h-[80px] bg-background border-gray-300"
35421
+ }
35422
+ )
35306
35423
  };
35307
35424
  }
35308
35425
  if (key === "platforms" && Array.isArray(value)) {
@@ -35323,7 +35440,19 @@ function buildCampaignSeedFields(data) {
35323
35440
  },
35324
35441
  p
35325
35442
  )) });
35326
- }
35443
+ },
35444
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
35445
+ Textarea,
35446
+ {
35447
+ value: Array.isArray(v) ? v.join(", ") : String(v || ""),
35448
+ onChange: (e) => {
35449
+ const items = e.target.value.split(",").map((s) => s.trim()).filter(Boolean);
35450
+ onChange(items);
35451
+ },
35452
+ placeholder: "Enter platforms separated by commas...",
35453
+ className: "min-h-[80px] bg-background border-gray-300"
35454
+ }
35455
+ )
35327
35456
  };
35328
35457
  }
35329
35458
  if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
@@ -35355,7 +35484,26 @@ function buildCampaignSeedFields(data) {
35355
35484
  key,
35356
35485
  label,
35357
35486
  type: "custom",
35358
- renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(ObjectDisplay, { value: v })
35487
+ renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(ObjectDisplay, { value: v }),
35488
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
35489
+ Textarea,
35490
+ {
35491
+ value: Object.entries(v || {}).map(([k, val]) => `${k.replace(/_/g, " ")}: ${val}`).join("\n"),
35492
+ onChange: (e) => {
35493
+ const lines = e.target.value.split("\n").filter(Boolean);
35494
+ const newObj = {};
35495
+ lines.forEach((line) => {
35496
+ const [k, ...rest] = line.split(":");
35497
+ if (k) {
35498
+ newObj[k.trim().replace(/\s+/g, "_").toLowerCase()] = rest.join(":").trim();
35499
+ }
35500
+ });
35501
+ onChange(newObj);
35502
+ },
35503
+ placeholder: "Enter key: value pairs (one per line)...",
35504
+ className: "min-h-[120px] bg-background border-gray-300 font-mono text-xs"
35505
+ }
35506
+ )
35359
35507
  };
35360
35508
  }
35361
35509
  const [generated] = generateFieldsFromData({ [key]: value });
@@ -35396,7 +35544,7 @@ var CampaignSeedCard = import_react60.default.memo(
35396
35544
  showTimeline: true,
35397
35545
  isLatestMessage: effectiveIsLatest,
35398
35546
  className: cn("font-noto", className),
35399
- footer: !effectiveIsLatest && (selectionStatus || hasUserResponded) ? /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex justify-end items-center gap-1.5 text-green-600 text-[10px] font-semibold py-4 pr-6", children: [
35547
+ footer: !effectiveIsLatest && selectionStatus ? /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex justify-end items-center gap-1.5 text-green-600 text-[10px] font-semibold py-4 pr-6", children: [
35400
35548
  /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(CircleCheck, { className: "h-3.5 w-3.5" }),
35401
35549
  /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { children: selectionStatus === "agent" ? "Suggested by Agent" : "Selected by you" })
35402
35550
  ] }) : formCardProps.footer
@@ -35422,7 +35570,7 @@ var ObjectDisplay2 = ({ value }) => {
35422
35570
  var StringArrayDisplay2 = ({ value }) => {
35423
35571
  if (!Array.isArray(value) || value.length === 0)
35424
35572
  return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("span", { className: "text-muted-foreground italic text-sm", children: "Not specified" });
35425
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("div", { className: "flex flex-wrap gap-1.5 pt-1", children: value.map((item) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(Badge2, { variant: "outline", className: "text-xs", children: item }, item)) });
35573
+ return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("div", { className: "flex flex-wrap gap-1.5 pt-1", children: value.map((item) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(Badge2, { variant: "outline", className: "text-sm border-gray-200 py-1", children: item }, item)) });
35426
35574
  };
35427
35575
  function buildSearchSpecFields(data) {
35428
35576
  if (!data || typeof data !== "object") return [];
@@ -35446,12 +35594,25 @@ function buildSearchSpecFields(data) {
35446
35594
  renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(CountrySelectEdit, { value: v, onChange })
35447
35595
  };
35448
35596
  }
35449
- if (key === "platforms" && Array.isArray(value)) {
35597
+ if ((key === "platforms" || key === "exclude_keywords" || key === "excludeKeywords") && Array.isArray(value)) {
35598
+ const label = key === "platforms" ? "Platforms" : "Exclude Keywords";
35450
35599
  return {
35451
35600
  key,
35452
- label: "Platforms",
35601
+ label,
35453
35602
  type: "custom",
35454
- renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(StringArrayDisplay2, { value: v })
35603
+ renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(StringArrayDisplay2, { value: v }),
35604
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
35605
+ Textarea,
35606
+ {
35607
+ value: Array.isArray(v) ? v.join(", ") : String(v || ""),
35608
+ onChange: (e) => {
35609
+ const items = e.target.value.split(",").map((s) => s.trim()).filter(Boolean);
35610
+ onChange(items);
35611
+ },
35612
+ placeholder: `Enter ${label.toLowerCase()} separated by commas...`,
35613
+ className: "min-h-[100px] bg-background border-gray-300"
35614
+ }
35615
+ )
35455
35616
  };
35456
35617
  }
35457
35618
  if (typeof value === "object" && value !== null && !Array.isArray(value) && !("min" in value && "max" in value)) {
@@ -35460,7 +35621,26 @@ function buildSearchSpecFields(data) {
35460
35621
  key,
35461
35622
  label,
35462
35623
  type: "custom",
35463
- renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(ObjectDisplay2, { value: v })
35624
+ renderDisplay: (v) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(ObjectDisplay2, { value: v }),
35625
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
35626
+ Textarea,
35627
+ {
35628
+ value: Object.entries(v || {}).map(([k, val]) => `${k.replace(/_/g, " ")}: ${val}`).join("\n"),
35629
+ onChange: (e) => {
35630
+ const lines = e.target.value.split("\n").filter(Boolean);
35631
+ const newObj = {};
35632
+ lines.forEach((line) => {
35633
+ const [k, ...rest] = line.split(":");
35634
+ if (k) {
35635
+ newObj[k.trim().replace(/\s+/g, "_").toLowerCase()] = rest.join(":").trim();
35636
+ }
35637
+ });
35638
+ onChange(newObj);
35639
+ },
35640
+ placeholder: "Enter key: value pairs (one per line)...",
35641
+ className: "min-h-[120px] bg-background border-gray-300 font-mono text-xs"
35642
+ }
35643
+ )
35464
35644
  };
35465
35645
  }
35466
35646
  const [generated] = generateFieldsFromData({ [key]: value });
@@ -35491,7 +35671,7 @@ var SearchSpecCard = import_react61.default.memo(
35491
35671
  });
35492
35672
  };
35493
35673
  const effectiveIsLatest = isLatestMessage && !hasUserResponded;
35494
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
35674
+ return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
35495
35675
  FormCard,
35496
35676
  {
35497
35677
  ...formCardProps,
@@ -35502,12 +35682,12 @@ var SearchSpecCard = import_react61.default.memo(
35502
35682
  onProceed: handleProceed,
35503
35683
  isLatestMessage: effectiveIsLatest,
35504
35684
  className,
35505
- footer: !effectiveIsLatest && (selectionStatus || hasUserResponded) ? /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("div", { className: "flex justify-end items-center gap-1.5 text-green-600 text-xs font-semibold py-1", children: [
35685
+ footer: !effectiveIsLatest && selectionStatus ? /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("div", { className: "flex justify-end items-center gap-1.5 text-green-600 text-xs font-semibold py-1", children: [
35506
35686
  /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(CircleCheck, { className: "h-4 w-4" }),
35507
35687
  /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("span", { children: selectionStatus === "agent" ? "Selected by Agent" : "Selected by User" })
35508
35688
  ] }) : formCardProps.footer
35509
35689
  }
35510
- );
35690
+ ) });
35511
35691
  }
35512
35692
  );
35513
35693
  SearchSpecCard.displayName = "SearchSpecCard";
@@ -36344,7 +36524,26 @@ var CampaignConceptCard = import_react64.default.memo(
36344
36524
  ] }, k)) });
36345
36525
  }
36346
36526
  return /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "text-muted-foreground text-sm", children: String(val) });
36347
- }
36527
+ },
36528
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(
36529
+ Textarea,
36530
+ {
36531
+ value: typeof v === "object" ? Object.entries(v || {}).map(([k, val]) => `${k.replace(/_/g, " ")}: ${val}`).join("\n") : String(v || ""),
36532
+ onChange: (e) => {
36533
+ const lines = e.target.value.split("\n").filter(Boolean);
36534
+ const newObj = {};
36535
+ lines.forEach((line) => {
36536
+ if (line.includes(":")) {
36537
+ const [k, ...rest] = line.split(":");
36538
+ newObj[k.trim().replace(/\s+/g, "_").toLowerCase()] = rest.join(":").trim().replace("%", "");
36539
+ }
36540
+ });
36541
+ onChange(newObj);
36542
+ },
36543
+ placeholder: "Tier name: percentage (one per line)...",
36544
+ className: "min-h-[120px] bg-background border-gray-300 font-mono text-xs"
36545
+ }
36546
+ )
36348
36547
  };
36349
36548
  }
36350
36549
  if (field.key === "estimatedCreators" || field.key === "estimated_creators") {
@@ -36377,14 +36576,40 @@ var CampaignConceptCard = import_react64.default.memo(
36377
36576
  )) });
36378
36577
  }
36379
36578
  return /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "text-txtColor font-medium", children: String(val) });
36380
- }
36579
+ },
36580
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(
36581
+ Input,
36582
+ {
36583
+ value: typeof v === "object" ? `${v.min ?? 0}-${v.max ?? 0}` : String(v || ""),
36584
+ onChange: (e) => {
36585
+ const val = e.target.value;
36586
+ if (val.includes("-")) {
36587
+ const [min2, max2] = val.split("-").map((s) => parseInt(s.trim()) || 0);
36588
+ onChange({ min: min2, max: max2 });
36589
+ } else {
36590
+ onChange(val);
36591
+ }
36592
+ },
36593
+ placeholder: "Min-Max (e.g. 10-30)...",
36594
+ className: "bg-background border-gray-300"
36595
+ }
36596
+ )
36381
36597
  };
36382
36598
  }
36383
36599
  if (field.key === "primary_kpi" || field.key === "primaryKpi") {
36384
36600
  return {
36385
36601
  ...field,
36386
36602
  label: field.label || "Primary KPI",
36387
- renderDisplay: (val) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "text-foreground text-sm", children: val ? String(val) : "-" })
36603
+ renderDisplay: (val) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "text-foreground text-sm", children: val ? String(val) : "-" }),
36604
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(
36605
+ Input,
36606
+ {
36607
+ value: String(v || ""),
36608
+ onChange: (e) => onChange(e.target.value),
36609
+ placeholder: "Enter primary KPI...",
36610
+ className: "bg-background border-gray-300"
36611
+ }
36612
+ )
36388
36613
  };
36389
36614
  }
36390
36615
  if (field.key === "secondary_kpis" || field.key === "secondaryKpis") {
@@ -36394,7 +36619,19 @@ var CampaignConceptCard = import_react64.default.memo(
36394
36619
  renderDisplay: (val) => {
36395
36620
  const display = Array.isArray(val) ? val.map(String).join(", ") : val ? String(val) : "-";
36396
36621
  return /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "text-foreground text-sm", children: display });
36397
- }
36622
+ },
36623
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(
36624
+ Textarea,
36625
+ {
36626
+ value: Array.isArray(v) ? v.join(", ") : String(v || ""),
36627
+ onChange: (e) => {
36628
+ const items = e.target.value.split(",").map((s) => s.trim()).filter(Boolean);
36629
+ onChange(items);
36630
+ },
36631
+ placeholder: "Enter KPIs separated by commas...",
36632
+ className: "min-h-[80px] bg-background border-gray-300"
36633
+ }
36634
+ )
36398
36635
  };
36399
36636
  }
36400
36637
  if (field.key === "platforms" || field.key === "target_platforms" || field.key === "targetPlatforms") {
@@ -36411,7 +36648,19 @@ var CampaignConceptCard = import_react64.default.memo(
36411
36648
  },
36412
36649
  p
36413
36650
  )) });
36414
- }
36651
+ },
36652
+ renderEdit: (v, onChange) => /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(
36653
+ Textarea,
36654
+ {
36655
+ value: Array.isArray(v) ? v.join(", ") : String(v || ""),
36656
+ onChange: (e) => {
36657
+ const items = e.target.value.split(",").map((s) => s.trim()).filter(Boolean);
36658
+ onChange(items);
36659
+ },
36660
+ placeholder: "Enter platforms separated by commas...",
36661
+ className: "min-h-[80px] bg-background border-gray-300"
36662
+ }
36663
+ )
36415
36664
  };
36416
36665
  }
36417
36666
  return {
@@ -36457,8 +36706,8 @@ var CampaignConceptCard = import_react64.default.memo(
36457
36706
  /* @__PURE__ */ (0, import_jsx_runtime121.jsxs)("div", { className: "flex-1", children: [
36458
36707
  /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("h2", { className: "mb-1 py-1 text-txtColor font-bold", children: typeof cardTitle === "object" ? JSON.stringify(cardTitle) : String(cardTitle) }),
36459
36708
  /* @__PURE__ */ (0, import_jsx_runtime121.jsxs)("div", { className: "flex flex-wrap gap-2", children: [
36460
- isRecommended && /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("div", { className: "inline-flex text-[10px] font-bold uppercase tracking-widest text-[#22C55E]", children: /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "bg-[#22C55E]/10 px-2 py-0.5 rounded border border-[#22C55E]/20", children: "Recommended" }) }),
36461
- !effectiveIsLatest && (selectionStatus || hasUserResponded) && /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("div", { className: "inline-flex text-[10px] font-bold uppercase tracking-widest text-[#3B82F6]", children: /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "bg-[#3B82F6]/10 px-2 py-0.5 rounded border border-[#3B82F6]/20", children: selectionStatus === "agent" ? "Selected by Agent" : "Selected by You" }) })
36709
+ isRecommended && /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("div", { className: "inline-flex text-[10px] font-bold uppercase tracking-widest", children: /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "bg-green-600 text-white px-2 py-0.5 rounded border border-green-700", children: "Recommended" }) }),
36710
+ !effectiveIsLatest && selectionStatus && /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("div", { className: "inline-flex text-[10px] font-bold uppercase tracking-widest text-[#3B82F6]", children: /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { className: "bg-[#3B82F6]/10 px-2 py-0.5 rounded border border-[#3B82F6]/20", children: selectionStatus === "agent" ? "Selected by Agent" : "Selected by You" }) })
36462
36711
  ] })
36463
36712
  ] }),
36464
36713
  /* @__PURE__ */ (0, import_jsx_runtime121.jsxs)("div", { className: "flex items-center gap-2 ml-3", onClick: (e) => e.stopPropagation(), children: [
@@ -36524,8 +36773,10 @@ var CampaignConceptCard = import_react64.default.memo(
36524
36773
  proceedLabel: "Continue with this concept",
36525
36774
  onProceed: handleProceed,
36526
36775
  isLatestMessage: effectiveIsLatest,
36776
+ hideTitle: true,
36777
+ hideCopyButton: true,
36527
36778
  className: "bg-transparent border-none shadow-none mb-0 p-0",
36528
- footer: !effectiveIsLatest && (selectionStatus || hasUserResponded) ? /* @__PURE__ */ (0, import_jsx_runtime121.jsxs)("div", { className: "flex justify-end items-center gap-1.5 text-green-600 text-[10px] font-semibold py-4 pr-6", children: [
36779
+ footer: !effectiveIsLatest && selectionStatus ? /* @__PURE__ */ (0, import_jsx_runtime121.jsxs)("div", { className: "flex justify-end items-center gap-1.5 text-green-600 text-[10px] font-semibold py-4 pr-6", children: [
36529
36780
  /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(CircleCheck, { className: "h-3.5 w-3.5" }),
36530
36781
  /* @__PURE__ */ (0, import_jsx_runtime121.jsx)("span", { children: selectionStatus === "agent" ? "Selected by Agent" : "Selected by You" })
36531
36782
  ] }) : formCardProps.footer