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