memi-board 0.47.0 → 0.48.0

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.
Files changed (48) hide show
  1. package/README.md +86 -18
  2. package/dist/{ar-D_6hknjh.js → ar-C-X7I5_n.js} +9 -2
  3. package/dist/ar-C-X7I5_n.js.map +1 -0
  4. package/dist/{slugify-DzXnx16m.js → commentImages-D1PEZIU9.js} +65 -16
  5. package/dist/commentImages-D1PEZIU9.js.map +1 -0
  6. package/dist/composables/useMemiBoardComments.d.ts +20 -2
  7. package/dist/composables/useMemiBoardStorage.d.ts +4 -0
  8. package/dist/{de-DQqSsBsZ.js → de-clWR1v1K.js} +9 -2
  9. package/dist/de-clWR1v1K.js.map +1 -0
  10. package/dist/{en-Broh-9df.js → en-BSBqcgqW.js} +11 -4
  11. package/dist/en-BSBqcgqW.js.map +1 -0
  12. package/dist/{es-D3eEYN6w.js → es-D65HxdZE.js} +9 -2
  13. package/dist/es-D65HxdZE.js.map +1 -0
  14. package/dist/{fr-CbXPRKeU.js → fr-Cn_Ys4zN.js} +9 -2
  15. package/dist/fr-Cn_Ys4zN.js.map +1 -0
  16. package/dist/{id-DxVqvPpo.js → id-zjyRo6dg.js} +9 -2
  17. package/dist/id-zjyRo6dg.js.map +1 -0
  18. package/dist/index.js +1090 -1016
  19. package/dist/index.js.map +1 -1
  20. package/dist/{ja-D2dIWUse.js → ja-BOTpLmpf.js} +9 -2
  21. package/dist/ja-BOTpLmpf.js.map +1 -0
  22. package/dist/{pt-BAuHdglU.js → pt-M4T-sRwC.js} +9 -2
  23. package/dist/pt-M4T-sRwC.js.map +1 -0
  24. package/dist/runtime/components/CommentForm.vue +40 -6
  25. package/dist/runtime/components/CommentImageField.vue +201 -0
  26. package/dist/runtime/components/CommentItem.vue +56 -10
  27. package/dist/storage.d.ts +2 -1
  28. package/dist/storage.js +101 -62
  29. package/dist/storage.js.map +1 -1
  30. package/dist/types.d.ts +8 -1
  31. package/dist/utils/commentImages.d.ts +7 -0
  32. package/dist/utils/deletePostCascade.d.ts +4 -1
  33. package/dist/{zh-CMyzTdQ5.js → zh-CtswuQ57.js} +9 -2
  34. package/dist/zh-CtswuQ57.js.map +1 -0
  35. package/docs/firebase-setup.md +8 -9
  36. package/docs/firestore.rules.example +70 -1
  37. package/docs/storage.rules.example +17 -2
  38. package/package.json +1 -1
  39. package/dist/ar-D_6hknjh.js.map +0 -1
  40. package/dist/de-DQqSsBsZ.js.map +0 -1
  41. package/dist/en-Broh-9df.js.map +0 -1
  42. package/dist/es-D3eEYN6w.js.map +0 -1
  43. package/dist/fr-CbXPRKeU.js.map +0 -1
  44. package/dist/id-DxVqvPpo.js.map +0 -1
  45. package/dist/ja-D2dIWUse.js.map +0 -1
  46. package/dist/pt-BAuHdglU.js.map +0 -1
  47. package/dist/slugify-DzXnx16m.js.map +0 -1
  48. package/dist/zh-CMyzTdQ5.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
- import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, R as g, S as _, T as v, U as y, V as b, W as x, _ as S, a as C, b as w, c as T, d as E, f as D, g as O, h as ee, i as k, j as A, k as j, l as te, m as ne, n as re, o as ie, p as ae, q as oe, r as se, s as ce, u as le, v as ue, w as de, x as M, y as fe, z as pe } from "./slugify-DzXnx16m.js";
2
- import { computed as N, onScopeDispose as P, reactive as me, ref as F, toValue as I, watch as L } from "vue";
3
- import { deleteDoc as he, deleteField as ge, doc as _e, documentId as R, endAt as ve, endBefore as ye, getDoc as z, getDocs as B, increment as V, limit as H, limitToLast as be, onSnapshot as U, orderBy as W, query as G, runTransaction as xe, serverTimestamp as K, setDoc as q, startAfter as J, updateDoc as Y, where as X, writeBatch as Se } from "firebase/firestore";
4
- import { useCollection as Ce, useCurrentUser as we, useDocument as Te, useFirebaseApp as Ee, useFirebaseAuth as De, useFirestore as Z } from "vuefire";
5
- import { GoogleAuthProvider as Oe, OAuthProvider as ke, createUserWithEmailAndPassword as Ae, signInWithEmailAndPassword as je, signInWithPopup as Me, signOut as Ne, updateProfile as Pe } from "firebase/auth";
6
- import { deleteObject as Fe, getStorage as Ie, listAll as Le, ref as Re } from "firebase/storage";
7
- import { GoogleAIBackend as ze, Schema as Be, getAI as Ve, getGenerativeModel as He } from "firebase/ai";
1
+ import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, R as g, S as _, T as v, U as y, V as b, W as x, X as S, Y as C, Z as w, _ as T, a as E, b as D, c as ee, d as te, f as ne, g as O, h as re, j as ie, k as ae, l as oe, m as k, o as se, p as ce, q as le, r as ue, s as A, t as de, u as fe, v as pe, w as j, x as me, y as M, z as he } from "./commentImages-D1PEZIU9.js";
2
+ import { computed as N, onScopeDispose as P, reactive as ge, ref as F, toValue as I, watch as L } from "vue";
3
+ import { deleteDoc as _e, deleteField as ve, doc as ye, documentId as R, endAt as be, endBefore as xe, getDoc as z, getDocs as B, increment as V, limit as H, limitToLast as Se, onSnapshot as U, orderBy as W, query as G, runTransaction as Ce, serverTimestamp as K, setDoc as q, startAfter as J, updateDoc as Y, where as X, writeBatch as we } from "firebase/firestore";
4
+ import { useCollection as Te, useCurrentUser as Ee, useDocument as De, useFirebaseApp as Oe, useFirebaseAuth as ke, useFirestore as Z } from "vuefire";
5
+ import { GoogleAuthProvider as Ae, OAuthProvider as je, createUserWithEmailAndPassword as Me, signInWithEmailAndPassword as Ne, signInWithPopup as Pe, signOut as Fe, updateProfile as Ie } from "firebase/auth";
6
+ import { deleteObject as Le, getStorage as Re, listAll as ze, ref as Be } from "firebase/storage";
7
+ import { GoogleAIBackend as Ve, Schema as He, getAI as Ue, getGenerativeModel as We } from "firebase/ai";
8
8
  //#region src/utils/boardSeo.ts
9
- function Ue(e, t) {
10
- return !e || e === "전체" || e === E(t, "seo.allCategory");
9
+ function Ge(e, t) {
10
+ return !e || e === "전체" || e === k(t, "seo.allCategory");
11
11
  }
12
- function We(e) {
12
+ function Ke(e) {
13
13
  if (typeof e != "string") return null;
14
14
  let t = e.trim();
15
15
  return /^https?:\/\//i.test(t) ? t : null;
16
16
  }
17
- function Ge(e) {
18
- let t = We(e);
17
+ function qe(e) {
18
+ let t = Ke(e);
19
19
  if (!t) return null;
20
20
  if (!/firebasestorage\.googleapis\.com/i.test(t)) return t;
21
21
  try {
@@ -32,49 +32,49 @@ function Ge(e) {
32
32
  return t;
33
33
  }
34
34
  }
35
- function Ke(e, t, n = "") {
35
+ function Je(e, t, n = "") {
36
36
  let r = t.replace(/\/$/, ""), i = e.trim();
37
- return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? Ke(n, t) : r;
37
+ return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? Je(n, t) : r;
38
38
  }
39
- function qe(e, t, n, r, i) {
40
- let a = r?.trim().slice(0, 40), o = e.trim() || a || E(i, "seo.photo"), s = t?.trim(), c = n.trim() || "Board";
39
+ function Ye(e, t, n, r, i) {
40
+ let a = r?.trim().slice(0, 40), o = e.trim() || a || k(i, "seo.photo"), s = t?.trim(), c = n.trim() || "Board";
41
41
  return s ? `${o} · ${s} | ${c}` : `${o} | ${c}`;
42
42
  }
43
- function Je(e, t) {
43
+ function Xe(e, t) {
44
44
  let n = [];
45
- return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(E(t, "seo.postDescriptionFallback")), e.categoryLabel?.trim() && n.push(e.categoryLabel.trim()), e.authorName?.trim() && n.push(e.authorName.trim()), n.join(" · ").slice(0, 200);
45
+ return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(k(t, "seo.postDescriptionFallback")), e.categoryLabel?.trim() && n.push(e.categoryLabel.trim()), e.authorName?.trim() && n.push(e.authorName.trim()), n.join(" · ").slice(0, 200);
46
46
  }
47
- function Ye(e, t, n) {
47
+ function Ze(e, t, n) {
48
48
  let r = t.trim() || "Board", i = e?.trim();
49
- return Ue(i, n) ? E(n, "seo.listTitleAll", { site: r }) : E(n, "seo.listTitle", {
49
+ return Ge(i, n) ? k(n, "seo.listTitleAll", { site: r }) : k(n, "seo.listTitle", {
50
50
  name: i,
51
51
  site: r
52
52
  });
53
53
  }
54
- function Xe(e, t) {
54
+ function Qe(e, t) {
55
55
  if (e.description?.trim()) return e.description.trim().slice(0, 200);
56
- let n = e.categoryLabel?.trim(), r = Ue(n, t) ? E(t, "seo.listDescriptionAll") : E(t, "seo.listDescription", { name: n }), i = (e.recentTitles || []).filter(Boolean).slice(0, 3);
56
+ let n = e.categoryLabel?.trim(), r = Ge(n, t) ? k(t, "seo.listDescriptionAll") : k(t, "seo.listDescription", { name: n }), i = (e.recentTitles || []).filter(Boolean).slice(0, 3);
57
57
  return i.length ? `${r} ${i.map((e) => `「${e}」`).join(" ")}`.slice(0, 200) : r.slice(0, 200);
58
58
  }
59
- function Ze(e) {
59
+ function $e(e) {
60
60
  let t = (e || "/board").trim() || "/board";
61
61
  return (t.startsWith("/") ? t : `/${t}`).replace(/\/$/, "") || "/board";
62
62
  }
63
63
  //#endregion
64
64
  //#region src/utils/localizedFields.ts
65
- var Qe = [
65
+ var et = [
66
66
  "label",
67
67
  "description",
68
68
  "title",
69
69
  "summary",
70
70
  "contentHash"
71
71
  ];
72
- function $e(e) {
72
+ function tt(e) {
73
73
  let t = 5381;
74
74
  for (let n = 0; n < e.length; n++) t = (t << 5) + t ^ e.charCodeAt(n);
75
75
  return (t >>> 0).toString(36);
76
76
  }
77
- function et(e, t) {
77
+ function nt(e, t) {
78
78
  let n = e?.[t];
79
79
  return typeof n == "string" ? n.trim() : "";
80
80
  }
@@ -82,7 +82,7 @@ function Q(e) {
82
82
  if (!e || typeof e != "object") return;
83
83
  let t = {};
84
84
  for (let [n, r] of Object.entries(e)) {
85
- let e = O(n);
85
+ let e = M(n);
86
86
  if (!e || !r || typeof r != "object") continue;
87
87
  let i = {};
88
88
  for (let [e, t] of Object.entries(r)) typeof t == "string" && t.trim() && (i[e] = t.trim());
@@ -90,21 +90,21 @@ function Q(e) {
90
90
  }
91
91
  return Object.keys(t).length ? t : void 0;
92
92
  }
93
- function tt(e) {
93
+ function rt(e) {
94
94
  if (!e || typeof e != "object") return;
95
- let t = e, n = {}, r = O(t.locale);
95
+ let t = e, n = {}, r = M(t.locale);
96
96
  r && (n.locale = r);
97
- for (let e of Qe) typeof t[e] == "string" && (n[e] = t[e]);
97
+ for (let e of et) typeof t[e] == "string" && (n[e] = t[e]);
98
98
  return Object.keys(n).length ? n : void 0;
99
99
  }
100
- function nt(e) {
100
+ function it(e) {
101
101
  if (!e || typeof e != "object") return;
102
- let t = e, n = {}, r = O(t.locale);
102
+ let t = e, n = {}, r = M(t.locale);
103
103
  return r && (n.locale = r), typeof t.hash == "string" && t.hash && (n.hash = t.hash), n.locale || n.hash ? n : void 0;
104
104
  }
105
- function rt(e, t, n) {
105
+ function at(e, t, n) {
106
106
  let r = {};
107
- if (n) for (let e of ne) {
107
+ if (n) for (let e of T) {
108
108
  let t = n[e.code];
109
109
  if (!t) continue;
110
110
  let i = {};
@@ -121,58 +121,58 @@ function rt(e, t, n) {
121
121
  ...i
122
122
  }), r;
123
123
  }
124
- function it(e, t) {
125
- return !e || !t.length ? !1 : ne.every((n) => t.every((t) => !!et(e[n.code], t)));
126
- }
127
- function at(e, t, n, r, i) {
128
- if (!w()) return r;
129
- let a = O(t), o = O(i);
130
- if (!a || o && a === o) return r;
131
- let s = et(e?.[a], n);
132
- if (s) return s;
133
- if (a !== "en" && o !== "en") {
134
- let t = et(e?.en, n);
124
+ function ot(e, t) {
125
+ return !e || !t.length ? !1 : T.every((n) => t.every((t) => !!nt(e[n.code], t)));
126
+ }
127
+ function st(e, t, r, i, a) {
128
+ if (!n()) return i;
129
+ let o = M(t), s = M(a);
130
+ if (!o || s && o === s) return i;
131
+ let c = nt(e?.[o], r);
132
+ if (c) return c;
133
+ if (o !== "en" && s !== "en") {
134
+ let t = nt(e?.en, r);
135
135
  if (t) return t;
136
136
  }
137
- return r;
137
+ return i;
138
138
  }
139
- function ot(e, t, n, r, i) {
140
- return r ? !t || t[n] !== r ? r : at(e, i, n, r, t.locale) : "";
139
+ function ct(e, t, n, r, i) {
140
+ return r ? !t || t[n] !== r ? r : st(e, i, n, r, t.locale) : "";
141
141
  }
142
- function st(e, t) {
143
- return ot(e.i18n, e.i18nSource, "title", e.title ?? "", t);
142
+ function lt(e, t) {
143
+ return ct(e.i18n, e.i18nSource, "title", e.title ?? "", t);
144
144
  }
145
- function ct(e, t) {
146
- return ot(e.i18n, e.i18nSource, "summary", e.summary ?? "", t);
145
+ function ut(e, t) {
146
+ return ct(e.i18n, e.i18nSource, "summary", e.summary ?? "", t);
147
147
  }
148
- function lt(e, t) {
148
+ function dt(e, t) {
149
149
  let n = e.content || "", r = e.contentI18nSource?.hash;
150
- return !n || !r || r !== $e(n) ? n : at(e.contentI18n, t, "content", n, e.contentI18nSource?.locale) || n;
150
+ return !n || !r || r !== tt(n) ? n : st(e.contentI18n, t, "content", n, e.contentI18nSource?.locale) || n;
151
151
  }
152
- function ut(e) {
152
+ function ft(e) {
153
153
  let t = e.label.trim(), n = (e.description ?? "").trim();
154
- return !t || !e.i18nSource || e.i18nSource.label !== t || (e.i18nSource.description ?? "") !== n ? !1 : it(e.i18n, n ? ["label", "description"] : ["label"]);
154
+ return !t || !e.i18nSource || e.i18nSource.label !== t || (e.i18nSource.description ?? "") !== n ? !1 : ot(e.i18n, n ? ["label", "description"] : ["label"]);
155
155
  }
156
156
  //#endregion
157
157
  //#region src/composables/fetchPublicSeo.ts
158
- function dt() {
158
+ function pt() {
159
159
  return {
160
160
  db: Z(),
161
- paths: M()
161
+ paths: j()
162
162
  };
163
163
  }
164
- async function ft(e, t, n) {
164
+ async function mt(e, t, n) {
165
165
  try {
166
- let r = await z(l(e.db, e.paths, t));
166
+ let r = await z(w(e.db, e.paths, t));
167
167
  if (!r.exists()) return {
168
168
  label: t,
169
169
  description: "",
170
170
  hidden: !1
171
171
  };
172
- let i = r.data() ?? {}, a = typeof i.label == "string" && i.label.trim() ? i.label.trim() : t, o = typeof i.description == "string" ? i.description.trim() : "", s = Q(i.i18n), c = tt(i.i18nSource);
172
+ let i = r.data() ?? {}, a = typeof i.label == "string" && i.label.trim() ? i.label.trim() : t, o = typeof i.description == "string" ? i.description.trim() : "", s = Q(i.i18n), c = rt(i.i18nSource);
173
173
  return {
174
- label: ot(s, c, "label", a, n) || a,
175
- description: ot(s, c, "description", o, n),
174
+ label: ct(s, c, "label", a, n) || a,
175
+ description: ct(s, c, "description", o, n),
176
176
  hidden: i.visibility === "hidden"
177
177
  };
178
178
  } catch {
@@ -183,7 +183,7 @@ async function ft(e, t, n) {
183
183
  };
184
184
  }
185
185
  }
186
- function pt(e) {
186
+ function ht(e) {
187
187
  if (e && typeof e == "object" && "toDate" in e) try {
188
188
  let t = e.toDate();
189
189
  return t instanceof Date ? t.toISOString() : null;
@@ -192,17 +192,17 @@ function pt(e) {
192
192
  }
193
193
  return null;
194
194
  }
195
- async function mt(e, t, n, r) {
195
+ async function gt(e, t, n, r) {
196
196
  let i = e.trim(), a = t.trim();
197
197
  if (!i || !a) return null;
198
- let o = n ?? dt();
199
- o.paths = u(o.paths), r && await le(r);
200
- let c = await ft(o, i, r);
198
+ let s = n ?? pt();
199
+ s.paths = C(s.paths), r && await ce(r);
200
+ let c = await mt(s, i, r);
201
201
  if (c.hidden) return null;
202
202
  try {
203
- let e = (await B(G(s(o.db, o.paths), X("boardId", "==", i), X("slug", "==", a), X("listed", "==", !0), X("isPublished", "==", !0), H(1)))).docs[0];
203
+ let e = (await B(G(o(s.db, s.paths), X("boardId", "==", i), X("slug", "==", a), X("listed", "==", !0), X("isPublished", "==", !0), H(1)))).docs[0];
204
204
  if (!e) return null;
205
- let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "", l = typeof t.summary == "string" ? t.summary : "", u = Q(t.i18n), d = tt(t.i18nSource), f = st({
205
+ let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "", l = typeof t.summary == "string" ? t.summary : "", u = Q(t.i18n), d = rt(t.i18nSource), f = lt({
206
206
  title: n,
207
207
  i18n: u,
208
208
  i18nSource: d
@@ -213,24 +213,24 @@ async function mt(e, t, n, r) {
213
213
  category: i,
214
214
  categoryLabel: c.label,
215
215
  title: f,
216
- summary: ct({
216
+ summary: ut({
217
217
  summary: l,
218
218
  i18n: u,
219
219
  i18nSource: d
220
220
  }, r).trim().slice(0, 200),
221
- previewImage: Ge(t.previewImage),
221
+ previewImage: qe(t.previewImage),
222
222
  authorName: typeof t.authorName == "string" && t.authorName.trim() ? t.authorName.trim() : null,
223
- createdAt: pt(t.createdAt)
223
+ createdAt: ht(t.createdAt)
224
224
  } : null;
225
225
  } catch (e) {
226
226
  return import.meta.dev && console.warn("[memi-board] fetchPublicPostForSeo failed", e), null;
227
227
  }
228
228
  }
229
- async function ht(e, t, n) {
230
- n && await le(n);
231
- let r = e?.trim() || null, i = t ?? dt();
232
- if (i.paths = u(i.paths), r) {
233
- let e = await ft(i, r, n);
229
+ async function _t(e, t, n) {
230
+ n && await ce(n);
231
+ let r = e?.trim() || null, i = t ?? pt();
232
+ if (i.paths = C(i.paths), r) {
233
+ let e = await mt(i, r, n);
234
234
  if (e.hidden) return {
235
235
  kind: "category",
236
236
  category: r,
@@ -239,12 +239,12 @@ async function ht(e, t, n) {
239
239
  ogImage: null,
240
240
  recentTitles: []
241
241
  };
242
- let { recentTitles: t, ogImage: a } = await gt(i, r, n);
242
+ let { recentTitles: t, ogImage: a } = await vt(i, r, n);
243
243
  return {
244
244
  kind: "category",
245
245
  category: r,
246
246
  categoryLabel: e.label,
247
- description: e.description || E(n, "seo.boardDescription", { name: e.label }),
247
+ description: e.description || k(n, "seo.boardDescription", { name: e.label }),
248
248
  ogImage: a,
249
249
  recentTitles: t
250
250
  };
@@ -252,23 +252,23 @@ async function ht(e, t, n) {
252
252
  return {
253
253
  kind: "all",
254
254
  category: null,
255
- categoryLabel: E(n, "seo.allCategory"),
256
- description: E(n, "seo.allDescription"),
255
+ categoryLabel: k(n, "seo.allCategory"),
256
+ description: k(n, "seo.allDescription"),
257
257
  ogImage: null,
258
258
  recentTitles: []
259
259
  };
260
260
  }
261
- async function gt(e, t, n) {
261
+ async function vt(e, t, n) {
262
262
  let r = [], i = null;
263
263
  try {
264
- let a = await B(G(s(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), W("createdAt", "desc"), H(12)));
264
+ let a = await B(G(o(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), W("createdAt", "desc"), H(12)));
265
265
  for (let e of a.docs) {
266
- let t = e.data() ?? {}, a = st({
266
+ let t = e.data() ?? {}, a = lt({
267
267
  title: typeof t.title == "string" ? t.title : "",
268
268
  i18n: Q(t.i18n),
269
- i18nSource: tt(t.i18nSource)
269
+ i18nSource: rt(t.i18nSource)
270
270
  }, n).trim();
271
- a && r.length < 5 && r.push(a), i ||= Ge(t.previewImage);
271
+ a && r.length < 5 && r.push(a), i ||= qe(t.previewImage);
272
272
  }
273
273
  } catch (e) {
274
274
  import.meta.dev && console.warn("[memi-board] loadRecentListed failed", e);
@@ -280,31 +280,31 @@ async function gt(e, t, n) {
280
280
  }
281
281
  //#endregion
282
282
  //#region src/utils/boardAccess.ts
283
- function _t(e, t) {
283
+ function yt(e, t) {
284
284
  return !e || !t ? !1 : [...t.allowedStaffUids ?? [], ...t.allowedManagerUids ?? []].includes(e);
285
285
  }
286
- function vt(e, t, n, r) {
287
- return e ? t ? !0 : n ? _t(e, r) : !1 : !1;
286
+ function bt(e, t, n, r) {
287
+ return e ? t ? !0 : n ? yt(e, r) : !1 : !1;
288
288
  }
289
- function yt(e, t, n, r) {
289
+ function xt(e, t, n, r) {
290
290
  if (!e) return !1;
291
- if (r?.visibility === "hidden") return vt(e, t, n, r);
291
+ if (r?.visibility === "hidden") return bt(e, t, n, r);
292
292
  let i = r?.commentWriteRole ?? "user";
293
- return i === "admin" ? t : i !== "staff" || vt(e, t, n, r);
293
+ return i === "admin" ? t : i !== "staff" || bt(e, t, n, r);
294
294
  }
295
295
  //#endregion
296
296
  //#region src/composables/boardLookup.ts
297
- var bt;
298
- function xt(e) {
299
- bt = e;
297
+ var St;
298
+ function Ct(e) {
299
+ St = e;
300
300
  }
301
- function St(e) {
302
- return bt?.(e);
301
+ function wt(e) {
302
+ return St?.(e);
303
303
  }
304
304
  //#endregion
305
305
  //#region src/utils/moderation-strike.ts
306
- var Ct = 10, wt = 864e5;
307
- function Tt(e, t, n = Date.now(), r = wt) {
306
+ var Tt = 10, Et = 864e5;
307
+ function Dt(e, t, n = Date.now(), r = Et) {
308
308
  let i = Math.max(0, Math.floor(Number(e) || 0));
309
309
  if (i <= 0) return 0;
310
310
  let a = typeof t == "number" && Number.isFinite(t) ? t : null;
@@ -312,7 +312,7 @@ function Tt(e, t, n = Date.now(), r = wt) {
312
312
  let o = Math.floor((n - a) / r);
313
313
  return Math.max(0, i - o);
314
314
  }
315
- function Et(e, t, n = Date.now(), r = 10, i = wt) {
315
+ function Ot(e, t, n = Date.now(), r = 10, i = Et) {
316
316
  let a = Math.max(0, Math.floor(Number(e) || 0));
317
317
  if (a < r) return null;
318
318
  let o = typeof t == "number" && Number.isFinite(t) ? t : null;
@@ -320,20 +320,20 @@ function Et(e, t, n = Date.now(), r = 10, i = wt) {
320
320
  let s = o + (a - (r - 1)) * i;
321
321
  return s > n ? s : null;
322
322
  }
323
- function Dt(e, t, n = Date.now(), r = 10, i = wt) {
324
- return Et(e, t, n, r, i) != null;
323
+ function kt(e, t, n = Date.now(), r = 10, i = Et) {
324
+ return Ot(e, t, n, r, i) != null;
325
325
  }
326
- function Ot(e, t = Date.now(), n) {
326
+ function At(e, t = Date.now(), n) {
327
327
  let r = Math.max(0, e - t), i = Math.ceil(r / 36e5);
328
- if (i <= 0) return E(n, "moderationStrike.liftSoon");
329
- if (i < 24) return E(n, "moderationStrike.liftInHours", { hours: i });
328
+ if (i <= 0) return k(n, "moderationStrike.liftSoon");
329
+ if (i < 24) return k(n, "moderationStrike.liftInHours", { hours: i });
330
330
  let a = Math.floor(i / 24), o = i % 24;
331
- return o === 0 ? E(n, "moderationStrike.liftInDays", { days: a }) : E(n, "moderationStrike.liftInDaysHours", {
331
+ return o === 0 ? k(n, "moderationStrike.liftInDays", { days: a }) : k(n, "moderationStrike.liftInDaysHours", {
332
332
  days: a,
333
333
  hours: o
334
334
  });
335
335
  }
336
- function kt(e) {
336
+ function jt(e) {
337
337
  if (e == null) return null;
338
338
  if (typeof e == "number" && Number.isFinite(e)) return e;
339
339
  if (typeof e == "object" && e && "toMillis" in e && typeof e.toMillis == "function") return e.toMillis();
@@ -345,45 +345,45 @@ function kt(e) {
345
345
  }
346
346
  //#endregion
347
347
  //#region src/composables/useMemiBoardAuth.ts
348
- var At = "__MEMI_BOARD_AUTH_STATE__";
349
- function jt() {
348
+ var Mt = "__MEMI_BOARD_AUTH_STATE__";
349
+ function Nt() {
350
350
  let e = globalThis;
351
- return e[At] || (e[At] = {
351
+ return e[Mt] || (e[Mt] = {
352
352
  role: F("user"),
353
353
  rolePending: F(!0),
354
354
  rawBlockCount: F(0),
355
355
  blockAtMs: F(null),
356
356
  watchStarted: !1
357
- }), e[At];
357
+ }), e[Mt];
358
358
  }
359
- function Mt() {
360
- let e = _(), { t, locale: n } = k(), r = jt(), i = Z(), a = De(), o = we(), { role: s, rolePending: c, rawBlockCount: l, blockAtMs: u } = r;
361
- function d() {
359
+ function Pt() {
360
+ let e = v(), { t, locale: n } = A(), r = Nt(), i = Z(), o = ke(), s = Ee(), { role: c, rolePending: l, rawBlockCount: u, blockAtMs: d } = r;
361
+ function f() {
362
362
  let t = e.moderation?.blockBanThreshold;
363
363
  return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
364
364
  }
365
365
  function p() {
366
366
  let t = e.moderation?.blockBanDecayMs;
367
- return typeof t == "number" && t > 0 ? t : wt;
367
+ return typeof t == "number" && t > 0 ? t : Et;
368
368
  }
369
369
  function m(e) {
370
- return A(i, M(), e);
370
+ return h(i, j(), e);
371
371
  }
372
- function h(e) {
373
- if (s.value = [
372
+ function g(e) {
373
+ if (c.value = [
374
374
  "owner",
375
375
  "admin",
376
376
  "manager",
377
377
  "staff",
378
378
  "user"
379
379
  ].includes(String(e?.role)) ? e?.role : "user", !e) {
380
- l.value = 0, u.value = null;
380
+ u.value = 0, d.value = null;
381
381
  return;
382
382
  }
383
- l.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), u.value = kt(e.moderationBlockAt);
383
+ u.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), d.value = jt(e.moderationBlockAt);
384
384
  }
385
- async function g(e) {
386
- let t = m(e.uid), n = f(i, M(), e.uid), r = await z(t);
385
+ async function _(e) {
386
+ let t = m(e.uid), n = a(i, j(), e.uid), r = await z(t);
387
387
  if (!r.exists()) return await Promise.all([q(t, {
388
388
  role: "user",
389
389
  displayName: e.displayName,
@@ -391,58 +391,58 @@ function Mt() {
391
391
  joinedAt: K(),
392
392
  lastVisitAt: K(),
393
393
  updatedAt: K()
394
- }), q(n, { email: e.email })]), h({ moderationBlockCount: 0 }), "user";
395
- let a = r.data();
396
- h(a);
397
- let o = typeof a.displayName == "string" && a.displayName.trim(), s = typeof a.photoURL == "string" && a.photoURL.trim(), c = {
394
+ }), q(n, { email: e.email })]), g({ moderationBlockCount: 0 }), "user";
395
+ let o = r.data();
396
+ g(o);
397
+ let s = typeof o.displayName == "string" && o.displayName.trim(), c = typeof o.photoURL == "string" && o.photoURL.trim(), l = {
398
398
  lastVisitAt: K(),
399
399
  updatedAt: K()
400
400
  };
401
- return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([Y(t, c), q(n, { email: e.email }, { merge: !0 })]), [
401
+ return !s && e.displayName && (l.displayName = e.displayName), !c && e.photoURL && (l.photoURL = e.photoURL), await Promise.all([Y(t, l), q(n, { email: e.email }, { merge: !0 })]), [
402
402
  "owner",
403
403
  "admin",
404
404
  "manager",
405
405
  "staff",
406
406
  "user"
407
- ].includes(String(a.role)) ? a.role : "user";
407
+ ].includes(String(o.role)) ? o.role : "user";
408
408
  }
409
- async function v() {
410
- let e = o.value?.uid;
409
+ async function y() {
410
+ let e = s.value?.uid;
411
411
  if (!e) {
412
- h(void 0);
412
+ g(void 0);
413
413
  return;
414
414
  }
415
415
  let t = await z(m(e));
416
- h(t.exists() ? t.data() : void 0);
416
+ g(t.exists() ? t.data() : void 0);
417
417
  }
418
- r.watchStarted || (r.watchStarted = !0, L(o, async (e) => {
419
- if (c.value = !0, !e) {
420
- s.value = "user", h(void 0), c.value = !1;
418
+ r.watchStarted || (r.watchStarted = !0, L(s, async (e) => {
419
+ if (l.value = !0, !e) {
420
+ c.value = "user", g(void 0), l.value = !1;
421
421
  return;
422
422
  }
423
423
  try {
424
- s.value = await g(e);
424
+ c.value = await _(e);
425
425
  } catch (e) {
426
- console.error("[memi-board] ensureUserDoc failed", e), s.value = "user", h(void 0);
426
+ console.error("[memi-board] ensureUserDoc failed", e), c.value = "user", g(void 0);
427
427
  } finally {
428
- c.value = !1;
428
+ l.value = !1;
429
429
  }
430
430
  }, { immediate: !0 }));
431
- let y = N(() => !!o.value), b = N(() => s.value === "owner"), x = N(() => s.value === "manager"), S = N(() => b.value || s.value === "admin"), C = N(() => x.value || s.value === "staff"), w = N(() => S.value || C.value), T = N(() => Tt(l.value, u.value, Date.now(), p())), E = N(() => {
432
- let e = d();
433
- return e <= 0 ? !1 : Dt(l.value, u.value, Date.now(), e, p());
434
- }), D = N(() => {
435
- let e = d();
431
+ let b = N(() => !!s.value), x = N(() => c.value === "owner"), S = N(() => c.value === "manager"), C = N(() => x.value || c.value === "admin"), w = N(() => S.value || c.value === "staff"), T = N(() => C.value || w.value), E = N(() => Dt(u.value, d.value, Date.now(), p())), D = N(() => {
432
+ let e = f();
433
+ return e <= 0 ? !1 : kt(u.value, d.value, Date.now(), e, p());
434
+ }), ee = N(() => {
435
+ let e = f();
436
436
  if (e <= 0) return null;
437
- let t = Et(l.value, u.value, Date.now(), e, p());
438
- return t == null ? null : Ot(t, Date.now(), n.value);
439
- }), O = N(() => {
440
- if (!E.value) return null;
441
- let e = D.value;
437
+ let t = Ot(u.value, d.value, Date.now(), e, p());
438
+ return t == null ? null : At(t, Date.now(), n.value);
439
+ }), te = N(() => {
440
+ if (!D.value) return null;
441
+ let e = ee.value;
442
442
  return e ? t("auth.writeRestrictedUntil", { until: e }) : t("auth.writeRestricted");
443
443
  });
444
- async function ee() {
445
- let e = o.value?.uid, r = d();
444
+ async function ne() {
445
+ let e = s.value?.uid, r = f();
446
446
  if (!e || r <= 0) return {
447
447
  effectiveCount: 0,
448
448
  restricted: !1,
@@ -455,125 +455,125 @@ function Mt() {
455
455
  updatedAt: K()
456
456
  }) : await q(i, {
457
457
  role: "user",
458
- displayName: o.value?.displayName ?? null,
458
+ displayName: s.value?.displayName ?? null,
459
459
  moderationBlockCount: 1,
460
460
  moderationBlockAt: K(),
461
461
  updatedAt: K()
462
462
  });
463
- let s = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, c = Date.now();
464
- l.value = s, u.value = c;
465
- let f = Tt(s, c, c, p()), h = Dt(s, c, c, r, p()), g = t("auth.strikeSuffix", {
466
- count: f,
463
+ let o = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, c = Date.now();
464
+ u.value = o, d.value = c;
465
+ let l = Dt(o, c, c, p()), h = kt(o, c, c, r, p()), g = t("auth.strikeSuffix", {
466
+ count: l,
467
467
  threshold: r
468
468
  });
469
469
  if (h) {
470
- let e = Et(s, c, c, r, p()), i = e == null ? null : Ot(e, c, n.value);
470
+ let e = Ot(o, c, c, r, p()), i = e == null ? null : At(e, c, n.value);
471
471
  g = i ? t("auth.strikeRestrictedUntil", {
472
- count: f,
472
+ count: l,
473
473
  until: i
474
- }) : t("auth.strikeRestricted", { count: f });
474
+ }) : t("auth.strikeRestricted", { count: l });
475
475
  }
476
476
  return {
477
- effectiveCount: f,
477
+ effectiveCount: l,
478
478
  restricted: h,
479
479
  messageSuffix: g
480
480
  };
481
481
  }
482
- function j() {
483
- if (!a) throw Error(t("auth.notInitialized"));
484
- return a;
485
- }
486
- async function te() {
487
- return Me(j(), new Oe());
482
+ function O() {
483
+ if (!o) throw Error(t("auth.notInitialized"));
484
+ return o;
488
485
  }
489
- async function ne() {
490
- let e = new ke("apple.com");
491
- return e.addScope("email"), e.addScope("name"), Me(j(), e);
486
+ async function re() {
487
+ return Pe(O(), new Ae());
492
488
  }
493
- async function re(e, t) {
494
- return je(j(), e, t);
489
+ async function ie() {
490
+ let e = new je("apple.com");
491
+ return e.addScope("email"), e.addScope("name"), Pe(O(), e);
495
492
  }
496
- async function ie(e, t, n) {
497
- let r = await Ae(j(), e, t);
498
- return n && await Pe(r.user, { displayName: n }), r;
493
+ async function ae(e, t) {
494
+ return Ne(O(), e, t);
499
495
  }
500
- async function ae() {
501
- await Ne(j());
496
+ async function oe(e, t, n) {
497
+ let r = await Me(O(), e, t);
498
+ return n && await Ie(r.user, { displayName: n }), r;
502
499
  }
503
- function oe(e) {
504
- return vt(o.value?.uid, S.value, C.value, e ? St(e) : void 0);
500
+ async function k() {
501
+ await Fe(O());
505
502
  }
506
503
  function se(e) {
507
- return o.value ? S.value ? !0 : x.value && !!e && (St(e)?.allowedManagerUids ?? []).includes(o.value.uid) : !1;
504
+ return bt(s.value?.uid, C.value, w.value, e ? wt(e) : void 0);
508
505
  }
509
506
  function ce(e) {
510
- return y.value && (o.value?.uid === e.authorUid || oe(e.boardId));
507
+ return s.value ? C.value ? !0 : S.value && !!e && (wt(e)?.allowedManagerUids ?? []).includes(s.value.uid) : !1;
511
508
  }
512
509
  function le(e) {
513
- return y.value && o.value?.uid === e.authorUid;
510
+ return b.value && (s.value?.uid === e.authorUid || se(e.boardId));
514
511
  }
515
512
  function ue(e) {
516
- return y.value && (o.value?.uid === e.authorUid || oe(e.boardId));
513
+ return b.value && s.value?.uid === e.authorUid;
514
+ }
515
+ function de(e) {
516
+ return b.value && (s.value?.uid === e.authorUid || se(e.boardId));
517
517
  }
518
518
  return {
519
- user: o,
520
- role: s,
521
- isOwner: b,
522
- isManager: x,
523
- canConfigureBoard: se,
524
- isSignedIn: y,
525
- isAdmin: S,
526
- isStaff: C,
527
- canManageContent: w,
528
- canManageBoard: oe,
529
- rolePending: c,
530
- moderationBlockCount: T,
531
- isWriteRestricted: E,
532
- restrictedUntilLabel: D,
533
- restrictedMessage: O,
534
- signInWithGoogle: te,
535
- signInWithApple: ne,
536
- signInWithEmail: re,
537
- signUpWithEmail: ie,
538
- signOut: ae,
539
- canEdit: ce,
540
- canDelete: ce,
541
- canEditComment: le,
542
- canDeleteComment: ue,
543
- recordContentModerationBlock: ee,
544
- refreshBoardUser: v
519
+ user: s,
520
+ role: c,
521
+ isOwner: x,
522
+ isManager: S,
523
+ canConfigureBoard: ce,
524
+ isSignedIn: b,
525
+ isAdmin: C,
526
+ isStaff: w,
527
+ canManageContent: T,
528
+ canManageBoard: se,
529
+ rolePending: l,
530
+ moderationBlockCount: E,
531
+ isWriteRestricted: D,
532
+ restrictedUntilLabel: ee,
533
+ restrictedMessage: te,
534
+ signInWithGoogle: re,
535
+ signInWithApple: ie,
536
+ signInWithEmail: ae,
537
+ signUpWithEmail: oe,
538
+ signOut: k,
539
+ canEdit: le,
540
+ canDelete: le,
541
+ canEditComment: ue,
542
+ canDeleteComment: de,
543
+ recordContentModerationBlock: ne,
544
+ refreshBoardUser: y
545
545
  };
546
546
  }
547
547
  //#endregion
548
548
  //#region src/utils/imeSafeSubmit.ts
549
- var Nt = /* @__PURE__ */ new WeakMap();
550
- function Pt(e) {
549
+ var Ft = /* @__PURE__ */ new WeakMap();
550
+ function It(e) {
551
551
  let t = e.currentTarget;
552
552
  return t instanceof HTMLButtonElement ? t : t instanceof Element ? t.closest("button") : null;
553
553
  }
554
- function Ft(e) {
554
+ function Lt(e) {
555
555
  if (e.pointerType !== "mouse" || e.button !== 0) return;
556
- let t = Pt(e), n = t?.form;
556
+ let t = It(e), n = t?.form;
557
557
  if (!t || !n || t.disabled) return;
558
- Nt.set(t, Date.now() + 1e3);
558
+ Ft.set(t, Date.now() + 1e3);
559
559
  let r = document.activeElement;
560
560
  r instanceof HTMLElement && r.blur(), setTimeout(() => n.requestSubmit(t), 0);
561
561
  }
562
- function It(e) {
563
- let t = Pt(e);
562
+ function Rt(e) {
563
+ let t = It(e);
564
564
  if (!t) return;
565
- let n = Nt.get(t);
566
- n && Date.now() < n && (e.preventDefault(), Nt.delete(t));
565
+ let n = Ft.get(t);
566
+ n && Date.now() < n && (e.preventDefault(), Ft.delete(t));
567
567
  }
568
568
  //#endregion
569
569
  //#region src/utils/findReadablePost.ts
570
- async function Lt(e, t, n, r, i, a) {
571
- let o = [X("boardId", "==", n), X("slug", "==", r)];
572
- return a ? (await B(G(s(e, t), ...o, H(1)))).docs[0] : (await Promise.all([B(G(s(e, t), ...o, X("listed", "==", !0), X("isPublished", "==", !0), H(1))), ...i ? [B(G(s(e, t), ...o, X("authorUid", "==", i), H(1)))] : []])).flatMap((e) => e.docs)[0];
570
+ async function zt(e, t, n, r, i, a) {
571
+ let s = [X("boardId", "==", n), X("slug", "==", r)];
572
+ return a ? (await B(G(o(e, t), ...s, H(1)))).docs[0] : (await Promise.all([B(G(o(e, t), ...s, X("listed", "==", !0), X("isPublished", "==", !0), H(1))), ...i ? [B(G(o(e, t), ...s, X("authorUid", "==", i), H(1)))] : []])).flatMap((e) => e.docs)[0];
573
573
  }
574
574
  //#endregion
575
575
  //#region src/utils/extractEditorImageUrls.ts
576
- function Rt(e) {
576
+ function Bt(e) {
577
577
  if (!e) return [];
578
578
  let t = /* @__PURE__ */ new Set();
579
579
  for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&amp;", "&"));
@@ -582,7 +582,7 @@ function Rt(e) {
582
582
  }
583
583
  //#endregion
584
584
  //#region src/utils/storagePath.ts
585
- function zt(e) {
585
+ function Vt(e) {
586
586
  try {
587
587
  let t = new URL(e), n = t.hostname.toLowerCase();
588
588
  if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
@@ -592,106 +592,107 @@ function zt(e) {
592
592
  return null;
593
593
  }
594
594
  }
595
- function Bt(e) {
595
+ function Ht(e) {
596
596
  return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
597
597
  }
598
598
  //#endregion
599
599
  //#region src/utils/deletePostCascade.ts
600
- async function Vt(e) {
600
+ async function Ut(e) {
601
601
  try {
602
- let t = await Le(e);
603
- await Promise.all([...t.items.map((e) => Fe(e).catch(() => {})), ...t.prefixes.map((e) => Vt(e))]);
602
+ let t = await ze(e);
603
+ await Promise.all([...t.items.map((e) => Le(e).catch(() => {})), ...t.prefixes.map((e) => Ut(e))]);
604
604
  } catch {}
605
605
  }
606
- async function Ht(e, t) {
607
- await Vt(Re(e, `${t}/images`)), await Vt(Re(e, `${t}/attachments`));
606
+ async function Wt(e, t) {
607
+ await Ut(Be(e, `${t}/images`)), await Ut(Be(e, `${t}/attachments`)), await Ut(Be(e, `${t}/comment-images`));
608
608
  }
609
- async function Ut(e, t) {
609
+ var Gt = 450;
610
+ async function Kt(e, t, n) {
611
+ return (await B(G(g(e, t), X("postId", "==", n)))).docs.flatMap((e) => de(e.data().images, `${x(t, n)}/comment-images/`));
612
+ }
613
+ async function qt(e, t) {
610
614
  let n = [...new Set([...t].filter(Boolean))];
611
- await Promise.all(n.map((t) => Fe(Re(e, t)).catch(() => {})));
615
+ await Promise.all(n.map((t) => Le(Be(e, t)).catch(() => {})));
612
616
  }
613
- var Wt = 450;
614
- async function Gt(e, t) {
617
+ async function Jt(e, t) {
615
618
  let n = await B(t);
616
- for (let t = 0; t < n.docs.length; t += Wt) {
617
- let r = Se(e);
618
- n.docs.slice(t, t + Wt).forEach((e) => r.delete(e.ref)), await r.commit();
619
+ for (let t = 0; t < n.docs.length; t += Gt) {
620
+ let r = we(e);
621
+ n.docs.slice(t, t + Gt).forEach((e) => r.delete(e.ref)), await r.commit();
619
622
  }
620
623
  }
621
- async function Kt(e, t, n) {
622
- await Gt(e, G(g(e, t), X("postId", "==", n)));
623
- }
624
- async function qt(e, t, n) {
625
- await Gt(e, G(g(e, t), X("commentId", "==", n), X("target", "==", "comment")));
626
- }
627
- async function Jt(e, n, r, i) {
628
- let o = t(e, r, i), s = pe(e, r, i), [c, l] = await Promise.all([z(o), z(s)]);
629
- if (!c.exists()) return;
630
- let u = c.data(), d = l.exists() ? String(l.data().content ?? "") : "";
631
- await Gt(e, G(a(e, r), X("postId", "==", i))), await Kt(e, r, i);
632
- let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
633
- for (let e of u.attachments ?? []) {
624
+ async function Yt(e, t, n) {
625
+ await Jt(e, G(b(e, t), X("postId", "==", n)));
626
+ }
627
+ async function Xt(e, t, n) {
628
+ await Jt(e, G(b(e, t), X("commentId", "==", n), X("target", "==", "comment")));
629
+ }
630
+ async function Zt(e, t, n, r) {
631
+ let i = y(e, n, r), a = s(e, n, r), [o, c] = await Promise.all([z(i), z(a)]);
632
+ if (!o.exists()) return;
633
+ let l = o.data(), u = c.exists() ? String(c.data().content ?? "") : "", d = await Kt(e, n, r), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
634
+ for (let e of l.attachments ?? []) {
634
635
  if (!e?.path) continue;
635
636
  f.add(e.path);
636
- let t = Bt(e.path);
637
- t && t !== i && p.add(t);
637
+ let t = Ht(e.path);
638
+ t && t !== r && p.add(t);
638
639
  }
639
- for (let e of Rt(d)) {
640
- let t = zt(e);
640
+ for (let e of Bt(u)) {
641
+ let t = Vt(e);
641
642
  if (!t) continue;
642
643
  f.add(t);
643
644
  let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
644
645
  n !== t && n.includes("/images/thumbnails/") && f.add(n);
645
- let r = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
646
- r && !t.includes("/thumbnails/") && f.add(`${r[1]}thumbnails/${r[2]}.jpg`);
647
- let a = Bt(t);
648
- a && a !== i && p.add(a);
646
+ let i = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
647
+ i && !t.includes("/thumbnails/") && f.add(`${i[1]}thumbnails/${i[2]}.jpg`);
648
+ let a = Ht(t);
649
+ a && a !== r && p.add(a);
649
650
  }
650
- await he(s), await Ht(n, b(r, i));
651
- for (let e of p) await Ht(n, b(r, e));
652
- await Ut(n, f), await he(o);
651
+ await Wt(t, x(n, r));
652
+ for (let e of p) await Wt(t, x(n, e));
653
+ await qt(t, d), await qt(t, f), await Jt(e, G(g(e, n), X("postId", "==", r))), await Yt(e, n, r), await _e(a), await _e(i);
653
654
  }
654
655
  //#endregion
655
656
  //#region src/utils/postBody.ts
656
- function Yt(e) {
657
+ function Qt(e) {
657
658
  return String(e || "").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<img\b[^>]*>/gi, " ").replace(/<iframe\b[^>]*>[\s\S]*?<\/iframe>/gi, " ").replace(/<video\b[\s\S]*?<\/video>/gi, " ").replace(/<audio\b[\s\S]*?<\/audio>/gi, " ").replace(/<[^>]+>/g, " ").replace(/&nbsp;/gi, " ").replace(/&#160;/g, " ").replace(/&[a-z]+;/gi, " ").replace(/&#\d+;/g, " ").replace(/[\u200B-\u200D\uFEFF\u00AD]/g, "").replace(/\s+/g, " ").trim();
658
659
  }
659
- function Xt(e, t = 40) {
660
- let n = Yt(e);
660
+ function $t(e, t = 40) {
661
+ let n = Qt(e);
661
662
  if (!n) return "";
662
663
  if (n.length <= t) return n;
663
664
  let r = n.slice(0, t), i = r.lastIndexOf(" ");
664
665
  return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
665
666
  }
666
- function Zt(e) {
667
- return Yt(e).length > 0;
667
+ function en(e) {
668
+ return Qt(e).length > 0;
668
669
  }
669
- function Qt(e, t) {
670
+ function tn(e, t) {
670
671
  return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
671
672
  }
672
- function $t(e) {
673
- return !Zt(e);
673
+ function nn(e) {
674
+ return !en(e);
674
675
  }
675
676
  //#endregion
676
677
  //#region src/utils/postPreview.ts
677
- function en(e) {
678
+ function rn(e) {
678
679
  return e.replace(/&amp;/g, "&").replace(/&quot;/g, "\"").replace(/&#39;/g, "'");
679
680
  }
680
- function tn(e) {
681
+ function an(e) {
681
682
  if (e) try {
682
- let t = new URL(en(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
683
+ let t = new URL(rn(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
683
684
  if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
684
685
  if (n.endsWith("youtube.com") || n === "youtube-nocookie.com") return t.pathname.startsWith("/embed/") || t.pathname.startsWith("/shorts/") ? t.pathname.split("/")[2] : t.searchParams.get("v") || void 0;
685
686
  } catch {
686
687
  return;
687
688
  }
688
689
  }
689
- function nn(e) {
690
- let t = tn(e.videoUrl);
690
+ function on(e) {
691
+ let t = an(e.videoUrl);
691
692
  return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
692
693
  }
693
- function rn(e, t = []) {
694
- let n = e.match(/<img\b[^>]*\bsrc=["']([^"']+)["']/i), r = e.match(/<iframe\b[^>]*\bsrc=["']([^"']+)["']/i), i = t.find((e) => e.type.startsWith("image/"))?.url, a = t.find((e) => e.type.startsWith("video/"))?.url, o = r ? en(r[1]) : a, s = o ? tn(o) : void 0, c = n ? en(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
694
+ function sn(e, t = []) {
695
+ let n = e.match(/<img\b[^>]*\bsrc=["']([^"']+)["']/i), r = e.match(/<iframe\b[^>]*\bsrc=["']([^"']+)["']/i), i = t.find((e) => e.type.startsWith("image/"))?.url, a = t.find((e) => e.type.startsWith("video/"))?.url, o = r ? rn(r[1]) : a, s = o ? an(o) : void 0, c = n ? rn(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
695
696
  return {
696
697
  summary: e.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|li|h[1-6]|blockquote)>/gi, "\n").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/[^\S\n]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{2,}/g, "\n").trim().slice(0, 160),
697
698
  ...c ? { previewImage: c } : {},
@@ -700,33 +701,33 @@ function rn(e, t = []) {
700
701
  }
701
702
  //#endregion
702
703
  //#region src/utils/saveBoardVisibility.ts
703
- function an(e) {
704
+ function cn(e) {
704
705
  return e === "hidden" ? "hidden" : "public";
705
706
  }
706
- async function on(e, t, n, r) {
707
+ async function ln(e, t, n, r) {
707
708
  let i;
708
709
  for (;;) {
709
710
  let a = await B(G(t, X("boardId", "==", n), W("__name__"), ...i ? [J(i)] : [], H(400)));
710
711
  if (a.empty) break;
711
- let o = Se(e), s = 0;
712
+ let o = we(e), s = 0;
712
713
  for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
713
714
  if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
714
715
  }
715
716
  }
716
- async function sn(e, t, n, r) {
717
- await on(e, s(e, t), n, r), await on(e, a(e, t), n, r);
717
+ async function un(e, t, n, r) {
718
+ await ln(e, o(e, t), n, r), await ln(e, g(e, t), n, r);
718
719
  }
719
- async function cn(e, t, n, r) {
720
- let i = l(e, t, n), a = an(r.visibility);
721
- await xe(e, async (e) => {
720
+ async function dn(e, t, n, r) {
721
+ let i = w(e, t, n), a = cn(r.visibility);
722
+ await Ce(e, async (e) => {
722
723
  let t = await e.get(i), n = t.data(), o = n?.visibilityTransition || "";
723
724
  if (o && o !== a) throw Error("Finish the pending visibility change before changing it again.");
724
- return !t.exists() || !o && an(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
725
+ return !t.exists() || !o && cn(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
725
726
  ...r,
726
- visibility: a === "public" ? "public" : an(n?.visibility),
727
+ visibility: a === "public" ? "public" : cn(n?.visibility),
727
728
  visibilityTransition: a
728
729
  }, { merge: !0 }), !0);
729
- }) && (await sn(e, t, n, a !== "hidden"), await xe(e, async (e) => {
730
+ }) && (await un(e, t, n, a !== "hidden"), await Ce(e, async (e) => {
730
731
  if ((await e.get(i)).data()?.visibilityTransition !== a) throw Error("The visibility transition changed. Reload and retry.");
731
732
  e.update(i, {
732
733
  visibility: a,
@@ -737,7 +738,7 @@ async function cn(e, t, n, r) {
737
738
  }
738
739
  //#endregion
739
740
  //#region src/utils/moderation-prompt.ts
740
- var ln = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\n아래 텍스트에 욕설·비속어·성희롱·혐오·위협·스팸·도배성 광고가 있으면 반드시 거부(flagged=true)합니다.\n\nflagged=true 예:\n- 욕설/비속어: 씨발, 시발, 병신, 지랄, 좆, 개새끼, 존나, fuck, shit, bitch 등\n- 성적 모욕, 혐오 발언, 협박\n- 게시판 주제와 무관한 도배성 광고/스팸\n\nflagged=false:\n- 게시판 주제에 맞는 정상적인 글/댓글 (강한 의견이나 정당한 비판은 허용)\n\nJSON만 출력:\n{\"flagged\":boolean,\"category\":\"none\"|\"abuse\"|\"spam\"|\"adult\"|\"violence\"|\"other\",\"reason\":string}\n- flagged=true면 category를 고르고, reason은 한국어로 **무엇이 문제인지** 구체적으로 1문장\n (예: \"욕설(비속어)이 포함되어 게시할 수 없습니다.\", \"광고·스팸성 문구가 있어 게시할 수 없습니다.\")\n 욕설 단어 전체를 그대로 길게 인용하지 말고, 유형(욕설/혐오/스팸 등)을 분명히 밝힌다.\n- flagged=false면 category는 \"none\", reason은 \"\"", un = {
741
+ var fn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\n아래 텍스트에 욕설·비속어·성희롱·혐오·위협·스팸·도배성 광고가 있으면 반드시 거부(flagged=true)합니다.\n\nflagged=true 예:\n- 욕설/비속어: 씨발, 시발, 병신, 지랄, 좆, 개새끼, 존나, fuck, shit, bitch 등\n- 성적 모욕, 혐오 발언, 협박\n- 게시판 주제와 무관한 도배성 광고/스팸\n\nflagged=false:\n- 게시판 주제에 맞는 정상적인 글/댓글 (강한 의견이나 정당한 비판은 허용)\n\nJSON만 출력:\n{\"flagged\":boolean,\"category\":\"none\"|\"abuse\"|\"spam\"|\"adult\"|\"violence\"|\"other\",\"reason\":string}\n- flagged=true면 category를 고르고, reason은 한국어로 **무엇이 문제인지** 구체적으로 1문장\n (예: \"욕설(비속어)이 포함되어 게시할 수 없습니다.\", \"광고·스팸성 문구가 있어 게시할 수 없습니다.\")\n 욕설 단어 전체를 그대로 길게 인용하지 말고, 유형(욕설/혐오/스팸 등)을 분명히 밝힌다.\n- flagged=false면 category는 \"none\", reason은 \"\"", pn = {
741
742
  ko: "Korean",
742
743
  en: "English",
743
744
  ja: "Japanese",
@@ -749,12 +750,12 @@ var ln = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
749
750
  ar: "Arabic",
750
751
  id: "Indonesian"
751
752
  };
752
- function dn(e) {
753
- let t = un[e] ?? "English", n = ee(e).name;
753
+ function mn(e) {
754
+ let t = pn[e] ?? "English", n = pe(e).name;
754
755
  return t === n ? t : `${t} (${n})`;
755
756
  }
756
- function fn(e) {
757
- let t = dn(e);
757
+ function hn(e) {
758
+ let t = mn(e);
758
759
  return `You are a strict moderator reviewing content for a message board.
759
760
  If the text below contains profanity, vulgar slang, sexual harassment, hate speech, threats, spam, or repetitive/flooding advertisements, you MUST reject it (flagged=true).
760
761
 
@@ -781,17 +782,17 @@ Output JSON only:
781
782
  Do not quote the offensive words at length; clearly state the type (profanity/hate/spam, etc.).
782
783
  - If flagged=false, category is "none" and reason is ""`;
783
784
  }
784
- function pn(e = "ko") {
785
- return e === "ko" ? ln : fn(e);
785
+ function gn(e = "ko") {
786
+ return e === "ko" ? fn : hn(e);
786
787
  }
787
- function mn(e, t = "ko") {
788
+ function _n(e, t = "ko") {
788
789
  let n = `"""${e.slice(0, 4e3)}"""`;
789
790
  return t === "ko" ? `심사할 텍스트:\n${n}` : `Text to review:\n${n}`;
790
791
  }
791
- function hn(e = "ko") {
792
+ function vn(e = "ko") {
792
793
  return e === "ko" ? "이 이미지를 심사해 주세요." : "Please review this image.";
793
794
  }
794
- var gn = {
795
+ var yn = {
795
796
  abuse: "욕설·비속어·모욕",
796
797
  spam: "스팸·광고",
797
798
  adult: "선정적·성인 내용",
@@ -799,21 +800,21 @@ var gn = {
799
800
  other: "부적절한 내용",
800
801
  none: ""
801
802
  };
802
- function _n(e, t = "ko") {
803
- return !e || e === "none" ? "" : e in gn ? E(t, `moderationPrompt.categories.${e}`) : e;
803
+ function bn(e, t = "ko") {
804
+ return !e || e === "none" ? "" : e in yn ? k(t, `moderationPrompt.categories.${e}`) : e;
804
805
  }
805
- function vn(e) {
806
+ function xn(e) {
806
807
  let t = e.locale ?? "ko";
807
808
  if (e.via === "local" && e.localHit) {
808
809
  let n = e.localHit.trim();
809
- return n.length > 0 && n.length <= 12 ? E(t, "moderationPrompt.localHit", { hit: n }) : E(t, "moderationPrompt.localGeneric");
810
+ return n.length > 0 && n.length <= 12 ? k(t, "moderationPrompt.localHit", { hit: n }) : k(t, "moderationPrompt.localGeneric");
810
811
  }
811
812
  let n = (e.reason || "").trim();
812
813
  if (n) return n;
813
- let r = e.category ? _n(e.category, t) : "";
814
- return r ? E(t, "moderationPrompt.categoryBlocked", { category: r }) : E(t, "moderationPrompt.genericBlocked");
814
+ let r = e.category ? bn(e.category, t) : "";
815
+ return r ? k(t, "moderationPrompt.categoryBlocked", { category: r }) : k(t, "moderationPrompt.genericBlocked");
815
816
  }
816
- var yn = [
817
+ var Sn = [
817
818
  "씨발",
818
819
  "시발",
819
820
  "시이발",
@@ -839,10 +840,10 @@ var yn = [
839
840
  "bitch",
840
841
  "asshole"
841
842
  ];
842
- function bn(e) {
843
+ function Cn(e) {
843
844
  return new RegExp(e.join("|"), "i");
844
845
  }
845
- var xn = /* @__PURE__ */ new Set([
846
+ var wn = /* @__PURE__ */ new Set([
846
847
  "none",
847
848
  "abuse",
848
849
  "spam",
@@ -850,7 +851,7 @@ var xn = /* @__PURE__ */ new Set([
850
851
  "violence",
851
852
  "other"
852
853
  ]);
853
- function Sn(e) {
854
+ function Tn(e) {
854
855
  let t = e.trim();
855
856
  if (!t) return null;
856
857
  let n;
@@ -868,7 +869,7 @@ function Sn(e) {
868
869
  if (typeof n != "object" || !n) return null;
869
870
  let r = n;
870
871
  if (typeof r.flagged != "boolean") return null;
871
- let i = typeof r.category == "string" && xn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
872
+ let i = typeof r.category == "string" && wn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
872
873
  return {
873
874
  flagged: r.flagged,
874
875
  category: i,
@@ -877,11 +878,11 @@ function Sn(e) {
877
878
  }
878
879
  //#endregion
879
880
  //#region src/composables/useMemiBoardAutoTranslate.ts
880
- var Cn = 3e4, wn = 45e3, Tn = 12e3, En = 3;
881
- function Dn(e) {
881
+ var En = 3e4, Dn = 45e3, On = 12e3, kn = 3;
882
+ function An(e) {
882
883
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
883
884
  }
884
- async function On(e, t, n) {
885
+ async function jn(e, t, n) {
885
886
  let r = Array(e.length), i = 0;
886
887
  async function a() {
887
888
  for (; i < e.length;) {
@@ -891,7 +892,7 @@ async function On(e, t, n) {
891
892
  }
892
893
  return await Promise.all(Array.from({ length: Math.min(t, e.length) }, () => a())), r;
893
894
  }
894
- function kn(e, t) {
895
+ function Mn(e, t) {
895
896
  return new Promise((n, r) => {
896
897
  let i = setTimeout(() => r(/* @__PURE__ */ Error(`translation timed out after ${t / 1e3}s`)), t);
897
898
  e.then((e) => {
@@ -901,14 +902,14 @@ function kn(e, t) {
901
902
  });
902
903
  });
903
904
  }
904
- function An() {
905
- let e = Ee(), { moderation: t } = _();
905
+ function Nn() {
906
+ let e = Oe(), { moderation: t } = v();
906
907
  function n(n, r) {
907
- let i = Ve(e, {
908
- backend: new ze(),
908
+ let i = Ue(e, {
909
+ backend: new Ve(),
909
910
  useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
910
- }), a = Be.object({ properties: Object.fromEntries(r.map((e) => [e, Be.string()])) });
911
- return He(i, {
911
+ }), a = He.object({ properties: Object.fromEntries(r.map((e) => [e, He.string()])) });
912
+ return We(i, {
912
913
  model: t.model ?? "gemini-3.5-flash-lite",
913
914
  systemInstruction: [
914
915
  "You translate short user-interface strings for a website.",
@@ -920,19 +921,19 @@ function An() {
920
921
  temperature: .2,
921
922
  maxOutputTokens: 2048,
922
923
  responseMimeType: "application/json",
923
- responseSchema: Be.object({ properties: Object.fromEntries(n.map((e) => [e, a])) })
924
+ responseSchema: He.object({ properties: Object.fromEntries(n.map((e) => [e, a])) })
924
925
  }
925
926
  });
926
927
  }
927
928
  async function r(e, t, r, i) {
928
929
  let a = Object.keys(e.fields), o = [
929
930
  `Purpose: ${i}`,
930
- `Source language: ${dn(t)} (${t})`,
931
- `Translate into: ${r.map((e) => `${e} = ${dn(e)}`).join(", ")}`,
931
+ `Source language: ${mn(t)} (${t})`,
932
+ `Translate into: ${r.map((e) => `${e} = ${mn(e)}`).join(", ")}`,
932
933
  e.context ? `Context (do not translate): ${e.context}` : "",
933
934
  "Text (JSON):",
934
935
  JSON.stringify(e.fields)
935
- ].filter(Boolean).join("\n"), s = await kn(n(r, a).generateContent(o), Cn), c = JSON.parse(s.response.text()), l = {};
936
+ ].filter(Boolean).join("\n"), s = await Mn(n(r, a).generateContent(o), En), c = JSON.parse(s.response.text()), l = {};
936
937
  for (let e of r) {
937
938
  let t = c?.[e];
938
939
  if (!t) continue;
@@ -946,8 +947,8 @@ function An() {
946
947
  return l;
947
948
  }
948
949
  async function i(e, t = {}) {
949
- S();
950
- let n = t.source ?? "ko", i = (t.targets ?? ne.map((e) => e.code)).filter((e) => e !== n), a = t.purpose ?? "website UI labels", o = e.map((e) => ({
950
+ D();
951
+ let n = t.source ?? "ko", i = (t.targets ?? T.map((e) => e.code)).filter((e) => e !== n), a = t.purpose ?? "website UI labels", o = e.map((e) => ({
951
952
  ...e,
952
953
  fields: Object.fromEntries(Object.entries(e.fields).map(([e, t]) => [e, t.trim()]).filter(([, e]) => e))
953
954
  })).filter((e) => Object.keys(e.fields).length);
@@ -956,11 +957,11 @@ function An() {
956
957
  return Object.fromEntries(o.map((e, t) => [e.id, s[t]]));
957
958
  }
958
959
  function a() {
959
- let n = Ve(e, {
960
- backend: new ze(),
960
+ let n = Ue(e, {
961
+ backend: new Ve(),
961
962
  useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
962
963
  });
963
- return He(n, {
964
+ return We(n, {
964
965
  model: t.model ?? "gemini-3.5-flash-lite",
965
966
  systemInstruction: [
966
967
  "You translate an HTML fragment of a message-board post.",
@@ -975,17 +976,17 @@ function An() {
975
976
  });
976
977
  }
977
978
  async function o(e, t = {}) {
978
- S();
979
- let n = t.source ?? "ko", r = (t.targets ?? ne.map((e) => e.code)).filter((e) => e !== n), i = e.trim();
979
+ D();
980
+ let n = t.source ?? "ko", r = (t.targets ?? T.map((e) => e.code)).filter((e) => e !== n), i = e.trim();
980
981
  if (!i || !r.length) return {};
981
- if (i.length > 12e3) throw Error(`translation is limited to ${Tn} characters`);
982
- let o = await On(r, En, async (e) => {
982
+ if (i.length > 12e3) throw Error(`translation is limited to ${On} characters`);
983
+ let o = await jn(r, kn, async (e) => {
983
984
  let t = [
984
- `Source language: ${dn(n)} (${n})`,
985
- `Translate into: ${e} = ${dn(e)}`,
985
+ `Source language: ${mn(n)} (${n})`,
986
+ `Translate into: ${e} = ${mn(e)}`,
986
987
  "HTML:",
987
988
  i
988
- ].join("\n"), r = Dn((await kn(a().generateContent(t), wn)).response.text());
989
+ ].join("\n"), r = An((await Mn(a().generateContent(t), Dn)).response.text());
989
990
  if (!r) throw Error(`empty translation for ${e}`);
990
991
  return [e, r];
991
992
  });
@@ -998,7 +999,7 @@ function An() {
998
999
  }
999
1000
  //#endregion
1000
1001
  //#region src/composables/useMemiBoardSettings.ts
1001
- var jn = [
1002
+ var Pn = [
1002
1003
  {
1003
1004
  id: "free",
1004
1005
  label: "자유",
@@ -1026,17 +1027,17 @@ var jn = [
1026
1027
  visibility: "public",
1027
1028
  order: 2
1028
1029
  }
1029
- ], Mn = jn;
1030
- function Nn(e) {
1030
+ ], Fn = Pn;
1031
+ function In(e) {
1031
1032
  return e === "hidden" ? "hidden" : "public";
1032
1033
  }
1033
- function Pn(e, t, n) {
1034
+ function Ln(e, t, n) {
1034
1035
  return {
1035
1036
  id: e,
1036
1037
  label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
1037
1038
  order: typeof t.order == "number" ? t.order : n,
1038
1039
  description: (typeof t.description == "string" ? t.description : "") || "",
1039
- visibility: Nn(t.visibility),
1040
+ visibility: In(t.visibility),
1040
1041
  visibilityTransition: t.visibilityTransition === "hidden" || t.visibilityTransition === "public" ? t.visibilityTransition : void 0,
1041
1042
  listView: t.listView ?? "default",
1042
1043
  editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
@@ -1044,54 +1045,54 @@ function Pn(e, t, n) {
1044
1045
  commentWriteRole: t.commentWriteRole ?? "user",
1045
1046
  allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : [],
1046
1047
  allowedManagerUids: Array.isArray(t.allowedManagerUids) ? t.allowedManagerUids : [],
1047
- locale: O(t.locale) ?? "",
1048
+ locale: M(t.locale) ?? "",
1048
1049
  autoTranslate: t.autoTranslate === !0,
1049
1050
  i18n: Q(t.i18n),
1050
- i18nSource: tt(t.i18nSource)
1051
+ i18nSource: rt(t.i18nSource)
1051
1052
  };
1052
1053
  }
1053
- function Fn() {
1054
- let t = () => M(), n = Z(), r = Ee(), { isSignedIn: i, isAdmin: a, isStaff: o, user: c } = Mt(), { t: u, locale: d } = k(), { translateEntries: f } = An(), p = N(() => G(oe(n, t()), W("order", "asc"))), { data: m, pending: h } = Ce(p, { ssrKey: e(t(), "boards") }), g = N(() => m.value.map((e, t) => Pn(e.id, e, t))), _ = g, v = N(() => g.value.filter((e) => e.visibility !== "hidden")), y = v;
1054
+ function Rn() {
1055
+ let e = () => j(), t = Z(), r = Oe(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = Pt(), { t: l, locale: u } = A(), { translateEntries: d } = Nn(), f = N(() => G(S(t, e()), W("order", "asc"))), { data: m, pending: h } = Te(f, { ssrKey: p(e(), "boards") }), g = N(() => m.value.map((e, t) => Ln(e.id, e, t))), _ = g, v = N(() => g.value.filter((e) => e.visibility !== "hidden")), y = v;
1055
1056
  function b(e, t) {
1056
1057
  if (!e) return;
1057
1058
  let n = g.value.find((t) => t.id === e);
1058
- return n ? ot(n.i18n, n.i18nSource, "label", n.label, t ?? d.value) || n.label : e;
1059
+ return n ? ct(n.i18n, n.i18nSource, "label", n.label, t ?? u.value) || n.label : e;
1059
1060
  }
1060
1061
  let x = b;
1061
- function S(e, t) {
1062
+ function C(e, t) {
1062
1063
  if (!e) return;
1063
1064
  let n = g.value.find((t) => t.id === e), r = n?.description?.trim();
1064
- if (n && r) return ot(n.i18n, n.i18nSource, "description", r, t ?? d.value) || void 0;
1065
+ if (n && r) return ct(n.i18n, n.i18nSource, "description", r, t ?? u.value) || void 0;
1065
1066
  }
1066
- let C = S;
1067
- function T(e) {
1068
- return e ? g.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
1069
- }
1070
- let E = T;
1067
+ let T = C;
1071
1068
  function D(e) {
1072
- return T(e) === "hidden";
1069
+ return e ? g.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
1073
1070
  }
1074
1071
  let ee = D;
1075
- function A(e) {
1072
+ function te(e) {
1073
+ return D(e) === "hidden";
1074
+ }
1075
+ let ne = te;
1076
+ function O(e) {
1076
1077
  if (e) return g.value.find((t) => t.id === e);
1077
1078
  }
1078
- xt((e) => A(e));
1079
- function j(e) {
1080
- return vt(c.value?.uid, a.value, o.value, e ? A(e) : void 0);
1079
+ Ct((e) => O(e));
1080
+ function re(e) {
1081
+ return bt(c.value?.uid, a.value, s.value, e ? O(e) : void 0);
1081
1082
  }
1082
- let te = N(() => g.value.filter((e) => j(e.id)));
1083
- function ne(e, t) {
1083
+ let ie = N(() => g.value.filter((e) => re(e.id)));
1084
+ function ae(e, t) {
1084
1085
  return {
1085
1086
  label: e.label.trim(),
1086
1087
  description: (e.description ?? "").trim(),
1087
- visibility: Nn(e.visibility),
1088
+ visibility: In(e.visibility),
1088
1089
  listView: e.listView ?? "default",
1089
1090
  editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
1090
1091
  writeRole: e.writeRole ?? "user",
1091
1092
  commentWriteRole: e.commentWriteRole ?? "user",
1092
1093
  allowedStaffUids: e.allowedStaffUids ?? [],
1093
1094
  allowedManagerUids: e.allowedManagerUids ?? [],
1094
- locale: O(e.locale) ?? "",
1095
+ locale: M(e.locale) ?? "",
1095
1096
  autoTranslate: e.autoTranslate === !0,
1096
1097
  ...e.i18n ? { i18n: e.i18n } : {},
1097
1098
  ...e.i18nSource ? { i18nSource: e.i18nSource } : {},
@@ -1099,70 +1100,70 @@ function Fn() {
1099
1100
  updatedAt: K()
1100
1101
  };
1101
1102
  }
1102
- async function ie(e) {
1103
- if (!w()) return e;
1104
- let t = e.label.trim(), n = (e.description ?? "").trim();
1103
+ async function oe(e) {
1104
+ if (!n()) return e;
1105
+ let t = e.label.trim(), r = (e.description ?? "").trim();
1105
1106
  if (!t) return e;
1106
- if (ut({
1107
+ if (ft({
1107
1108
  ...e,
1108
1109
  label: t,
1109
- description: n
1110
+ description: r
1110
1111
  })) return {
1111
1112
  ...e,
1112
1113
  label: t,
1113
- description: n
1114
+ description: r
1114
1115
  };
1115
- let r = d.value, i = { label: t };
1116
- n && (i.description = n);
1117
- let a = rt(r, i, (await f([{
1116
+ let i = u.value, a = { label: t };
1117
+ r && (a.description = r);
1118
+ let o = at(i, a, (await d([{
1118
1119
  id: e.id || "board",
1119
- fields: i,
1120
+ fields: a,
1120
1121
  context: e.id
1121
1122
  }], {
1122
- source: r,
1123
+ source: i,
1123
1124
  purpose: "board name and short description shown in navigation and page headers"
1124
1125
  }))[e.id || "board"]);
1125
- if (!it(a, Object.keys(i))) throw Error(u("settings.autoTranslate.failed"));
1126
+ if (!ot(o, Object.keys(a))) throw Error(l("settings.autoTranslate.failed"));
1126
1127
  return {
1127
1128
  ...e,
1128
1129
  label: t,
1129
- description: n,
1130
- i18n: a,
1130
+ description: r,
1131
+ i18n: o,
1131
1132
  i18nSource: {
1132
- locale: r,
1133
+ locale: i,
1133
1134
  label: t,
1134
- description: n
1135
+ description: r
1135
1136
  }
1136
1137
  };
1137
1138
  }
1138
- async function ae(e, r = e.order ?? 0) {
1139
- if (!i.value) throw Error(u("boardSettings.signInRequired"));
1140
- let a = e.id.trim(), o = e.label.trim();
1141
- if (!a || !o) throw Error(u("boardSettings.idAndNameRequired"));
1142
- let s = Nn(e.visibility), c = ne({
1143
- ...e,
1139
+ async function k(n, r = n.order ?? 0) {
1140
+ if (!i.value) throw Error(l("boardSettings.signInRequired"));
1141
+ let a = n.id.trim(), o = n.label.trim();
1142
+ if (!a || !o) throw Error(l("boardSettings.idAndNameRequired"));
1143
+ let s = In(n.visibility), c = ae({
1144
+ ...n,
1144
1145
  label: o,
1145
1146
  visibility: s
1146
1147
  }, r);
1147
- await cn(n, t(), a, c);
1148
+ await dn(t, e(), a, c);
1148
1149
  }
1149
- let se = ae;
1150
+ let se = k;
1150
1151
  async function ce(e) {
1151
- if (!i.value) throw Error(u("boardSettings.signInRequired"));
1152
- for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(u("boardSettings.idAndNameRequired"));
1153
- for (let [t, n] of e.entries()) await ae(n, t);
1152
+ if (!i.value) throw Error(l("boardSettings.signInRequired"));
1153
+ for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(l("boardSettings.idAndNameRequired"));
1154
+ for (let [t, n] of e.entries()) await k(n, t);
1154
1155
  }
1155
1156
  let le = ce;
1156
- async function ue(e) {
1157
- if (!i.value) throw Error(u("boardSettings.signInRequired"));
1158
- let a = e.trim();
1159
- if (!a) throw Error(u("boardSettings.deleteIdRequired"));
1157
+ async function ue(n) {
1158
+ if (!i.value) throw Error(l("boardSettings.signInRequired"));
1159
+ let a = n.trim();
1160
+ if (!a) throw Error(l("boardSettings.deleteIdRequired"));
1160
1161
  for (;;) {
1161
- let e = await B(G(s(n, t()), X("boardId", "==", a), H(25)));
1162
- if (e.empty) break;
1163
- for (let i of e.docs) await Jt(n, Ie(r), t(), i.id);
1162
+ let n = await B(G(o(t, e()), X("boardId", "==", a), H(25)));
1163
+ if (n.empty) break;
1164
+ for (let i of n.docs) await Zt(t, Re(r), e(), i.id);
1164
1165
  }
1165
- await he(l(n, t(), e));
1166
+ await _e(w(t, e(), n));
1166
1167
  }
1167
1168
  let de = ue;
1168
1169
  async function fe() {
@@ -1170,13 +1171,13 @@ function Fn() {
1170
1171
  }
1171
1172
  async function pe(e) {
1172
1173
  let t = e.trim();
1173
- if (!t) throw Error(u("boardSettings.nameRequired"));
1174
- if (!i.value) throw Error(u("boardSettings.signInRequired"));
1174
+ if (!t) throw Error(l("boardSettings.nameRequired"));
1175
+ if (!i.value) throw Error(l("boardSettings.signInRequired"));
1175
1176
  let n = g.value.find((e) => e.label === t);
1176
1177
  if (n) return n.id;
1177
- let r = re(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(g.value.map((e) => e.id));
1178
+ let r = E(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(g.value.map((e) => e.id));
1178
1179
  for (; s.has(a);) a = `${r}-${o++}`;
1179
- return await ae({
1180
+ return await k({
1180
1181
  id: a,
1181
1182
  label: t,
1182
1183
  visibility: "public",
@@ -1191,67 +1192,67 @@ function Fn() {
1191
1192
  boards: g,
1192
1193
  publicBoards: v,
1193
1194
  boardLabel: b,
1194
- boardDescription: S,
1195
- boardVisibility: T,
1196
- isBoardHidden: D,
1197
- getBoard: A,
1198
- canManageBoard: j,
1199
- managedBoards: te,
1195
+ boardDescription: C,
1196
+ boardVisibility: D,
1197
+ isBoardHidden: te,
1198
+ getBoard: O,
1199
+ canManageBoard: re,
1200
+ managedBoards: ie,
1200
1201
  categories: _,
1201
1202
  publicCategories: y,
1202
1203
  categoryLabel: x,
1203
- categoryDescription: C,
1204
- categoryVisibility: E,
1205
- isCategoryHidden: ee,
1204
+ categoryDescription: T,
1205
+ categoryVisibility: ee,
1206
+ isCategoryHidden: ne,
1206
1207
  settingsPending: h,
1207
1208
  ensureSettings: fe,
1208
1209
  addBoard: pe,
1209
1210
  addCategory: pe,
1210
- saveBoard: ae,
1211
+ saveBoard: k,
1211
1212
  saveCategory: se,
1212
- translateBoard: ie,
1213
+ translateBoard: oe,
1213
1214
  saveBoards: ce,
1214
1215
  saveCategories: le,
1215
1216
  deleteBoard: ue,
1216
1217
  deleteCategory: de,
1217
- DEFAULT_BOARDS: jn,
1218
- DEFAULT_CATEGORIES: Mn
1218
+ DEFAULT_BOARDS: Pn,
1219
+ DEFAULT_CATEGORIES: Fn
1219
1220
  };
1220
1221
  }
1221
1222
  //#endregion
1222
1223
  //#region src/composables/useMemiBoardPosts.ts
1223
- var In = /* @__PURE__ */ new Map();
1224
- function Ln(e) {
1224
+ var zn = /* @__PURE__ */ new Map();
1225
+ function Bn(e) {
1225
1226
  if (!e || typeof e != "object") return !1;
1226
1227
  let t = "code" in e ? String(e.code) : "";
1227
1228
  return t === "permission-denied" || t === "firestore/permission-denied";
1228
1229
  }
1229
- function Rn(e, t) {
1230
+ function Vn(e, t) {
1230
1231
  let n = I(e)?.trim();
1231
- if (!n) throw Error(E(t, "posts.boardIdRequired"));
1232
+ if (!n) throw Error(k(t, "posts.boardIdRequired"));
1232
1233
  return n;
1233
1234
  }
1234
- function zn(e) {
1235
- let n = Z(), r = Ee(), { isBoardHidden: i, getBoard: a } = Fn(), { user: o, canManageBoard: c } = Mt(), { t: l, locale: u } = k(), d = () => M(), f = () => Rn(e, u.value), p = () => s(n, d()), m = (e) => t(n, d(), e), h = (e) => pe(n, d(), e);
1235
+ function Hn(e) {
1236
+ let t = Z(), n = Oe(), { isBoardHidden: r, getBoard: i } = Rn(), { user: a, canManageBoard: c } = Pt(), { t: l, locale: u } = A(), d = () => j(), f = () => Vn(e, u.value), p = () => o(t, d()), m = (e) => y(t, d(), e), h = (e) => s(t, d(), e);
1236
1237
  function g(e, t, n) {
1237
1238
  return {
1238
1239
  id: e,
1239
1240
  ...t,
1240
1241
  i18n: Q(t.i18n),
1241
- i18nSource: tt(t.i18nSource),
1242
+ i18nSource: rt(t.i18nSource),
1242
1243
  content: typeof n?.content == "string" ? n.content : "",
1243
1244
  contentI18n: Q(n?.i18n),
1244
- contentI18nSource: nt(n?.i18nSource)
1245
+ contentI18nSource: it(n?.i18nSource)
1245
1246
  };
1246
1247
  }
1247
1248
  function _() {
1248
- return !i(f());
1249
+ return !r(f());
1249
1250
  }
1250
1251
  function v() {
1251
- return a(f())?.editorType === "image";
1252
+ return i(f())?.editorType === "image";
1252
1253
  }
1253
- function y(e) {
1254
- let t = v(), n = Zt(e.content), r = Qt(e.content, e.attachments);
1254
+ function b(e) {
1255
+ let t = v(), n = en(e.content), r = tn(e.content, e.attachments);
1255
1256
  if (t) {
1256
1257
  if (!r) throw Error(l("posts.photoRequired"));
1257
1258
  return;
@@ -1259,11 +1260,11 @@ function zn(e) {
1259
1260
  if (!n && !r) throw Error(l("posts.bodyRequired"));
1260
1261
  if (!e.title?.trim()) throw Error(l("posts.titleRequired"));
1261
1262
  }
1262
- function b() {
1263
- return _e(p()).id;
1263
+ function x() {
1264
+ return ye(p()).id;
1264
1265
  }
1265
- function x(e) {
1266
- return Lt(n, d(), f(), e, o.value?.uid, c(f()));
1266
+ function S(e) {
1267
+ return zt(t, d(), f(), e, a.value?.uid, c(f()));
1267
1268
  }
1268
1269
  async function C(e = {}) {
1269
1270
  let t = e.pageSize ?? 20, n = [X("boardId", "==", f()), X("isPublished", "==", !0)];
@@ -1284,7 +1285,7 @@ function zn(e) {
1284
1285
  }
1285
1286
  async function T(e) {
1286
1287
  try {
1287
- let t = await x(e.trim());
1288
+ let t = await S(e.trim());
1288
1289
  if (!t) return { status: "not-found" };
1289
1290
  try {
1290
1291
  let e = await w(t.id);
@@ -1293,41 +1294,41 @@ function zn(e) {
1293
1294
  post: e
1294
1295
  } : { status: "not-found" };
1295
1296
  } catch (e) {
1296
- return Ln(e) ? { status: "permission-denied" } : {
1297
+ return Bn(e) ? { status: "permission-denied" } : {
1297
1298
  status: "error",
1298
1299
  message: e instanceof Error ? e.message : String(e)
1299
1300
  };
1300
1301
  }
1301
1302
  } catch (e) {
1302
- return Ln(e) ? { status: "permission-denied" } : {
1303
+ return Bn(e) ? { status: "permission-denied" } : {
1303
1304
  status: "error",
1304
1305
  message: e instanceof Error ? e.message : String(e)
1305
1306
  };
1306
1307
  }
1307
1308
  }
1308
- async function E(e) {
1309
- let t = e.trim(), n = In.get(`${f()}/${t}`);
1309
+ async function ee(e) {
1310
+ let t = e.trim(), n = zn.get(`${f()}/${t}`);
1310
1311
  if (n) return {
1311
1312
  status: "ok",
1312
1313
  id: n
1313
1314
  };
1314
1315
  try {
1315
- let e = await x(t);
1316
+ let e = await S(t);
1316
1317
  return e ? {
1317
1318
  status: "ok",
1318
1319
  id: e.id
1319
- } : { status: i(f()) ? "permission-denied" : "not-found" };
1320
+ } : { status: r(f()) ? "permission-denied" : "not-found" };
1320
1321
  } catch (e) {
1321
- return Ln(e) ? { status: "permission-denied" } : {
1322
+ return Bn(e) ? { status: "permission-denied" } : {
1322
1323
  status: "error",
1323
1324
  message: e instanceof Error ? e.message : String(e)
1324
1325
  };
1325
1326
  }
1326
1327
  }
1327
- async function D(e) {
1328
- return `${re(e.trim()) || "post"}-${b()}`;
1328
+ async function te(e) {
1329
+ return `${E(e.trim()) || "post"}-${x()}`;
1329
1330
  }
1330
- async function O(e) {
1331
+ async function ne(e) {
1331
1332
  if (!e.createdAt) return {
1332
1333
  previous: null,
1333
1334
  next: null
@@ -1338,7 +1339,7 @@ function zn(e) {
1338
1339
  X("isPublished", "==", !0),
1339
1340
  ...e.listed === !1 ? [] : [X("listed", "==", !0)],
1340
1341
  W("createdAt", "desc")
1341
- ], [n, r] = await Promise.all([B(G(p(), ...t, J(e.createdAt), H(1))), B(G(p(), ...t, ye(e.createdAt), be(1)))]), i = (e) => {
1342
+ ], [n, r] = await Promise.all([B(G(p(), ...t, J(e.createdAt), H(1))), B(G(p(), ...t, xe(e.createdAt), Se(1)))]), i = (e) => {
1342
1343
  let t = e.docs[0];
1343
1344
  return t ? {
1344
1345
  id: t.id,
@@ -1356,12 +1357,12 @@ function zn(e) {
1356
1357
  };
1357
1358
  }
1358
1359
  }
1359
- async function ee(e) {
1360
- y(e);
1361
- let t = e.postId || b(), r = v(), i, a;
1362
- r ? (i = t, a = Xt(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await D(a));
1363
- let o = rn(e.content, e.attachments), s = _(), c = Se(n);
1364
- return c.set(m(t), {
1360
+ async function O(e) {
1361
+ b(e);
1362
+ let n = e.postId || x(), r = v(), i, a;
1363
+ r ? (i = n, a = $t(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await te(a));
1364
+ let o = sn(e.content, e.attachments), s = _(), c = we(t);
1365
+ return c.set(m(n), {
1365
1366
  boardId: f(),
1366
1367
  slug: i,
1367
1368
  title: a,
@@ -1384,22 +1385,22 @@ function zn(e) {
1384
1385
  i18n: e.translations.i18n,
1385
1386
  i18nSource: e.translations.i18nSource
1386
1387
  } : {}
1387
- }), c.set(h(t), {
1388
+ }), c.set(h(n), {
1388
1389
  content: e.content,
1389
1390
  ...e.translations?.contentI18n ? {
1390
1391
  i18n: e.translations.contentI18n,
1391
1392
  i18nSource: e.translations.contentI18nSource
1392
1393
  } : {}
1393
- }), await c.commit(), In.set(`${f()}/${i}`, t), i;
1394
+ }), await c.commit(), zn.set(`${f()}/${i}`, n), i;
1394
1395
  }
1395
- async function A(e, t) {
1396
- y(t);
1397
- let n = v() ? Xt(t.content) : t.title.trim(), r = rn(t.content, t.attachments), i = _();
1396
+ async function re(e, t) {
1397
+ b(t);
1398
+ let n = v() ? $t(t.content) : t.title.trim(), r = sn(t.content, t.attachments), i = _();
1398
1399
  await Promise.all([Y(m(e), {
1399
1400
  title: n,
1400
1401
  ...r,
1401
- previewImage: r.previewImage ? r.previewImage : ge(),
1402
- videoUrl: r.videoUrl ? r.videoUrl : ge(),
1402
+ previewImage: r.previewImage ? r.previewImage : ve(),
1403
+ videoUrl: r.videoUrl ? r.videoUrl : ve(),
1403
1404
  tags: t.tags ?? [],
1404
1405
  listed: i,
1405
1406
  attachments: t.attachments ?? [],
@@ -1414,13 +1415,13 @@ function zn(e) {
1414
1415
  i18n: t.translations.contentI18n,
1415
1416
  i18nSource: t.translations.contentI18nSource
1416
1417
  } : {
1417
- i18n: ge(),
1418
- i18nSource: ge()
1418
+ i18n: ve(),
1419
+ i18nSource: ve()
1419
1420
  } : {}
1420
1421
  }, { merge: !0 })]);
1421
1422
  }
1422
- async function j(e, t) {
1423
- S(), await Promise.all([Y(m(e), {
1423
+ async function ie(e, t) {
1424
+ D(), await Promise.all([Y(m(e), {
1424
1425
  i18n: t.i18n,
1425
1426
  i18nSource: t.i18nSource,
1426
1427
  updatedAt: K()
@@ -1428,39 +1429,39 @@ function zn(e) {
1428
1429
  i18n: t.contentI18n,
1429
1430
  i18nSource: t.contentI18nSource
1430
1431
  } : {
1431
- i18n: ge(),
1432
- i18nSource: ge()
1432
+ i18n: ve(),
1433
+ i18nSource: ve()
1433
1434
  }, { merge: !0 })]);
1434
1435
  }
1435
- async function te(e) {
1436
+ async function ae(e) {
1436
1437
  await Y(m(e), {
1437
1438
  isPublished: !0,
1438
1439
  publishedAt: K(),
1439
1440
  updatedAt: K()
1440
1441
  });
1441
1442
  }
1442
- async function ne(e) {
1443
- await Jt(n, Ie(r), d(), e);
1444
- for (let [t, n] of In) n === e && In.delete(t);
1443
+ async function oe(e) {
1444
+ await Zt(t, Re(n), d(), e);
1445
+ for (let [t, n] of zn) n === e && zn.delete(t);
1445
1446
  }
1446
1447
  return {
1447
- createPostId: b,
1448
+ createPostId: x,
1448
1449
  getPosts: C,
1449
1450
  getPost: w,
1450
1451
  getPostBySlug: T,
1451
- resolvePostIdBySlug: E,
1452
- resolveUniqueSlug: D,
1453
- getAdjacentPosts: O,
1454
- createPost: ee,
1455
- updatePost: A,
1456
- savePostTranslations: j,
1457
- publishPost: te,
1458
- deletePost: ne
1452
+ resolvePostIdBySlug: ee,
1453
+ resolveUniqueSlug: te,
1454
+ getAdjacentPosts: ne,
1455
+ createPost: O,
1456
+ updatePost: re,
1457
+ savePostTranslations: ie,
1458
+ publishPost: ae,
1459
+ deletePost: oe
1459
1460
  };
1460
1461
  }
1461
- var Bn = 10;
1462
- function Vn(e, t = {}) {
1463
- let n = Z(), { isAdmin: r, user: i, canManageBoard: a } = Mt(), o = () => M(), c = t.pageSize ?? Bn, l = N(() => i.value?.uid ?? ""), u = N(() => Rn(e)), d = () => s(n, o()), f = N(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = F([]), m = F([]), h = F([]), g = F(!0), _ = F(!0), v = F(!1), y = F(""), b = null, x = null, S, C;
1462
+ var Un = 10;
1463
+ function Wn(e, t = {}) {
1464
+ let n = Z(), { isAdmin: r, user: i, canManageBoard: a } = Pt(), s = () => j(), c = t.pageSize ?? Un, l = N(() => i.value?.uid ?? ""), u = N(() => Vn(e)), d = () => o(n, s()), f = N(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = F([]), m = F([]), h = F([]), g = F(!0), _ = F(!0), v = F(!1), y = F(""), b = null, x = null, S, C;
1464
1465
  function w(e) {
1465
1466
  return e.createdAt?.toMillis?.() ?? 0;
1466
1467
  }
@@ -1487,7 +1488,7 @@ function Vn(e, t = {}) {
1487
1488
  console.error("[memi-board:postList] onSnapshot failed", e), y.value = e.message || String(e), g.value = !1;
1488
1489
  });
1489
1490
  }
1490
- function O() {
1491
+ function ee() {
1491
1492
  C?.();
1492
1493
  let e = l.value;
1493
1494
  if (!e) {
@@ -1503,7 +1504,7 @@ function Vn(e, t = {}) {
1503
1504
  console.error("[memi-board:postList] own draft onSnapshot failed", e);
1504
1505
  });
1505
1506
  }
1506
- async function ee() {
1507
+ async function te() {
1507
1508
  if (!(v.value || !_.value || g.value)) {
1508
1509
  v.value = !0, y.value = "";
1509
1510
  try {
@@ -1525,14 +1526,14 @@ function Vn(e, t = {}) {
1525
1526
  }
1526
1527
  }
1527
1528
  }
1528
- function k() {
1529
- S?.(), p.value = [], m.value = [], b = null, x = null, _.value = !0, y.value = "", g.value = !0, D(), O();
1529
+ function ne() {
1530
+ S?.(), p.value = [], m.value = [], b = null, x = null, _.value = !0, y.value = "", g.value = !0, D(), ee();
1530
1531
  }
1531
1532
  return L([
1532
1533
  u,
1533
1534
  f,
1534
1535
  l
1535
- ], k, { immediate: !0 }), P(() => {
1536
+ ], ne, { immediate: !0 }), P(() => {
1536
1537
  S?.(), C?.();
1537
1538
  }), {
1538
1539
  posts: T,
@@ -1540,23 +1541,23 @@ function Vn(e, t = {}) {
1540
1541
  hasMore: _,
1541
1542
  loadingMore: v,
1542
1543
  loadError: y,
1543
- loadMore: ee
1544
+ loadMore: te
1544
1545
  };
1545
1546
  }
1546
- function Hn(e, n) {
1547
- let r = Z(), i = () => M(), a = N(() => Rn(e)), o = N(() => typeof n == "string" ? n : n.value), s = N(() => t(r, i(), o.value)), c = N(() => pe(r, i(), o.value)), { data: l, pending: u } = Te(s), { data: d, pending: f } = Te(c);
1547
+ function Gn(e, t) {
1548
+ let n = Z(), r = () => j(), i = N(() => Vn(e)), a = N(() => typeof t == "string" ? t : t.value), o = N(() => y(n, r(), a.value)), c = N(() => s(n, r(), a.value)), { data: l, pending: u } = De(o), { data: d, pending: f } = De(c);
1548
1549
  return {
1549
1550
  post: N(() => {
1550
- if (!l.value || l.value.boardId !== a.value) return null;
1551
+ if (!l.value || l.value.boardId !== i.value) return null;
1551
1552
  let e = d.value;
1552
1553
  return {
1553
1554
  ...l.value,
1554
- id: o.value,
1555
+ id: a.value,
1555
1556
  i18n: Q(l.value.i18n),
1556
- i18nSource: tt(l.value.i18nSource),
1557
+ i18nSource: rt(l.value.i18nSource),
1557
1558
  content: d.value?.content ?? "",
1558
1559
  contentI18n: Q(e?.i18n),
1559
- contentI18nSource: nt(e?.i18nSource)
1560
+ contentI18nSource: it(e?.i18nSource)
1560
1561
  };
1561
1562
  }),
1562
1563
  pending: N(() => u.value || f.value)
@@ -1564,9 +1565,9 @@ function Hn(e, n) {
1564
1565
  }
1565
1566
  //#endregion
1566
1567
  //#region src/composables/useMemiBoardUserPosts.ts
1567
- var Un = 10;
1568
- function Wn(e, t = {}) {
1569
- let n = Z(), r = () => M(), i = () => s(n, r()), a = t.pageSize ?? Un, o = N(() => I(e)?.trim() || ""), c = F([]), l = F([]), u = F(!0), d = F(!0), f = F(!1), p = F(""), m = null, h = null, g;
1568
+ var Kn = 10;
1569
+ function qn(e, t = {}) {
1570
+ let n = Z(), r = () => j(), i = () => o(n, r()), a = t.pageSize ?? Kn, s = N(() => I(e)?.trim() || ""), c = F([]), l = F([]), u = F(!0), d = F(!0), f = F(!1), p = F(""), m = null, h = null, g;
1570
1571
  function _(e) {
1571
1572
  return {
1572
1573
  id: e.id,
@@ -1583,13 +1584,13 @@ function Wn(e, t = {}) {
1583
1584
  });
1584
1585
  function b() {
1585
1586
  return [
1586
- X("authorUid", "==", o.value),
1587
+ X("authorUid", "==", s.value),
1587
1588
  X("isPublished", "==", !0),
1588
1589
  X("listed", "==", !0)
1589
1590
  ];
1590
1591
  }
1591
1592
  function x() {
1592
- if (g?.(), !o.value) {
1593
+ if (g?.(), !s.value) {
1593
1594
  u.value = !1;
1594
1595
  return;
1595
1596
  }
@@ -1600,7 +1601,7 @@ function Wn(e, t = {}) {
1600
1601
  });
1601
1602
  }
1602
1603
  async function S() {
1603
- if (!f.value && d.value && !u.value && o.value) {
1604
+ if (!f.value && d.value && !u.value && s.value) {
1604
1605
  f.value = !0, p.value = "";
1605
1606
  try {
1606
1607
  let e = h ?? m, t = [
@@ -1621,7 +1622,7 @@ function Wn(e, t = {}) {
1621
1622
  function C() {
1622
1623
  g?.(), c.value = [], l.value = [], m = null, h = null, d.value = !0, p.value = "", u.value = !0, x();
1623
1624
  }
1624
- return L(o, C, { immediate: !0 }), P(() => g?.()), {
1625
+ return L(s, C, { immediate: !0 }), P(() => g?.()), {
1625
1626
  posts: y,
1626
1627
  postsPending: u,
1627
1628
  hasMore: d,
@@ -1632,9 +1633,9 @@ function Wn(e, t = {}) {
1632
1633
  }
1633
1634
  //#endregion
1634
1635
  //#region src/composables/useMemiBoardUserComments.ts
1635
- var Gn = 10;
1636
- function Kn(e, t = {}) {
1637
- let n = Z(), r = () => M(), i = () => a(n, r()), o = t.pageSize ?? Gn, s = N(() => I(e)?.trim() || ""), c = F([]), l = F([]), u = F(!0), d = F(!0), f = F(!1), p = F(""), m = null, h = null, g;
1636
+ var Jn = 10;
1637
+ function Yn(e, t = {}) {
1638
+ let n = Z(), r = () => j(), i = () => g(n, r()), a = t.pageSize ?? Jn, o = N(() => I(e)?.trim() || ""), s = F([]), c = F([]), l = F(!0), u = F(!0), d = F(!1), f = F(""), p = null, m = null, h;
1638
1639
  function _(e) {
1639
1640
  return {
1640
1641
  id: e.id,
@@ -1646,62 +1647,62 @@ function Kn(e, t = {}) {
1646
1647
  }
1647
1648
  let y = N(() => {
1648
1649
  let e = /* @__PURE__ */ new Map();
1649
- for (let t of [...l.value, ...c.value]) t.id && e.set(t.id, t);
1650
+ for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1650
1651
  return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
1651
1652
  });
1652
1653
  function b() {
1653
- return [X("authorUid", "==", s.value), X("listed", "==", !0)];
1654
+ return [X("authorUid", "==", o.value), X("listed", "==", !0)];
1654
1655
  }
1655
1656
  function x() {
1656
- if (g?.(), !s.value) {
1657
- u.value = !1;
1657
+ if (h?.(), !o.value) {
1658
+ l.value = !1;
1658
1659
  return;
1659
1660
  }
1660
- g = U(G(i(), ...b(), W("createdAt", "desc"), W(R(), "desc"), H(o)), (e) => {
1661
- c.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= o), u.value = !1;
1661
+ h = U(G(i(), ...b(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
1662
+ s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1662
1663
  }, (e) => {
1663
- console.error("[memi-board:userComments] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
1664
+ console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
1664
1665
  });
1665
1666
  }
1666
1667
  async function S() {
1667
- if (!f.value && d.value && !u.value && s.value) {
1668
- f.value = !0, p.value = "";
1668
+ if (!d.value && u.value && !l.value && o.value) {
1669
+ d.value = !0, f.value = "";
1669
1670
  try {
1670
- let e = h ?? m, t = [
1671
+ let e = m ?? p, t = [
1671
1672
  ...b(),
1672
1673
  W("createdAt", "desc"),
1673
1674
  W(R(), "desc"),
1674
1675
  ...e ? [J(e)] : [],
1675
- H(o + 1)
1676
- ], n = await B(G(i(), ...t)), r = n.docs.slice(0, o), a = r.map(_), s = new Set([...l.value, ...c.value].map((e) => e.id));
1677
- l.value.push(...a.filter((e) => !s.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > o;
1676
+ H(a + 1)
1677
+ ], n = await B(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
1678
+ c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
1678
1679
  } catch (e) {
1679
- p.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
1680
+ f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
1680
1681
  } finally {
1681
- f.value = !1;
1682
+ d.value = !1;
1682
1683
  }
1683
1684
  }
1684
1685
  }
1685
1686
  function C() {
1686
- g?.(), c.value = [], l.value = [], m = null, h = null, d.value = !0, p.value = "", u.value = !0, x();
1687
+ h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
1687
1688
  }
1688
- return L(s, C, { immediate: !0 }), P(() => g?.()), {
1689
+ return L(o, C, { immediate: !0 }), P(() => h?.()), {
1689
1690
  comments: y,
1690
- commentsPending: u,
1691
- hasMore: d,
1692
- loadingMore: f,
1693
- loadError: p,
1691
+ commentsPending: l,
1692
+ hasMore: u,
1693
+ loadingMore: d,
1694
+ loadError: f,
1694
1695
  loadMore: S
1695
1696
  };
1696
1697
  }
1697
1698
  //#endregion
1698
1699
  //#region src/composables/useMemiBoardCommentFeed.ts
1699
- var qn = 10;
1700
- function Jn(e = "latest", t = {}) {
1701
- let n = Z(), r = () => M(), i = () => a(n, r()), o = N(() => {
1700
+ var Xn = 10;
1701
+ function Zn(e = "latest", t = {}) {
1702
+ let n = Z(), r = () => j(), i = () => g(n, r()), a = N(() => {
1702
1703
  let e = Math.floor(Number(I(t.pageSize)));
1703
- return Number.isFinite(e) && e > 0 ? e : qn;
1704
- }), s = N(() => I(e) === "likes" ? "likes" : "latest"), c = F([]), l = F([]), u = F(!0), d = F(!0), f = F(!1), p = F(""), m = null, h = null, g;
1704
+ return Number.isFinite(e) && e > 0 ? e : Xn;
1705
+ }), o = N(() => I(e) === "likes" ? "likes" : "latest"), s = F([]), c = F([]), l = F(!0), u = F(!0), d = F(!1), f = F(""), p = null, m = null, h;
1705
1706
  function _(e) {
1706
1707
  return {
1707
1708
  id: e.id,
@@ -1712,7 +1713,7 @@ function Jn(e = "latest", t = {}) {
1712
1713
  return e.createdAt?.toMillis?.() ?? 0;
1713
1714
  }
1714
1715
  function y(e, t) {
1715
- if (s.value === "likes") {
1716
+ if (o.value === "likes") {
1716
1717
  let n = (t.likeCount ?? 0) - (e.likeCount ?? 0);
1717
1718
  if (n) return n;
1718
1719
  }
@@ -1720,11 +1721,11 @@ function Jn(e = "latest", t = {}) {
1720
1721
  }
1721
1722
  let b = N(() => {
1722
1723
  let e = /* @__PURE__ */ new Map();
1723
- for (let t of [...l.value, ...c.value]) t.id && e.set(t.id, t);
1724
+ for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1724
1725
  return [...e.values()].sort(y);
1725
1726
  });
1726
1727
  function x() {
1727
- return s.value === "likes" ? [
1728
+ return o.value === "likes" ? [
1728
1729
  X("listed", "==", !0),
1729
1730
  W("likeCount", "desc"),
1730
1731
  W("createdAt", "desc"),
@@ -1736,63 +1737,63 @@ function Jn(e = "latest", t = {}) {
1736
1737
  ];
1737
1738
  }
1738
1739
  function S() {
1739
- g?.(), g = U(G(i(), ...x(), H(o.value)), (e) => {
1740
- c.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= o.value), u.value = !1;
1740
+ h?.(), h = U(G(i(), ...x(), H(a.value)), (e) => {
1741
+ s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1741
1742
  }, (e) => {
1742
- console.error("[memi-board:commentFeed] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
1743
+ console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
1743
1744
  });
1744
1745
  }
1745
1746
  async function C() {
1746
- if (!(f.value || !d.value || u.value)) {
1747
- f.value = !0, p.value = "";
1747
+ if (!(d.value || !u.value || l.value)) {
1748
+ d.value = !0, f.value = "";
1748
1749
  try {
1749
- let e = h ?? m, t = await B(G(i(), ...x(), ...e ? [J(e)] : [], H(o.value + 1))), n = t.docs.slice(0, o.value), r = n.map(_), a = new Set([...l.value, ...c.value].map((e) => e.id));
1750
- l.value.push(...r.filter((e) => !a.has(e.id))), h = n.at(-1) ?? h, d.value = t.docs.length > o.value;
1750
+ let e = m ?? p, t = await B(G(i(), ...x(), ...e ? [J(e)] : [], H(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
1751
+ c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
1751
1752
  } catch (e) {
1752
- p.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
1753
+ f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
1753
1754
  } finally {
1754
- f.value = !1;
1755
+ d.value = !1;
1755
1756
  }
1756
1757
  }
1757
1758
  }
1758
1759
  function w() {
1759
- g?.(), c.value = [], l.value = [], m = null, h = null, d.value = !0, p.value = "", u.value = !0, S();
1760
+ h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, S();
1760
1761
  }
1761
- return L([s, o], w, { immediate: !0 }), P(() => g?.()), {
1762
+ return L([o, a], w, { immediate: !0 }), P(() => h?.()), {
1762
1763
  comments: b,
1763
- commentsPending: u,
1764
- hasMore: d,
1765
- loadingMore: f,
1766
- loadError: p,
1764
+ commentsPending: l,
1765
+ hasMore: u,
1766
+ loadingMore: d,
1767
+ loadError: f,
1767
1768
  loadMore: C,
1768
- sort: s
1769
+ sort: o
1769
1770
  };
1770
1771
  }
1771
1772
  //#endregion
1772
1773
  //#region src/composables/useMemiBoardAuthorMemo.ts
1773
- var Yn = 100, Xn = /* @__PURE__ */ new Map();
1774
+ var Qn = 100, $n = /* @__PURE__ */ new Map();
1774
1775
  function $(e) {
1775
- let t = Xn.get(e);
1776
- return t || (t = me({
1776
+ let t = $n.get(e);
1777
+ return t || (t = ge({
1777
1778
  text: "",
1778
1779
  sentiment: null,
1779
1780
  loaded: !1,
1780
1781
  pending: !1,
1781
1782
  saving: !1,
1782
1783
  error: ""
1783
- }), Xn.set(e, t)), t;
1784
+ }), $n.set(e, t)), t;
1784
1785
  }
1785
- function Zn(e) {
1786
- let t = Z(), n = () => M(), { user: r } = Mt(), { t: i, formatNumber: a } = k(), o = N(() => I(e)), s = N(() => `${r.value?.uid ?? ""}:${o.value}`), c = N(() => {
1786
+ function er(e) {
1787
+ let t = Z(), n = () => j(), { user: r } = Pt(), { t: i, formatNumber: a } = A(), o = N(() => I(e)), s = N(() => `${r.value?.uid ?? ""}:${o.value}`), c = N(() => {
1787
1788
  let e = r.value?.uid, i = o.value;
1788
- return !e || !i ? null : j(t, n(), e, i);
1789
+ return !e || !i ? null : f(t, n(), e, i);
1789
1790
  }), l = N({
1790
1791
  get: () => $(s.value).text,
1791
1792
  set: (e) => {
1792
1793
  $(s.value).text = e;
1793
1794
  }
1794
- }), u = N(() => $(s.value).sentiment), d = N(() => $(s.value).loaded), f = N(() => $(s.value).pending), p = N(() => $(s.value).saving), m = N(() => $(s.value).error);
1795
- async function h() {
1795
+ }), u = N(() => $(s.value).sentiment), d = N(() => $(s.value).loaded), p = N(() => $(s.value).pending), m = N(() => $(s.value).saving), h = N(() => $(s.value).error);
1796
+ async function g() {
1796
1797
  let e = c.value;
1797
1798
  if (!e) return;
1798
1799
  let t = $(s.value);
@@ -1806,7 +1807,7 @@ function Zn(e) {
1806
1807
  t.pending = !1;
1807
1808
  }
1808
1809
  }
1809
- async function g(e, t) {
1810
+ async function _(e, t) {
1810
1811
  let n = c.value;
1811
1812
  if (!n) return;
1812
1813
  let r = e.trim();
@@ -1825,13 +1826,13 @@ function Zn(e) {
1825
1826
  o.saving = !1;
1826
1827
  }
1827
1828
  }
1828
- async function _() {
1829
+ async function v() {
1829
1830
  let e = c.value;
1830
1831
  if (!e) return;
1831
1832
  let t = $(s.value);
1832
1833
  t.saving = !0, t.error = "";
1833
1834
  try {
1834
- await he(e), t.text = "", t.sentiment = null, t.loaded = !0;
1835
+ await _e(e), t.text = "", t.sentiment = null, t.loaded = !0;
1835
1836
  } catch (e) {
1836
1837
  throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
1837
1838
  } finally {
@@ -1842,75 +1843,75 @@ function Zn(e) {
1842
1843
  text: l,
1843
1844
  sentiment: u,
1844
1845
  loaded: d,
1845
- pending: f,
1846
- saving: p,
1847
- error: m,
1848
- load: h,
1849
- save: g,
1850
- remove: _
1846
+ pending: p,
1847
+ saving: m,
1848
+ error: h,
1849
+ load: g,
1850
+ save: _,
1851
+ remove: v
1851
1852
  };
1852
1853
  }
1853
1854
  //#endregion
1854
1855
  //#region src/utils/subscribeCommentRange.ts
1855
- function Qn(e, t, n, r, i, o) {
1856
- return U(G(a(e, t), X("postId", "==", n), ...r.rootId ? [X("rootId", "==", r.rootId), X("isReply", "==", !0)] : [X("parentId", "==", null)], W("createdAt", "asc"), W(R(), "asc"), ...r.hasMore && r.cursor ? [ve(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
1856
+ function tr(e, t, n, r, i, a) {
1857
+ return U(G(g(e, t), X("postId", "==", n), ...r.rootId ? [X("rootId", "==", r.rootId), X("isReply", "==", !0)] : [X("parentId", "==", null)], W("createdAt", "asc"), W(R(), "asc"), ...r.hasMore && r.cursor ? [be(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
1857
1858
  ...e.data(),
1858
1859
  id: e.id
1859
- }))), o);
1860
+ }))), a);
1860
1861
  }
1861
1862
  //#endregion
1862
1863
  //#region src/composables/useMemiBoardComments.ts
1863
- var $n = 10, er = 5, tr = 1e3;
1864
- function nr(e, { t, formatNumber: n }) {
1864
+ var nr = 10, rr = 5, ir = 1e3;
1865
+ function ar(e, { t, formatNumber: n }) {
1865
1866
  let r = e.trim();
1866
1867
  if (!r) throw Error(t("comments.bodyRequired"));
1867
- if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(tr) }));
1868
+ if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(ir) }));
1868
1869
  return r;
1869
1870
  }
1870
- function rr(e, n, r = {}) {
1871
- let i = Z(), o = () => M(), { isBoardHidden: s } = Fn(), c = k(), { t: l } = c, u = () => a(i, o()), d = N(() => I(e)), f = N(() => I(n)), p = () => !s(d.value), m = F([]), g = F(r.subscribe !== !1), _ = F([]), v = F(!1), y = F(r.subscribe !== !1), b = F(r.subscribe !== !1), x = null, S = 0, C = 0, w;
1872
- function T(e) {
1871
+ function or(e, t, n = {}) {
1872
+ let r = Z(), i = Oe(), a = () => j(), { isBoardHidden: o } = Rn(), s = A(), { t: c } = s, l = () => g(r, a()), u = N(() => I(e)), f = N(() => I(t)), p = () => !o(u.value), m = F([]), h = F(n.subscribe !== !1), _ = F([]), v = F(!1), b = F(n.subscribe !== !1), S = F(n.subscribe !== !1), C = null, w = 0, T = 0, E;
1873
+ function D(e) {
1873
1874
  return e.createdAt?.toMillis?.() ?? 0;
1874
1875
  }
1875
- let E = N(() => {
1876
+ let ee = N(() => {
1876
1877
  let e = /* @__PURE__ */ new Map();
1877
1878
  for (let t of [...m.value, ..._.value]) t.id && e.set(t.id, t);
1878
- return [...e.values()].sort((e, t) => T(e) - T(t) || String(e.id).localeCompare(String(t.id)));
1879
+ return [...e.values()].sort((e, t) => D(e) - D(t) || String(e.id).localeCompare(String(t.id)));
1879
1880
  });
1880
- L([f, d], async ([e]) => {
1881
- let t = ++S;
1882
- if (C++, v.value = !1, _.value = [], m.value = [], x = null, w?.(), w = void 0, y.value = r.subscribe !== !1, r.subscribe !== !1) {
1883
- g.value = !0, b.value = !0;
1881
+ L([f, u], async ([e]) => {
1882
+ let t = ++w;
1883
+ if (T++, v.value = !1, _.value = [], m.value = [], C = null, E?.(), E = void 0, b.value = n.subscribe !== !1, n.subscribe !== !1) {
1884
+ h.value = !0, S.value = !0;
1884
1885
  try {
1885
- let n = B(G(u(), X("postId", "==", e), W("createdAt", "desc"), W(R(), "desc")));
1886
+ let n = B(G(l(), X("postId", "==", e), W("createdAt", "desc"), W(R(), "desc")));
1886
1887
  if (await Promise.all([n.then((e) => {
1887
- if (t !== S) return;
1888
+ if (t !== w) return;
1888
1889
  let n = e.docs.map((e) => ({
1889
1890
  id: e.id,
1890
1891
  ...e.data()
1891
1892
  }));
1892
1893
  m.value = n.filter((e) => e.parentId === void 0);
1893
- }), O()]), t !== S) return;
1894
+ }), ne()]), t !== w) return;
1894
1895
  } finally {
1895
- t === S && (g.value = !1, b.value = !1);
1896
+ t === w && (h.value = !1, S.value = !1);
1896
1897
  }
1897
1898
  }
1898
1899
  }, { immediate: !0 });
1899
- function D() {
1900
- w?.();
1901
- let e = ++C;
1902
- w = Qn(i, o(), f.value, {
1903
- cursor: x,
1904
- hasMore: y.value
1900
+ function te() {
1901
+ E?.();
1902
+ let e = ++T;
1903
+ E = tr(r, a(), f.value, {
1904
+ cursor: C,
1905
+ hasMore: b.value
1905
1906
  }, (t) => {
1906
- e === C && (_.value = t);
1907
+ e === T && (_.value = t);
1907
1908
  }, (e) => {
1908
1909
  console.error("[memi-board:comments] onSnapshot failed", e);
1909
1910
  });
1910
1911
  }
1911
- async function O() {
1912
- if (v.value || !y.value) return;
1913
- let e = S;
1912
+ async function ne() {
1913
+ if (v.value || !b.value) return;
1914
+ let e = w;
1914
1915
  v.value = !0;
1915
1916
  try {
1916
1917
  let t = [
@@ -1918,250 +1919,268 @@ function rr(e, n, r = {}) {
1918
1919
  X("parentId", "==", null),
1919
1920
  W("createdAt", "asc"),
1920
1921
  W(R(), "asc"),
1921
- ...x ? [J(x)] : [],
1922
+ ...C ? [J(C)] : [],
1922
1923
  H(11)
1923
- ], n = await B(G(u(), ...t));
1924
- if (e !== S) return;
1925
- let r = n.docs.slice(0, $n), i = r.map((e) => ({
1924
+ ], n = await B(G(l(), ...t));
1925
+ if (e !== w) return;
1926
+ let r = n.docs.slice(0, nr), i = r.map((e) => ({
1926
1927
  id: e.id,
1927
1928
  ...e.data()
1928
1929
  })), a = new Set(_.value.map((e) => e.id));
1929
- _.value.push(...i.filter((e) => !a.has(e.id))), x = r.at(-1) ?? x, y.value = n.size > $n, D();
1930
+ _.value.push(...i.filter((e) => !a.has(e.id))), C = r.at(-1) ?? C, b.value = n.size > nr, te();
1930
1931
  } finally {
1931
- e === S && (v.value = !1);
1932
+ e === w && (v.value = !1);
1932
1933
  }
1933
1934
  }
1934
1935
  P(() => {
1935
- S++, C++, w?.();
1936
+ w++, T++, E?.();
1936
1937
  });
1937
- async function ee(e) {
1938
- let n = nr(e.body, c), r = Se(i), a = _e(u());
1939
- r.set(a, {
1938
+ function O() {
1939
+ return ye(l()).id;
1940
+ }
1941
+ function re(e) {
1942
+ if (!e) return ye(l());
1943
+ if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(c("commentForm.uploadFailed"));
1944
+ return d(r, a(), e);
1945
+ }
1946
+ function ie(e, t) {
1947
+ let n = `${x(a(), f.value)}/comment-images/${e}/`;
1948
+ return ue(t).filter((e) => e.path.startsWith(n));
1949
+ }
1950
+ function ae(e, t) {
1951
+ let n = ie(t, e.images);
1952
+ return {
1940
1953
  postId: f.value,
1941
- boardId: d.value,
1954
+ boardId: u.value,
1942
1955
  listed: p(),
1943
- body: n,
1956
+ body: ar(e.body, s),
1944
1957
  authorUid: e.authorUid,
1945
1958
  authorName: e.authorName,
1946
1959
  authorPhoto: e.authorPhoto,
1947
1960
  moderationStatus: "approved",
1961
+ replyCount: 0,
1962
+ likeCount: 0,
1963
+ createdAt: K(),
1964
+ updatedAt: K(),
1965
+ ...n.length ? { images: n } : {}
1966
+ };
1967
+ }
1968
+ async function oe(e) {
1969
+ if (!e.length) return;
1970
+ let t = Re(i);
1971
+ await Promise.all(e.map((e) => Le(Be(t, e)).catch(() => {})));
1972
+ }
1973
+ async function k(e) {
1974
+ let t = we(r), n = re(e.id);
1975
+ t.set(n, {
1976
+ ...ae(e, n.id),
1948
1977
  parentId: null,
1949
- rootId: a.id,
1978
+ rootId: n.id,
1950
1979
  depth: 0,
1951
1980
  replyToUid: null,
1952
1981
  replyToName: null,
1953
- replyCount: 0,
1954
- likeCount: 0,
1955
- isReply: !1,
1956
- createdAt: K(),
1957
- updatedAt: K()
1958
- }), r.update(t(i, o(), f.value), { commentCount: V(1) }), await r.commit();
1959
- }
1960
- async function A(e) {
1961
- let n = nr(e.body, c);
1962
- if (!e.parent.id) throw Error(l("comments.replyTargetNotFound"));
1963
- let r = Se(i), a = _e(u()), s = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
1964
- if (!s) throw Error(l("comments.threadNotFound"));
1965
- let m = Math.min((e.parent.depth ?? 0) + 1, 2);
1966
- r.set(a, {
1967
- postId: f.value,
1968
- boardId: d.value,
1969
- listed: p(),
1970
- body: n,
1971
- authorUid: e.authorUid,
1972
- authorName: e.authorName,
1973
- authorPhoto: e.authorPhoto,
1974
- moderationStatus: "approved",
1982
+ isReply: !1
1983
+ }), t.update(y(r, a(), f.value), { commentCount: V(1) }), await t.commit();
1984
+ }
1985
+ async function se(e) {
1986
+ if (!e.parent.id) throw Error(c("comments.replyTargetNotFound"));
1987
+ let t = we(r), n = re(e.id), i = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
1988
+ if (!i) throw Error(c("comments.threadNotFound"));
1989
+ let o = Math.min((e.parent.depth ?? 0) + 1, 2);
1990
+ t.set(n, {
1991
+ ...ae(e, n.id),
1975
1992
  parentId: e.parent.id,
1976
- rootId: s,
1977
- depth: m,
1993
+ rootId: i,
1994
+ depth: o,
1978
1995
  replyToUid: e.parent.authorUid,
1979
1996
  replyToName: e.parent.authorName,
1980
- replyCount: 0,
1981
- likeCount: 0,
1982
- isReply: !0,
1983
- createdAt: K(),
1984
- updatedAt: K()
1985
- }), r.update(h(i, o(), s), { replyCount: V(1) }), r.update(t(i, o(), f.value), { commentCount: V(1) }), await r.commit();
1997
+ isReply: !0
1998
+ }), t.update(d(r, a(), i), { replyCount: V(1) }), t.update(y(r, a(), f.value), { commentCount: V(1) }), await t.commit();
1986
1999
  }
1987
- async function j(e) {
2000
+ async function ce(e) {
1988
2001
  if (!e.id) return;
1989
- if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(l("comments.hasRepliesCannotDelete"));
1990
- await qt(i, o(), e.id);
1991
- let n = Se(i);
1992
- n.delete(h(i, o(), e.id)), e.parentId && e.rootId && n.update(h(i, o(), e.rootId), { replyCount: V(-1) }), n.update(t(i, o(), f.value), { commentCount: V(-1) }), await n.commit(), _.value = _.value.filter((t) => t.id !== e.id), m.value = m.value.filter((t) => t.id !== e.id);
1993
- }
1994
- async function te(e, t) {
1995
- let n = nr(t, c);
1996
- await Y(h(i, o(), e), {
1997
- body: n,
2002
+ if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(c("comments.hasRepliesCannotDelete"));
2003
+ let t = de(e.images, `${x(a(), f.value)}/comment-images/${e.id}/`);
2004
+ await Xt(r, a(), e.id);
2005
+ let n = we(r);
2006
+ n.delete(d(r, a(), e.id)), e.parentId && e.rootId && n.update(d(r, a(), e.rootId), { replyCount: V(-1) }), n.update(y(r, a(), f.value), { commentCount: V(-1) }), await n.commit(), await oe(t), _.value = _.value.filter((t) => t.id !== e.id), m.value = m.value.filter((t) => t.id !== e.id);
2007
+ }
2008
+ async function le(e, t, n) {
2009
+ let i = {
2010
+ body: ar(t, s),
1998
2011
  updatedAt: K()
1999
- });
2012
+ };
2013
+ if (n !== void 0) {
2014
+ let t = ie(e, n);
2015
+ i.images = t.length ? t : ve();
2016
+ }
2017
+ await Y(d(r, a(), e), i);
2000
2018
  }
2001
- async function ne(e, t, n) {
2002
- await Y(h(i, o(), e), {
2019
+ async function fe(e, t, n) {
2020
+ await Y(d(r, a(), e), {
2003
2021
  isBlinded: t,
2004
2022
  moderatedAt: K(),
2005
2023
  moderatedBy: n
2006
2024
  });
2007
2025
  }
2008
2026
  return {
2009
- comments: E,
2010
- commentsPending: N(() => b.value || g.value),
2011
- hasMore: y,
2027
+ comments: ee,
2028
+ commentsPending: N(() => S.value || h.value),
2029
+ hasMore: b,
2012
2030
  loadingMore: v,
2013
- loadMore: O,
2014
- addComment: ee,
2015
- addReply: A,
2016
- updateComment: te,
2017
- setCommentBlinded: ne,
2018
- deleteComment: j
2031
+ loadMore: ne,
2032
+ newCommentId: O,
2033
+ addComment: k,
2034
+ addReply: se,
2035
+ updateComment: le,
2036
+ setCommentBlinded: fe,
2037
+ deleteComment: ce
2019
2038
  };
2020
2039
  }
2021
- function ir(e, t, n) {
2022
- let r = Z(), i = () => M(), o = () => a(r, i()), s = t.trim(), c = F([]), l = F(!1), u = F(!1), d = F(!0), f = null, p, m = 0, h = 0;
2023
- function g(e) {
2040
+ function sr(e, t, n) {
2041
+ let r = Z(), i = () => j(), a = () => g(r, i()), o = t.trim(), s = F([]), c = F(!1), l = F(!1), u = F(!0), d = null, f, p = 0, m = 0;
2042
+ function h(e) {
2024
2043
  return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
2025
2044
  }
2026
2045
  function _() {
2027
- p?.();
2028
- let e = ++h;
2029
- p = Qn(r, i(), s, {
2046
+ f?.();
2047
+ let e = ++m;
2048
+ f = tr(r, i(), o, {
2030
2049
  rootId: n,
2031
- cursor: f,
2032
- hasMore: d.value
2050
+ cursor: d,
2051
+ hasMore: u.value
2033
2052
  }, (t) => {
2034
- e === h && (c.value = t);
2053
+ e === m && (s.value = t);
2035
2054
  }, (e) => {
2036
2055
  console.error("[memi-board:replies] onSnapshot failed", e);
2037
2056
  });
2038
2057
  }
2039
2058
  async function v() {
2040
- if (l.value || !d.value) return;
2041
- let e = m;
2042
- l.value = !0;
2059
+ if (c.value || !u.value) return;
2060
+ let e = p;
2061
+ c.value = !0;
2043
2062
  try {
2044
2063
  let t = [
2045
- X("postId", "==", s),
2064
+ X("postId", "==", o),
2046
2065
  X("rootId", "==", n),
2047
2066
  X("isReply", "==", !0),
2048
2067
  W("createdAt", "asc"),
2049
2068
  W(R(), "asc"),
2050
- ...f ? [J(f)] : [],
2069
+ ...d ? [J(d)] : [],
2051
2070
  H(6)
2052
- ], r = await B(G(o(), ...t));
2053
- if (e !== m) return;
2054
- let i = new Set(c.value.map((e) => e.id)), a = r.docs.slice(0, er), l = a.map((e) => ({
2071
+ ], r = await B(G(a(), ...t));
2072
+ if (e !== p) return;
2073
+ let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0, rr), f = c.map((e) => ({
2055
2074
  id: e.id,
2056
2075
  ...e.data()
2057
2076
  })).filter((e) => !i.has(e.id));
2058
- c.value = g([...c.value, ...l]), f = a.at(-1) ?? f, u.value = !0, d.value = r.size > er, _();
2077
+ s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size > rr, _();
2059
2078
  } finally {
2060
- e === m && (l.value = !1);
2079
+ e === p && (c.value = !1);
2061
2080
  }
2062
2081
  }
2063
2082
  function y() {
2064
- m++, h++, l.value = !1, p?.(), p = void 0, c.value = [], f = null, u.value = !1, d.value = !0;
2083
+ p++, m++, c.value = !1, f?.(), f = void 0, s.value = [], d = null, l.value = !1, u.value = !0;
2065
2084
  }
2066
2085
  async function b() {
2067
2086
  y(), await v();
2068
2087
  }
2069
2088
  return P(() => {
2070
- m++, h++, p?.();
2089
+ p++, m++, f?.();
2071
2090
  }), {
2072
- replies: c,
2073
- loading: l,
2074
- loaded: u,
2075
- hasMore: d,
2091
+ replies: s,
2092
+ loading: c,
2093
+ loaded: l,
2094
+ hasMore: u,
2076
2095
  loadMore: v,
2077
2096
  refresh: b
2078
2097
  };
2079
2098
  }
2080
2099
  //#endregion
2081
2100
  //#region src/composables/useMemiBoardLikes.ts
2082
- function ar(e, n) {
2083
- let r = () => M(), i = Z(), a = we(), { t: o } = k(), s = F(!1), l = F(!1), u;
2084
- function d(e) {
2085
- return c(i, r(), n, e);
2101
+ function cr(e, t) {
2102
+ let n = () => j(), r = Z(), i = Ee(), { t: a } = A(), o = F(!1), s = F(!1), c;
2103
+ function l(e) {
2104
+ return he(r, n(), t, e);
2086
2105
  }
2087
- L(a, (e) => {
2088
- if (u?.(), u = void 0, !e) {
2089
- s.value = !1;
2106
+ L(i, (e) => {
2107
+ if (c?.(), c = void 0, !e) {
2108
+ o.value = !1;
2090
2109
  return;
2091
2110
  }
2092
- u = U(d(e.uid), (e) => {
2093
- s.value = e.exists();
2111
+ c = U(l(e.uid), (e) => {
2112
+ o.value = e.exists();
2094
2113
  }, (e) => {
2095
2114
  console.error("[memi-board:likes] onSnapshot failed", e);
2096
2115
  });
2097
- }, { immediate: !0 }), P(() => u?.());
2098
- async function f() {
2099
- let c = a.value?.uid;
2100
- if (!c) throw Error(o("likes.signInRequired"));
2101
- if (l.value) return s.value;
2102
- l.value = !0;
2116
+ }, { immediate: !0 }), P(() => c?.());
2117
+ async function u() {
2118
+ let c = i.value?.uid;
2119
+ if (!c) throw Error(a("likes.signInRequired"));
2120
+ if (s.value) return o.value;
2121
+ s.value = !0;
2103
2122
  try {
2104
- let a = d(c), o = t(i, r(), n);
2105
- return await xe(i, async (t) => (await t.get(a)).exists() ? (t.delete(a), t.update(o, { likeCount: V(-1) }), !1) : (t.set(a, {
2123
+ let i = l(c), a = y(r, n(), t);
2124
+ return await Ce(r, async (n) => (await n.get(i)).exists() ? (n.delete(i), n.update(a, { likeCount: V(-1) }), !1) : (n.set(i, {
2106
2125
  uid: c,
2107
- postId: n,
2126
+ postId: t,
2108
2127
  boardId: e,
2109
2128
  createdAt: K()
2110
- }), t.update(o, { likeCount: V(1) }), !0));
2129
+ }), n.update(a, { likeCount: V(1) }), !0));
2111
2130
  } finally {
2112
- l.value = !1;
2131
+ s.value = !1;
2113
2132
  }
2114
2133
  }
2115
2134
  return {
2116
- isLiked: s,
2117
- likePending: l,
2118
- toggleLike: f
2135
+ isLiked: o,
2136
+ likePending: s,
2137
+ toggleLike: u
2119
2138
  };
2120
2139
  }
2121
- var or = Symbol.for("memi-board:comment-likes");
2122
- function sr(e, t) {
2123
- let n = () => M(), r = Z(), i = we(), { t: a } = k(), o = N(() => I(e)), s = N(() => I(t)), l = F(/* @__PURE__ */ new Set()), u = F(null), d;
2140
+ var lr = Symbol.for("memi-board:comment-likes");
2141
+ function ur(e, t) {
2142
+ let n = () => j(), r = Z(), i = Ee(), { t: a } = A(), o = N(() => I(e)), s = N(() => I(t)), c = F(/* @__PURE__ */ new Set()), l = F(null), u;
2124
2143
  L([i, s], ([e, t]) => {
2125
- d?.(), d = void 0, l.value = /* @__PURE__ */ new Set(), e && t && (d = U(G(g(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
2144
+ u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = U(G(b(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
2126
2145
  let t = /* @__PURE__ */ new Set();
2127
2146
  for (let n of e.docs) {
2128
2147
  let e = n.data().commentId;
2129
2148
  typeof e == "string" && e && t.add(e);
2130
2149
  }
2131
- l.value = t;
2150
+ c.value = t;
2132
2151
  }, (e) => {
2133
2152
  console.error("[memi-board:comment-likes] onSnapshot failed", e);
2134
2153
  }));
2135
- }, { immediate: !0 }), P(() => d?.());
2154
+ }, { immediate: !0 }), P(() => u?.());
2136
2155
  function f(e) {
2137
- return !!e && l.value.has(e);
2156
+ return !!e && c.value.has(e);
2138
2157
  }
2139
2158
  function p(e) {
2140
- return !!e && u.value === e;
2159
+ return !!e && l.value === e;
2141
2160
  }
2142
2161
  async function m(e) {
2143
2162
  let t = i.value?.uid;
2144
2163
  if (!t) throw Error(a("likes.signInRequired"));
2145
2164
  if (!e) return !1;
2146
- if (u.value) return f(e);
2147
- u.value = e;
2165
+ if (l.value) return f(e);
2166
+ l.value = e;
2148
2167
  try {
2149
- let i = c(r, n(), e, t), u = h(r, n(), e), d = await xe(r, async (n) => {
2150
- let r = await n.get(i), c = await n.get(u);
2168
+ let i = he(r, n(), e, t), l = d(r, n(), e), u = await Ce(r, async (n) => {
2169
+ let r = await n.get(i), c = await n.get(l);
2151
2170
  if (!c.exists()) throw Error(a("likes.commentNotFound"));
2152
- let l = Number(c.data()?.likeCount ?? 0);
2153
- return r.exists() ? (n.delete(i), n.update(u, { likeCount: Math.max(0, l - 1) }), !1) : (n.set(i, {
2171
+ let u = Number(c.data()?.likeCount ?? 0);
2172
+ return r.exists() ? (n.delete(i), n.update(l, { likeCount: Math.max(0, u - 1) }), !1) : (n.set(i, {
2154
2173
  uid: t,
2155
2174
  postId: s.value,
2156
2175
  boardId: o.value,
2157
2176
  commentId: e,
2158
2177
  target: "comment",
2159
2178
  createdAt: K()
2160
- }), n.update(u, { likeCount: l + 1 }), !0);
2161
- }), f = new Set(l.value);
2162
- return d ? f.add(e) : f.delete(e), l.value = f, d;
2179
+ }), n.update(l, { likeCount: u + 1 }), !0);
2180
+ }), f = new Set(c.value);
2181
+ return u ? f.add(e) : f.delete(e), c.value = f, u;
2163
2182
  } finally {
2164
- u.value = null;
2183
+ l.value = null;
2165
2184
  }
2166
2185
  }
2167
2186
  return {
@@ -2172,7 +2191,7 @@ function sr(e, t) {
2172
2191
  }
2173
2192
  //#endregion
2174
2193
  //#region src/composables/useMemiBoardReports.ts
2175
- var cr = 200, lr = [
2194
+ var dr = 200, fr = [
2176
2195
  {
2177
2196
  value: "spam",
2178
2197
  label: "스팸·광고"
@@ -2194,17 +2213,17 @@ var cr = 200, lr = [
2194
2213
  label: "기타"
2195
2214
  }
2196
2215
  ];
2197
- function ur(e, t) {
2198
- return lr.some((t) => t.value === e) ? E(t, `reports.reason.${e}`) : e || E(t, "reports.fallbackLabel");
2216
+ function pr(e, t) {
2217
+ return fr.some((t) => t.value === e) ? k(t, `reports.reason.${e}`) : e || k(t, "reports.fallbackLabel");
2199
2218
  }
2200
- function dr(e, t) {
2201
- let n = () => M(), r = Z(), i = we(), { t: a } = k(), o = F(!1), s = F(!1), c;
2219
+ function mr(e, t) {
2220
+ let n = () => j(), r = Z(), i = Ee(), { t: a } = A(), o = F(!1), s = F(!1), c;
2202
2221
  L(i, (e) => {
2203
2222
  if (c?.(), c = void 0, !e) {
2204
2223
  o.value = !1;
2205
2224
  return;
2206
2225
  }
2207
- c = U(y(r, n(), t, e.uid), (e) => {
2226
+ c = U(u(r, n(), t, e.uid), (e) => {
2208
2227
  o.value = e.exists();
2209
2228
  }, (e) => {
2210
2229
  console.error("[memi-board:reports] onSnapshot failed", e);
@@ -2215,19 +2234,19 @@ function dr(e, t) {
2215
2234
  if (!l) throw Error(a("reports.signInRequired"));
2216
2235
  if (s.value) return;
2217
2236
  if (c.authorUid && c.authorUid === l) throw Error(a("reports.cannotReportOwn"));
2218
- let u = lr.some((e) => e.value === c.reason) ? c.reason : null;
2219
- if (!u) throw Error(a("reports.reasonRequired"));
2220
- let d = (c.detail || "").trim();
2221
- if (d.length > 200) throw Error(a("reports.detailTooLong", { max: 200 }));
2237
+ let d = fr.some((e) => e.value === c.reason) ? c.reason : null;
2238
+ if (!d) throw Error(a("reports.reasonRequired"));
2239
+ let f = (c.detail || "").trim();
2240
+ if (f.length > 200) throw Error(a("reports.detailTooLong", { max: 200 }));
2222
2241
  s.value = !0;
2223
2242
  try {
2224
- await q(y(r, n(), t, l), {
2243
+ await q(u(r, n(), t, l), {
2225
2244
  uid: l,
2226
2245
  target: "post",
2227
2246
  postId: t,
2228
2247
  boardId: e,
2229
- reason: u,
2230
- detail: d,
2248
+ reason: d,
2249
+ detail: f,
2231
2250
  status: "open",
2232
2251
  postTitle: (c.postTitle || "").trim().slice(0, 200),
2233
2252
  authorUid: c.authorUid || "",
@@ -2244,116 +2263,116 @@ function dr(e, t) {
2244
2263
  submitReport: l
2245
2264
  };
2246
2265
  }
2247
- var fr = 20;
2248
- function pr(e = {}) {
2249
- let t = () => M(), n = Z(), { isAdmin: r, canManageContent: i, canManageBoard: a } = Mt(), s = e.pageSize ?? fr, c = N(() => I(e.boardId)?.trim() || ""), l = F([]), u = F(!0), d = F(!1), f = F(!1), p = F(""), m = null, h;
2250
- function g(e) {
2266
+ var hr = 20;
2267
+ function gr(e = {}) {
2268
+ let t = () => j(), n = Z(), { isAdmin: r, canManageContent: i, canManageBoard: a } = Pt(), o = e.pageSize ?? hr, s = N(() => I(e.boardId)?.trim() || ""), c = F([]), d = F(!0), f = F(!1), p = F(!1), m = F(""), h = null, g;
2269
+ function _(e) {
2251
2270
  return {
2252
2271
  id: e.id,
2253
2272
  ...e.data()
2254
2273
  };
2255
2274
  }
2256
- function _() {
2257
- if (h?.(), !i.value || !r.value && !c.value) {
2258
- l.value = [], u.value = !1;
2275
+ function v() {
2276
+ if (g?.(), !i.value || !r.value && !s.value) {
2277
+ c.value = [], d.value = !1;
2259
2278
  return;
2260
2279
  }
2261
- u.value = !0;
2262
- let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")];
2263
- h = U(G(o(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), H(s)), (e) => {
2264
- l.value = e.docs.map(g).filter((e) => a(e.boardId)), m = e.docs.at(-1) ?? null, f.value = e.docs.length >= s, u.value = !1;
2280
+ d.value = !0;
2281
+ let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")];
2282
+ g = U(G(l(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), H(o)), (e) => {
2283
+ c.value = e.docs.map(_).filter((e) => a(e.boardId)), h = e.docs.at(-1) ?? null, p.value = e.docs.length >= o, d.value = !1;
2265
2284
  }, (e) => {
2266
- console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
2285
+ console.error("[memi-board:report-queue] onSnapshot failed", e), m.value = e.message || String(e), d.value = !1;
2267
2286
  });
2268
2287
  }
2269
- L([i, c], _, { immediate: !0 }), P(() => h?.());
2270
- async function v() {
2271
- if (!d.value && f.value && m && i.value) {
2272
- d.value = !0, p.value = "";
2288
+ L([i, s], v, { immediate: !0 }), P(() => g?.());
2289
+ async function y() {
2290
+ if (!f.value && p.value && h && i.value) {
2291
+ f.value = !0, m.value = "";
2273
2292
  try {
2274
- let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await B(G(o(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), J(m), H(s + 1))), i = r.docs.slice(0, s), u = new Set(l.value.map((e) => e.id));
2275
- l.value.push(...i.map(g).filter((e) => !u.has(e.id) && a(e.boardId))), m = i.at(-1) ?? m, f.value = r.docs.length > s;
2293
+ let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await B(G(l(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), J(h), H(o + 1))), i = r.docs.slice(0, o), u = new Set(c.value.map((e) => e.id));
2294
+ c.value.push(...i.map(_).filter((e) => !u.has(e.id) && a(e.boardId))), h = i.at(-1) ?? h, p.value = r.docs.length > o;
2276
2295
  } catch (e) {
2277
- p.value = e.message || String(e);
2296
+ m.value = e.message || String(e);
2278
2297
  } finally {
2279
- d.value = !1;
2298
+ f.value = !1;
2280
2299
  }
2281
2300
  }
2282
2301
  }
2283
2302
  async function b(e, r) {
2284
- e.id && a(e.boardId) && await Y(y(n, t(), e.postId, e.uid), {
2303
+ e.id && a(e.boardId) && await Y(u(n, t(), e.postId, e.uid), {
2285
2304
  status: r,
2286
2305
  reviewedAt: K(),
2287
- reviewedBy: we().value?.uid || ""
2306
+ reviewedBy: Ee().value?.uid || ""
2288
2307
  });
2289
2308
  }
2290
2309
  return {
2291
- reports: l,
2292
- pending: u,
2293
- loadingMore: d,
2294
- hasMore: f,
2295
- loadError: p,
2296
- loadMore: v,
2310
+ reports: c,
2311
+ pending: d,
2312
+ loadingMore: f,
2313
+ hasMore: p,
2314
+ loadError: m,
2315
+ loadMore: y,
2297
2316
  dismissReport: (e) => b(e, "dismissed"),
2298
2317
  actionReport: (e) => b(e, "actioned")
2299
2318
  };
2300
2319
  }
2301
2320
  //#endregion
2302
2321
  //#region src/composables/useMemiBoardViews.ts
2303
- function mr() {
2304
- let e = () => M(), n = Z();
2305
- function r(t, n) {
2322
+ function _r() {
2323
+ let e = () => j(), t = Z();
2324
+ function n(t, n) {
2306
2325
  let { postsCollection: r } = e();
2307
2326
  return `memi-board:viewed:${r}:${t}:${n}`;
2308
2327
  }
2309
- function i(e, t) {
2328
+ function r(e, t) {
2310
2329
  if (typeof sessionStorage > "u") return !1;
2311
2330
  try {
2312
- return sessionStorage.getItem(r(e, t)) === "1";
2331
+ return sessionStorage.getItem(n(e, t)) === "1";
2313
2332
  } catch {
2314
2333
  return !1;
2315
2334
  }
2316
2335
  }
2317
- function a(e, t) {
2336
+ function i(e, t) {
2318
2337
  if (typeof sessionStorage < "u") try {
2319
- sessionStorage.setItem(r(e, t), "1");
2338
+ sessionStorage.setItem(n(e, t), "1");
2320
2339
  } catch {}
2321
2340
  }
2322
- async function o(o, s) {
2323
- let c = o?.trim(), l = s?.trim();
2324
- if (c && l && !i(c, l)) {
2325
- a(c, l);
2341
+ async function a(a, o) {
2342
+ let s = a?.trim(), c = o?.trim();
2343
+ if (s && c && !r(s, c)) {
2344
+ i(s, c);
2326
2345
  try {
2327
- await Y(t(n, e(), l), { viewCount: V(1) });
2346
+ await Y(y(t, e(), c), { viewCount: V(1) });
2328
2347
  } catch (e) {
2329
2348
  try {
2330
- sessionStorage.removeItem(r(c, l));
2349
+ sessionStorage.removeItem(n(s, c));
2331
2350
  } catch {}
2332
2351
  import.meta.dev && console.warn("[memi-board] recordView failed", e);
2333
2352
  }
2334
2353
  }
2335
2354
  }
2336
2355
  return {
2337
- recordView: o,
2338
- hasRecordedView: i
2356
+ recordView: a,
2357
+ hasRecordedView: r
2339
2358
  };
2340
2359
  }
2341
2360
  //#endregion
2342
2361
  //#region src/composables/useMemiBoardModeration.ts
2343
- var hr = {
2362
+ var vr = {
2344
2363
  flagged: !1,
2345
2364
  category: "none",
2346
2365
  reason: "",
2347
2366
  via: "empty"
2348
2367
  };
2349
- function gr(e = {}) {
2350
- let t = k(), n = N(() => O(I(e.locale)) ?? t.locale.value), r = _().moderation ?? {}, i = Ee(), a = (e) => E(n.value, e), { isWriteRestricted: o, restrictedMessage: s, recordContentModerationBlock: c } = Mt(), l = bn([...yn, ...r.localBlocklist ?? []]);
2368
+ function yr(e = {}) {
2369
+ let t = A(), n = N(() => M(I(e.locale)) ?? t.locale.value), r = v().moderation ?? {}, i = Oe(), a = (e) => k(n.value, e), { isWriteRestricted: o, restrictedMessage: s, recordContentModerationBlock: c } = Pt(), l = Cn([...Sn, ...r.localBlocklist ?? []]);
2351
2370
  function u(e) {
2352
2371
  let t = e.match(l);
2353
2372
  return t ? {
2354
2373
  flagged: !0,
2355
2374
  category: "abuse",
2356
- reason: vn({
2375
+ reason: xn({
2357
2376
  via: "local",
2358
2377
  localHit: t[0] || "",
2359
2378
  category: "abuse"
@@ -2362,21 +2381,21 @@ function gr(e = {}) {
2362
2381
  } : null;
2363
2382
  }
2364
2383
  function d() {
2365
- let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, a = Ve(i, {
2366
- backend: new ze(),
2384
+ let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, a = Ue(i, {
2385
+ backend: new Ve(),
2367
2386
  useLimitedUseAppCheckTokens: t
2368
2387
  });
2369
- return He(a, {
2388
+ return We(a, {
2370
2389
  model: e,
2371
- systemInstruction: pn(n.value),
2390
+ systemInstruction: gn(n.value),
2372
2391
  generationConfig: {
2373
2392
  temperature: 0,
2374
2393
  maxOutputTokens: 256,
2375
2394
  responseMimeType: "application/json",
2376
- responseSchema: Be.object({ properties: {
2377
- flagged: Be.boolean(),
2378
- category: Be.string(),
2379
- reason: Be.string()
2395
+ responseSchema: He.object({ properties: {
2396
+ flagged: He.boolean(),
2397
+ category: He.string(),
2398
+ reason: He.string()
2380
2399
  } })
2381
2400
  }
2382
2401
  });
@@ -2397,7 +2416,7 @@ function gr(e = {}) {
2397
2416
  };
2398
2417
  }
2399
2418
  function p(e, t = "") {
2400
- let n = vn({
2419
+ let n = xn({
2401
2420
  reason: e.reason,
2402
2421
  category: e.category,
2403
2422
  via: e.via
@@ -2425,26 +2444,26 @@ function gr(e = {}) {
2425
2444
  };
2426
2445
  let i = e.trim();
2427
2446
  if (!i) return {
2428
- ...hr,
2447
+ ...vr,
2429
2448
  via: "empty"
2430
2449
  };
2431
2450
  if (t?.skipFilter) return {
2432
- ...hr,
2451
+ ...vr,
2433
2452
  via: "admin-override"
2434
2453
  };
2435
2454
  let c = u(i);
2436
2455
  if (c) return m(c);
2437
2456
  if (r.enabled === !1) return {
2438
- ...hr,
2457
+ ...vr,
2439
2458
  via: "disabled"
2440
2459
  };
2441
2460
  try {
2442
- let e = Sn((await d().generateContent(mn(i, n.value))).response.text());
2461
+ let e = Tn((await d().generateContent(_n(i, n.value))).response.text());
2443
2462
  if (!e) return f();
2444
2463
  let t = {
2445
2464
  flagged: e.flagged,
2446
2465
  category: e.category,
2447
- reason: vn({
2466
+ reason: xn({
2448
2467
  reason: e.reason,
2449
2468
  category: e.category,
2450
2469
  via: "ai"
@@ -2464,22 +2483,22 @@ function gr(e = {}) {
2464
2483
  via: "restricted"
2465
2484
  };
2466
2485
  if (r.enabled === !1 || !r.moderateImages) return {
2467
- ...hr,
2486
+ ...vr,
2468
2487
  via: "disabled"
2469
2488
  };
2470
2489
  try {
2471
2490
  let t = await new Promise((t, n) => {
2472
2491
  let r = new FileReader();
2473
2492
  r.onload = () => t(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(e);
2474
- }), r = Sn((await d().generateContent([{ inlineData: {
2493
+ }), r = Tn((await d().generateContent([{ inlineData: {
2475
2494
  mimeType: e.type || "image/jpeg",
2476
2495
  data: t
2477
- } }, hn(n.value)])).response.text());
2496
+ } }, vn(n.value)])).response.text());
2478
2497
  if (!r) return f();
2479
2498
  let i = {
2480
2499
  flagged: r.flagged,
2481
2500
  category: r.category,
2482
- reason: vn({
2501
+ reason: xn({
2483
2502
  reason: r.reason,
2484
2503
  category: r.category,
2485
2504
  via: "ai"
@@ -2498,7 +2517,7 @@ function gr(e = {}) {
2498
2517
  }
2499
2518
  //#endregion
2500
2519
  //#region src/composables/useMemiBoardUsers.ts
2501
- var _r = [
2520
+ var br = [
2502
2521
  "owner",
2503
2522
  "admin",
2504
2523
  "manager",
@@ -2506,31 +2525,31 @@ var _r = [
2506
2525
  "user"
2507
2526
  ].map((e) => ({
2508
2527
  value: e,
2509
- label: E("ko", `common.role.${e}`),
2510
- description: E("ko", `boardUsers.roleDescription.${e}`)
2528
+ label: k("ko", `common.role.${e}`),
2529
+ description: k("ko", `boardUsers.roleDescription.${e}`)
2511
2530
  }));
2512
- function vr(t = {}) {
2513
- let n = () => M(), r = Z(), { t: i } = k(), a = N(() => I(t.enabled) ?? !0 ? p(r, n()) : null), o = Ce(a, { ssrKey: e(n(), "users-management") });
2514
- async function s(e, t) {
2515
- if (!_r.some((e) => e.value === t)) throw Error(i("boardUsers.unsupportedRole"));
2516
- await Y(A(r, n(), e), {
2517
- role: t,
2531
+ function xr(e = {}) {
2532
+ let t = () => j(), n = Z(), { t: r } = A(), i = N(() => I(e.enabled) ?? !0 ? c(n, t()) : null), a = Te(i, { ssrKey: p(t(), "users-management") });
2533
+ async function o(e, i) {
2534
+ if (!br.some((e) => e.value === i)) throw Error(r("boardUsers.unsupportedRole"));
2535
+ await Y(h(n, t(), e), {
2536
+ role: i,
2518
2537
  updatedAt: K()
2519
2538
  });
2520
2539
  }
2521
2540
  return {
2522
- users: o,
2523
- usersPending: o.pending,
2524
- updateUserRole: s
2541
+ users: a,
2542
+ usersPending: a.pending,
2543
+ updateUserRole: o
2525
2544
  };
2526
2545
  }
2527
2546
  //#endregion
2528
2547
  //#region src/composables/useMemiBoardUserProfile.ts
2529
- function yr(e) {
2530
- let t = Z(), n = () => M(), r = N(() => I(e)), i = N(() => {
2548
+ function Sr(e) {
2549
+ let t = Z(), n = () => j(), r = N(() => I(e)), i = N(() => {
2531
2550
  let e = r.value;
2532
- return e ? A(t, n(), e) : null;
2533
- }), { data: a, pending: o } = Te(i);
2551
+ return e ? h(t, n(), e) : null;
2552
+ }), { data: a, pending: o } = De(i);
2534
2553
  return {
2535
2554
  profile: a,
2536
2555
  profilePending: o
@@ -2538,7 +2557,7 @@ function yr(e) {
2538
2557
  }
2539
2558
  //#endregion
2540
2559
  //#region src/utils/section.ts
2541
- var br = [
2560
+ var Cr = [
2542
2561
  3,
2543
2562
  4,
2544
2563
  5,
@@ -2548,43 +2567,43 @@ var br = [
2548
2567
  9,
2549
2568
  12
2550
2569
  ];
2551
- function xr(e) {
2570
+ function wr(e) {
2552
2571
  return [
2553
2572
  {
2554
2573
  value: "list",
2555
- label: E(e, "sectionUtil.kind.list")
2574
+ label: k(e, "sectionUtil.kind.list")
2556
2575
  },
2557
2576
  {
2558
2577
  value: "post",
2559
- label: E(e, "sectionUtil.kind.post")
2578
+ label: k(e, "sectionUtil.kind.post")
2560
2579
  },
2561
2580
  {
2562
2581
  value: "comments",
2563
- label: E(e, "sectionUtil.kind.comments")
2582
+ label: k(e, "sectionUtil.kind.comments")
2564
2583
  }
2565
2584
  ];
2566
2585
  }
2567
- function Sr(e) {
2586
+ function Tr(e) {
2568
2587
  return [{
2569
2588
  value: "latest",
2570
- label: E(e, "sectionUtil.sort.latest")
2589
+ label: k(e, "sectionUtil.sort.latest")
2571
2590
  }, {
2572
2591
  value: "likes",
2573
- label: E(e, "sectionUtil.sort.likes")
2592
+ label: k(e, "sectionUtil.sort.likes")
2574
2593
  }];
2575
2594
  }
2576
- var Cr = xr("ko"), wr = Sr("ko");
2577
- function Tr(e) {
2595
+ var Er = wr("ko"), Dr = Tr("ko");
2596
+ function Or(e) {
2578
2597
  return e === "list" ? 5 : 4;
2579
2598
  }
2580
- function Er(e, t) {
2599
+ function kr(e, t) {
2581
2600
  let n = Math.floor(Number(t));
2582
- return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : Tr(e);
2601
+ return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : Or(e);
2583
2602
  }
2584
- function Dr(e) {
2603
+ function Ar(e) {
2585
2604
  return e === 12 ? null : 12 - e;
2586
2605
  }
2587
- function Or(e) {
2606
+ function jr(e) {
2588
2607
  return {
2589
2608
  3: "col-span-12 md:col-span-3",
2590
2609
  4: "col-span-12 md:col-span-4",
@@ -2596,36 +2615,36 @@ function Or(e) {
2596
2615
  12: "col-span-12"
2597
2616
  }[e];
2598
2617
  }
2599
- function kr(e) {
2618
+ function Mr(e) {
2600
2619
  return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
2601
2620
  }
2602
- function Ar(e) {
2621
+ function Nr(e) {
2603
2622
  let t = e.boardId || e.category || "free";
2604
2623
  return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
2605
2624
  }
2606
- function jr(e) {
2625
+ function Pr(e) {
2607
2626
  return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
2608
2627
  }
2609
- function Mr(e) {
2628
+ function Fr(e) {
2610
2629
  if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
2611
2630
  }
2612
- function Nr(e) {
2631
+ function Ir(e) {
2613
2632
  return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
2614
2633
  }
2615
- function Pr(e, t) {
2616
- return st(e, t).trim() || ct(e, t).trim() || E(t, "sectionUtil.untitledPost");
2634
+ function Lr(e, t) {
2635
+ return lt(e, t).trim() || ut(e, t).trim() || k(t, "sectionUtil.untitledPost");
2617
2636
  }
2618
- function Fr(e) {
2637
+ function Rr(e) {
2619
2638
  return e === "image" || e === "video" ? "media" : "list";
2620
2639
  }
2621
- function Ir(e, t) {
2622
- return E(t, Fr(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
2640
+ function zr(e, t) {
2641
+ return k(t, Rr(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
2623
2642
  }
2624
- function Lr(e, t) {
2643
+ function Br(e, t) {
2625
2644
  return e ? t(e)?.listView ?? "default" : "default";
2626
2645
  }
2627
- function Rr(e, t) {
2628
- let n = e.map((e) => Lr(e.boardId, t));
2646
+ function Vr(e, t) {
2647
+ let n = e.map((e) => Br(e.boardId, t));
2629
2648
  if (!n.length) return "default";
2630
2649
  if (n.every((e) => e === n[0])) return n[0];
2631
2650
  let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
@@ -2633,27 +2652,27 @@ function Rr(e, t) {
2633
2652
  }
2634
2653
  //#endregion
2635
2654
  //#region src/composables/useMemiBoardSections.ts
2636
- var zr = [];
2637
- function Br(e) {
2655
+ var Hr = [];
2656
+ function Ur(e) {
2638
2657
  let t = Number(e.cols);
2639
- if (br.includes(t)) return t;
2658
+ if (Cr.includes(t)) return t;
2640
2659
  let n = e.width;
2641
2660
  return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
2642
2661
  }
2643
- function Vr(e) {
2662
+ function Wr(e) {
2644
2663
  let t = e.height ?? e.size;
2645
2664
  return t === "sm" || t === "lg" ? t : "md";
2646
2665
  }
2647
- function Hr(e) {
2666
+ function Gr(e) {
2648
2667
  return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
2649
2668
  }
2650
- function Ur(e) {
2669
+ function Kr(e) {
2651
2670
  return e.sort === "likes" ? "likes" : "latest";
2652
2671
  }
2653
- function Wr(e) {
2672
+ function qr(e) {
2654
2673
  return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
2655
2674
  }
2656
- function Gr(e, t) {
2675
+ function Jr(e, t) {
2657
2676
  let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
2658
2677
  for (let e of n) {
2659
2678
  let n = String(e || "").trim();
@@ -2661,131 +2680,145 @@ function Gr(e, t) {
2661
2680
  }
2662
2681
  return r;
2663
2682
  }
2664
- function Kr(e, t) {
2665
- return E(t, "sections.defaultTitle", { n: e + 1 });
2683
+ function Yr(e, t) {
2684
+ return k(t, "sections.defaultTitle", { n: e + 1 });
2666
2685
  }
2667
- function qr(e, t, n) {
2668
- let r = Hr(e), i = Er(r, e.count), a = Q(e.i18n), o = tt(e.i18nSource);
2686
+ function Xr(e, t, n) {
2687
+ let r = Gr(e), i = kr(r, e.count), a = Q(e.i18n), o = rt(e.i18nSource);
2669
2688
  return {
2670
2689
  id: String(e.id || `box-${t + 1}`),
2671
- title: String(e.title || Kr(t, n)),
2690
+ title: String(e.title || Yr(t, n)),
2672
2691
  showTitle: e.showTitle !== !1,
2673
2692
  kind: r,
2674
- boardId: Wr(e),
2693
+ boardId: qr(e),
2675
2694
  count: i,
2676
- postIds: Gr(e, i),
2677
- sort: Ur(e),
2678
- cols: Br(e),
2679
- height: Vr(e),
2695
+ postIds: Jr(e, i),
2696
+ sort: Kr(e),
2697
+ cols: Ur(e),
2698
+ height: Wr(e),
2680
2699
  order: t,
2681
2700
  ...a ? { i18n: a } : {},
2682
2701
  ...o ? { i18nSource: o } : {}
2683
2702
  };
2684
2703
  }
2685
- function Jr() {
2686
- let { locale: e } = k(), { translateEntries: t } = An(), n = Z(), r = _e(n, "settings", "homeLayout"), { data: i, pending: a } = Te(r), o = N(() => (Array.isArray(i.value?.blocks) ? i.value.blocks : zr).map((t, n) => qr(t, n, e.value)));
2687
- async function s(n) {
2688
- if (!w()) return n;
2689
- let r = e.value, i = n.filter((e) => {
2704
+ function Zr() {
2705
+ let { locale: e } = A(), { translateEntries: t } = Nn(), r = Z(), i = ye(r, "settings", "homeLayout"), { data: a, pending: o } = De(i), s = N(() => (Array.isArray(a.value?.blocks) ? a.value.blocks : Hr).map((t, n) => Xr(t, n, e.value)));
2706
+ async function c(r) {
2707
+ if (!n()) return r;
2708
+ let i = e.value, a = r.filter((e) => {
2690
2709
  let t = e.title.trim();
2691
- return t ? !(e.i18nSource?.title === t && it(e.i18n, ["title"])) : !1;
2710
+ return t ? !(e.i18nSource?.title === t && ot(e.i18n, ["title"])) : !1;
2692
2711
  });
2693
- if (!i.length) return n;
2694
- let a = await t(i.map((e) => ({
2712
+ if (!a.length) return r;
2713
+ let o = await t(a.map((e) => ({
2695
2714
  id: e.id,
2696
2715
  fields: { title: e.title.trim() },
2697
2716
  context: e.kind
2698
2717
  })), {
2699
- source: r,
2718
+ source: i,
2700
2719
  purpose: "section heading on a website home page"
2701
2720
  });
2702
- return n.map((e) => {
2703
- let t = a[e.id];
2721
+ return r.map((e) => {
2722
+ let t = o[e.id];
2704
2723
  if (!t) return e;
2705
- let n = e.title.trim(), i = rt(r, { title: n }, t);
2706
- return it(i, ["title"]) ? {
2724
+ let n = e.title.trim(), r = at(i, { title: n }, t);
2725
+ return ot(r, ["title"]) ? {
2707
2726
  ...e,
2708
2727
  title: n,
2709
- i18n: i,
2728
+ i18n: r,
2710
2729
  i18nSource: {
2711
- locale: r,
2730
+ locale: i,
2712
2731
  title: n
2713
2732
  }
2714
2733
  } : e;
2715
2734
  });
2716
2735
  }
2717
- function c(t, n) {
2718
- let r = t, i = Hr(r), a = Er(i, t.count), o = t.title.trim() || Kr(n, e.value);
2736
+ function l(t, n) {
2737
+ let r = t, i = Gr(r), a = kr(i, t.count), o = t.title.trim() || Yr(n, e.value);
2719
2738
  return {
2720
2739
  id: t.id,
2721
2740
  title: o,
2722
2741
  showTitle: t.showTitle !== !1,
2723
2742
  kind: i,
2724
- boardId: Wr(r),
2743
+ boardId: qr(r),
2725
2744
  count: a,
2726
- postIds: Gr(r, a),
2727
- sort: Ur(r),
2728
- cols: Br(r),
2729
- height: Vr(r),
2745
+ postIds: Jr(r, a),
2746
+ sort: Kr(r),
2747
+ cols: Ur(r),
2748
+ height: Wr(r),
2730
2749
  order: n,
2731
2750
  ...t.i18n ? { i18n: t.i18n } : {},
2732
2751
  ...t.i18nSource?.title === o ? { i18nSource: t.i18nSource } : {}
2733
2752
  };
2734
2753
  }
2735
- async function l(e) {
2754
+ async function u(e) {
2736
2755
  let t = e;
2737
2756
  try {
2738
- t = await s(e);
2757
+ t = await c(e);
2739
2758
  } catch (e) {
2740
2759
  console.warn("[memi-board] section translation skipped", e);
2741
2760
  }
2742
- await q(r, {
2761
+ await q(i, {
2743
2762
  columns: 12,
2744
- blocks: t.map((e, t) => c(e, t)),
2763
+ blocks: t.map((e, t) => l(e, t)),
2745
2764
  updatedAt: K()
2746
2765
  });
2747
2766
  }
2748
2767
  return {
2749
- settings: i,
2750
- pending: a,
2751
- sections: o,
2752
- blocks: o,
2753
- hasSavedLayout: N(() => Array.isArray(i.value?.blocks)),
2754
- saveSections: l,
2755
- saveBlocks: l
2768
+ settings: a,
2769
+ pending: o,
2770
+ sections: s,
2771
+ blocks: s,
2772
+ hasSavedLayout: N(() => Array.isArray(a.value?.blocks)),
2773
+ saveSections: u,
2774
+ saveBlocks: u
2756
2775
  };
2757
2776
  }
2758
2777
  //#endregion
2759
2778
  //#region src/composables/useMemiBoardMiniPosts.ts
2760
- function Yr(t, n) {
2761
- let r = Z(), i = () => M(), a = I(t)?.trim() || "all", o = N(() => {
2762
- let e = Math.max(1, Math.floor(Number(I(n)) || 5)), a = I(t)?.trim() || "", o = [X("isPublished", "==", !0), X("listed", "==", !0)];
2763
- return a && o.unshift(X("boardId", "==", a)), G(s(r, i()), ...o, W("createdAt", "desc"), H(e));
2764
- }), { data: c, pending: l, error: u } = Ce(o, { ssrKey: e(i(), `mini-list/${a}`) });
2779
+ function Qr(e, t) {
2780
+ let n = Z(), r = () => j(), i = I(e)?.trim() || "all", a = N(() => {
2781
+ let i = Math.max(1, Math.floor(Number(I(t)) || 5)), a = I(e)?.trim() || "", s = [X("isPublished", "==", !0), X("listed", "==", !0)];
2782
+ return a && s.unshift(X("boardId", "==", a)), G(o(n, r()), ...s, W("createdAt", "desc"), H(i));
2783
+ }), { data: s, pending: c, error: l } = Te(a, { ssrKey: p(r(), `mini-list/${i}`) });
2765
2784
  return {
2766
- posts: N(() => c.value ?? []),
2767
- pending: l,
2768
- error: u
2785
+ posts: N(() => s.value ?? []),
2786
+ pending: c,
2787
+ error: l
2769
2788
  };
2770
2789
  }
2771
- function Xr(t) {
2772
- let n = Z(), r = () => M(), i = N(() => [...new Set(I(t).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), a = i.value.join(",") || "none", o = N(() => i.value.length ? G(s(n, r()), X(R(), "in", i.value)) : null), { data: c, pending: l, error: u } = Ce(o, { ssrKey: e(r(), `mini-picked/${a}`) });
2790
+ function $r(e) {
2791
+ let t = Z(), n = () => j(), r = N(() => [...new Set(I(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = N(() => r.value.length ? G(o(t, n()), X(R(), "in", r.value)) : null), { data: s, pending: c, error: l } = Te(a, { ssrKey: p(n(), `mini-picked/${i}`) });
2773
2792
  return {
2774
2793
  posts: N(() => {
2775
- let e = new Map((c.value ?? []).map((e) => [e.id, e])), t = [];
2776
- for (let n of i.value) {
2794
+ let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
2795
+ for (let n of r.value) {
2777
2796
  let r = e.get(n);
2778
2797
  r && r.isPublished !== !1 && t.push(r);
2779
2798
  }
2780
2799
  return t;
2781
2800
  }),
2782
- pending: l,
2783
- error: u
2801
+ pending: c,
2802
+ error: l
2784
2803
  };
2785
2804
  }
2786
2805
  //#endregion
2787
2806
  //#region src/data/versionHistory.ts
2788
- var Zr = [
2807
+ var ei = [
2808
+ {
2809
+ version: "0.48.0",
2810
+ date: "2026-10-29",
2811
+ highlights: [
2812
+ "댓글과 답글에 이미지를 한 장 첨부할 수 있어요",
2813
+ "큰 이미지는 올리기 전에 5MB 이하로 줄여요",
2814
+ "글을 지우면 댓글 이미지도 함께 지워요"
2815
+ ]
2816
+ },
2817
+ {
2818
+ version: "0.47.1",
2819
+ date: "2026-10-29",
2820
+ highlights: ["AI 글쓰기 도우미가 실패하면 그 시도는 하루 횟수에서 빠져요", "App Check 연결 안내를 한 번용 토큰과 SPA에 맞게 고쳤어요"]
2821
+ },
2789
2822
  {
2790
2823
  version: "0.47.0",
2791
2824
  date: "2026-10-23",
@@ -3111,7 +3144,7 @@ var Zr = [
3111
3144
  highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
3112
3145
  note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
3113
3146
  }
3114
- ], Qr = 10, $r = 864e5, ei = 200, ti = {
3147
+ ], ti = 10, ni = 864e5, ri = 200, ii = {
3115
3148
  proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
3116
3149
  polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
3117
3150
  continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
@@ -3120,7 +3153,7 @@ var Zr = [
3120
3153
  "translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
3121
3154
  title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
3122
3155
  };
3123
- function ni(e) {
3156
+ function ai(e) {
3124
3157
  return {
3125
3158
  proofread: "Fix only spelling, spacing, and grammar errors. Do not change the meaning or tone.",
3126
3159
  polish: "Refine the text into more natural, readable sentences while keeping the meaning and the author's tone.",
@@ -3131,136 +3164,177 @@ function ni(e) {
3131
3164
  title: `Create one concise title in ${e} that represents the body. Output only the title, without quotes or explanation.`
3132
3165
  };
3133
3166
  }
3134
- function ri(e, t, n) {
3135
- let r = t === "ko", i = dn(t);
3167
+ function oi(e, t, n) {
3168
+ let r = t === "ko", i = mn(t);
3136
3169
  if (e.action !== "custom") {
3137
- if (r) return ti[e.action];
3138
- let t = ni(i)[e.action];
3170
+ if (r) return ii[e.action];
3171
+ let t = ai(i)[e.action];
3139
3172
  return e.action === "translate-en" || e.action === "translate-ko" || e.action === "title" ? t : `${t} Write the result in the same language as the original text; if unclear, write in ${i}.`;
3140
3173
  }
3141
- let a = e.customInstruction?.trim().slice(0, ei);
3174
+ let a = e.customInstruction?.trim().slice(0, ri);
3142
3175
  if (!a) throw Error(n("writingAssistant.customRequired"));
3143
3176
  return r ? `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${a}` : `Rewrite the text applying the following style instruction while keeping the meaning: ${a}`;
3144
3177
  }
3145
- function ii(e) {
3178
+ function si(e) {
3146
3179
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
3147
3180
  }
3148
- function ai(e) {
3181
+ function ci(e) {
3149
3182
  return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
3150
3183
  }
3151
- function oi(e = {}) {
3152
- let t = k(), n = N(() => O(I(e.locale)) ?? t.locale.value), r = (e, t) => E(n.value, e, t), i = Ee(), a = Z(), o = we(), s = _(), { translateEntries: c, translateHtml: l } = An();
3153
- async function u() {
3154
- let e = o.value?.uid;
3155
- if (!e) throw Error(r("writingAssistant.loginRequired"));
3156
- await xe(a, async (t) => {
3157
- let n = A(a, M(), e), i = await t.get(n);
3158
- if (!i.exists()) throw Error(r("writingAssistant.userMissing"));
3159
- let o = i.data(), s = ai(o.aiWritingWindowAt), c = Math.max(0, Math.floor(Number(o.aiWritingCount) || 0)), l = Date.now(), u = s != null && l - s < $r;
3160
- if (u && c >= 10) {
3161
- let e = s + $r, t = Math.max(1, Math.ceil((e - l) / 36e5));
3162
- throw Error(r("writingAssistant.dailyLimit", {
3163
- limit: 10,
3164
- hours: t
3165
- }));
3166
- }
3167
- t.update(n, {
3168
- aiWritingCount: u ? c + 1 : 1,
3169
- aiWritingWindowAt: u ? o.aiWritingWindowAt : K(),
3184
+ function li(e = {}) {
3185
+ let t = A(), n = N(() => M(I(e.locale)) ?? t.locale.value), r = (e, t) => k(n.value, e, t), i = Oe(), a = Z(), o = Ee(), s = v(), { translateEntries: c, translateHtml: l } = Nn();
3186
+ function u(e, t) {
3187
+ let n = ci(e.aiWritingWindowAt), r = n != null && t - n < ni, i = Math.max(0, Math.floor(Number(e.aiWritingCount) || 0)), a = Math.max(0, Math.floor(Number(e.aiWritingPending) || 0));
3188
+ return {
3189
+ active: r,
3190
+ windowAt: n,
3191
+ count: r ? i : 0,
3192
+ pending: r ? a : 0
3193
+ };
3194
+ }
3195
+ function d(e, t) {
3196
+ let n = e + ni, i = Math.max(1, Math.ceil((n - t) / 36e5));
3197
+ return Error(r("writingAssistant.dailyLimit", {
3198
+ limit: 10,
3199
+ hours: i
3200
+ }));
3201
+ }
3202
+ async function f(e) {
3203
+ let t = o.value?.uid;
3204
+ if (!t) throw Error(r("writingAssistant.loginRequired"));
3205
+ await Ce(a, async (n) => {
3206
+ let i = h(a, j(), t), o = await n.get(i);
3207
+ if (!o.exists()) throw Error(r("writingAssistant.userMissing"));
3208
+ let s = o.data(), c = e(u(s, Date.now()), s);
3209
+ c && n.update(i, {
3210
+ ...c,
3170
3211
  updatedAt: K()
3171
3212
  });
3172
3213
  });
3173
3214
  }
3174
- async function d(e) {
3175
- (e.action === "translate-en" || e.action === "translate-ko") && S();
3176
- let t = n.value, a = t === "ko", o = ri(e, t, r);
3215
+ async function p() {
3216
+ await f((e) => {
3217
+ if (e.active && e.windowAt != null && e.count + e.pending >= 10) throw d(e.windowAt, Date.now());
3218
+ return e.active ? { aiWritingPending: e.pending + 1 } : {
3219
+ aiWritingCount: 0,
3220
+ aiWritingPending: 1,
3221
+ aiWritingWindowAt: K()
3222
+ };
3223
+ });
3224
+ }
3225
+ async function m() {
3226
+ await f((e) => !e.active || e.pending < 1 || e.count >= 10 ? null : {
3227
+ aiWritingCount: e.count + 1,
3228
+ aiWritingPending: e.pending - 1
3229
+ });
3230
+ }
3231
+ async function g() {
3232
+ await f((e) => !e.active || e.pending < 1 ? null : { aiWritingPending: e.pending - 1 });
3233
+ }
3234
+ async function _(e) {
3235
+ await p();
3236
+ try {
3237
+ let t = await e();
3238
+ try {
3239
+ await m();
3240
+ } catch {}
3241
+ return t;
3242
+ } catch (e) {
3243
+ throw await g().catch(() => {}), e;
3244
+ }
3245
+ }
3246
+ async function y(e) {
3247
+ (e.action === "translate-en" || e.action === "translate-ko") && D();
3248
+ let t = n.value, a = t === "ko", o = oi(e, t, r);
3177
3249
  if (!e.content.trim()) throw Error(r("writingAssistant.contentRequired"));
3178
- await u();
3179
- let c = s.moderation ?? {}, l = Ve(i, {
3180
- backend: new ze(),
3181
- useLimitedUseAppCheckTokens: c.useLimitedUseAppCheckTokens !== !1
3182
- }), d = He(l, {
3183
- model: c.model ?? "gemini-3.5-flash-lite",
3184
- systemInstruction: (a ? [
3185
- "너는 게시판 글쓰기 편집 도우미다.",
3186
- "사용자가 요청한 편집 결과만 출력하고 설명, 인사, 마크다운 코드 펜스를 붙이지 마라.",
3187
- e.action === "title" || e.selection ? "출력은 일반 텍스트로 작성하라." : "입력의 HTML 구조와 링크, 이미지 태그를 보존하고 결과도 HTML 조각으로 출력하라."
3250
+ return _(async () => {
3251
+ let t = s.moderation ?? {}, n = Ue(i, {
3252
+ backend: new Ve(),
3253
+ useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
3254
+ }), c = We(n, {
3255
+ model: t.model ?? "gemini-3.5-flash-lite",
3256
+ systemInstruction: (a ? [
3257
+ "너는 게시판 글쓰기 편집 도우미다.",
3258
+ "사용자가 요청한 편집 결과만 출력하고 설명, 인사, 마크다운 코드 펜스를 붙이지 마라.",
3259
+ e.action === "title" || e.selection ? "출력은 일반 텍스트로 작성하라." : "입력의 HTML 구조와 링크, 이미지 태그를 보존하고 결과도 HTML 조각으로 출력하라."
3260
+ ] : [
3261
+ "You are an editing assistant for writing message board posts.",
3262
+ "Output only the requested edit result. Do not add explanations, greetings, or markdown code fences.",
3263
+ e.action === "title" || e.selection ? "Write the output as plain text." : "Preserve the HTML structure, links, and image tags of the input, and output the result as an HTML fragment as well."
3264
+ ]).join("\n"),
3265
+ generationConfig: {
3266
+ temperature: e.action === "continue" || e.action === "title" || e.action === "custom" ? .6 : .2,
3267
+ maxOutputTokens: 2048
3268
+ }
3269
+ }), l = e.content.trim(), u = (a ? [
3270
+ `작업: ${o}`,
3271
+ e.title ? `현재 제목: ${e.title}` : "",
3272
+ `본문:\n${l.slice(0, 12e3)}`
3188
3273
  ] : [
3189
- "You are an editing assistant for writing message board posts.",
3190
- "Output only the requested edit result. Do not add explanations, greetings, or markdown code fences.",
3191
- e.action === "title" || e.selection ? "Write the output as plain text." : "Preserve the HTML structure, links, and image tags of the input, and output the result as an HTML fragment as well."
3192
- ]).join("\n"),
3193
- generationConfig: {
3194
- temperature: e.action === "continue" || e.action === "title" || e.action === "custom" ? .6 : .2,
3195
- maxOutputTokens: 2048
3196
- }
3197
- }), f = e.content.trim(), p = (a ? [
3198
- `작업: ${o}`,
3199
- e.title ? `현재 제목: ${e.title}` : "",
3200
- `본문:\n${f.slice(0, 12e3)}`
3201
- ] : [
3202
- `Task: ${o}`,
3203
- e.title ? `Current title: ${e.title}` : "",
3204
- `Body:\n${f.slice(0, 12e3)}`
3205
- ]).filter(Boolean).join("\n\n"), m = ii((await d.generateContent(p)).response.text());
3206
- if (!m) throw Error(r("writingAssistant.emptyResult"));
3207
- return m;
3274
+ `Task: ${o}`,
3275
+ e.title ? `Current title: ${e.title}` : "",
3276
+ `Body:\n${l.slice(0, 12e3)}`
3277
+ ]).filter(Boolean).join("\n\n"), d = si((await c.generateContent(u)).response.text());
3278
+ if (!d) throw Error(r("writingAssistant.emptyResult"));
3279
+ return d;
3280
+ });
3208
3281
  }
3209
- async function f(e) {
3210
- S();
3282
+ async function b(e) {
3283
+ D();
3211
3284
  let t = e.source ?? n.value, i = e.title?.trim() ?? "", a = e.summary?.trim() ?? "", o = e.content ?? "", s = {};
3212
3285
  i && (s.title = i), a && (s.summary = a);
3213
- let d = !!Yt(o);
3214
- if (!Object.keys(s).length && !d) throw Error(r("writingAssistant.translateEmpty"));
3215
- if (d && o.length > 12e3) throw Error(r("writingAssistant.translateTooLong", { limit: Tn }));
3216
- await u();
3217
- let [f, p] = await Promise.all([Object.keys(s).length ? c([{
3218
- id: "post",
3219
- fields: s,
3220
- context: "message board post title and short summary"
3221
- }], {
3222
- source: t,
3223
- purpose: "message board post title and short summary"
3224
- }) : Promise.resolve({}), d ? l(o, { source: t }) : Promise.resolve({})]), m = rt(t, s, f.post);
3225
- if (Object.keys(s).length && !it(m, Object.keys(s))) throw Error(r("writingAssistant.translateIncomplete"));
3226
- let h = {
3227
- i18n: m,
3228
- i18nSource: {
3229
- locale: t,
3230
- title: i,
3231
- summary: a
3232
- }
3233
- };
3234
- if (d) {
3235
- let e = {};
3236
- for (let [t, n] of Object.entries(p)) {
3237
- let r = O(t);
3238
- r && typeof n == "string" && n.trim() && (e[r] = { content: n.trim() });
3239
- }
3240
- let n = rt(t, { content: o }, e);
3241
- if (!it(n, ["content"])) throw Error(r("writingAssistant.translateIncomplete"));
3242
- h.contentI18n = n, h.contentI18nSource = {
3243
- locale: t,
3244
- hash: $e(o)
3286
+ let u = !!Qt(o);
3287
+ if (!Object.keys(s).length && !u) throw Error(r("writingAssistant.translateEmpty"));
3288
+ if (u && o.length > 12e3) throw Error(r("writingAssistant.translateTooLong", { limit: On }));
3289
+ return _(async () => {
3290
+ let [e, n] = await Promise.all([Object.keys(s).length ? c([{
3291
+ id: "post",
3292
+ fields: s,
3293
+ context: "message board post title and short summary"
3294
+ }], {
3295
+ source: t,
3296
+ purpose: "message board post title and short summary"
3297
+ }) : Promise.resolve({}), u ? l(o, { source: t }) : Promise.resolve({})]), d = at(t, s, e.post);
3298
+ if (Object.keys(s).length && !ot(d, Object.keys(s))) throw Error(r("writingAssistant.translateIncomplete"));
3299
+ let f = {
3300
+ i18n: d,
3301
+ i18nSource: {
3302
+ locale: t,
3303
+ title: i,
3304
+ summary: a
3305
+ }
3245
3306
  };
3246
- }
3247
- return h;
3307
+ if (u) {
3308
+ let e = {};
3309
+ for (let [t, r] of Object.entries(n)) {
3310
+ let n = M(t);
3311
+ n && typeof r == "string" && r.trim() && (e[n] = { content: r.trim() });
3312
+ }
3313
+ let i = at(t, { content: o }, e);
3314
+ if (!ot(i, ["content"])) throw Error(r("writingAssistant.translateIncomplete"));
3315
+ f.contentI18n = i, f.contentI18nSource = {
3316
+ locale: t,
3317
+ hash: tt(o)
3318
+ };
3319
+ }
3320
+ return f;
3321
+ });
3248
3322
  }
3249
3323
  return {
3250
- assist: d,
3251
- translatePost: f
3324
+ assist: y,
3325
+ translatePost: b
3252
3326
  };
3253
3327
  }
3254
3328
  //#endregion
3255
3329
  //#region src/utils/renderMarkdown.ts
3256
- function si(e) {
3330
+ function ui(e) {
3257
3331
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3258
3332
  }
3259
- function ci(e) {
3333
+ function di(e) {
3260
3334
  let t = e;
3261
3335
  return t = t.replace(/`([^`]+)`/g, "<code>$1</code>"), t = t.replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)\)/g, "<img src=\"$2\" alt=\"$1\" class=\"max-w-full h-auto rounded-lg my-3\" loading=\"lazy\" />"), t = t.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, "<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-primary underline\">$1</a>"), t = t.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>"), t = t.replace(/\*([^*]+)\*/g, "<em>$1</em>"), t = t.replace(/~~([^~]+)~~/g, "<del>$1</del>"), t;
3262
3336
  }
3263
- function li(e) {
3337
+ function fi(e) {
3264
3338
  if (!e?.trim()) return "";
3265
3339
  let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
3266
3340
  function c() {
@@ -3269,7 +3343,7 @@ function li(e) {
3269
3343
  return;
3270
3344
  }
3271
3345
  let e = o;
3272
- n.push(`<${e}>${s.map((e) => `<li>${ci(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3346
+ n.push(`<${e}>${s.map((e) => `<li>${di(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3273
3347
  }
3274
3348
  for (; r < t.length;) {
3275
3349
  let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
@@ -3278,7 +3352,7 @@ function li(e) {
3278
3352
  continue;
3279
3353
  }
3280
3354
  if (i) {
3281
- a.push(si(e)), r++;
3355
+ a.push(ui(e)), r++;
3282
3356
  continue;
3283
3357
  }
3284
3358
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
@@ -3289,24 +3363,24 @@ function li(e) {
3289
3363
  if (u) {
3290
3364
  c();
3291
3365
  let e = u[1].length;
3292
- n.push(`<h${e} class="font-semibold mt-4 mb-2">${ci(si(u[2]))}</h${e}>`), r++;
3366
+ n.push(`<h${e} class="font-semibold mt-4 mb-2">${di(ui(u[2]))}</h${e}>`), r++;
3293
3367
  continue;
3294
3368
  }
3295
3369
  if (e.startsWith("> ")) {
3296
3370
  c();
3297
3371
  let e = [];
3298
- for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(si((t[r] ?? "").slice(2))), r++;
3299
- n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${ci(e.join("<br />"))}</blockquote>`);
3372
+ for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(ui((t[r] ?? "").slice(2))), r++;
3373
+ n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${di(e.join("<br />"))}</blockquote>`);
3300
3374
  continue;
3301
3375
  }
3302
3376
  let d = e.match(/^[-*+]\s+(.+)$/);
3303
3377
  if (d) {
3304
- o && o !== "ul" && c(), o = "ul", s.push(si(d[1])), r++;
3378
+ o && o !== "ul" && c(), o = "ul", s.push(ui(d[1])), r++;
3305
3379
  continue;
3306
3380
  }
3307
3381
  let f = e.match(/^\d+\.\s+(.+)$/);
3308
3382
  if (f) {
3309
- o && o !== "ol" && c(), o = "ol", s.push(si(f[1])), r++;
3383
+ o && o !== "ol" && c(), o = "ol", s.push(ui(f[1])), r++;
3310
3384
  continue;
3311
3385
  }
3312
3386
  if (!e.trim()) {
@@ -3318,13 +3392,13 @@ function li(e) {
3318
3392
  for (; r < t.length;) {
3319
3393
  let e = t[r] ?? "";
3320
3394
  if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
3321
- p.push(si(e)), r++;
3395
+ p.push(ui(e)), r++;
3322
3396
  }
3323
- n.push(`<p class="my-2 leading-relaxed">${ci(p.join("<br />"))}</p>`);
3397
+ n.push(`<p class="my-2 leading-relaxed">${di(p.join("<br />"))}</p>`);
3324
3398
  }
3325
3399
  return c(), i && a.length && n.push(`<pre class="overflow-x-auto rounded-lg bg-muted p-3 text-sm"><code>${a.join("\n")}</code></pre>`), n.join("\n");
3326
3400
  }
3327
3401
  //#endregion
3328
- export { Yn as AUTHOR_MEMO_MAX_LENGTH, br as BOARD_SECTION_COLS, Cr as BOARD_SECTION_KINDS, wr as BOARD_SECTION_SORTS, _r as BOARD_USER_ROLES, tr as COMMENT_BODY_MAX_LENGTH, wt as DEFAULT_BLOCK_BAN_DECAY_MS, Ct as DEFAULT_BLOCK_BAN_THRESHOLD, jn as DEFAULT_BOARDS, Mn as DEFAULT_CATEGORIES, n as DEFAULT_COMMENTS_COLLECTION, de as DEFAULT_LIKES_COLLECTION, D as DEFAULT_MEMI_BOARD_LOCALE, v as DEFAULT_POSTS_COLLECTION, i as DEFAULT_REPORTS_COLLECTION, r as DEFAULT_SETTINGS_COLLECTION, m as DEFAULT_USERS_COLLECTION, ae as FALLBACK_MEMI_BOARD_LOCALE, Tn as HTML_MAX_CHARS, ne as MEMI_BOARD_LOCALES, cr as REPORT_DETAIL_MAX_LENGTH, lr as REPORT_REASONS, Qr as WRITING_ASSISTANT_DAILY_LIMIT, We as asHttpUrl, ut as boardCopyIsTranslated, Xe as boardListOgDescription, Ye as boardListOgTitle, Je as boardPostOgDescription, qe as boardPostOgTitle, xr as boardSectionKinds, Sr as boardSectionSorts, e as boardSsrKey, A as boardUserDoc, p as boardUsersCol, rn as buildPostPreview, vt as canManageBoardByRole, yt as canWriteCommentByRole, Er as clampSectionCount, h as commentDoc, a as commentsCol, ue as configureMemiBoard, it as coversLocales, Tr as defaultSectionCount, lt as displayPostContent, ct as displayPostSummary, st as displayPostTitle, ot as displayStoredField, Tt as effectiveModerationBlockCount, Rt as extractEditorImageUrls, ht as fetchPublicListForSeo, mt as fetchPublicPostForSeo, C as formatDate, ie as formatFullDate, ce as formatRelativeDate, Ot as formatRestrictedUntilLabel, T as formatTimestampDetails, Qt as hasBodyImage, Zt as hasBodyText, $e as hashText, It as imeSafeSubmitClick, Ft as imeSafeSubmitPointerDown, _t as isAssignedStaff, $t as isContentEmpty, Ln as isFirestorePermissionDenied, fe as isMemiBoardI18nEnabled, te as isMemiBoardLocaleLoaded, w as isMemiBoardTranslationEnabled, Dt as isModerationWriteRestricted, c as likeDoc, d as likeDocId, g as likesCol, le as loadMemiBoardLocale, at as localizedText, or as memiBoardCommentLikesKey, se as memiBoardHostLocaleKey, ee as memiBoardLocaleInfo, rt as mergeSourceFields, Lr as miniBoardView, Mr as miniCommentLink, jr as miniMoreLink, Nr as miniPostImage, Ar as miniPostLink, Pr as miniPostTitle, Rr as miniPostsView, Fr as miniViewGroup, Ir as miniViewLabel, Et as moderationWriteRestrictedUntilMs, Ze as normalizeBasePath, qr as normalizeBoardSection, O as normalizeMemiBoardLocale, Dr as pairSectionCols, Yt as plainTextFromHtml, pe as postBodyDoc, t as postDoc, Bt as postNamespaceFromStoragePath, b as postStorageFolder, s as postsCol, tt as readI18nSource, Q as readLocalizedFields, li as renderMarkdownToHtml, y as reportDoc, x as reportDocId, ur as reportReasonLabel, o as reportsCol, u as resolveBoardPathConfig, dt as resolvePublicSeoDb, Or as sectionColClass, kr as sectionMinHeight, oe as settingsCol, l as settingsDoc, re as slugify, zt as storagePathFromDownloadUrl, Xt as titleFromBody, Ke as toAbsoluteUrl, Ge as toBoardOgImageUrl, E as translate, M as useBoardPathConfig, Mt as useMemiBoardAuth, Zn as useMemiBoardAuthorMemo, An as useMemiBoardAutoTranslate, Jn as useMemiBoardCommentFeed, sr as useMemiBoardCommentLikes, rr as useMemiBoardComments, _ as useMemiBoardConfig, k as useMemiBoardI18n, ar as useMemiBoardLikes, Yr as useMemiBoardMiniLatest, Xr as useMemiBoardMiniPicked, gr as useMemiBoardModeration, Hn as useMemiBoardPost, Vn as useMemiBoardPostList, zn as useMemiBoardPosts, ir as useMemiBoardReplies, pr as useMemiBoardReportQueue, dr as useMemiBoardReports, Jr as useMemiBoardSections, Fn as useMemiBoardSettings, Kn as useMemiBoardUserComments, Wn as useMemiBoardUserPosts, yr as useMemiBoardUserProfile, vr as useMemiBoardUsers, mr as useMemiBoardViews, oi as useMemiBoardWritingAssistant, Zr as versionHistory, nn as videoListCoverUrl, tn as youtubeId };
3402
+ export { Qn as AUTHOR_MEMO_MAX_LENGTH, Cr as BOARD_SECTION_COLS, Er as BOARD_SECTION_KINDS, Dr as BOARD_SECTION_SORTS, br as BOARD_USER_ROLES, ir as COMMENT_BODY_MAX_LENGTH, Et as DEFAULT_BLOCK_BAN_DECAY_MS, Tt as DEFAULT_BLOCK_BAN_THRESHOLD, Pn as DEFAULT_BOARDS, Fn as DEFAULT_CATEGORIES, i as DEFAULT_COMMENTS_COLLECTION, r as DEFAULT_LIKES_COLLECTION, re as DEFAULT_MEMI_BOARD_LOCALE, m as DEFAULT_POSTS_COLLECTION, ae as DEFAULT_REPORTS_COLLECTION, e as DEFAULT_SETTINGS_COLLECTION, ie as DEFAULT_USERS_COLLECTION, O as FALLBACK_MEMI_BOARD_LOCALE, On as HTML_MAX_CHARS, T as MEMI_BOARD_LOCALES, dr as REPORT_DETAIL_MAX_LENGTH, fr as REPORT_REASONS, ti as WRITING_ASSISTANT_DAILY_LIMIT, Ke as asHttpUrl, ft as boardCopyIsTranslated, Qe as boardListOgDescription, Ze as boardListOgTitle, Xe as boardPostOgDescription, Ye as boardPostOgTitle, wr as boardSectionKinds, Tr as boardSectionSorts, p as boardSsrKey, h as boardUserDoc, c as boardUsersCol, sn as buildPostPreview, bt as canManageBoardByRole, xt as canWriteCommentByRole, kr as clampSectionCount, d as commentDoc, g as commentsCol, me as configureMemiBoard, ot as coversLocales, Or as defaultSectionCount, dt as displayPostContent, ut as displayPostSummary, lt as displayPostTitle, ct as displayStoredField, Dt as effectiveModerationBlockCount, Bt as extractEditorImageUrls, _t as fetchPublicListForSeo, gt as fetchPublicPostForSeo, ee as formatDate, oe as formatFullDate, fe as formatRelativeDate, At as formatRestrictedUntilLabel, te as formatTimestampDetails, tn as hasBodyImage, en as hasBodyText, tt as hashText, Rt as imeSafeSubmitClick, Lt as imeSafeSubmitPointerDown, yt as isAssignedStaff, nn as isContentEmpty, Bn as isFirestorePermissionDenied, _ as isMemiBoardI18nEnabled, ne as isMemiBoardLocaleLoaded, n as isMemiBoardTranslationEnabled, kt as isModerationWriteRestricted, he as likeDoc, t as likeDocId, b as likesCol, ce as loadMemiBoardLocale, st as localizedText, lr as memiBoardCommentLikesKey, se as memiBoardHostLocaleKey, pe as memiBoardLocaleInfo, at as mergeSourceFields, Br as miniBoardView, Fr as miniCommentLink, Pr as miniMoreLink, Ir as miniPostImage, Nr as miniPostLink, Lr as miniPostTitle, Vr as miniPostsView, Rr as miniViewGroup, zr as miniViewLabel, Ot as moderationWriteRestrictedUntilMs, $e as normalizeBasePath, Xr as normalizeBoardSection, M as normalizeMemiBoardLocale, Ar as pairSectionCols, Qt as plainTextFromHtml, s as postBodyDoc, y as postDoc, Ht as postNamespaceFromStoragePath, x as postStorageFolder, o as postsCol, rt as readI18nSource, Q as readLocalizedFields, fi as renderMarkdownToHtml, u as reportDoc, le as reportDocId, pr as reportReasonLabel, l as reportsCol, C as resolveBoardPathConfig, pt as resolvePublicSeoDb, jr as sectionColClass, Mr as sectionMinHeight, S as settingsCol, w as settingsDoc, E as slugify, Vt as storagePathFromDownloadUrl, $t as titleFromBody, Je as toAbsoluteUrl, qe as toBoardOgImageUrl, k as translate, j as useBoardPathConfig, Pt as useMemiBoardAuth, er as useMemiBoardAuthorMemo, Nn as useMemiBoardAutoTranslate, Zn as useMemiBoardCommentFeed, ur as useMemiBoardCommentLikes, or as useMemiBoardComments, v as useMemiBoardConfig, A as useMemiBoardI18n, cr as useMemiBoardLikes, Qr as useMemiBoardMiniLatest, $r as useMemiBoardMiniPicked, yr as useMemiBoardModeration, Gn as useMemiBoardPost, Wn as useMemiBoardPostList, Hn as useMemiBoardPosts, sr as useMemiBoardReplies, gr as useMemiBoardReportQueue, mr as useMemiBoardReports, Zr as useMemiBoardSections, Rn as useMemiBoardSettings, Yn as useMemiBoardUserComments, qn as useMemiBoardUserPosts, Sr as useMemiBoardUserProfile, xr as useMemiBoardUsers, _r as useMemiBoardViews, li as useMemiBoardWritingAssistant, ei as versionHistory, on as videoListCoverUrl, an as youtubeId };
3329
3403
 
3330
3404
  //# sourceMappingURL=index.js.map