your-ai-workflow-firebase-os 1.2.2 → 1.2.4

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.
@@ -78814,9 +78814,9 @@ function OVn() {
78814
78814
  className: "flex justify-start",
78815
78815
  children: /* @__PURE__ */ B(p9, {})
78816
78816
  }), /* @__PURE__ */ V("div", {
78817
- className: "w-full flex-1 glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]",
78817
+ className: "w-full flex-1 flex flex-col glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]",
78818
78818
  children: [/* @__PURE__ */ B("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-accent/5 blur-[100px] rounded-full pointer-events-none" }), /* @__PURE__ */ B("div", {
78819
- className: "relative z-10 h-full flex flex-col",
78819
+ className: "relative z-10 flex-1 flex flex-col",
78820
78820
  children: n ? /* @__PURE__ */ B("div", {
78821
78821
  className: "flex-1 flex items-center justify-center min-h-[500px]",
78822
78822
  children: /* @__PURE__ */ B("div", { className: "w-8 h-8 md:w-10 md:h-10 border-4 border-accent/20 border-t-accent rounded-full animate-spin" })
@@ -79194,9 +79194,9 @@ function kVn() {
79194
79194
  className: "flex justify-start",
79195
79195
  children: /* @__PURE__ */ B(p9, {})
79196
79196
  }), /* @__PURE__ */ V("div", {
79197
- className: "w-full flex-1 glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]",
79197
+ className: "w-full flex-1 flex flex-col glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]",
79198
79198
  children: [/* @__PURE__ */ B("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-accent/5 blur-[100px] rounded-full pointer-events-none" }), /* @__PURE__ */ B("div", {
79199
- className: "relative z-10 h-full flex flex-col",
79199
+ className: "relative z-10 flex-1 flex flex-col",
79200
79200
  children: n ? /* @__PURE__ */ B("div", {
79201
79201
  className: "flex-1 flex items-center justify-center min-h-[500px]",
79202
79202
  children: /* @__PURE__ */ B("div", { className: "w-8 h-8 md:w-10 md:h-10 border-4 border-accent/20 border-t-accent rounded-full animate-spin" })
@@ -79813,9 +79813,9 @@ function AVn() {
79813
79813
  onDragLeave: fe,
79814
79814
  onDrop: pe,
79815
79815
  children: [/* @__PURE__ */ B(p9, {}), /* @__PURE__ */ V("div", {
79816
- className: "flex flex-col md:flex-row glass-panel border border-[var(--panel-border)] rounded-3xl overflow-hidden flex-1 shadow-2xl min-h-[600px] bg-background",
79816
+ className: "flex flex-row glass-panel border border-[var(--panel-border)] rounded-3xl overflow-hidden flex-1 shadow-2xl min-h-[600px] bg-background",
79817
79817
  children: [/* @__PURE__ */ V("div", {
79818
- className: "md:w-[280px] border-b md:border-b-0 md:border-r border-[var(--panel-border)] bg-foreground/[0.01] p-4 flex flex-col shrink-0 overflow-y-auto hide-scrollbar",
79818
+ className: "w-[280px] border-r border-[var(--panel-border)] bg-foreground/[0.01] p-4 flex flex-col shrink-0 overflow-y-auto hide-scrollbar",
79819
79819
  children: [/* @__PURE__ */ B("div", {
79820
79820
  className: "text-[11px] font-extrabold text-foreground/40 uppercase tracking-widest pl-4 mb-4 mt-2",
79821
79821
  children: "Locations"
@@ -80153,7 +80153,7 @@ function AVn() {
80153
80153
  }),
80154
80154
  /* @__PURE__ */ B(ds, {
80155
80155
  onClick: () => ue.current?.click(),
80156
- className: "px-8 py-3 rounded-full font-bold shadow-md bg-accent text-white hover:bg-accent/90 transition-colors",
80156
+ className: "px-8 py-3 rounded-full font-bold shadow-md btn-primary transition-colors",
80157
80157
  children: "Browse Files"
80158
80158
  })
80159
80159
  ]
@@ -80246,7 +80246,7 @@ function AVn() {
80246
80246
  download: !0,
80247
80247
  target: "_blank",
80248
80248
  rel: "noreferrer",
80249
- className: "p-2.5 bg-accent text-white hover:bg-accent/90 transition-colors rounded-xl shadow-lg ml-1",
80249
+ className: "p-2.5 btn-primary transition-colors rounded-xl shadow-lg ml-1",
80250
80250
  title: "Download",
80251
80251
  children: /* @__PURE__ */ B(mt, { className: "w-4 h-4" })
80252
80252
  })
@@ -85445,42 +85445,35 @@ W && ee(C(W, "sys_forms")).then((e) => {
85445
85445
  }), t.length > 0 && Object.assign(iUn, { form: t });
85446
85446
  }).catch(() => {});
85447
85447
  var aUn = ({ value: e, onChange: t, onBlur: n, onFocus: r, className: a, isNumber: o, handleBlurOrEnter: s, placeholder: c, disabled: l }) => {
85448
- let [u, d] = i.useState(e), [f, p] = i.useState(!1), [h, g] = i.useState(0), _ = i.useRef(null), v = i.useRef(null);
85448
+ let [u, d] = i.useState(e), [f, p] = i.useState(!1), h = i.useRef(null);
85449
85449
  i.useEffect(() => {
85450
85450
  d(e);
85451
- }, [e]), i.useLayoutEffect(() => {
85452
- v.current && g(v.current.getBoundingClientRect().width);
85453
- }, [u, c]), m(() => {
85454
- !f && _.current && (_.current.scrollLeft = 0);
85451
+ }, [e]), m(() => {
85452
+ !f && h.current && (h.current.scrollLeft = 0);
85455
85453
  }, [u, f]);
85456
- let y = typeof a == "string" ? a.match(/(?:max-w-\[[^\]]+\]|sm:max-w-\[[^\]]+\]|md:max-w-\[[^\]]+\])\s*/g) : null, b = y ? y.join(" ") : "max-w-[200px] sm:max-w-[300px]", x = typeof a == "string" ? a.replace(/(?:max-w-\[[^\]]+\]|sm:max-w-\[[^\]]+\]|md:max-w-\[[^\]]+\]|text-ellipsis)\s*/g, "") : "", S = x.trim();
85454
+ let g = typeof a == "string" ? a.match(/(?:max-w-\[[^\]]+\]|sm:max-w-\[[^\]]+\]|md:max-w-\[[^\]]+\])\s*/g) : null, _ = g ? g.join(" ") : "max-w-[200px] sm:max-w-[300px]", v = typeof a == "string" ? a.replace(/(?:max-w-\[[^\]]+\]|sm:max-w-\[[^\]]+\]|md:max-w-\[[^\]]+\]|text-ellipsis)\s*/g, "") : "", y = v.trim();
85457
85455
  return /* @__PURE__ */ B("div", {
85458
- className: `relative inline-flex flex-col group/autoresize ${b}`,
85456
+ className: `relative inline-grid group/autoresize ${_}`,
85459
85457
  children: /* @__PURE__ */ V("div", {
85460
- className: "flex-1 overflow-x-auto overflow-y-hidden pb-[1px] styled-scrollbars-mini flex items-center",
85458
+ className: "col-start-1 row-start-1 overflow-x-auto overflow-y-hidden pb-[1px] styled-scrollbars-mini inline-grid items-center",
85461
85459
  children: [/* @__PURE__ */ B("span", {
85462
- ref: v,
85463
- className: `${x} absolute opacity-0 pointer-events-none whitespace-pre border-none p-0 inline-block`,
85464
- style: {
85465
- width: "max-content",
85466
- minWidth: "max-content"
85467
- },
85460
+ className: `${v} invisible whitespace-pre col-start-1 row-start-1 border-none p-0 inline-block px-[2px]`,
85468
85461
  "aria-hidden": "true",
85469
85462
  children: u || c || (o ? "0" : " ")
85470
85463
  }), /* @__PURE__ */ B("input", {
85471
85464
  disabled: l,
85472
- ref: _,
85465
+ ref: h,
85473
85466
  type: o ? "number" : "text",
85474
85467
  value: u,
85475
85468
  placeholder: c,
85476
85469
  spellCheck: !1,
85477
- className: `${S} transition-all duration-200 ${l ? "cursor-not-allowed opacity-50 select-none" : ""} ${f ? "relative z-50 bg-background shadow-md" : ""}`,
85470
+ className: `${y} col-start-1 row-start-1 w-full min-w-[20px] transition-all duration-200 ${l ? "cursor-not-allowed opacity-50 select-none" : ""} ${f ? "relative z-50 bg-background shadow-md" : ""}`,
85478
85471
  onDoubleClick: (e) => {
85479
85472
  l || e.currentTarget.select();
85480
85473
  },
85481
85474
  onPaste: () => {
85482
85475
  setTimeout(() => {
85483
- _.current && (_.current.scrollLeft = 0);
85476
+ h.current && (h.current.scrollLeft = 0);
85484
85477
  }, 10);
85485
85478
  },
85486
85479
  onChange: (e) => {
@@ -85500,11 +85493,6 @@ var aUn = ({ value: e, onChange: t, onBlur: n, onFocus: r, className: a, isNumbe
85500
85493
  },
85501
85494
  onFocus: (e) => {
85502
85495
  l || (p(!0), r && r(e));
85503
- },
85504
- style: {
85505
- width: h > 0 ? `${h + 6}px` : "auto",
85506
- minWidth: "20px",
85507
- maxWidth: f ? "none" : void 0
85508
85496
  }
85509
85497
  })]
85510
85498
  })
@@ -85857,7 +85845,8 @@ var aUn = ({ value: e, onChange: t, onBlur: n, onFocus: r, className: a, isNumbe
85857
85845
  required: !0,
85858
85846
  placeholder: "Enter your name"
85859
85847
  };
85860
- } else if (typeof e[0] == "string") {
85848
+ } else if (typeof e[0] == "string") if (e[0].startsWith("#") || e[0].startsWith("rgba") || e[0].startsWith("rgb") || e[0].startsWith("color-mix")) n = e[e.length - 1];
85849
+ else {
85861
85850
  let t = [
85862
85851
  "Marketing",
85863
85852
  "Support",
@@ -85866,7 +85855,8 @@ var aUn = ({ value: e, onChange: t, onBlur: n, onFocus: r, className: a, isNumbe
85866
85855
  "Maintenance"
85867
85856
  ];
85868
85857
  n = t[Math.min(e.length, t.length) - 1] || `Option ${e.length + 1}`;
85869
- } else n = e.length > 0 ? JSON.parse(JSON.stringify(e[e.length - 1])) : "", n && typeof n == "object" && (n.name &&= `${n.name}_${e.length}`, n.label &&= `${n.label} ${e.length}`);
85858
+ }
85859
+ else n = e.length > 0 ? JSON.parse(JSON.stringify(e[e.length - 1])) : "", n && typeof n == "object" && (n.name &&= `${n.name}_${e.length}`, n.label &&= `${n.label} ${e.length}`);
85870
85860
  e.push(n), a(e);
85871
85861
  },
85872
85862
  className: "mt-2 mb-1 w-fit flex items-center gap-1.5 px-3 py-1 bg-accent/10 hover:bg-accent/20 text-accent font-extrabold text-[11px] uppercase tracking-wider rounded-md transition-colors border border-accent/20",
@@ -86041,54 +86031,55 @@ var aUn = ({ value: e, onChange: t, onBlur: n, onFocus: r, className: a, isNumbe
86041
86031
  }));
86042
86032
  };
86043
86033
  function oUn() {
86044
- let { activeConfig: e } = Je(), [t, n] = x(null), [r, i] = x(!1), [a, o] = x(!1);
86034
+ let { activeConfig: e } = Je(), [t, n] = x(null), [r, a] = x(!1), [o, s] = x(!1), c = i.useRef(null);
86045
86035
  m(() => {
86046
- t || n(JSON.parse(JSON.stringify(e)));
86036
+ if (!t && e) {
86037
+ let t = JSON.parse(JSON.stringify(e));
86038
+ n(t), c.current = JSON.stringify(t);
86039
+ }
86047
86040
  }, [e]);
86048
- let [s, c] = x(!1), [l, u] = x(!1);
86041
+ let [l, u] = x(!1), [d, f] = x(!1);
86049
86042
  m(() => {
86050
- if (!t || !e) return;
86051
- if (JSON.stringify(t) === JSON.stringify(e)) {
86052
- i(!1);
86053
- return;
86054
- }
86043
+ if (!t) return;
86044
+ let e = JSON.stringify(t);
86045
+ if (e === c.current) return;
86055
86046
  let n = setTimeout(async () => {
86056
- i(!0);
86047
+ a(!0);
86057
86048
  try {
86058
- await j(T(W, "sys_configs", "theme"), t);
86049
+ await j(T(W, "sys_configs", "theme"), t), c.current = e;
86059
86050
  } catch (e) {
86060
86051
  console.error("Auto-save failed", e);
86061
86052
  }
86062
- i(!1);
86053
+ a(!1);
86063
86054
  }, 300);
86064
86055
  return () => clearTimeout(n);
86065
- }, [t, e]);
86066
- let d = async () => {
86067
- o(!0);
86056
+ }, [t]);
86057
+ let p = async () => {
86058
+ s(!0);
86068
86059
  try {
86069
- let e = await import("./theme.config-BbEzcEDR.js");
86070
- await j(T(W, "sys_configs", "theme"), e.themeConfig), n(JSON.parse(JSON.stringify(e.themeConfig)));
86060
+ let e = await import("./theme.config-BbEzcEDR.js"), t = JSON.parse(JSON.stringify(e.themeConfig));
86061
+ await j(T(W, "sys_configs", "theme"), e.themeConfig), c.current = JSON.stringify(t), n(t);
86071
86062
  } catch {}
86072
86063
  setTimeout(() => {
86073
- o(!1), u(!1);
86064
+ s(!1), f(!1);
86074
86065
  }, 1e3);
86075
- }, f = (e) => {
86066
+ }, h = (e) => {
86076
86067
  if (!e) return "167, 139, 250";
86077
86068
  let t = 0, n = 0, r = 0;
86078
86069
  return e.length === 4 ? (t = parseInt(e[1] + e[1], 16), n = parseInt(e[2] + e[2], 16), r = parseInt(e[3] + e[3], 16)) : e.length === 7 && (t = parseInt(e.substring(1, 3), 16), n = parseInt(e.substring(3, 5), 16), r = parseInt(e.substring(5, 7), 16)), `${t}, ${n}, ${r}`;
86079
- }, p = (e) => {
86070
+ }, g = (e) => {
86080
86071
  if (!t) return;
86081
86072
  let r = JSON.parse(JSON.stringify(t));
86082
86073
  if (r.colors && r.colors.dark) {
86083
- let t = f(e.dark.accent);
86074
+ let t = h(e.dark.accent);
86084
86075
  r.colors.dark.accent = e.dark.accent, r.colors.dark.buttonGradient = e.dark.gradient, r.colors.dark.buttonHoverGradient = e.dark.gradient, r.colors.dark.buttonText = e.dark.buttonText, r.colors.dark.notificationIconColor = e.dark.accent, r.colors.dark.textGradient = e.dark.text, r.colors.dark.foreground = e.dark.text[0], r.colors.dark.background = e.dark.background, r.colors.dark.backgroundSecondary = e.dark.backgroundSecondary, r.colors.dark.panelBg = `rgba(${t}, 0.05)`, r.colors.dark.panelBorder = `rgba(${t}, 0.15)`, r.colors.dark.glowColor = `rgba(${t}, 0.40)`, r.colors.dark.selectionBg = `rgba(${t}, 0.40)`, r.colors.dark.secondaryButton && (r.colors.dark.secondaryButton.text = e.dark.text[0]);
86085
86076
  }
86086
86077
  if (r.colors && r.colors.light) {
86087
- let t = f(e.light.accent);
86078
+ let t = h(e.light.accent);
86088
86079
  r.colors.light.accent = e.light.accent, r.colors.light.buttonGradient = e.light.gradient, r.colors.light.buttonHoverGradient = e.light.gradient, r.colors.light.buttonText = e.light.buttonText, r.colors.light.notificationIconColor = e.light.accent, r.colors.light.textGradient = e.light.text, r.colors.light.foreground = e.light.text[0], r.colors.light.background = e.light.background, r.colors.light.backgroundSecondary = e.light.backgroundSecondary, r.colors.light.panelBg = "rgba(255, 255, 255, 0.70)", r.colors.light.panelBorder = `rgba(${t}, 0.08)`, r.colors.light.glowColor = `rgba(${t}, 0.30)`, r.colors.light.selectionBg = `rgba(${t}, 0.30)`, r.colors.light.secondaryButton && (r.colors.light.secondaryButton.text = e.light.text[0]);
86089
86080
  }
86090
86081
  n(r);
86091
- }, h = () => {
86082
+ }, _ = () => {
86092
86083
  if (t) {
86093
86084
  let e = t, n = e.colors?.dark || {}, r = e.colors?.light || {};
86094
86085
  e.fontCustomization;
@@ -86193,23 +86184,15 @@ export const themeConfig = {
86193
86184
  modalRadius: ${i.modalRadius || 2.5}, // Global popups and main internal boxes
86194
86185
  }
86195
86186
  };`;
86196
- navigator.clipboard.writeText(a), c(!0), setTimeout(() => c(!1), 2e3);
86187
+ navigator.clipboard.writeText(a), u(!0), setTimeout(() => u(!1), 2e3);
86197
86188
  }
86198
86189
  };
86199
86190
  return m(() => {
86200
86191
  let e = (e) => {
86201
- (e.ctrlKey || e.metaKey) && e.key === "a" && document.activeElement === document.body && e.preventDefault(), (e.ctrlKey || e.metaKey) && e.key === "c" && !window.getSelection()?.toString() && t && h();
86192
+ (e.ctrlKey || e.metaKey) && e.key === "a" && document.activeElement === document.body && e.preventDefault(), (e.ctrlKey || e.metaKey) && e.key === "c" && !window.getSelection()?.toString() && t && _();
86202
86193
  };
86203
86194
  return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
86204
- }, [t]), m(() => {
86205
- if (!t?.colors) return;
86206
- let e = (document.documentElement.getAttribute("data-theme") || "dark") === "dark" ? t.colors.dark : t.colors.light, n = document.documentElement;
86207
- n.style.setProperty("--bg-color", e.background), e.backgroundSecondary && n.style.setProperty("--bg-secondary-color", e.backgroundSecondary), n.style.setProperty("--fg-color", e.foreground), n.style.setProperty("--accent-color", e.accent), n.style.setProperty("--accent-deep", e.accentDeep), n.style.setProperty("--panel-bg", e.panelBg), n.style.setProperty("--panel-border", e.panelBorder), n.style.setProperty("--button-bg", `linear-gradient(135deg, ${e.buttonGradient[0]} 0%, ${e.buttonGradient[1]} 100%)`), n.style.setProperty("--button-hover-bg", `linear-gradient(135deg, ${e.buttonHoverGradient?.[0] || e.buttonGradient[0]} 0%, ${e.buttonHoverGradient?.[1] || e.buttonGradient[1]} 100%)`), n.style.setProperty("--text-gradient", `linear-gradient(135deg, ${e.textGradient[0]} 0%, ${e.textGradient[1]} 50%, ${e.textGradient[2]} 100%)`), n.style.setProperty("--glow-color", e.glowColor || "rgba(124, 58, 237, 0.3)"), n.style.setProperty("--button-fg", e.buttonText || "#ffffff"), e.notificationIconColor && n.style.setProperty("--notification-icon-color", e.notificationIconColor);
86208
- }, [t]), m(() => () => {
86209
- if (!e?.colors) return;
86210
- let t = (document.documentElement.getAttribute("data-theme") || "dark") === "dark" ? e.colors.dark : e.colors.light, n = document.documentElement;
86211
- n.style.setProperty("--bg-color", t.background), t.backgroundSecondary && n.style.setProperty("--bg-secondary-color", t.backgroundSecondary), n.style.setProperty("--fg-color", t.foreground), n.style.setProperty("--accent-color", t.accent), n.style.setProperty("--accent-deep", t.accentDeep), n.style.setProperty("--panel-bg", t.panelBg), n.style.setProperty("--panel-border", t.panelBorder), n.style.setProperty("--button-bg", `linear-gradient(135deg, ${t.buttonGradient[0]} 0%, ${t.buttonGradient[1]} 100%)`), n.style.setProperty("--button-hover-bg", `linear-gradient(135deg, ${t.buttonHoverGradient?.[0] || t.buttonGradient[0]} 0%, ${t.buttonHoverGradient?.[1] || t.buttonGradient[1]} 100%)`), n.style.setProperty("--text-gradient", `linear-gradient(135deg, ${t.textGradient[0]} 0%, ${t.textGradient[1]} 50%, ${t.textGradient[2]} 100%)`), n.style.setProperty("--glow-color", t.glowColor || "rgba(124, 58, 237, 0.3)"), n.style.setProperty("--button-fg", t.buttonText || "#ffffff"), t.notificationIconColor && n.style.setProperty("--notification-icon-color", t.notificationIconColor);
86212
- }, [e]), /* @__PURE__ */ V("main", {
86195
+ }, [t]), /* @__PURE__ */ V("main", {
86213
86196
  className: "flex-1 w-full max-w-7xl mx-auto p-4 md:p-8 z-10 flex flex-col pt-12 min-h-screen",
86214
86197
  children: [/* @__PURE__ */ B(Y.div, {
86215
86198
  initial: {
@@ -86244,21 +86227,21 @@ export const themeConfig = {
86244
86227
  className: "flex items-center gap-2 shrink-0",
86245
86228
  children: [/* @__PURE__ */ B(ds, {
86246
86229
  variant: "secondary",
86247
- onClick: d,
86230
+ onClick: p,
86248
86231
  className: "w-10 h-10 p-0 border-transparent bg-transparent hover:bg-red-500/10 rounded-xl flex items-center justify-center shrink-0 transition-colors group",
86249
86232
  title: "Reset to Defaults",
86250
- children: a ? /* @__PURE__ */ B(K, { className: "w-4 h-4 text-red-500 animate-spin" }) : /* @__PURE__ */ B(kt, { className: "w-4 h-4 text-foreground/60 group-hover:text-red-500 transition-colors" })
86233
+ children: o ? /* @__PURE__ */ B(K, { className: "w-4 h-4 text-red-500 animate-spin" }) : /* @__PURE__ */ B(kt, { className: "w-4 h-4 text-foreground/60 group-hover:text-red-500 transition-colors" })
86251
86234
  }), /* @__PURE__ */ B(ds, {
86252
86235
  variant: "secondary",
86253
- onClick: h,
86236
+ onClick: _,
86254
86237
  className: "w-10 h-10 p-0 border-transparent bg-transparent hover:bg-foreground/5 rounded-xl flex items-center justify-center shrink-0 transition-colors",
86255
86238
  title: "Copy Config (Ctrl+C)",
86256
- children: s ? /* @__PURE__ */ B(st, { className: "w-4 h-4 text-emerald-500" }) : /* @__PURE__ */ B(ft, { className: "w-4 h-4 text-foreground/60 hover:text-foreground transition-colors" })
86239
+ children: l ? /* @__PURE__ */ B(st, { className: "w-4 h-4 text-emerald-500" }) : /* @__PURE__ */ B(ft, { className: "w-4 h-4 text-foreground/60 hover:text-foreground transition-colors" })
86257
86240
  })]
86258
86241
  })]
86259
86242
  }), /* @__PURE__ */ V("div", {
86260
86243
  className: "flex flex-col gap-6 w-full relative z-10 items-start",
86261
- children: [a && /* @__PURE__ */ B("div", {
86244
+ children: [o && /* @__PURE__ */ B("div", {
86262
86245
  className: "absolute inset-0 bg-background/60 backdrop-blur-[2px] z-50 flex items-center justify-center rounded-3xl pointer-events-none transition-all duration-300",
86263
86246
  children: /* @__PURE__ */ B(K, { className: "w-8 h-8 animate-spin text-accent" })
86264
86247
  }), /* @__PURE__ */ V("div", {
@@ -86276,7 +86259,7 @@ export const themeConfig = {
86276
86259
  }), rUn.map((e) => {
86277
86260
  let n = t?.colors?.dark?.accent === e.dark.accent && t?.colors?.dark?.buttonGradient?.[0] === e.dark.gradient[0], r = e.name === "Black & White";
86278
86261
  return /* @__PURE__ */ B("button", {
86279
- onClick: () => p(e),
86262
+ onClick: () => g(e),
86280
86263
  className: `w-9 h-9 rounded-full shrink-0 outline-none transition-all shadow-sm relative group overflow-visible ${n ? "ring-[3px] ring-foreground ring-offset-2 ring-offset-[var(--background)] scale-110 z-10" : "opacity-80 hover:opacity-100 hover:ring-2 hover:ring-foreground/30 hover:ring-offset-2 hover:ring-offset-[var(--background)] hover:scale-105"}`,
86281
86264
  title: e.name,
86282
86265
  children: /* @__PURE__ */ B("div", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "your-ai-workflow-firebase-os",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "A complete Firebase-powered admin OS — one React component.",
5
5
  "type": "module",
6
6
  "main": "dist/your-ai-workflow-firebase-os.cjs.js",
@@ -121,10 +121,10 @@ export function Requests() {
121
121
  <DashboardNav />
122
122
  </div>
123
123
 
124
- <div className="w-full flex-1 glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]">
124
+ <div className="w-full flex-1 flex flex-col glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]">
125
125
  <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-accent/5 blur-[100px] rounded-full pointer-events-none" />
126
126
 
127
- <div className="relative z-10 h-full flex flex-col">
127
+ <div className="relative z-10 flex-1 flex flex-col">
128
128
  {loading ? (
129
129
  <div className="flex-1 flex items-center justify-center min-h-[500px]">
130
130
  <div className="w-8 h-8 md:w-10 md:h-10 border-4 border-accent/20 border-t-accent rounded-full animate-spin" />
@@ -389,10 +389,10 @@ export function StorageAdmin() {
389
389
  >
390
390
  <DashboardNav />
391
391
 
392
- <div className="flex flex-col md:flex-row glass-panel border border-[var(--panel-border)] rounded-3xl overflow-hidden flex-1 shadow-2xl min-h-[600px] bg-background">
392
+ <div className="flex flex-row glass-panel border border-[var(--panel-border)] rounded-3xl overflow-hidden flex-1 shadow-2xl min-h-[600px] bg-background">
393
393
 
394
394
  {/* Sidebar Navigation */}
395
- <div className="md:w-[280px] border-b md:border-b-0 md:border-r border-[var(--panel-border)] bg-foreground/[0.01] p-4 flex flex-col shrink-0 overflow-y-auto hide-scrollbar">
395
+ <div className="w-[280px] border-r border-[var(--panel-border)] bg-foreground/[0.01] p-4 flex flex-col shrink-0 overflow-y-auto hide-scrollbar">
396
396
  <div className="text-[11px] font-extrabold text-foreground/40 uppercase tracking-widest pl-4 mb-4 mt-2">Locations</div>
397
397
  <div className="flex flex-col gap-2">
398
398
  {visibleFolders.map(folder => (
@@ -603,7 +603,7 @@ export function StorageAdmin() {
603
603
  <p className="text-[15px] font-bold text-foreground mb-1">Drag and drop file here</p>
604
604
  <p className="text-[13px] text-foreground/50 font-medium mb-8">or click to browse local files</p>
605
605
  <input type="file" ref={fileInputRef} onChange={handleSelectFile} className="hidden" />
606
- <Button onClick={() => fileInputRef.current?.click()} className="px-8 py-3 rounded-full font-bold shadow-md bg-accent text-white hover:bg-accent/90 transition-colors">Browse Files</Button>
606
+ <Button onClick={() => fileInputRef.current?.click()} className="px-8 py-3 rounded-full font-bold shadow-md btn-primary transition-colors">Browse Files</Button>
607
607
  </div>
608
608
  ) : (
609
609
  <form onSubmit={handleSaveUpload} className="p-6 flex flex-col gap-6 relative z-10 rounded-b-[2rem]">
@@ -673,7 +673,7 @@ export function StorageAdmin() {
673
673
  </button>
674
674
  </>
675
675
  )}
676
- <a href={previewFile.downloadURL} download target="_blank" rel="noreferrer" className="p-2.5 bg-accent text-white hover:bg-accent/90 transition-colors rounded-xl shadow-lg ml-1" title="Download">
676
+ <a href={previewFile.downloadURL} download target="_blank" rel="noreferrer" className="p-2.5 btn-primary transition-colors rounded-xl shadow-lg ml-1" title="Download">
677
677
  <Download className="w-4 h-4" />
678
678
  </a>
679
679
  </div>
@@ -119,10 +119,10 @@ export function Submissions() {
119
119
  <DashboardNav />
120
120
  </div>
121
121
 
122
- <div className="w-full flex-1 glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]">
122
+ <div className="w-full flex-1 flex flex-col glass-panel rounded-3xl p-6 md:p-10 relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]">
123
123
  <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-accent/5 blur-[100px] rounded-full pointer-events-none" />
124
124
 
125
- <div className="relative z-10 h-full flex flex-col">
125
+ <div className="relative z-10 flex-1 flex flex-col">
126
126
  {loading ? (
127
127
  <div className="flex-1 flex items-center justify-center min-h-[500px]">
128
128
  <div className="w-8 h-8 md:w-10 md:h-10 border-4 border-accent/20 border-t-accent rounded-full animate-spin" />
@@ -85,19 +85,10 @@ if (db) {
85
85
  export const AutoResizeInput = ({ value, onChange, onBlur, onFocus, className, isNumber, handleBlurOrEnter, placeholder, disabled }: any) => {
86
86
  const [localVal, setLocalVal] = React.useState(value);
87
87
  const [isFocused, setIsFocused] = React.useState(false);
88
- const [inputWidth, setInputWidth] = React.useState(0);
89
88
  const inputRef = React.useRef<HTMLInputElement>(null);
90
- const spanRef = React.useRef<HTMLSpanElement>(null);
91
89
 
92
90
  React.useEffect(() => { setLocalVal(value); }, [value]);
93
91
 
94
- React.useLayoutEffect(() => {
95
- if (spanRef.current) {
96
- // Perfect hugging width.
97
- setInputWidth(spanRef.current.getBoundingClientRect().width);
98
- }
99
- }, [localVal, placeholder]);
100
-
101
92
  // If text or link is pasted into quotes, make sure to always scroll to the left
102
93
  useEffect(() => {
103
94
  if (!isFocused && inputRef.current) {
@@ -112,12 +103,10 @@ export const AutoResizeInput = ({ value, onChange, onBlur, onFocus, className, i
112
103
  const inputCleanClass = spanClass.trim();
113
104
 
114
105
  return (
115
- <div className={`relative inline-flex flex-col group/autoresize ${wrapperClasses}`}>
116
- <div className="flex-1 overflow-x-auto overflow-y-hidden pb-[1px] styled-scrollbars-mini flex items-center">
106
+ <div className={`relative inline-grid group/autoresize ${wrapperClasses}`}>
107
+ <div className="col-start-1 row-start-1 overflow-x-auto overflow-y-hidden pb-[1px] styled-scrollbars-mini inline-grid items-center">
117
108
  <span
118
- ref={spanRef}
119
- className={`${spanClass} absolute opacity-0 pointer-events-none whitespace-pre border-none p-0 inline-block`}
120
- style={{ width: 'max-content', minWidth: 'max-content' }}
109
+ className={`${spanClass} invisible whitespace-pre col-start-1 row-start-1 border-none p-0 inline-block px-[2px]`}
121
110
  aria-hidden="true"
122
111
  >
123
112
  {localVal || placeholder || (isNumber ? '0' : ' ')}
@@ -129,7 +118,7 @@ export const AutoResizeInput = ({ value, onChange, onBlur, onFocus, className, i
129
118
  value={localVal}
130
119
  placeholder={placeholder}
131
120
  spellCheck={false}
132
- className={`${inputCleanClass} transition-all duration-200 ${disabled ? 'cursor-not-allowed opacity-50 select-none' : ''} ${isFocused ? 'relative z-50 bg-background shadow-md' : ''}`}
121
+ className={`${inputCleanClass} col-start-1 row-start-1 w-full min-w-[20px] transition-all duration-200 ${disabled ? 'cursor-not-allowed opacity-50 select-none' : ''} ${isFocused ? 'relative z-50 bg-background shadow-md' : ''}`}
133
122
  onDoubleClick={(e) => { if (!disabled) e.currentTarget.select(); }}
134
123
  onPaste={() => {
135
124
  setTimeout(() => {
@@ -162,11 +151,6 @@ export const AutoResizeInput = ({ value, onChange, onBlur, onFocus, className, i
162
151
  setIsFocused(true);
163
152
  if (onFocus) onFocus(e);
164
153
  }}
165
- style={{
166
- width: inputWidth > 0 ? `${inputWidth + 6}px` : 'auto',
167
- minWidth: '20px',
168
- maxWidth: isFocused ? 'none' : undefined
169
- }}
170
154
  />
171
155
  </div>
172
156
  </div>
@@ -442,8 +426,12 @@ export const JsonNode = ({ objectKey, displayKey, value, onChange, depth = 0, is
442
426
  }
443
427
  }
444
428
  } else if (typeof arr[0] === 'string') {
445
- const genericServices = ['Marketing', 'Support', 'Analysis', 'Strategy', 'Maintenance'];
446
- clone = genericServices[Math.min(arr.length, genericServices.length) - 1] || `Option ${arr.length + 1}`;
429
+ if (arr[0].startsWith('#') || arr[0].startsWith('rgba') || arr[0].startsWith('rgb') || arr[0].startsWith('color-mix')) {
430
+ clone = arr[arr.length - 1]; // Duplicate last color
431
+ } else {
432
+ const genericServices = ['Marketing', 'Support', 'Analysis', 'Strategy', 'Maintenance'];
433
+ clone = genericServices[Math.min(arr.length, genericServices.length) - 1] || `Option ${arr.length + 1}`;
434
+ }
447
435
  } else {
448
436
  clone = arr.length > 0 ? JSON.parse(JSON.stringify(arr[arr.length - 1])) : '';
449
437
  if (clone && typeof clone === 'object') {
@@ -600,43 +588,51 @@ export function ThemeAdmin() {
600
588
  const [localConfig, setLocalConfig] = useState<any>(null);
601
589
  const [isSaving, setIsSaving] = useState(false);
602
590
  const [isResetting, setIsResetting] = useState(false);
591
+ // Tracks the JSON of the last config we saved — prevents re-saving
592
+ // when Firestore echoes the snapshot back (which would cause an infinite loop).
593
+ const lastSavedRef = React.useRef<string | null>(null);
603
594
 
604
595
  useEffect(() => {
605
- // Clone live config locally to edit
606
- if (!localConfig) {
607
- setLocalConfig(JSON.parse(JSON.stringify(activeConfig)));
596
+ // Clone live config locally on first load only
597
+ if (!localConfig && activeConfig) {
598
+ const cloned = JSON.parse(JSON.stringify(activeConfig));
599
+ setLocalConfig(cloned);
600
+ lastSavedRef.current = JSON.stringify(cloned);
608
601
  }
609
602
  }, [activeConfig]);
610
603
 
611
604
  const [copiedStatus, setCopiedStatus] = useState<boolean>(false);
612
605
  const [showResetConfirm, setShowResetConfirm] = useState<boolean>(false);
613
606
 
614
- // Auto-Save background processor (debounced 1s)
607
+ // Auto-Save: only fires when localConfig actually changes compared to
608
+ // what we last saved. Does NOT depend on activeConfig to avoid the
609
+ // Firestore snapshot echo loop.
615
610
  useEffect(() => {
616
- if (!localConfig || !activeConfig) return;
617
- if (JSON.stringify(localConfig) === JSON.stringify(activeConfig)) {
618
- setIsSaving(false);
619
- return;
620
- }
611
+ if (!localConfig) return;
612
+ const serialized = JSON.stringify(localConfig);
613
+ if (serialized === lastSavedRef.current) return;
621
614
 
622
615
  const timer = setTimeout(async () => {
623
616
  setIsSaving(true);
624
617
  try {
625
618
  await setDoc(doc(db, 'sys_configs', 'theme'), localConfig);
619
+ lastSavedRef.current = serialized;
626
620
  } catch (err: any) {
627
621
  console.error("Auto-save failed", err);
628
622
  }
629
623
  setIsSaving(false);
630
624
  }, 300);
631
625
  return () => clearTimeout(timer);
632
- }, [localConfig, activeConfig]);
626
+ }, [localConfig]);
633
627
 
634
628
  const resetToDefault = async () => {
635
629
  setIsResetting(true);
636
630
  try {
637
631
  const module = await import('../configs/theme.config');
632
+ const cloned = JSON.parse(JSON.stringify(module.themeConfig));
638
633
  await setDoc(doc(db, 'sys_configs', 'theme'), module.themeConfig);
639
- setLocalConfig(JSON.parse(JSON.stringify(module.themeConfig)));
634
+ lastSavedRef.current = JSON.stringify(cloned);
635
+ setLocalConfig(cloned);
640
636
  } catch (e) {}
641
637
  setTimeout(() => {
642
638
  setIsResetting(false);
@@ -831,59 +827,6 @@ export const themeConfig = {
831
827
  return () => window.removeEventListener('keydown', handleKeyDown);
832
828
  }, [localConfig]);
833
829
 
834
- // Live real-time Preview engine mapping values to Document root
835
- useEffect(() => {
836
- if (!localConfig?.colors) return;
837
- const docTheme = document.documentElement.getAttribute('data-theme') || 'dark';
838
- const isDark = docTheme === 'dark';
839
- const activeColors = isDark ? localConfig.colors.dark : localConfig.colors.light;
840
-
841
- const root = document.documentElement;
842
- root.style.setProperty('--bg-color', activeColors.background);
843
- if (activeColors.backgroundSecondary) root.style.setProperty('--bg-secondary-color', activeColors.backgroundSecondary);
844
- root.style.setProperty('--fg-color', activeColors.foreground);
845
- root.style.setProperty('--accent-color', activeColors.accent);
846
- root.style.setProperty('--accent-deep', activeColors.accentDeep);
847
- root.style.setProperty('--panel-bg', activeColors.panelBg);
848
- root.style.setProperty('--panel-border', activeColors.panelBorder);
849
- root.style.setProperty('--button-bg', `linear-gradient(135deg, ${activeColors.buttonGradient[0]} 0%, ${activeColors.buttonGradient[1]} 100%)`);
850
- root.style.setProperty('--button-hover-bg', `linear-gradient(135deg, ${activeColors.buttonHoverGradient?.[0] || activeColors.buttonGradient[0]} 0%, ${activeColors.buttonHoverGradient?.[1] || activeColors.buttonGradient[1]} 100%)`);
851
- root.style.setProperty('--text-gradient', `linear-gradient(135deg, ${activeColors.textGradient[0]} 0%, ${activeColors.textGradient[1]} 50%, ${activeColors.textGradient[2]} 100%)`);
852
- root.style.setProperty('--glow-color', activeColors.glowColor || 'rgba(124, 58, 237, 0.3)');
853
- root.style.setProperty('--button-fg', activeColors.buttonText || '#ffffff');
854
- if (activeColors.notificationIconColor) {
855
- root.style.setProperty('--notification-icon-color', activeColors.notificationIconColor);
856
- }
857
-
858
- }, [localConfig]);
859
-
860
- // Cleanup effect on unmount matching the DB config
861
- useEffect(() => {
862
- return () => {
863
- // Reset styles by firing a custom event for ThemeContext to reload, or manually re-inject
864
- if (!activeConfig?.colors) return;
865
- const docTheme = document.documentElement.getAttribute('data-theme') || 'dark';
866
- const isDark = docTheme === 'dark';
867
- const c = isDark ? activeConfig.colors.dark : activeConfig.colors.light;
868
- const root = document.documentElement;
869
- root.style.setProperty('--bg-color', c.background);
870
- if (c.backgroundSecondary) root.style.setProperty('--bg-secondary-color', c.backgroundSecondary);
871
- root.style.setProperty('--fg-color', c.foreground);
872
- root.style.setProperty('--accent-color', c.accent);
873
- root.style.setProperty('--accent-deep', c.accentDeep);
874
- root.style.setProperty('--panel-bg', c.panelBg);
875
- root.style.setProperty('--panel-border', c.panelBorder);
876
- root.style.setProperty('--button-bg', `linear-gradient(135deg, ${c.buttonGradient[0]} 0%, ${c.buttonGradient[1]} 100%)`);
877
- root.style.setProperty('--button-hover-bg', `linear-gradient(135deg, ${c.buttonHoverGradient?.[0] || c.buttonGradient[0]} 0%, ${c.buttonHoverGradient?.[1] || c.buttonGradient[1]} 100%)`);
878
- root.style.setProperty('--text-gradient', `linear-gradient(135deg, ${c.textGradient[0]} 0%, ${c.textGradient[1]} 50%, ${c.textGradient[2]} 100%)`);
879
- root.style.setProperty('--glow-color', c.glowColor || 'rgba(124, 58, 237, 0.3)');
880
- root.style.setProperty('--button-fg', c.buttonText || '#ffffff');
881
- if (c.notificationIconColor) {
882
- root.style.setProperty('--notification-icon-color', c.notificationIconColor);
883
- }
884
- };
885
- }, [activeConfig]);
886
-
887
830
  return (
888
831
  <main className="flex-1 w-full max-w-7xl mx-auto p-4 md:p-8 z-10 flex flex-col pt-12 min-h-screen">
889
832
  <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="mb-6 flex items-center justify-between">