frontend-auto-cms 1.0.3 → 1.0.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.
@@ -1,19 +1,19 @@
1
- const fe = "cms-export.patch.json", pe = "frontend-auto-cms::content", Z = "frontend-auto-cms::locales";
2
- function Q(e) {
3
- localStorage.setItem(pe, JSON.stringify(e));
1
+ const ge = "cms-export.patch.json", be = "frontend-auto-cms::content", ee = "frontend-auto-cms::locales";
2
+ function te(e) {
3
+ localStorage.setItem(be, JSON.stringify(e));
4
4
  }
5
- function ee() {
5
+ function ae() {
6
6
  try {
7
- const e = localStorage.getItem(Z);
7
+ const e = localStorage.getItem(ee);
8
8
  return e ? JSON.parse(e) : {};
9
9
  } catch {
10
10
  return {};
11
11
  }
12
12
  }
13
13
  function A(e) {
14
- localStorage.setItem(Z, JSON.stringify(e));
14
+ localStorage.setItem(ee, JSON.stringify(e));
15
15
  }
16
- async function ge() {
16
+ async function me() {
17
17
  try {
18
18
  const e = await fetch("/cms-locales.json", { cache: "no-store" });
19
19
  if (!e.ok)
@@ -24,9 +24,9 @@ async function ge() {
24
24
  return {};
25
25
  }
26
26
  }
27
- function be(e) {
28
- const t = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), a = URL.createObjectURL(t), r = document.createElement("a");
29
- r.href = a, r.download = fe, r.click(), URL.revokeObjectURL(a);
27
+ function ye(e) {
28
+ const t = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), a = URL.createObjectURL(t), o = document.createElement("a");
29
+ o.href = a, o.download = ge, o.click(), URL.revokeObjectURL(a);
30
30
  }
31
31
  function E(e) {
32
32
  return e.replace(/[^\w]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
@@ -38,26 +38,26 @@ function k(e) {
38
38
  const a = (e.getAttribute("class") ?? "").split(/\s+/).filter(Boolean)[0];
39
39
  return a ? `${e.tagName.toLowerCase()}.${a}` : e.tagName.toLowerCase();
40
40
  }
41
- function te(e) {
41
+ function ne(e) {
42
42
  return ["SCRIPT", "STYLE", "NOSCRIPT", "IFRAME"].includes(e.tagName);
43
43
  }
44
- function z(e) {
44
+ function N(e) {
45
45
  return (e ?? "").replace(/\s+/g, " ").trim();
46
46
  }
47
- function me(e, t, a) {
48
- const r = t.parentElement;
49
- if (!r || te(r))
47
+ function xe(e, t, a) {
48
+ const o = t.parentElement;
49
+ if (!o || ne(o))
50
50
  return null;
51
- if (Array.from(r.childNodes).filter(
52
- (s) => s.nodeType === Node.TEXT_NODE && z(s.nodeValue).length > 0
53
- ).length === 1 && r.children.length === 0)
54
- return r.setAttribute("data-cms-key", a), r;
55
- const o = e.createElement("span");
56
- return o.textContent = t.nodeValue ?? "", o.setAttribute("data-cms-key", a), t.parentNode?.replaceChild(o, t), o;
57
- }
58
- function N(e = document, t) {
51
+ if (Array.from(o.childNodes).filter(
52
+ (s) => s.nodeType === Node.TEXT_NODE && N(s.nodeValue).length > 0
53
+ ).length === 1 && o.children.length === 0)
54
+ return o.setAttribute("data-cms-key", a), o;
55
+ const r = e.createElement("span");
56
+ return r.textContent = t.nodeValue ?? "", r.setAttribute("data-cms-key", a), t.parentNode?.replaceChild(r, t), r;
57
+ }
58
+ function T(e = document, t) {
59
59
  const a = [];
60
- let r = 0, n = 0, o = 0, s = 0;
60
+ let o = 0, n = 0, r = 0, s = 0;
61
61
  const l = t ?? e.location?.pathname ?? location.pathname, c = e.body;
62
62
  if (!c)
63
63
  return {
@@ -67,28 +67,28 @@ function N(e = document, t) {
67
67
  };
68
68
  const f = e.createTreeWalker(c, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
69
69
  for (; f.nextNode(); ) {
70
- const u = f.currentNode;
71
- if (u.nodeType === Node.TEXT_NODE) {
72
- const b = u, m = z(b.nodeValue);
70
+ const d = f.currentNode;
71
+ if (d.nodeType === Node.TEXT_NODE) {
72
+ const b = d, m = N(b.nodeValue);
73
73
  if (m.length < 2)
74
74
  continue;
75
- r += 1;
76
- const U = `${E(l || "index")}.text.${r}`, C = me(e, b, U);
77
- if (!C)
75
+ o += 1;
76
+ const G = `${E(l || "index")}.text.${o}`, O = xe(e, b, G);
77
+ if (!O)
78
78
  continue;
79
79
  a.push({
80
- id: `dom_txt_${r}`,
81
- key: U,
80
+ id: `dom_txt_${o}`,
81
+ key: G,
82
82
  type: "text",
83
- label: k(C),
83
+ label: k(O),
84
84
  value: m,
85
- selector: k(C),
85
+ selector: k(O),
86
86
  sourceRefs: [{ file: l, original: m }]
87
87
  });
88
88
  continue;
89
89
  }
90
- const i = u;
91
- if (te(i))
90
+ const i = d;
91
+ if (ne(i))
92
92
  continue;
93
93
  const p = i.tagName.toLowerCase();
94
94
  if (p === "img" || p === "video") {
@@ -109,12 +109,12 @@ function N(e = document, t) {
109
109
  }
110
110
  }
111
111
  if (["section", "ul", "ol"].includes(p) || i.hasAttribute("data-repeatable")) {
112
- const b = Array.from(i.children).map((m) => z(m.textContent)).filter(Boolean);
112
+ const b = Array.from(i.children).map((m) => N(m.textContent)).filter(Boolean);
113
113
  if (b.length >= 2) {
114
- o += 1;
115
- const m = `${E(l || "index")}.section.${o}`;
114
+ r += 1;
115
+ const m = `${E(l || "index")}.section.${r}`;
116
116
  i.setAttribute("data-cms-key", m), a.push({
117
- id: `dom_sec_${o}`,
117
+ id: `dom_sec_${r}`,
118
118
  key: m,
119
119
  type: "section",
120
120
  label: k(i),
@@ -150,7 +150,7 @@ function N(e = document, t) {
150
150
  nodes: a
151
151
  };
152
152
  }
153
- function ae(e, t = document) {
153
+ function oe(e, t = document) {
154
154
  if (!e.key)
155
155
  return;
156
156
  const a = t.querySelector(`[data-cms-key="${CSS.escape(e.key)}"]`);
@@ -160,16 +160,16 @@ function ae(e, t = document) {
160
160
  else if (e.type === "image" || e.type === "video")
161
161
  a.src = e.value, e.attrs?.alt != null && a.setAttribute("alt", e.attrs.alt);
162
162
  else if (e.type === "property" && e.attrs)
163
- Object.entries(e.attrs).forEach(([r, n]) => a.setAttribute(r, n));
163
+ Object.entries(e.attrs).forEach(([o, n]) => a.setAttribute(o, n));
164
164
  else if (e.type === "section" && e.sectionItems) {
165
- const r = Array.from(a.children);
166
- e.sectionItems.forEach((n, o) => {
167
- r[o] && (r[o].textContent = n);
165
+ const o = Array.from(a.children);
166
+ e.sectionItems.forEach((n, r) => {
167
+ o[r] && (o[r].textContent = n);
168
168
  });
169
169
  }
170
170
  }
171
171
  }
172
- const B = [
172
+ const P = [
173
173
  { code: "af", label: "Afrikaans", nllb: "afr_Latn" },
174
174
  { code: "ar", label: "Arabic", nllb: "arb_Arab" },
175
175
  { code: "az", label: "Azerbaijani", nllb: "azj_Latn" },
@@ -234,51 +234,51 @@ const B = [
234
234
  { code: "uz", label: "Uzbek", nllb: "uzn_Latn" },
235
235
  { code: "vi", label: "Vietnamese", nllb: "vie_Latn" },
236
236
  { code: "zh", label: "Chinese (Simplified)", nllb: "zho_Hans" }
237
- ], G = Object.fromEntries(
238
- B.map((e) => [e.nllb.slice(0, 3).toLowerCase(), e.code])
239
- ), xe = "https://api.mymemory.translated.net/get";
240
- function K(e) {
237
+ ], K = Object.fromEntries(
238
+ P.map((e) => [e.nllb.slice(0, 3).toLowerCase(), e.code])
239
+ ), he = "https://api.mymemory.translated.net/get";
240
+ function J(e) {
241
241
  const t = e.trim().toLowerCase().split(/[-_]/)[0];
242
242
  if (/^[a-z]{2}$/i.test(t))
243
243
  return t;
244
- if (/^[a-z]{3}$/i.test(t) && G[t])
245
- return G[t];
244
+ if (/^[a-z]{3}$/i.test(t) && K[t])
245
+ return K[t];
246
246
  throw new Error(`Unsupported language code "${e}" for MyMemory translation.`);
247
247
  }
248
- async function ye(e, t, a) {
248
+ async function ke(e, t, a) {
249
249
  if (!e.trim())
250
250
  return e;
251
- const r = new URLSearchParams({
251
+ const o = new URLSearchParams({
252
252
  q: e,
253
253
  langpair: `${t}|${a}`
254
- }), n = await fetch(`${xe}?${r.toString()}`, { method: "GET" });
254
+ }), n = await fetch(`${he}?${o.toString()}`, { method: "GET" });
255
255
  if (!n.ok)
256
256
  throw new Error(`MyMemory request failed (${n.status})`);
257
- const o = await n.json();
258
- if (o.responseStatus && o.responseStatus !== 200)
259
- throw new Error(`MyMemory translation failed with status ${o.responseStatus}`);
260
- const s = o.responseData?.translatedText;
257
+ const r = await n.json();
258
+ if (r.responseStatus && r.responseStatus !== 200)
259
+ throw new Error(`MyMemory translation failed with status ${r.responseStatus}`);
260
+ const s = r.responseData?.translatedText;
261
261
  return typeof s == "string" && s.trim() ? s : e;
262
262
  }
263
- async function he(e, t, a = "en", r) {
264
- const n = K(a), o = K(t), s = /* @__PURE__ */ new Map(), l = {}, c = Object.entries(e), f = c.length;
265
- let u = 0;
263
+ async function ve(e, t, a = "en", o) {
264
+ const n = J(a), r = J(t), s = /* @__PURE__ */ new Map(), l = {}, c = Object.entries(e), f = c.length;
265
+ let d = 0;
266
266
  for (const [i, p] of c) {
267
267
  if (s.has(p)) {
268
- l[i] = s.get(p), u += 1, r?.(u, f);
268
+ l[i] = s.get(p), d += 1, o?.(d, f);
269
269
  continue;
270
270
  }
271
271
  try {
272
- const g = await ye(p, n, o);
272
+ const g = await ke(p, n, r);
273
273
  s.set(p, g), l[i] = g;
274
274
  } catch {
275
275
  l[i] = p;
276
276
  }
277
- u += 1, r?.(u, f);
277
+ d += 1, o?.(d, f);
278
278
  }
279
279
  return l;
280
280
  }
281
- async function ke(e, t, a) {
281
+ async function we(e, t, a) {
282
282
  return (await fetch(
283
283
  `https://gitlab.com/api/v4/projects/${encodeURIComponent(e.repository)}/repository/files/${encodeURIComponent(a)}?ref=${encodeURIComponent(e.branch)}`,
284
284
  {
@@ -287,7 +287,7 @@ async function ke(e, t, a) {
287
287
  }
288
288
  )).ok;
289
289
  }
290
- async function ve() {
290
+ async function Le() {
291
291
  try {
292
292
  const e = await fetch("/cms-hosting.json", { cache: "no-store" });
293
293
  if (!e.ok)
@@ -298,20 +298,20 @@ async function ve() {
298
298
  return null;
299
299
  }
300
300
  }
301
- async function O(e, t, a, r, n) {
302
- const o = `https://api.github.com/repos/${e.repository}/contents/${encodeURIComponent(a).replace(/%2F/g, "/")}`;
301
+ async function j(e, t, a, o, n) {
302
+ const r = `https://api.github.com/repos/${e.repository}/contents/${encodeURIComponent(a).replace(/%2F/g, "/")}`;
303
303
  let s;
304
- const l = await fetch(`${o}?ref=${encodeURIComponent(e.branch)}`, {
304
+ const l = await fetch(`${r}?ref=${encodeURIComponent(e.branch)}`, {
305
305
  headers: { Authorization: `Bearer ${t}` }
306
306
  });
307
307
  l.ok && (s = (await l.json()).sha);
308
308
  const c = {
309
309
  message: n,
310
- content: btoa(unescape(encodeURIComponent(r))),
310
+ content: btoa(unescape(encodeURIComponent(o))),
311
311
  branch: e.branch,
312
312
  sha: s
313
313
  };
314
- if (!(await fetch(o, {
314
+ if (!(await fetch(r, {
315
315
  method: "PUT",
316
316
  headers: {
317
317
  Authorization: `Bearer ${t}`,
@@ -321,24 +321,24 @@ async function O(e, t, a, r, n) {
321
321
  })).ok)
322
322
  throw new Error(`GitHub publish failed for ${a}`);
323
323
  }
324
- async function we(e, t, a) {
325
- const r = `chore(cms): publish content updates ${(/* @__PURE__ */ new Date()).toISOString()}`;
326
- if (await O(e, t, "cms-content.json", JSON.stringify(a.content, null, 2), r), a.locales)
327
- for (const [n, o] of Object.entries(a.locales))
328
- await O(e, t, `locales/${n}.json`, JSON.stringify(o, null, 2), r);
329
- await O(e, t, "cms-export.patch.json", JSON.stringify(a, null, 2), r);
330
- }
331
- async function Le(e, t, a) {
332
- const r = [
324
+ async function $e(e, t, a) {
325
+ const o = `chore(cms): publish content updates ${(/* @__PURE__ */ new Date()).toISOString()}`;
326
+ if (await j(e, t, "cms-content.json", JSON.stringify(a.content, null, 2), o), a.locales)
327
+ for (const [n, r] of Object.entries(a.locales))
328
+ await j(e, t, `locales/${n}.json`, JSON.stringify(r, null, 2), o);
329
+ await j(e, t, "cms-export.patch.json", JSON.stringify(a, null, 2), o);
330
+ }
331
+ async function Se(e, t, a) {
332
+ const o = [
333
333
  { filePath: "cms-content.json", content: JSON.stringify(a.content, null, 2) },
334
334
  { filePath: "cms-export.patch.json", content: JSON.stringify(a, null, 2) }
335
335
  ];
336
336
  if (a.locales)
337
337
  for (const [s, l] of Object.entries(a.locales))
338
- r.push({ filePath: `locales/${s}.json`, content: JSON.stringify(l, null, 2) });
338
+ o.push({ filePath: `locales/${s}.json`, content: JSON.stringify(l, null, 2) });
339
339
  const n = [];
340
- for (const s of r) {
341
- const l = await ke(e, t, s.filePath);
340
+ for (const s of o) {
341
+ const l = await we(e, t, s.filePath);
342
342
  n.push({
343
343
  action: l ? "update" : "create",
344
344
  file_path: s.filePath,
@@ -359,12 +359,12 @@ async function Le(e, t, a) {
359
359
  })).ok)
360
360
  throw new Error("GitLab publish failed.");
361
361
  }
362
- async function $e(e, t, a) {
363
- return !a || !t.trim() ? !1 : a.provider === "github" ? (await we(a, t.trim(), e), !0) : a.provider === "gitlab" ? (await Le(a, t.trim(), e), !0) : !1;
362
+ async function Ee(e, t, a) {
363
+ return !a || !t.trim() ? !1 : a.provider === "github" ? (await $e(a, t.trim(), e), !0) : a.provider === "gitlab" ? (await Se(a, t.trim(), e), !0) : !1;
364
364
  }
365
- const J = "facms-auth-modal", M = "facms-auth-missing", F = "facms-token-modal", Y = "facms-language-modal", Se = "frontend-auto-cms::theme", ne = "frontend-auto-cms::main-language", oe = "frontend-auto-cms::language-labels";
366
- let P = !1, v = null, V = !1, h = null, d = "dark";
367
- function re() {
365
+ const F = "facms-auth-modal", M = "facms-auth-missing", Y = "facms-token-modal", W = "facms-language-modal", _e = "frontend-auto-cms::theme", re = "frontend-auto-cms::main-language", se = "frontend-auto-cms::language-labels";
366
+ let R = !1, v = null, V = !1, h = null, u = "dark";
367
+ function ie() {
368
368
  if (document.getElementById("facms-dashboard-css"))
369
369
  return;
370
370
  const e = document.createElement("style");
@@ -603,24 +603,24 @@ function re() {
603
603
  }
604
604
  `, document.head.appendChild(e);
605
605
  }
606
- function se(e) {
607
- d = e;
606
+ function le(e) {
607
+ u = e;
608
608
  const t = e === "dark";
609
- document.documentElement.classList.toggle("dark", t), document.body.classList.toggle("dark", t), document.documentElement.style.background = t ? "#020617" : "#f1f5f9", document.body.style.background = t ? "#020617" : "#f1f5f9", document.documentElement.setAttribute("data-facms-theme", e), document.getElementById("facms-app")?.classList.toggle("dark", t), localStorage.setItem(Se, e);
610
- const r = document.getElementById("facms-theme-toggle");
611
- r && (r.textContent = e === "dark" ? "Switch to light" : "Switch to dark");
609
+ document.documentElement.classList.toggle("dark", t), document.body.classList.toggle("dark", t), document.documentElement.style.background = t ? "#020617" : "#f1f5f9", document.body.style.background = t ? "#020617" : "#f1f5f9", document.documentElement.setAttribute("data-facms-theme", e), document.getElementById("facms-app")?.classList.toggle("dark", t), localStorage.setItem(_e, e);
610
+ const o = document.getElementById("facms-theme-toggle");
611
+ o && (o.textContent = e === "dark" ? "Switch to light" : "Switch to dark");
612
612
  }
613
- function le() {
614
- d = "dark", se("dark");
613
+ function ce() {
614
+ u = "dark", le("dark");
615
615
  }
616
- function Ee(e) {
616
+ function Ae(e) {
617
617
  return Array.from(new Uint8Array(e)).map((t) => t.toString(16).padStart(2, "0")).join("");
618
618
  }
619
- async function _e(e) {
619
+ async function Te(e) {
620
620
  const t = new TextEncoder().encode(e), a = await crypto.subtle.digest("SHA-256", t);
621
- return Ee(a);
621
+ return Ae(a);
622
622
  }
623
- async function ie() {
623
+ async function de() {
624
624
  if (h)
625
625
  return h;
626
626
  try {
@@ -638,7 +638,7 @@ async function ie() {
638
638
  }
639
639
  return h = { dashboardPath: "/dashboard", pages: ["/"], showFloatingButton: !1, autoTranslateEnabled: !0 }, h;
640
640
  }
641
- async function R() {
641
+ async function D() {
642
642
  if (!V) {
643
643
  V = !0;
644
644
  try {
@@ -651,11 +651,11 @@ async function R() {
651
651
  }
652
652
  }
653
653
  }
654
- async function Ae(e) {
654
+ async function Ie(e) {
655
655
  const t = e.trim();
656
- return !t || (await R(), !v) ? !1 : await _e(`${v.salt}:${t}`) === v.passcodeHash;
656
+ return !t || (await D(), !v) ? !1 : await Te(`${v.salt}:${t}`) === v.passcodeHash;
657
657
  }
658
- function Te() {
658
+ function Ce() {
659
659
  let e = document.getElementById(M);
660
660
  e || (e = document.createElement("div"), e.id = M, e.style.position = "fixed", e.style.inset = "0", e.style.zIndex = "2147483647", e.style.background = "rgba(2, 6, 23, 0.88)", e.style.display = "grid", e.style.placeItems = "center", e.innerHTML = `
661
661
  <div style="width:min(560px,92vw);background:#0f172a;color:#e2e8f0;border:1px solid #334155;border-radius:16px;padding:16px;box-shadow:0 20px 55px rgba(2,6,23,.45);font-family:Inter,system-ui,sans-serif;">
@@ -665,134 +665,134 @@ function Te() {
665
665
  </div>
666
666
  `, document.body.appendChild(e));
667
667
  }
668
- function Ie() {
668
+ function Oe() {
669
669
  document.getElementById(M)?.remove();
670
670
  }
671
- async function ce() {
672
- return await R(), v ? (Ie(), !0) : (Te(), !1);
671
+ async function ue() {
672
+ return await D(), v ? (Oe(), !0) : (Ce(), !1);
673
673
  }
674
- function de(e) {
675
- const t = document.getElementById(J);
674
+ function fe(e) {
675
+ const t = document.getElementById(F);
676
676
  if (t) {
677
677
  t.style.display = "grid";
678
678
  return;
679
679
  }
680
680
  const a = document.createElement("div");
681
- a.id = J, a.style.position = "fixed", a.style.inset = "0", a.style.zIndex = "2147483647", a.style.background = "rgba(2, 6, 23, 0.45)", a.style.display = "grid", a.style.placeItems = "center", a.innerHTML = `
682
- <div style="width: min(420px, 92vw); background: ${d === "dark" ? "#0f172a" : "#ffffff"}; color: ${d === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${d === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
681
+ a.id = F, a.style.position = "fixed", a.style.inset = "0", a.style.zIndex = "2147483647", a.style.background = "rgba(2, 6, 23, 0.45)", a.style.display = "grid", a.style.placeItems = "center", a.innerHTML = `
682
+ <div style="width: min(420px, 92vw); background: ${u === "dark" ? "#0f172a" : "#ffffff"}; color: ${u === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${u === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
683
683
  <h3 style="margin: 0 0 6px 0; font-size: 20px; line-height: 1.2; font-weight: 700;">Unlock CMS</h3>
684
- <p style="margin: 0 0 12px 0; font-size: 12px; color: ${d === "dark" ? "#94a3b8" : "#475569"};">Enter your passcode to edit content.</p>
685
- <input id="facms-passcode-input" type="password" style="width: 100%; border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#ffffff"}; color: ${d === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box;" placeholder="Enter passcode" />
684
+ <p style="margin: 0 0 12px 0; font-size: 12px; color: ${u === "dark" ? "#94a3b8" : "#475569"};">Enter your passcode to edit content.</p>
685
+ <input id="facms-passcode-input" type="password" style="width: 100%; border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#ffffff"}; color: ${u === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box;" placeholder="Enter passcode" />
686
686
  <p id="facms-passcode-error" style="display:none; margin: 8px 0 0 0; font-size: 12px; color: #ef4444;">Incorrect passcode.</p>
687
687
  <div style="margin-top: 14px; display: flex; gap: 8px; justify-content: flex-end;">
688
- <button id="facms-passcode-cancel" style="border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#f1f5f9"}; color: ${d === "dark" ? "#e2e8f0" : "#334155"}; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Cancel</button>
688
+ <button id="facms-passcode-cancel" style="border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#f1f5f9"}; color: ${u === "dark" ? "#e2e8f0" : "#334155"}; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Cancel</button>
689
689
  <button id="facms-passcode-submit" style="border: 1px solid #4f46e5; background: #4f46e5; color: white; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Open CMS</button>
690
690
  </div>
691
691
  </div>
692
692
  `;
693
- const r = a.querySelector("#facms-passcode-input"), n = a.querySelector("#facms-passcode-error"), o = () => a.style.display = "none", s = async () => {
694
- if (await R(), !v) {
693
+ const o = a.querySelector("#facms-passcode-input"), n = a.querySelector("#facms-passcode-error"), r = () => a.style.display = "none", s = async () => {
694
+ if (await D(), !v) {
695
695
  n && (n.textContent = "CMS auth is not configured. Run setup to generate runtime auth files.", n.style.display = "block");
696
696
  return;
697
697
  }
698
- if (!await Ae(r?.value ?? "")) {
698
+ if (!await Ie(o?.value ?? "")) {
699
699
  n && (n.textContent = "Incorrect passcode.", n.style.display = "block");
700
700
  return;
701
701
  }
702
- n && (n.style.display = "none"), P = !0, o(), e();
702
+ n && (n.style.display = "none"), R = !0, r(), e();
703
703
  };
704
- a.querySelector("#facms-passcode-cancel")?.addEventListener("click", o), a.querySelector("#facms-passcode-submit")?.addEventListener("click", s), r?.addEventListener("keydown", (l) => l.key === "Enter" && void s()), document.body.appendChild(a), r?.focus();
704
+ a.querySelector("#facms-passcode-cancel")?.addEventListener("click", r), a.querySelector("#facms-passcode-submit")?.addEventListener("click", s), o?.addEventListener("keydown", (l) => l.key === "Enter" && void s()), document.body.appendChild(a), o?.focus();
705
705
  }
706
- function Ce(e, t) {
707
- const a = document.getElementById(F);
706
+ function je(e, t) {
707
+ const a = document.getElementById(Y);
708
708
  a && a.remove();
709
- const r = document.createElement("div");
710
- r.id = F, r.style.position = "fixed", r.style.inset = "0", r.style.zIndex = "2147483647", r.style.background = "rgba(2, 6, 23, 0.45)", r.style.display = "grid", r.style.placeItems = "center", r.innerHTML = `
711
- <div style="width: min(520px, 92vw); background: ${d === "dark" ? "#0f172a" : "#ffffff"}; color: ${d === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${d === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
709
+ const o = document.createElement("div");
710
+ o.id = Y, o.style.position = "fixed", o.style.inset = "0", o.style.zIndex = "2147483647", o.style.background = "rgba(2, 6, 23, 0.45)", o.style.display = "grid", o.style.placeItems = "center", o.innerHTML = `
711
+ <div style="width: min(520px, 92vw); background: ${u === "dark" ? "#0f172a" : "#ffffff"}; color: ${u === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${u === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
712
712
  <h3 style="margin: 0 0 6px 0; font-size: 20px; line-height: 1.2; font-weight: 700;">Publish token required</h3>
713
- <p style="margin: 0 0 12px 0; font-size: 12px; color: ${d === "dark" ? "#94a3b8" : "#475569"};">Enter your ${e} token for this publish only. It is not stored.</p>
714
- <input id="facms-token-input" type="password" style="width: 100%; border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#ffffff"}; color: ${d === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box;" placeholder="Token" />
713
+ <p style="margin: 0 0 12px 0; font-size: 12px; color: ${u === "dark" ? "#94a3b8" : "#475569"};">Enter your ${e} token for this publish only. It is not stored.</p>
714
+ <input id="facms-token-input" type="password" style="width: 100%; border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#ffffff"}; color: ${u === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box;" placeholder="Token" />
715
715
  <p id="facms-token-error" style="display:none; margin: 8px 0 0 0; font-size: 12px; color: #ef4444;">Token is required.</p>
716
716
  <div style="margin-top: 14px; display: flex; gap: 8px; justify-content: flex-end;">
717
- <button id="facms-token-cancel" style="border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#f1f5f9"}; color: ${d === "dark" ? "#e2e8f0" : "#334155"}; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Cancel</button>
717
+ <button id="facms-token-cancel" style="border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#f1f5f9"}; color: ${u === "dark" ? "#e2e8f0" : "#334155"}; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Cancel</button>
718
718
  <button id="facms-token-submit" style="border: 1px solid #4f46e5; background: #4f46e5; color: white; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Publish</button>
719
719
  </div>
720
720
  </div>
721
721
  `;
722
- const n = r.querySelector("#facms-token-input"), o = r.querySelector("#facms-token-error"), s = () => r.style.display = "none", l = () => {
722
+ const n = o.querySelector("#facms-token-input"), r = o.querySelector("#facms-token-error"), s = () => o.style.display = "none", l = () => {
723
723
  const c = (n?.value ?? "").trim();
724
724
  if (!c) {
725
- o && (o.style.display = "block");
725
+ r && (r.style.display = "block");
726
726
  return;
727
727
  }
728
- o && (o.style.display = "none"), s(), t(c);
728
+ r && (r.style.display = "none"), s(), t(c);
729
729
  };
730
- r.querySelector("#facms-token-cancel")?.addEventListener("click", s), r.querySelector("#facms-token-submit")?.addEventListener("click", l), n?.addEventListener("keydown", (c) => c.key === "Enter" && l()), document.body.appendChild(r), n?.focus();
730
+ o.querySelector("#facms-token-cancel")?.addEventListener("click", s), o.querySelector("#facms-token-submit")?.addEventListener("click", l), n?.addEventListener("keydown", (c) => c.key === "Enter" && l()), document.body.appendChild(o), n?.focus();
731
731
  }
732
- function Oe(e, t, a) {
733
- const r = document.getElementById(Y);
734
- r && r.remove();
732
+ function ze(e, t, a) {
733
+ const o = document.getElementById(W);
734
+ o && o.remove();
735
735
  const n = document.createElement("div");
736
- n.id = Y, n.style.position = "fixed", n.style.inset = "0", n.style.zIndex = "2147483647", n.style.background = "rgba(2, 6, 23, 0.45)", n.style.display = "grid", n.style.placeItems = "center", n.innerHTML = `
737
- <div style="width: min(520px, 92vw); background: ${d === "dark" ? "#0f172a" : "#ffffff"}; color: ${d === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${d === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
736
+ n.id = W, n.style.position = "fixed", n.style.inset = "0", n.style.zIndex = "2147483647", n.style.background = "rgba(2, 6, 23, 0.45)", n.style.display = "grid", n.style.placeItems = "center", n.innerHTML = `
737
+ <div style="width: min(520px, 92vw); background: ${u === "dark" ? "#0f172a" : "#ffffff"}; color: ${u === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${u === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
738
738
  <h3 style="margin: 0 0 6px 0; font-size: 20px; line-height: 1.2; font-weight: 700;">Add translation</h3>
739
- <p style="margin: 0 0 8px 0; font-size: 12px; color: ${d === "dark" ? "#94a3b8" : "#475569"};">Pick a supported language or define a custom one for manual translation.</p>
740
- <select id="facms-language-select" style="width: 100%; border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#ffffff"}; color: ${d === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; margin-bottom: 8px;">
739
+ <p style="margin: 0 0 8px 0; font-size: 12px; color: ${u === "dark" ? "#94a3b8" : "#475569"};">Pick a supported language or define a custom one for manual translation.</p>
740
+ <select id="facms-language-select" style="width: 100%; border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#ffffff"}; color: ${u === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; margin-bottom: 8px;">
741
741
  <option value="">Select supported language</option>
742
- ${B.filter((u) => !e.includes(u.code)).map((u) => `<option value="${u.code}">${u.label} (${u.code})</option>`).join("")}
742
+ ${P.filter((d) => !e.includes(d.code)).map((d) => `<option value="${d.code}">${d.label} (${d.code})</option>`).join("")}
743
743
  <option value="__custom__">Custom language (manual)</option>
744
744
  </select>
745
- <input id="facms-language-name" type="text" placeholder="Custom language name (e.g. Klingon)" style="width: 100%; border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#ffffff"}; color: ${d === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; margin-bottom: 8px; display:none;" />
746
- <input id="facms-language-input" type="text" placeholder="Custom language code (e.g. tlh)" style="width: 100%; border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#ffffff"}; color: ${d === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; display:none;" />
745
+ <input id="facms-language-name" type="text" placeholder="Custom language name (e.g. Klingon)" style="width: 100%; border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#ffffff"}; color: ${u === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; margin-bottom: 8px; display:none;" />
746
+ <input id="facms-language-input" type="text" placeholder="Custom language code (e.g. tlh)" style="width: 100%; border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#ffffff"}; color: ${u === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; display:none;" />
747
747
  <p id="facms-language-error" style="display:none; margin: 8px 0 0 0; font-size: 12px; color: #ef4444;">Enter a valid language code.</p>
748
748
  <div style="margin-top: 14px; display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap;">
749
- <button id="facms-language-cancel" style="border: 1px solid ${d === "dark" ? "#475569" : "#cbd5e1"}; background: ${d === "dark" ? "#1e293b" : "#f1f5f9"}; color: ${d === "dark" ? "#e2e8f0" : "#334155"}; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Cancel</button>
749
+ <button id="facms-language-cancel" style="border: 1px solid ${u === "dark" ? "#475569" : "#cbd5e1"}; background: ${u === "dark" ? "#1e293b" : "#f1f5f9"}; color: ${u === "dark" ? "#e2e8f0" : "#334155"}; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Cancel</button>
750
750
  <button id="facms-language-manual" style="border: 1px solid #334155; background: #334155; color: white; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Add manual</button>
751
751
  ${t ? '<button id="facms-language-autofill" style="border: 1px solid #4f46e5; background: #4f46e5; color: white; border-radius: 10px; padding: 8px 12px; font-size: 13px; cursor: pointer;">Add & Auto-fill</button>' : ""}
752
752
  </div>
753
753
  </div>
754
754
  `;
755
- const o = () => n.style.display = "none";
756
- n.querySelector("#facms-language-cancel")?.addEventListener("click", o);
755
+ const r = () => n.style.display = "none";
756
+ n.querySelector("#facms-language-cancel")?.addEventListener("click", r);
757
757
  const s = n.querySelector("#facms-language-select"), l = n.querySelector("#facms-language-input"), c = n.querySelector("#facms-language-name");
758
758
  s?.addEventListener("change", () => {
759
- const u = s.value === "__custom__";
760
- l && (l.style.display = u ? "block" : "none"), c && (c.style.display = u ? "block" : "none");
759
+ const d = s.value === "__custom__";
760
+ l && (l.style.display = d ? "block" : "none"), c && (c.style.display = d ? "block" : "none");
761
761
  });
762
- const f = (u) => {
762
+ const f = (d) => {
763
763
  const i = n.querySelector("#facms-language-error");
764
764
  let p = "";
765
765
  const g = s?.value ?? "";
766
- let y = "";
767
- if (g && g !== "__custom__" ? (p = T(g), y = $(p)) : (p = T(l?.value ?? ""), y = (c?.value ?? "").trim()), !p || !/^[a-z]{2,3}([_-][a-z0-9]{2,8})?$|^[a-z]{3}_[A-Za-z]+$/i.test(p)) {
766
+ let x = "";
767
+ if (g && g !== "__custom__" ? (p = I(g), x = $(p)) : (p = I(l?.value ?? ""), x = (c?.value ?? "").trim()), !p || !/^[a-z]{2,3}([_-][a-z0-9]{2,8})?$|^[a-z]{3}_[A-Za-z]+$/i.test(p)) {
768
768
  i && (i.textContent = "Enter a valid language code.", i.style.display = "block");
769
769
  return;
770
770
  }
771
- if (y || (y = $(p)), e.includes(p)) {
771
+ if (x || (x = $(p)), e.includes(p)) {
772
772
  i && (i.textContent = `Language "${p}" already exists.`, i.style.display = "block");
773
773
  return;
774
774
  }
775
- i && (i.style.display = "none"), o(), a(`${p}::${y}`, u);
775
+ i && (i.style.display = "none"), r(), a(`${p}::${x}`, d);
776
776
  };
777
777
  n.querySelector("#facms-language-manual")?.addEventListener("click", () => f("manual")), t && n.querySelector("#facms-language-autofill")?.addEventListener("click", () => f("auto")), document.body.appendChild(n);
778
778
  }
779
- function j(e, t) {
779
+ function z(e, t) {
780
780
  if (t === void 0) {
781
781
  console.info(`[frontend-auto-cms:dashboard] ${e}`);
782
782
  return;
783
783
  }
784
784
  console.info(`[frontend-auto-cms:dashboard] ${e}`, t);
785
785
  }
786
- function T(e) {
786
+ function I(e) {
787
787
  return e.trim().toLowerCase();
788
788
  }
789
789
  function $(e) {
790
- const t = T(e), a = B.find((r) => r.code === t);
790
+ const t = I(e), a = P.find((o) => o.code === t);
791
791
  return a ? a.label : t.toUpperCase();
792
792
  }
793
- function je() {
793
+ function Ne() {
794
794
  try {
795
- const e = localStorage.getItem(oe);
795
+ const e = localStorage.getItem(se);
796
796
  if (!e)
797
797
  return {};
798
798
  const t = JSON.parse(e);
@@ -801,59 +801,59 @@ function je() {
801
801
  return {};
802
802
  }
803
803
  }
804
- function D(e) {
805
- localStorage.setItem(oe, JSON.stringify(e));
804
+ function q(e) {
805
+ localStorage.setItem(se, JSON.stringify(e));
806
806
  }
807
- function I(e) {
808
- const t = localStorage.getItem(ne);
807
+ function C(e) {
808
+ const t = localStorage.getItem(re);
809
809
  return t && e[t] ? t : e.en ? "en" : Object.keys(e)[0] ?? "en";
810
810
  }
811
- function W(e) {
812
- localStorage.setItem(ne, e);
811
+ function X(e) {
812
+ localStorage.setItem(re, e);
813
813
  }
814
- function x(e) {
814
+ function y(e) {
815
815
  return e.replace(/[&<>'"]/g, (t) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", "'": "&#39;", '"': "&quot;" })[t]);
816
816
  }
817
817
  function _(e, t = 72) {
818
818
  const a = e.replace(/\s+/g, " ").trim();
819
819
  return a.length <= t ? a : `${a.slice(0, t)}...`;
820
820
  }
821
- function ze(e) {
821
+ function Me(e) {
822
822
  return e.type === "section" ? _((e.sectionItems ?? []).join(" | ")) : e.type === "property" ? _(JSON.stringify(e.attrs ?? {})) : _(e.value);
823
823
  }
824
- function Ne(e) {
824
+ function Be(e) {
825
825
  const t = [];
826
- return e.forEach((a, r) => {
827
- const n = (a.selector ?? "").trim(), o = t[t.length - 1];
828
- if (!!(o && n && o.selector === n) && o) {
829
- o.items.push({ node: a, index: r });
826
+ return e.forEach((a, o) => {
827
+ const n = (a.selector ?? "").trim(), r = t[t.length - 1];
828
+ if (!!(r && n && r.selector === n) && r) {
829
+ r.items.push({ node: a, index: o });
830
830
  return;
831
831
  }
832
832
  t.push({
833
- key: n || `group_${r}`,
833
+ key: n || `group_${o}`,
834
834
  selector: n,
835
- items: [{ node: a, index: r }]
835
+ items: [{ node: a, index: o }]
836
836
  });
837
837
  }), t;
838
838
  }
839
- function Me(e) {
839
+ function Pe(e) {
840
840
  const t = (a) => {
841
841
  if (Array.isArray(a))
842
842
  return a.map(t);
843
843
  if (a && typeof a == "object") {
844
- const r = Object.entries(a).sort(([n], [o]) => n.localeCompare(o));
845
- return Object.fromEntries(r.map(([n, o]) => [n, t(o)]));
844
+ const o = Object.entries(a).sort(([n], [r]) => n.localeCompare(r));
845
+ return Object.fromEntries(o.map(([n, r]) => [n, t(r)]));
846
846
  }
847
847
  return a;
848
848
  };
849
849
  return JSON.stringify(t(e));
850
850
  }
851
- async function Be(e) {
851
+ async function Re(e) {
852
852
  const t = new TextEncoder().encode(e), a = await crypto.subtle.digest("SHA-256", t);
853
- return Array.from(new Uint8Array(a)).map((r) => r.toString(16).padStart(2, "0")).join("");
853
+ return Array.from(new Uint8Array(a)).map((o) => o.toString(16).padStart(2, "0")).join("");
854
854
  }
855
- async function Pe(e, t, a) {
856
- const r = e.nodes.flatMap(
855
+ async function De(e, t, a) {
856
+ const o = e.nodes.flatMap(
857
857
  (s) => s.sourceRefs.map((l) => ({
858
858
  file: l.file,
859
859
  find: l.original,
@@ -863,122 +863,128 @@ async function Pe(e, t, a) {
863
863
  ), n = {
864
864
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
865
865
  content: { ...e, updatedAt: (/* @__PURE__ */ new Date()).toISOString() },
866
- operations: r,
866
+ operations: o,
867
867
  locales: t
868
- }, o = await Be(Me(n));
868
+ }, r = await Re(Pe(n));
869
869
  return {
870
870
  ...n,
871
871
  integrity: {
872
872
  algorithm: "sha256",
873
- value: o
873
+ value: r
874
874
  }
875
875
  };
876
876
  }
877
- function Re(e, t) {
878
- const a = `${e.type.toUpperCase()} • ${x(e.label || e.selector || "")}`, r = `<div class="text-xs text-slate-500 dark:text-slate-400 mb-2">#${t + 1} ${a}</div>`;
877
+ function qe(e, t) {
878
+ const a = `${e.type.toUpperCase()} • ${y(e.label || e.selector || "")}`, o = `<div class="text-xs text-slate-500 dark:text-slate-400 mb-2">#${t + 1} ${a}</div>`;
879
879
  if (e.type === "text")
880
- return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<textarea data-cms-id="${e.id}" data-cms-field="value" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm h-24 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${x(e.value)}</textarea></div>`;
880
+ return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${o}<textarea data-cms-id="${e.id}" data-cms-field="value" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm h-24 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${y(e.value)}</textarea></div>`;
881
881
  if (e.type === "image" || e.type === "video")
882
- return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<label class="text-xs text-slate-500 dark:text-slate-400">Source URL</label><input data-cms-id="${e.id}" data-cms-field="value" value="${x(e.value)}" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm mb-2 focus:outline-none focus:ring-2 focus:ring-indigo-500/40" /><label class="text-xs text-slate-500 dark:text-slate-400">Alt text</label><input data-cms-id="${e.id}" data-cms-field="alt" value="${x(e.attrs?.alt ?? "")}" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/40" /></div>`;
882
+ return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${o}<label class="text-xs text-slate-500 dark:text-slate-400">Source URL</label><input data-cms-id="${e.id}" data-cms-field="value" value="${y(e.value)}" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm mb-2 focus:outline-none focus:ring-2 focus:ring-indigo-500/40" /><label class="text-xs text-slate-500 dark:text-slate-400">Alt text</label><input data-cms-id="${e.id}" data-cms-field="alt" value="${y(e.attrs?.alt ?? "")}" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/40" /></div>`;
883
883
  if (e.type === "section") {
884
884
  const n = (e.sectionItems ?? []).join(`
885
885
  `);
886
- return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<textarea data-cms-id="${e.id}" data-cms-field="sectionItems" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm h-28 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${x(n)}</textarea></div>`;
886
+ return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${o}<textarea data-cms-id="${e.id}" data-cms-field="sectionItems" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm h-28 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${y(n)}</textarea></div>`;
887
887
  }
888
- return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<textarea data-cms-id="${e.id}" data-cms-field="attrs" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-xs h-28 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${x(JSON.stringify(e.attrs ?? {}, null, 2))}</textarea></div>`;
888
+ return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${o}<textarea data-cms-id="${e.id}" data-cms-field="attrs" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-xs h-28 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${y(JSON.stringify(e.attrs ?? {}, null, 2))}</textarea></div>`;
889
889
  }
890
- function S(e, t, a, r) {
890
+ function S(e, t, a, o) {
891
891
  e.nodes.forEach((n) => {
892
- n.type === "text" && (n.value = t[n.key] ?? r[n.key] ?? n.value, ae(n, a));
892
+ n.type === "text" && (n.value = t[n.key] ?? o[n.key] ?? n.value, oe(n, a));
893
893
  });
894
894
  }
895
- function De(e, t) {
895
+ function He(e, t) {
896
896
  e.activeLanguage = t;
897
897
  const a = e.locales[t] ?? e.locales[e.mainLanguage] ?? e.baseTextByKey;
898
898
  S(e.content, a, e.workingDocument, e.baseTextByKey);
899
899
  }
900
- function qe(e, t) {
900
+ function Ue(e, t) {
901
901
  const a = e.querySelector("#facms-language-tabs");
902
902
  if (!a)
903
903
  return;
904
- const r = Object.keys(t.locales);
905
- a.innerHTML = r.map((n) => {
906
- const o = n === t.activeLanguage, s = n === t.mainLanguage, l = t.languageLabels[n] ?? $(n);
907
- return `<div class="inline-flex items-center rounded-lg overflow-hidden border ${o ? "border-indigo-500" : "border-slate-200 dark:border-slate-700"}">
908
- <button data-lang="${n}" class="px-2.5 py-1.5 text-xs ${o ? "bg-indigo-600 text-white" : "bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-200"}">${x(l)}</button>
909
- ${s ? `<span class="px-2 py-1.5 text-[10px] font-semibold ${o ? "bg-indigo-700 text-indigo-100" : "bg-emerald-600 text-white"}">MAIN</span>` : `<button data-main-lang="${n}" title="Set as main language" class="px-2 py-1.5 text-xs ${o ? "bg-indigo-700 text-indigo-100 hover:bg-indigo-800" : "bg-emerald-600 text-white hover:bg-emerald-500"}">★</button>`}
910
- <button data-remove-lang="${n}" title="Remove language" class="px-2 py-1.5 text-xs ${o ? "bg-indigo-700 text-indigo-100 hover:bg-indigo-800" : "bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-300 dark:hover:bg-slate-600"}">×</button>
904
+ const o = Object.keys(t.locales);
905
+ a.innerHTML = o.map((n) => {
906
+ const r = n === t.activeLanguage, s = n === t.mainLanguage, l = t.languageLabels[n] ?? $(n);
907
+ return `<div class="inline-flex items-center rounded-lg overflow-hidden border ${r ? "border-indigo-500" : "border-slate-200 dark:border-slate-700"}">
908
+ <button data-lang="${n}" class="px-2.5 py-1.5 text-xs ${r ? "bg-indigo-600 text-white" : "bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-200"}">${y(l)}</button>
909
+ ${s ? `<span class="px-2 py-1.5 text-[10px] font-semibold ${r ? "bg-indigo-700 text-indigo-100" : "bg-emerald-600 text-white"}">MAIN</span>` : `<button data-main-lang="${n}" title="Set as main language" class="px-2 py-1.5 text-xs ${r ? "bg-indigo-700 text-indigo-100 hover:bg-indigo-800" : "bg-emerald-600 text-white hover:bg-emerald-500"}">★</button>`}
910
+ <button data-remove-lang="${n}" title="Remove language" class="px-2 py-1.5 text-xs ${r ? "bg-indigo-700 text-indigo-100 hover:bg-indigo-800" : "bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-300 dark:hover:bg-slate-600"}">×</button>
911
911
  </div>`;
912
912
  }).join(""), a.querySelectorAll("[data-lang]").forEach((n) => {
913
913
  n.addEventListener("click", () => {
914
- const o = n.dataset.lang;
915
- o && (De(t, o), L(e, t));
914
+ const r = n.dataset.lang;
915
+ r && (He(t, r), L(e, t));
916
916
  });
917
917
  }), a.querySelectorAll("[data-main-lang]").forEach((n) => {
918
- n.addEventListener("click", (o) => {
919
- o.stopPropagation();
918
+ n.addEventListener("click", (r) => {
919
+ r.stopPropagation();
920
920
  const s = n.dataset.mainLang;
921
- !s || !t.locales[s] || (t.mainLanguage = s, W(s), t.baseTextByKey = { ...t.locales[s] }, L(e, t));
921
+ !s || !t.locales[s] || (t.mainLanguage = s, X(s), t.baseTextByKey = { ...t.locales[s] }, L(e, t));
922
922
  });
923
923
  }), a.querySelectorAll("[data-remove-lang]").forEach((n) => {
924
- n.addEventListener("click", (o) => {
925
- o.stopPropagation();
924
+ n.addEventListener("click", (r) => {
925
+ r.stopPropagation();
926
926
  const s = n.dataset.removeLang;
927
927
  if (s) {
928
928
  if (Object.keys(t.locales).length <= 1) {
929
929
  alert("You must keep at least one language.");
930
930
  return;
931
931
  }
932
- delete t.locales[s], delete t.languageLabels[s], D(t.languageLabels), A(t.locales), t.mainLanguage === s && (t.mainLanguage = I(t.locales), W(t.mainLanguage), t.baseTextByKey = { ...t.locales[t.mainLanguage] ?? {} }), t.activeLanguage === s && (t.activeLanguage = q(t.locales, t.mainLanguage)), ue(t), L(e, t);
932
+ delete t.locales[s], delete t.languageLabels[s], q(t.languageLabels), A(t.locales), t.mainLanguage === s && (t.mainLanguage = C(t.locales), X(t.mainLanguage), t.baseTextByKey = { ...t.locales[t.mainLanguage] ?? {} }), t.activeLanguage === s && (t.activeLanguage = H(t.locales, t.mainLanguage)), pe(t), L(e, t);
933
933
  }
934
934
  });
935
935
  });
936
936
  }
937
- function He(e, t) {
937
+ function Ge(e, t) {
938
938
  e.querySelectorAll("[data-cms-id]").forEach((a) => {
939
- const r = a.dataset.cmsId, n = a.dataset.cmsField;
940
- !r || !n || a.addEventListener("input", () => {
941
- const o = t.content.nodes.find((s) => s.id === r);
942
- if (o) {
939
+ const o = a.dataset.cmsId, n = a.dataset.cmsField;
940
+ !o || !n || a.addEventListener("input", () => {
941
+ const r = t.content.nodes.find((s) => s.id === o);
942
+ if (r) {
943
943
  if (n === "value")
944
- o.value = a.value, o.type === "text" && (t.activeLanguage === t.mainLanguage ? (t.baseTextByKey[o.key] = a.value, t.locales[t.mainLanguage] = { ...t.locales[t.mainLanguage] ?? {}, [o.key]: a.value }) : t.locales[t.activeLanguage] = {
944
+ r.value = a.value, r.type === "text" && (t.activeLanguage === t.mainLanguage ? (t.baseTextByKey[r.key] = a.value, t.locales[t.mainLanguage] = { ...t.locales[t.mainLanguage] ?? {}, [r.key]: a.value }) : t.locales[t.activeLanguage] = {
945
945
  ...t.locales[t.activeLanguage] ?? {},
946
- [o.key]: a.value
946
+ [r.key]: a.value
947
947
  }, A(t.locales));
948
- else if (n === "alt") o.attrs = { ...o.attrs ?? {}, alt: a.value };
949
- else if (n === "sectionItems") o.sectionItems = a.value.split(`
948
+ else if (n === "alt") r.attrs = { ...r.attrs ?? {}, alt: a.value };
949
+ else if (n === "sectionItems") r.sectionItems = a.value.split(`
950
950
  `).map((s) => s.trim()).filter(Boolean);
951
951
  else if (n === "attrs")
952
952
  try {
953
- o.attrs = JSON.parse(a.value);
953
+ r.attrs = JSON.parse(a.value);
954
954
  } catch {
955
955
  return;
956
956
  }
957
- ae(o, t.workingDocument), Q(t.content);
957
+ oe(r, t.workingDocument), te(t.content);
958
958
  }
959
959
  });
960
960
  });
961
961
  }
962
962
  function w(e, t, a) {
963
- const r = e.querySelector("#facms-i18n-status"), n = e.querySelector("#facms-translate-loader"), o = e.querySelector("#facms-add-language"), s = document.getElementById("facms-global-loader"), l = document.getElementById("facms-global-loader-label");
964
- r && (r.textContent = t), n && (n.style.display = a ? "inline-flex" : "none"), o && (o.disabled = a), s && (s.style.display = a ? "flex" : "none"), l && (l.textContent = a ? t : "Translating");
963
+ const o = e.querySelector("#facms-i18n-status"), n = e.querySelector("#facms-translate-loader"), r = e.querySelector("#facms-add-language");
964
+ B(a, t), o && (o.textContent = t), n && (n.style.display = a ? "inline-flex" : "none"), r && (r.disabled = a);
965
+ }
966
+ function B(e, t) {
967
+ const a = document.getElementById("facms-global-loader"), o = document.getElementById("facms-global-loader-label");
968
+ a && (a.style.display = e ? "flex" : "none"), o && (o.textContent = e ? t : "Loading");
965
969
  }
966
970
  function L(e, t) {
967
- const r = Ne(t.content.nodes).map((n) => {
968
- const o = n.items[0], s = n.items[n.items.length - 1], l = o.index === s.index ? `#${o.index + 1}` : `#${o.index + 1} - #${s.index + 1}`, c = n.items.map((i) => ze(i.node)).filter(Boolean).join(" • "), f = n.items.length > 1 ? `${l} ${x(n.selector || "Grouped fields")} (${n.items.length} fields)` : `${l} ${x(o.node.type.toUpperCase())} • ${x(o.node.label || o.node.selector || "")}`, u = n.items.map((i) => Re(i.node, i.index)).join("");
971
+ const a = Be(t.content.nodes), o = a.length ? a.map((n) => {
972
+ const r = n.items[0], s = n.items[n.items.length - 1], l = r.index === s.index ? `#${r.index + 1}` : `#${r.index + 1} - #${s.index + 1}`, c = n.items.map((i) => Me(i.node)).filter(Boolean).join(" • "), f = n.items.length > 1 ? `${l} ${y(n.selector || "Grouped fields")} (${n.items.length} fields)` : `${l} ${y(r.node.type.toUpperCase())} • ${y(r.node.label || r.node.selector || "")}`, d = n.items.map((i) => qe(i.node, i.index)).join("");
969
973
  return `
970
974
  <details class="rounded-xl p-2 border border-slate-200 dark:border-transparent bg-white dark:bg-slate-900/60 shadow-sm">
971
975
  <summary class="list-none cursor-pointer flex items-center justify-between gap-2 p-3 rounded-lg bg-slate-50 dark:bg-slate-800/70 border border-slate-200 dark:border-slate-800">
972
976
  <div class="min-w-0">
973
977
  <div class="text-xs text-slate-500 dark:text-slate-400">${f}</div>
974
- <div class="text-sm text-slate-700 dark:text-slate-300 truncate">${x(_(c || "No preview"))}</div>
978
+ <div class="text-sm text-slate-700 dark:text-slate-300 truncate">${y(_(c || "No preview"))}</div>
975
979
  </div>
976
980
  <span class="text-xs text-indigo-600 dark:text-indigo-400">Expand</span>
977
981
  </summary>
978
- <div class="pt-3 px-2 pb-2 space-y-2">${u}</div>
982
+ <div class="pt-3 px-2 pb-2 space-y-2">${d}</div>
979
983
  </details>
980
984
  `;
981
- }).join("");
985
+ }).join("") : `<div class="rounded-xl p-3 border border-slate-700 bg-slate-900/70 text-slate-300 text-sm">
986
+ No editable elements detected yet on this route. This page may still be rendering client-side content. Wait a moment, then switch routes and come back.
987
+ </div>`;
982
988
  e.innerHTML = `
983
989
  <div class="p-4 space-y-3">
984
990
  <p class="text-xs text-slate-500 dark:text-slate-400 mb-2">All editable elements are shown in page order.</p>
@@ -986,7 +992,7 @@ function L(e, t) {
986
992
  <div id="facms-language-tabs" class="flex flex-wrap gap-2"></div>
987
993
  <button id="facms-add-language" class="px-2.5 py-1.5 rounded-lg text-xs border border-indigo-500 text-indigo-600 dark:text-indigo-300 dark:border-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-900/30">+ Add translation</button>
988
994
  </div>
989
- <div class="space-y-3">${r}</div>
995
+ <div class="space-y-3">${o}</div>
990
996
  <div class="mt-4 flex flex-wrap gap-2">
991
997
  <button id="facms-save" class="px-3 py-2 bg-emerald-600 text-white rounded-lg text-sm hover:bg-emerald-500 shadow">Save + Publish</button>
992
998
  </div>
@@ -995,17 +1001,17 @@ function L(e, t) {
995
1001
  <p id="facms-i18n-status" class="text-xs text-slate-500 dark:text-slate-400"></p>
996
1002
  </div>
997
1003
  </div>
998
- `, qe(e, t), e.querySelector("#facms-save")?.addEventListener("click", async () => {
999
- const n = await Pe(t.content, t.locales, t.baseTextByKey), o = await ve();
1000
- if (!o || o.provider === "none") {
1001
- be(n), alert("Patch downloaded. Configure hosting in setup for one-click publish.");
1004
+ `, Ue(e, t), e.querySelector("#facms-save")?.addEventListener("click", async () => {
1005
+ const n = await De(t.content, t.locales, t.baseTextByKey), r = await Le();
1006
+ if (!r || r.provider === "none") {
1007
+ ye(n), alert("Patch downloaded. Configure hosting in setup for one-click publish.");
1002
1008
  return;
1003
1009
  }
1004
- const s = o.provider;
1005
- Ce(s, async (l) => {
1010
+ const s = r.provider;
1011
+ je(s, async (l) => {
1006
1012
  let c = !1;
1007
1013
  try {
1008
- c = await $e(n, l, o);
1014
+ c = await Ee(n, l, r);
1009
1015
  } catch {
1010
1016
  c = !1;
1011
1017
  }
@@ -1016,92 +1022,105 @@ function L(e, t) {
1016
1022
  alert("Changes published successfully.");
1017
1023
  });
1018
1024
  }), e.querySelector("#facms-add-language")?.addEventListener("click", () => {
1019
- Oe(Object.keys(t.locales), h?.autoTranslateEnabled ?? !0, async (n, o) => {
1020
- const [s, l] = n.split("::"), c = T(s ?? ""), f = (l ?? "").trim() || $(c);
1025
+ ze(Object.keys(t.locales), h?.autoTranslateEnabled ?? !0, async (n, r) => {
1026
+ const [s, l] = n.split("::"), c = I(s ?? ""), f = (l ?? "").trim() || $(c);
1021
1027
  if (!c)
1022
1028
  return;
1023
- const u = performance.now(), i = t.locales[t.mainLanguage] ?? t.baseTextByKey, p = { ...i };
1024
- if (j("Add language requested", {
1029
+ const d = performance.now(), i = t.locales[t.mainLanguage] ?? t.baseTextByKey, p = { ...i };
1030
+ if (z("Add language requested", {
1025
1031
  lang: c,
1026
- mode: o,
1032
+ mode: r,
1027
1033
  sourceKeys: Object.keys(i).length,
1028
1034
  browserLanguage: navigator.language,
1029
1035
  browserLanguages: navigator.languages
1030
- }), t.locales[c] = p, t.languageLabels[c] = f, D(t.languageLabels), t.activeLanguage = c, A(t.locales), S(t.content, t.locales[c], t.workingDocument, t.baseTextByKey), L(e, t), j("Manual language tab created", { lang: c }), w(e, `Added ${f} tab prefilled with source text for manual translation.`, !1), o !== "auto" || !(h?.autoTranslateEnabled ?? !0)) {
1031
- o === "auto" && !(h?.autoTranslateEnabled ?? !0) && w(e, `Privacy mode is on. Added ${f} tab for manual translation only.`, !1);
1036
+ }), t.locales[c] = p, t.languageLabels[c] = f, q(t.languageLabels), t.activeLanguage = c, A(t.locales), S(t.content, t.locales[c], t.workingDocument, t.baseTextByKey), L(e, t), z("Manual language tab created", { lang: c }), w(e, `Added ${f} tab prefilled with source text for manual translation.`, !1), r !== "auto" || !(h?.autoTranslateEnabled ?? !0)) {
1037
+ r === "auto" && !(h?.autoTranslateEnabled ?? !0) && w(e, `Privacy mode is on. Added ${f} tab for manual translation only.`, !1);
1032
1038
  return;
1033
1039
  }
1034
1040
  try {
1035
1041
  const g = Object.keys(i).length;
1036
1042
  w(e, `Auto-filling ${f} translation... (0/${g})`, !0);
1037
- const y = await he(i, c, t.mainLanguage, (H, b) => {
1038
- w(e, `Auto-filling ${f} translation... (${H}/${b})`, !0);
1043
+ const x = await ve(i, c, t.mainLanguage, (U, b) => {
1044
+ w(e, `Auto-filling ${f} translation... (${U}/${b})`, !0);
1039
1045
  });
1040
- t.locales[c] = y, A(t.locales), t.activeLanguage = c, S(t.content, y, t.workingDocument, t.baseTextByKey), L(e, t), j("Automatic translation succeeded", {
1046
+ t.locales[c] = x, A(t.locales), t.activeLanguage = c, S(t.content, x, t.workingDocument, t.baseTextByKey), L(e, t), z("Automatic translation succeeded", {
1041
1047
  lang: c,
1042
- translatedKeys: Object.keys(y).length,
1043
- ms: Math.round(performance.now() - u)
1048
+ translatedKeys: Object.keys(x).length,
1049
+ ms: Math.round(performance.now() - d)
1044
1050
  }), w(e, `Added ${f} with auto-filled translation. Review and edit as needed.`, !1);
1045
1051
  } catch (g) {
1046
1052
  console.error("[frontend-auto-cms:dashboard] Automatic translation failed", {
1047
1053
  lang: c,
1048
1054
  message: g instanceof Error ? g.message : String(g),
1049
1055
  stack: g instanceof Error ? g.stack : void 0,
1050
- ms: Math.round(performance.now() - u)
1056
+ ms: Math.round(performance.now() - d)
1051
1057
  }), w(e, `Auto-fill failed. ${f} stays prefilled with source text for manual editing.`, !1);
1052
1058
  }
1053
1059
  });
1054
- }), He(e, t);
1060
+ }), Ge(e, t);
1055
1061
  }
1056
- function q(e, t) {
1057
- const a = Object.keys(e), r = t && e[t] ? t : I(e), n = [...navigator.languages ?? [], navigator.language].map((o) => o.toLowerCase().split("-")[0]);
1058
- for (const o of n)
1059
- if (a.includes(o))
1060
- return o;
1061
- return a.includes(r) ? r : a[0] ?? "en";
1062
+ function H(e, t) {
1063
+ const a = Object.keys(e), o = t && e[t] ? t : C(e), n = [...navigator.languages ?? [], navigator.language].map((r) => r.toLowerCase().split("-")[0]);
1064
+ for (const r of n)
1065
+ if (a.includes(r))
1066
+ return r;
1067
+ return a.includes(o) ? o : a[0] ?? "en";
1062
1068
  }
1063
- function ue(e) {
1069
+ function pe(e) {
1064
1070
  const t = e.locales[e.activeLanguage] ?? e.locales.en ?? e.baseTextByKey;
1065
1071
  S(e.content, t, e.workingDocument, e.baseTextByKey);
1066
1072
  }
1067
- function Ue(e, t, a) {
1068
- const r = ee(), n = {
1073
+ function Ke(e) {
1074
+ return new Promise((t) => window.setTimeout(t, e));
1075
+ }
1076
+ async function Z(e, t) {
1077
+ const a = [0, 120, 280, 600, 1100, 1800, 2600];
1078
+ let o = T(e, t);
1079
+ if (o.nodes.length > 0)
1080
+ return o;
1081
+ for (const n of a.slice(1))
1082
+ if (await Ke(n), o = T(e, t), o.nodes.length > 0)
1083
+ return o;
1084
+ return o;
1085
+ }
1086
+ function Je(e, t, a) {
1087
+ const o = ae(), n = {
1069
1088
  ...a,
1070
- ...r
1071
- }, o = je(), s = Object.fromEntries(e.nodes.filter((i) => i.type === "text").map((i) => [i.key, i.value])), l = I(n), c = {
1089
+ ...o
1090
+ }, r = Ne(), s = Object.fromEntries(e.nodes.filter((i) => i.type === "text").map((i) => [i.key, i.value])), l = C(n), c = {
1072
1091
  ...n,
1073
1092
  [l]: { ...n[l] ?? {}, ...s }
1074
1093
  };
1075
1094
  !c.en && l === "en" && (c.en = Object.assign({}, c.en ?? {}, s));
1076
- const f = q(c, l), u = { ...o };
1095
+ const f = H(c, l), d = { ...r };
1077
1096
  return Object.keys(c).forEach((i) => {
1078
- u[i] || (u[i] = $(i));
1079
- }), D(u), {
1097
+ d[i] || (d[i] = $(i));
1098
+ }), q(d), {
1080
1099
  content: e,
1081
1100
  locales: c,
1082
1101
  workingDocument: t,
1083
1102
  baseTextByKey: c[l] ?? s,
1084
1103
  activeLanguage: f,
1085
1104
  mainLanguage: l,
1086
- languageLabels: u
1105
+ languageLabels: d
1087
1106
  };
1088
1107
  }
1089
- function Ge() {
1090
- const e = ee();
1108
+ function Fe() {
1109
+ const e = ae();
1091
1110
  if (!Object.keys(e).length)
1092
1111
  return;
1093
- const t = q(e, I(e));
1112
+ const t = H(e, C(e));
1094
1113
  if (!t || t === "en")
1095
1114
  return;
1096
- const a = N(document, location.pathname), r = e[t];
1097
- if (!r)
1115
+ const a = T(document, location.pathname), o = e[t];
1116
+ if (!o)
1098
1117
  return;
1099
- const n = Object.fromEntries(a.nodes.filter((o) => o.type === "text").map((o) => [o.key, o.value]));
1100
- S(a, r, document, n);
1118
+ const n = Object.fromEntries(a.nodes.filter((r) => r.type === "text").map((r) => [r.key, r.value]));
1119
+ S(a, o, document, n);
1101
1120
  }
1102
- function Ke(e) {
1121
+ function Ye(e) {
1103
1122
  const t = e.pages.length ? e.pages : ["/"];
1104
- document.documentElement.style.margin = "0", document.documentElement.style.padding = "0", document.documentElement.style.background = d === "dark" ? "#020617" : "#f1f5f9", document.body.style.margin = "0", document.body.style.padding = "0", document.body.style.background = d === "dark" ? "#020617" : "#f1f5f9", document.body.innerHTML = `
1123
+ document.documentElement.style.margin = "0", document.documentElement.style.padding = "0", document.documentElement.style.background = u === "dark" ? "#020617" : "#f1f5f9", document.body.style.margin = "0", document.body.style.padding = "0", document.body.style.background = u === "dark" ? "#020617" : "#f1f5f9", document.body.innerHTML = `
1105
1124
  <div id="facms-app" class="h-screen w-screen grid grid-cols-1 lg:grid-cols-[760px_1fr] bg-slate-100 dark:bg-slate-950 text-slate-900 dark:text-slate-100">
1106
1125
  <div class="border-r border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 overflow-hidden grid grid-rows-[auto_1fr]">
1107
1126
  <div class="p-4 border-b border-slate-200 dark:border-slate-800 flex items-start justify-between gap-3">
@@ -1129,61 +1148,67 @@ function Ke(e) {
1129
1148
  </div>
1130
1149
  </div>
1131
1150
  `;
1132
- const a = document.getElementById("facms-route-preview"), r = document.getElementById("facms-route-editor"), n = document.getElementById("facms-page-tabs"), o = /* @__PURE__ */ new Map();
1151
+ const a = document.getElementById("facms-route-preview"), o = document.getElementById("facms-route-editor"), n = document.getElementById("facms-page-tabs"), r = /* @__PURE__ */ new Map();
1133
1152
  let s = t[0], l = {};
1134
1153
  const c = () => {
1135
1154
  n.innerHTML = t.map(
1136
- (f) => `<button data-page="${f}" class="w-full text-left px-3 py-2 rounded-lg text-sm border ${f === s ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-100 border-slate-200 dark:bg-slate-800 dark:border-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-200 dark:hover:bg-slate-700"}">${x(f)}</button>`
1155
+ (f) => `<button data-page="${f}" class="w-full text-left px-3 py-2 rounded-lg text-sm border ${f === s ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-100 border-slate-200 dark:bg-slate-800 dark:border-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-200 dark:hover:bg-slate-700"}">${y(f)}</button>`
1137
1156
  ).join(""), n.querySelectorAll("[data-page]").forEach((f) => {
1138
1157
  f.addEventListener("click", () => {
1139
1158
  s = f.dataset.page || "/", c(), a.src = s;
1140
1159
  });
1141
1160
  });
1142
1161
  };
1143
- se(d), a.addEventListener("load", () => {
1162
+ le(u), a.addEventListener("load", async () => {
1144
1163
  const f = a.contentDocument;
1145
- if (!f) return;
1146
- let u = o.get(s);
1147
- if (u) {
1148
- u.workingDocument = f;
1149
- const i = N(f, s);
1150
- i.nodes.length && !u.content.nodes.length && (u.content = i);
1151
- } else {
1152
- const i = N(f, s);
1153
- u = Ue(i, f, l), o.set(s, u);
1164
+ if (f) {
1165
+ B(!0, `Scanning page content for ${s}...`);
1166
+ try {
1167
+ let d = r.get(s);
1168
+ if (d) {
1169
+ d.workingDocument = f;
1170
+ const i = d.content.nodes.length ? T(f, s) : await Z(f, s);
1171
+ i.nodes.length && !d.content.nodes.length && (d.content = i);
1172
+ } else {
1173
+ const i = await Z(f, s);
1174
+ d = Je(i, f, l), r.set(s, d);
1175
+ }
1176
+ pe(d), te(d.content), L(o, d);
1177
+ } finally {
1178
+ B(!1, "Loading");
1179
+ }
1154
1180
  }
1155
- ue(u), Q(u.content), L(r, u);
1156
- }), c(), ge().then((f) => {
1181
+ }), c(), me().then((f) => {
1157
1182
  l = f, a.src = s;
1158
1183
  });
1159
1184
  }
1160
- async function X() {
1161
- if (re(), le(), !await ce())
1185
+ async function Q() {
1186
+ if (ie(), ce(), !await ue())
1162
1187
  return;
1163
- const e = await ie(), t = () => Ke(e);
1164
- if (!P) {
1165
- de(t);
1188
+ const e = await de(), t = () => Ye(e);
1189
+ if (!R) {
1190
+ fe(t);
1166
1191
  return;
1167
1192
  }
1168
1193
  t();
1169
1194
  }
1170
- async function Je() {
1171
- const e = await ie(), a = new URLSearchParams(location.search).get("__facms") === "1";
1195
+ async function We() {
1196
+ const e = await de(), a = new URLSearchParams(location.search).get("__facms") === "1";
1172
1197
  if (location.pathname !== e.dashboardPath && !a) {
1173
- Ge();
1198
+ Fe();
1174
1199
  return;
1175
1200
  }
1176
- if (re(), le(), !!await ce()) {
1177
- if (!P) {
1178
- de(() => {
1179
- X();
1201
+ if (ie(), ce(), !!await ue()) {
1202
+ if (!R) {
1203
+ fe(() => {
1204
+ Q();
1180
1205
  });
1181
1206
  return;
1182
1207
  }
1183
- X();
1208
+ Q();
1184
1209
  }
1185
1210
  }
1186
1211
  export {
1187
- X as launchDashboard,
1188
- Je as registerCmsLauncher
1212
+ Q as launchDashboard,
1213
+ We as registerCmsLauncher
1189
1214
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontend-auto-cms",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Turn any frontend into an editable mini-CMS with one import.",
5
5
  "type": "module",
6
6
  "license": "MIT",