memi-board 0.52.1 → 0.52.2
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/{commentImages-CzXO42gE.js → commentImages-D_JJnuoj.js} +5 -4
- package/dist/commentImages-D_JJnuoj.js.map +1 -0
- package/dist/composables/useMemiBoardComments.d.ts +35 -2
- package/dist/composables/useMemiBoardWritingAssistant.d.ts +5 -1
- package/dist/{en-CmPLbFcN.js → en-DSCLJyUd.js} +4 -3
- package/dist/en-DSCLJyUd.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +946 -897
- package/dist/index.js.map +1 -1
- package/dist/runtime/components/CommentAi.vue +93 -0
- package/dist/runtime/components/CommentFeed.vue +3 -3
- package/dist/runtime/components/CommentForm.vue +11 -4
- package/dist/runtime/components/CommentItem.vue +20 -8
- package/dist/runtime/components/MiniComments.vue +3 -3
- package/dist/runtime/components/UserCommentList.vue +3 -3
- package/dist/storage.js +1 -1
- package/dist/types.d.ts +10 -1
- package/dist/utils/localizedFields.d.ts +3 -1
- package/package.json +1 -1
- package/dist/commentImages-CzXO42gE.js.map +0 -1
- package/dist/en-CmPLbFcN.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, R as g, S as _, T as v, U as y, V as b, W as x, X as S, Y as C, Z as w, _ as T, a as E, b as D, c as
|
|
2
|
-
import { computed as
|
|
3
|
-
import { collection as
|
|
1
|
+
import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, R as g, S as _, T as v, U as y, V as b, W as x, X as S, Y as C, Z as w, _ as T, a as E, b as D, c as O, d as k, f as ee, g as A, h as te, j as ne, k as re, l as ie, m as j, o as ae, p as oe, q as se, r as ce, s as M, t as le, u as ue, v as de, w as N, x as fe, y as P, z as pe } from "./commentImages-D_JJnuoj.js";
|
|
2
|
+
import { computed as F, onScopeDispose as I, reactive as me, readonly as he, ref as L, toValue as R, watch as z } from "vue";
|
|
3
|
+
import { collection as ge, deleteDoc as _e, deleteField as ve, doc as ye, documentId as B, endAt as be, endBefore as xe, getDoc as Se, getDocFromServer as Ce, getDocs as V, getDocsFromServer as we, increment as Te, limit as H, limitToLast as Ee, onSnapshot as U, orderBy as W, query as G, runTransaction as De, serverTimestamp as K, setDoc as q, startAfter as J, updateDoc as Y, where as X, writeBatch as Oe } from "firebase/firestore";
|
|
4
4
|
import { useCollection as ke, useCurrentUser as Ae, useDocument as je, useFirebaseApp as Me, useFirebaseAuth as Ne, useFirestore as Z } from "vuefire";
|
|
5
5
|
import { GoogleAuthProvider as Pe, OAuthProvider as Fe, createUserWithEmailAndPassword as Ie, getAuth as Le, signInWithEmailAndPassword as Re, signInWithPopup as ze, signOut as Be, updateProfile as Ve } from "firebase/auth";
|
|
6
6
|
import { deleteObject as He, getMetadata as Ue, getStorage as We, list as Ge, listAll as Ke, ref as qe } from "firebase/storage";
|
|
7
7
|
import { GoogleAIBackend as Je, Schema as Ye, getAI as Xe, getGenerativeModel as Ze } from "firebase/ai";
|
|
8
8
|
//#region src/utils/boardSeo.ts
|
|
9
9
|
function Qe(e, t) {
|
|
10
|
-
return !e || e === "전체" || e ===
|
|
10
|
+
return !e || e === "전체" || e === j(t, "seo.allCategory");
|
|
11
11
|
}
|
|
12
12
|
function $e(e) {
|
|
13
13
|
if (typeof e != "string") return null;
|
|
@@ -37,23 +37,23 @@ function tt(e, t, n = "") {
|
|
|
37
37
|
return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? tt(n, t) : r;
|
|
38
38
|
}
|
|
39
39
|
function nt(e, t, n, r, i) {
|
|
40
|
-
let a = r?.trim().slice(0, 40), o = e.trim() || a ||
|
|
40
|
+
let a = r?.trim().slice(0, 40), o = e.trim() || a || j(i, "seo.photo"), s = t?.trim(), c = n.trim() || "Board";
|
|
41
41
|
return s ? `${o} · ${s} | ${c}` : `${o} | ${c}`;
|
|
42
42
|
}
|
|
43
43
|
function rt(e, t) {
|
|
44
44
|
let n = [];
|
|
45
|
-
return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(
|
|
45
|
+
return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(j(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
47
|
function it(e, t, n) {
|
|
48
48
|
let r = t.trim() || "Board", i = e?.trim();
|
|
49
|
-
return Qe(i, n) ?
|
|
49
|
+
return Qe(i, n) ? j(n, "seo.listTitleAll", { site: r }) : j(n, "seo.listTitle", {
|
|
50
50
|
name: i,
|
|
51
51
|
site: r
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
function at(e, t) {
|
|
55
55
|
if (e.description?.trim()) return e.description.trim().slice(0, 200);
|
|
56
|
-
let n = e.categoryLabel?.trim(), r = Qe(n, t) ?
|
|
56
|
+
let n = e.categoryLabel?.trim(), r = Qe(n, t) ? j(t, "seo.listDescriptionAll") : j(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
59
|
function ot(e) {
|
|
@@ -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 =
|
|
85
|
+
let e = P(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());
|
|
@@ -92,14 +92,14 @@ function Q(e) {
|
|
|
92
92
|
}
|
|
93
93
|
function ut(e) {
|
|
94
94
|
if (!e || typeof e != "object") return;
|
|
95
|
-
let t = e, n = {}, r =
|
|
95
|
+
let t = e, n = {}, r = P(t.locale);
|
|
96
96
|
r && (n.locale = r);
|
|
97
97
|
for (let e of st) typeof t[e] == "string" && (n[e] = t[e]);
|
|
98
98
|
return Object.keys(n).length ? n : void 0;
|
|
99
99
|
}
|
|
100
100
|
function dt(e) {
|
|
101
101
|
if (!e || typeof e != "object") return;
|
|
102
|
-
let t = e, n = {}, r =
|
|
102
|
+
let t = e, n = {}, r = P(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
105
|
function ft(e, t, n) {
|
|
@@ -122,7 +122,7 @@ function ft(e, t, n) {
|
|
|
122
122
|
}), r;
|
|
123
123
|
}
|
|
124
124
|
function pt(e) {
|
|
125
|
-
let t = new Set((e?.translationLocales ?? []).map((e) =>
|
|
125
|
+
let t = new Set((e?.translationLocales ?? []).map((e) => P(e)).filter((e) => !!e)), n = T.map((e) => e.code);
|
|
126
126
|
return t.size ? n.filter((e) => t.has(e)) : n;
|
|
127
127
|
}
|
|
128
128
|
function mt(e) {
|
|
@@ -135,7 +135,7 @@ function ht(e, t, n = T.map((e) => e.code)) {
|
|
|
135
135
|
}
|
|
136
136
|
function gt(e, t, r, i, a) {
|
|
137
137
|
if (!n()) return i;
|
|
138
|
-
let o =
|
|
138
|
+
let o = P(t), s = P(a);
|
|
139
139
|
if (!o || s && o === s) return i;
|
|
140
140
|
let c = lt(e?.[o], r);
|
|
141
141
|
if (c) return c;
|
|
@@ -162,17 +162,20 @@ function xt(e) {
|
|
|
162
162
|
let t = e.label.trim(), n = (e.description ?? "").trim();
|
|
163
163
|
return !t || !e.i18nSource || e.i18nSource.label !== t || (e.i18nSource.description ?? "") !== n ? !1 : ht(e.i18n, n ? ["label", "description"] : ["label"], pt(e));
|
|
164
164
|
}
|
|
165
|
+
function St(e, t) {
|
|
166
|
+
return e.i18nSource?.body === e.body ? gt(e.i18n, t, "body", e.body, e.i18nSource.locale) : e.body;
|
|
167
|
+
}
|
|
165
168
|
//#endregion
|
|
166
169
|
//#region src/composables/fetchPublicSeo.ts
|
|
167
|
-
function
|
|
170
|
+
function Ct() {
|
|
168
171
|
return {
|
|
169
172
|
db: Z(),
|
|
170
|
-
paths:
|
|
173
|
+
paths: N()
|
|
171
174
|
};
|
|
172
175
|
}
|
|
173
|
-
async function
|
|
176
|
+
async function wt(e, t, n) {
|
|
174
177
|
try {
|
|
175
|
-
let r = await
|
|
178
|
+
let r = await Se(w(e.db, e.paths, t));
|
|
176
179
|
if (!r.exists()) return {
|
|
177
180
|
label: t,
|
|
178
181
|
description: "",
|
|
@@ -192,7 +195,7 @@ async function Ct(e, t, n) {
|
|
|
192
195
|
};
|
|
193
196
|
}
|
|
194
197
|
}
|
|
195
|
-
function
|
|
198
|
+
function Tt(e) {
|
|
196
199
|
if (e && typeof e == "object" && "toDate" in e) try {
|
|
197
200
|
let t = e.toDate();
|
|
198
201
|
return t instanceof Date ? t.toISOString() : null;
|
|
@@ -201,15 +204,15 @@ function wt(e) {
|
|
|
201
204
|
}
|
|
202
205
|
return null;
|
|
203
206
|
}
|
|
204
|
-
async function
|
|
207
|
+
async function Et(e, t, n, r) {
|
|
205
208
|
let i = e.trim(), a = t.trim();
|
|
206
209
|
if (!i || !a) return null;
|
|
207
|
-
let s = n ??
|
|
208
|
-
s.paths = C(s.paths), r && await
|
|
209
|
-
let c = await
|
|
210
|
+
let s = n ?? Ct();
|
|
211
|
+
s.paths = C(s.paths), r && await oe(r);
|
|
212
|
+
let c = await wt(s, i, r);
|
|
210
213
|
if (c.hidden) return null;
|
|
211
214
|
try {
|
|
212
|
-
let e = (await
|
|
215
|
+
let e = (await V(G(o(s.db, s.paths), X("boardId", "==", i), X("slug", "==", a), X("listed", "==", !0), X("isPublished", "==", !0), H(1)))).docs[0];
|
|
213
216
|
if (!e) return null;
|
|
214
217
|
let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "", l = typeof t.summary == "string" ? t.summary : "", u = Q(t.i18n), d = ut(t.i18nSource), f = vt({
|
|
215
218
|
title: n,
|
|
@@ -229,17 +232,17 @@ async function Tt(e, t, n, r) {
|
|
|
229
232
|
}, r).trim().slice(0, 200),
|
|
230
233
|
previewImage: et(t.previewImage),
|
|
231
234
|
authorName: typeof t.authorName == "string" && t.authorName.trim() ? t.authorName.trim() : null,
|
|
232
|
-
createdAt:
|
|
235
|
+
createdAt: Tt(t.createdAt)
|
|
233
236
|
} : null;
|
|
234
237
|
} catch (e) {
|
|
235
238
|
return import.meta.dev && console.warn("[memi-board] fetchPublicPostForSeo failed", e), null;
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
|
-
async function
|
|
239
|
-
n && await
|
|
240
|
-
let r = e?.trim() || null, i = t ??
|
|
241
|
+
async function Dt(e, t, n) {
|
|
242
|
+
n && await oe(n);
|
|
243
|
+
let r = e?.trim() || null, i = t ?? Ct();
|
|
241
244
|
if (i.paths = C(i.paths), r) {
|
|
242
|
-
let e = await
|
|
245
|
+
let e = await wt(i, r, n);
|
|
243
246
|
if (e.hidden) return {
|
|
244
247
|
kind: "category",
|
|
245
248
|
category: r,
|
|
@@ -248,12 +251,12 @@ async function Et(e, t, n) {
|
|
|
248
251
|
ogImage: null,
|
|
249
252
|
recentTitles: []
|
|
250
253
|
};
|
|
251
|
-
let { recentTitles: t, ogImage: a } = await
|
|
254
|
+
let { recentTitles: t, ogImage: a } = await Ot(i, r, n);
|
|
252
255
|
return {
|
|
253
256
|
kind: "category",
|
|
254
257
|
category: r,
|
|
255
258
|
categoryLabel: e.label,
|
|
256
|
-
description: e.description ||
|
|
259
|
+
description: e.description || j(n, "seo.boardDescription", { name: e.label }),
|
|
257
260
|
ogImage: a,
|
|
258
261
|
recentTitles: t
|
|
259
262
|
};
|
|
@@ -261,16 +264,16 @@ async function Et(e, t, n) {
|
|
|
261
264
|
return {
|
|
262
265
|
kind: "all",
|
|
263
266
|
category: null,
|
|
264
|
-
categoryLabel:
|
|
265
|
-
description:
|
|
267
|
+
categoryLabel: j(n, "seo.allCategory"),
|
|
268
|
+
description: j(n, "seo.allDescription"),
|
|
266
269
|
ogImage: null,
|
|
267
270
|
recentTitles: []
|
|
268
271
|
};
|
|
269
272
|
}
|
|
270
|
-
async function
|
|
273
|
+
async function Ot(e, t, n) {
|
|
271
274
|
let r = [], i = null;
|
|
272
275
|
try {
|
|
273
|
-
let a = await
|
|
276
|
+
let a = await V(G(o(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), W("createdAt", "desc"), H(12)));
|
|
274
277
|
for (let e of a.docs) {
|
|
275
278
|
let t = e.data() ?? {}, a = vt({
|
|
276
279
|
title: typeof t.title == "string" ? t.title : "",
|
|
@@ -289,31 +292,31 @@ async function Dt(e, t, n) {
|
|
|
289
292
|
}
|
|
290
293
|
//#endregion
|
|
291
294
|
//#region src/utils/boardAccess.ts
|
|
292
|
-
function
|
|
295
|
+
function kt(e, t) {
|
|
293
296
|
return !e || !t ? !1 : [...t.allowedStaffUids ?? [], ...t.allowedManagerUids ?? []].includes(e);
|
|
294
297
|
}
|
|
295
|
-
function kt(e, t, n, r) {
|
|
296
|
-
return e ? t ? !0 : n ? Ot(e, r) : !1 : !1;
|
|
297
|
-
}
|
|
298
298
|
function At(e, t, n, r) {
|
|
299
|
+
return e ? t ? !0 : n ? kt(e, r) : !1 : !1;
|
|
300
|
+
}
|
|
301
|
+
function jt(e, t, n, r) {
|
|
299
302
|
if (!e) return !1;
|
|
300
|
-
if (r?.visibility === "hidden") return
|
|
303
|
+
if (r?.visibility === "hidden") return At(e, t, n, r);
|
|
301
304
|
let i = r?.commentWriteRole ?? "user";
|
|
302
|
-
return i === "admin" ? t : i !== "staff" ||
|
|
305
|
+
return i === "admin" ? t : i !== "staff" || At(e, t, n, r);
|
|
303
306
|
}
|
|
304
307
|
//#endregion
|
|
305
308
|
//#region src/composables/boardLookup.ts
|
|
306
|
-
var
|
|
307
|
-
function Mt(e) {
|
|
308
|
-
jt = e;
|
|
309
|
-
}
|
|
309
|
+
var Mt;
|
|
310
310
|
function Nt(e) {
|
|
311
|
-
|
|
311
|
+
Mt = e;
|
|
312
|
+
}
|
|
313
|
+
function Pt(e) {
|
|
314
|
+
return Mt?.(e);
|
|
312
315
|
}
|
|
313
316
|
//#endregion
|
|
314
317
|
//#region src/utils/moderation-strike.ts
|
|
315
|
-
var
|
|
316
|
-
function
|
|
318
|
+
var Ft = 10, It = 864e5;
|
|
319
|
+
function Lt(e, t, n = Date.now(), r = It) {
|
|
317
320
|
let i = Math.max(0, Math.floor(Number(e) || 0));
|
|
318
321
|
if (i <= 0) return 0;
|
|
319
322
|
let a = typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
@@ -321,7 +324,7 @@ function It(e, t, n = Date.now(), r = Ft) {
|
|
|
321
324
|
let o = Math.floor((n - a) / r);
|
|
322
325
|
return Math.max(0, i - o);
|
|
323
326
|
}
|
|
324
|
-
function
|
|
327
|
+
function Rt(e, t, n = Date.now(), r = 10, i = It) {
|
|
325
328
|
let a = Math.max(0, Math.floor(Number(e) || 0));
|
|
326
329
|
if (a < r) return null;
|
|
327
330
|
let o = typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
@@ -329,20 +332,20 @@ function Lt(e, t, n = Date.now(), r = 10, i = Ft) {
|
|
|
329
332
|
let s = o + (a - (r - 1)) * i;
|
|
330
333
|
return s > n ? s : null;
|
|
331
334
|
}
|
|
332
|
-
function
|
|
333
|
-
return
|
|
335
|
+
function zt(e, t, n = Date.now(), r = 10, i = It) {
|
|
336
|
+
return Rt(e, t, n, r, i) != null;
|
|
334
337
|
}
|
|
335
|
-
function
|
|
338
|
+
function Bt(e, t = Date.now(), n) {
|
|
336
339
|
let r = Math.max(0, e - t), i = Math.ceil(r / 36e5);
|
|
337
|
-
if (i <= 0) return
|
|
338
|
-
if (i < 24) return
|
|
340
|
+
if (i <= 0) return j(n, "moderationStrike.liftSoon");
|
|
341
|
+
if (i < 24) return j(n, "moderationStrike.liftInHours", { hours: i });
|
|
339
342
|
let a = Math.floor(i / 24), o = i % 24;
|
|
340
|
-
return o === 0 ?
|
|
343
|
+
return o === 0 ? j(n, "moderationStrike.liftInDays", { days: a }) : j(n, "moderationStrike.liftInDaysHours", {
|
|
341
344
|
days: a,
|
|
342
345
|
hours: o
|
|
343
346
|
});
|
|
344
347
|
}
|
|
345
|
-
function
|
|
348
|
+
function Vt(e) {
|
|
346
349
|
if (e == null) return null;
|
|
347
350
|
if (typeof e == "number" && Number.isFinite(e)) return e;
|
|
348
351
|
if (typeof e == "object" && e && "toMillis" in e && typeof e.toMillis == "function") return e.toMillis();
|
|
@@ -354,29 +357,29 @@ function Bt(e) {
|
|
|
354
357
|
}
|
|
355
358
|
//#endregion
|
|
356
359
|
//#region src/composables/useMemiBoardAuth.ts
|
|
357
|
-
var
|
|
358
|
-
function
|
|
360
|
+
var Ht = "__MEMI_BOARD_AUTH_STATE__";
|
|
361
|
+
function Ut() {
|
|
359
362
|
let e = globalThis;
|
|
360
|
-
return e[
|
|
361
|
-
role:
|
|
362
|
-
rolePending:
|
|
363
|
-
rawBlockCount:
|
|
364
|
-
blockAtMs:
|
|
363
|
+
return e[Ht] || (e[Ht] = {
|
|
364
|
+
role: L("user"),
|
|
365
|
+
rolePending: L(!0),
|
|
366
|
+
rawBlockCount: L(0),
|
|
367
|
+
blockAtMs: L(null),
|
|
365
368
|
watchStarted: !1
|
|
366
|
-
}), e[
|
|
369
|
+
}), e[Ht];
|
|
367
370
|
}
|
|
368
|
-
function
|
|
369
|
-
let e = v(), { t, locale: n } =
|
|
371
|
+
function Wt() {
|
|
372
|
+
let e = v(), { t, locale: n } = M(), r = Ut(), i = Z(), o = Ne(), s = Ae(), { role: c, rolePending: l, rawBlockCount: u, blockAtMs: d } = r;
|
|
370
373
|
function f() {
|
|
371
374
|
let t = e.moderation?.blockBanThreshold;
|
|
372
375
|
return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
|
|
373
376
|
}
|
|
374
377
|
function p() {
|
|
375
378
|
let t = e.moderation?.blockBanDecayMs;
|
|
376
|
-
return typeof t == "number" && t > 0 ? t :
|
|
379
|
+
return typeof t == "number" && t > 0 ? t : It;
|
|
377
380
|
}
|
|
378
381
|
function m(e) {
|
|
379
|
-
return h(i,
|
|
382
|
+
return h(i, N(), e);
|
|
380
383
|
}
|
|
381
384
|
function g(e) {
|
|
382
385
|
if (c.value = [
|
|
@@ -389,25 +392,25 @@ function Ut() {
|
|
|
389
392
|
u.value = 0, d.value = null;
|
|
390
393
|
return;
|
|
391
394
|
}
|
|
392
|
-
u.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), d.value =
|
|
395
|
+
u.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), d.value = Vt(e.moderationBlockAt);
|
|
393
396
|
}
|
|
394
397
|
async function _(e) {
|
|
395
|
-
let t = m(e.uid), n = a(i,
|
|
396
|
-
if (!r.exists()) return await Promise.all([
|
|
398
|
+
let t = m(e.uid), n = a(i, N(), e.uid), r = await Se(t);
|
|
399
|
+
if (!r.exists()) return await Promise.all([q(t, {
|
|
397
400
|
role: "user",
|
|
398
401
|
displayName: e.displayName,
|
|
399
402
|
photoURL: e.photoURL,
|
|
400
|
-
joinedAt:
|
|
401
|
-
lastVisitAt:
|
|
402
|
-
updatedAt:
|
|
403
|
-
}),
|
|
403
|
+
joinedAt: K(),
|
|
404
|
+
lastVisitAt: K(),
|
|
405
|
+
updatedAt: K()
|
|
406
|
+
}), q(n, { email: e.email })]), g({ moderationBlockCount: 0 }), "user";
|
|
404
407
|
let o = r.data();
|
|
405
408
|
g(o);
|
|
406
409
|
let s = typeof o.displayName == "string" && o.displayName.trim(), c = typeof o.photoURL == "string" && o.photoURL.trim(), l = {
|
|
407
|
-
lastVisitAt:
|
|
408
|
-
updatedAt:
|
|
410
|
+
lastVisitAt: K(),
|
|
411
|
+
updatedAt: K()
|
|
409
412
|
};
|
|
410
|
-
return !s && e.displayName && (l.displayName = e.displayName), !c && e.photoURL && (l.photoURL = e.photoURL), await Promise.all([Y(t, l),
|
|
413
|
+
return !s && e.displayName && (l.displayName = e.displayName), !c && e.photoURL && (l.photoURL = e.photoURL), await Promise.all([Y(t, l), q(n, { email: e.email }, { merge: !0 })]), [
|
|
411
414
|
"owner",
|
|
412
415
|
"admin",
|
|
413
416
|
"manager",
|
|
@@ -421,10 +424,10 @@ function Ut() {
|
|
|
421
424
|
g(void 0);
|
|
422
425
|
return;
|
|
423
426
|
}
|
|
424
|
-
let t = await
|
|
427
|
+
let t = await Se(m(e));
|
|
425
428
|
g(t.exists() ? t.data() : void 0);
|
|
426
429
|
}
|
|
427
|
-
r.watchStarted || (r.watchStarted = !0,
|
|
430
|
+
r.watchStarted || (r.watchStarted = !0, z(s, async (e) => {
|
|
428
431
|
if (l.value = !0, !e) {
|
|
429
432
|
c.value = "user", g(void 0), l.value = !1;
|
|
430
433
|
return;
|
|
@@ -437,46 +440,46 @@ function Ut() {
|
|
|
437
440
|
l.value = !1;
|
|
438
441
|
}
|
|
439
442
|
}, { immediate: !0 }));
|
|
440
|
-
let b =
|
|
443
|
+
let b = F(() => !!s.value), x = F(() => c.value === "owner"), S = F(() => c.value === "manager"), C = F(() => x.value || c.value === "admin"), w = F(() => S.value || c.value === "staff"), T = F(() => C.value || w.value), E = F(() => Lt(u.value, d.value, Date.now(), p())), D = F(() => {
|
|
441
444
|
let e = f();
|
|
442
|
-
return e <= 0 ? !1 :
|
|
443
|
-
}),
|
|
445
|
+
return e <= 0 ? !1 : zt(u.value, d.value, Date.now(), e, p());
|
|
446
|
+
}), O = F(() => {
|
|
444
447
|
let e = f();
|
|
445
448
|
if (e <= 0) return null;
|
|
446
|
-
let t =
|
|
447
|
-
return t == null ? null :
|
|
448
|
-
}),
|
|
449
|
+
let t = Rt(u.value, d.value, Date.now(), e, p());
|
|
450
|
+
return t == null ? null : Bt(t, Date.now(), n.value);
|
|
451
|
+
}), k = F(() => {
|
|
449
452
|
if (!D.value) return null;
|
|
450
|
-
let e =
|
|
453
|
+
let e = O.value;
|
|
451
454
|
return e ? t("auth.writeRestrictedUntil", { until: e }) : t("auth.writeRestricted");
|
|
452
455
|
});
|
|
453
|
-
async function
|
|
456
|
+
async function ee() {
|
|
454
457
|
let e = s.value?.uid, r = f();
|
|
455
458
|
if (!e || r <= 0) return {
|
|
456
459
|
effectiveCount: 0,
|
|
457
460
|
restricted: !1,
|
|
458
461
|
messageSuffix: ""
|
|
459
462
|
};
|
|
460
|
-
let i = m(e), a = await
|
|
463
|
+
let i = m(e), a = await Se(i);
|
|
461
464
|
a.exists() ? await Y(i, {
|
|
462
|
-
moderationBlockCount:
|
|
463
|
-
moderationBlockAt:
|
|
464
|
-
updatedAt:
|
|
465
|
-
}) : await
|
|
465
|
+
moderationBlockCount: Te(1),
|
|
466
|
+
moderationBlockAt: K(),
|
|
467
|
+
updatedAt: K()
|
|
468
|
+
}) : await q(i, {
|
|
466
469
|
role: "user",
|
|
467
470
|
displayName: s.value?.displayName ?? null,
|
|
468
471
|
moderationBlockCount: 1,
|
|
469
|
-
moderationBlockAt:
|
|
470
|
-
updatedAt:
|
|
472
|
+
moderationBlockAt: K(),
|
|
473
|
+
updatedAt: K()
|
|
471
474
|
});
|
|
472
475
|
let o = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, c = Date.now();
|
|
473
476
|
u.value = o, d.value = c;
|
|
474
|
-
let l =
|
|
477
|
+
let l = Lt(o, c, c, p()), h = zt(o, c, c, r, p()), g = t("auth.strikeSuffix", {
|
|
475
478
|
count: l,
|
|
476
479
|
threshold: r
|
|
477
480
|
});
|
|
478
481
|
if (h) {
|
|
479
|
-
let e =
|
|
482
|
+
let e = Rt(o, c, c, r, p()), i = e == null ? null : Bt(e, c, n.value);
|
|
480
483
|
g = i ? t("auth.strikeRestrictedUntil", {
|
|
481
484
|
count: l,
|
|
482
485
|
until: i
|
|
@@ -488,101 +491,101 @@ function Ut() {
|
|
|
488
491
|
messageSuffix: g
|
|
489
492
|
};
|
|
490
493
|
}
|
|
491
|
-
function
|
|
494
|
+
function A() {
|
|
492
495
|
if (!o) throw Error(t("auth.notInitialized"));
|
|
493
496
|
return o;
|
|
494
497
|
}
|
|
495
|
-
async function
|
|
496
|
-
return ze(
|
|
498
|
+
async function te() {
|
|
499
|
+
return ze(A(), new Pe());
|
|
497
500
|
}
|
|
498
|
-
async function
|
|
501
|
+
async function ne() {
|
|
499
502
|
let e = new Fe("apple.com");
|
|
500
|
-
return e.addScope("email"), e.addScope("name"), ze(
|
|
503
|
+
return e.addScope("email"), e.addScope("name"), ze(A(), e);
|
|
501
504
|
}
|
|
502
|
-
async function
|
|
503
|
-
return Re(
|
|
505
|
+
async function re(e, t) {
|
|
506
|
+
return Re(A(), e, t);
|
|
504
507
|
}
|
|
505
|
-
async function
|
|
506
|
-
let r = await Ie(
|
|
508
|
+
async function ie(e, t, n) {
|
|
509
|
+
let r = await Ie(A(), e, t);
|
|
507
510
|
return n && await Ve(r.user, { displayName: n }), r;
|
|
508
511
|
}
|
|
509
|
-
async function
|
|
510
|
-
await Be(
|
|
512
|
+
async function j() {
|
|
513
|
+
await Be(A());
|
|
514
|
+
}
|
|
515
|
+
function ae(e) {
|
|
516
|
+
return At(s.value?.uid, C.value, w.value, e ? Pt(e) : void 0);
|
|
511
517
|
}
|
|
512
518
|
function oe(e) {
|
|
513
|
-
return
|
|
519
|
+
return s.value ? C.value ? !0 : S.value && !!e && (Pt(e)?.allowedManagerUids ?? []).includes(s.value.uid) : !1;
|
|
514
520
|
}
|
|
515
521
|
function se(e) {
|
|
516
|
-
return
|
|
522
|
+
return b.value && (s.value?.uid === e.authorUid || ae(e.boardId));
|
|
517
523
|
}
|
|
518
524
|
function ce(e) {
|
|
519
|
-
return b.value && (s.value?.uid === e.authorUid || oe(e.boardId));
|
|
520
|
-
}
|
|
521
|
-
function le(e) {
|
|
522
525
|
return b.value && s.value?.uid === e.authorUid;
|
|
523
526
|
}
|
|
524
|
-
function
|
|
525
|
-
return b.value && (s.value?.uid === e.authorUid ||
|
|
527
|
+
function le(e) {
|
|
528
|
+
return b.value && (s.value?.uid === e.authorUid || ae(e.boardId));
|
|
526
529
|
}
|
|
527
530
|
return {
|
|
528
531
|
user: s,
|
|
529
532
|
role: c,
|
|
530
533
|
isOwner: x,
|
|
531
534
|
isManager: S,
|
|
532
|
-
canConfigureBoard:
|
|
535
|
+
canConfigureBoard: oe,
|
|
533
536
|
isSignedIn: b,
|
|
534
537
|
isAdmin: C,
|
|
535
538
|
isStaff: w,
|
|
536
539
|
canManageContent: T,
|
|
537
|
-
canManageBoard:
|
|
540
|
+
canManageBoard: ae,
|
|
538
541
|
rolePending: l,
|
|
539
542
|
moderationBlockCount: E,
|
|
540
543
|
isWriteRestricted: D,
|
|
541
|
-
restrictedUntilLabel:
|
|
542
|
-
restrictedMessage:
|
|
543
|
-
signInWithGoogle:
|
|
544
|
-
signInWithApple:
|
|
545
|
-
signInWithEmail:
|
|
546
|
-
signUpWithEmail:
|
|
547
|
-
signOut:
|
|
548
|
-
canEdit:
|
|
549
|
-
canDelete:
|
|
550
|
-
canEditComment:
|
|
551
|
-
canDeleteComment:
|
|
552
|
-
recordContentModerationBlock:
|
|
544
|
+
restrictedUntilLabel: O,
|
|
545
|
+
restrictedMessage: k,
|
|
546
|
+
signInWithGoogle: te,
|
|
547
|
+
signInWithApple: ne,
|
|
548
|
+
signInWithEmail: re,
|
|
549
|
+
signUpWithEmail: ie,
|
|
550
|
+
signOut: j,
|
|
551
|
+
canEdit: se,
|
|
552
|
+
canDelete: se,
|
|
553
|
+
canEditComment: ce,
|
|
554
|
+
canDeleteComment: le,
|
|
555
|
+
recordContentModerationBlock: ee,
|
|
553
556
|
refreshBoardUser: y
|
|
554
557
|
};
|
|
555
558
|
}
|
|
556
559
|
//#endregion
|
|
557
560
|
//#region src/utils/imeSafeSubmit.ts
|
|
558
|
-
var
|
|
559
|
-
function
|
|
561
|
+
var Gt = /* @__PURE__ */ new WeakMap();
|
|
562
|
+
function Kt(e) {
|
|
560
563
|
let t = e.currentTarget;
|
|
561
564
|
return t instanceof HTMLButtonElement ? t : t instanceof Element ? t.closest("button") : null;
|
|
562
565
|
}
|
|
563
|
-
function
|
|
566
|
+
function qt(e) {
|
|
564
567
|
if (e.pointerType !== "mouse" || e.button !== 0) return;
|
|
565
|
-
let t =
|
|
568
|
+
let t = Kt(e), n = t?.form;
|
|
566
569
|
if (!t || !n || t.disabled) return;
|
|
567
|
-
|
|
570
|
+
Gt.set(t, Date.now() + 1e3);
|
|
568
571
|
let r = document.activeElement;
|
|
569
572
|
r instanceof HTMLElement && r.blur(), setTimeout(() => n.requestSubmit(t), 0);
|
|
570
573
|
}
|
|
571
|
-
function
|
|
572
|
-
let t =
|
|
574
|
+
function Jt(e) {
|
|
575
|
+
let t = Kt(e);
|
|
573
576
|
if (!t) return;
|
|
574
|
-
let n =
|
|
575
|
-
n && Date.now() < n && (e.preventDefault(),
|
|
577
|
+
let n = Gt.get(t);
|
|
578
|
+
n && Date.now() < n && (e.preventDefault(), Gt.delete(t));
|
|
576
579
|
}
|
|
577
580
|
//#endregion
|
|
578
581
|
//#region src/utils/findReadablePost.ts
|
|
579
|
-
async function
|
|
582
|
+
async function Yt(e, t, n, r, i, a) {
|
|
580
583
|
let s = [X("boardId", "==", n), X("slug", "==", r)];
|
|
581
|
-
return a ? (await
|
|
584
|
+
return a ? (await V(G(o(e, t), ...s, H(1)))).docs[0] : (await Promise.all([V(G(o(e, t), ...s, X("listed", "==", !0), X("isPublished", "==", !0), H(1))), ...i ? [V(G(o(e, t), ...s, X("authorUid", "==", i), H(1)))] : []])).flatMap((e) => e.docs)[0];
|
|
582
585
|
}
|
|
583
586
|
//#endregion
|
|
584
587
|
//#region src/utils/extractEditorImageUrls.ts
|
|
585
|
-
function
|
|
588
|
+
function Xt(e) {
|
|
586
589
|
if (!e) return [];
|
|
587
590
|
let t = /* @__PURE__ */ new Set();
|
|
588
591
|
for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&", "&"));
|
|
@@ -591,7 +594,7 @@ function Yt(e) {
|
|
|
591
594
|
}
|
|
592
595
|
//#endregion
|
|
593
596
|
//#region src/utils/storagePath.ts
|
|
594
|
-
function
|
|
597
|
+
function Zt(e) {
|
|
595
598
|
try {
|
|
596
599
|
let t = new URL(e), n = t.hostname.toLowerCase();
|
|
597
600
|
if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
|
|
@@ -601,107 +604,107 @@ function Xt(e) {
|
|
|
601
604
|
return null;
|
|
602
605
|
}
|
|
603
606
|
}
|
|
604
|
-
function
|
|
607
|
+
function Qt(e) {
|
|
605
608
|
return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
|
|
606
609
|
}
|
|
607
610
|
//#endregion
|
|
608
611
|
//#region src/utils/deletePostCascade.ts
|
|
609
|
-
async function
|
|
612
|
+
async function $t(e) {
|
|
610
613
|
try {
|
|
611
614
|
let t = await Ke(e);
|
|
612
|
-
await Promise.all([...t.items.map((e) => He(e).catch(() => {})), ...t.prefixes.map((e) =>
|
|
615
|
+
await Promise.all([...t.items.map((e) => He(e).catch(() => {})), ...t.prefixes.map((e) => $t(e))]);
|
|
613
616
|
} catch {}
|
|
614
617
|
}
|
|
615
|
-
async function
|
|
616
|
-
await
|
|
618
|
+
async function en(e, t) {
|
|
619
|
+
await $t(qe(e, `${t}/images`)), await $t(qe(e, `${t}/attachments`)), await $t(qe(e, `${t}/comment-images`));
|
|
617
620
|
}
|
|
618
|
-
var
|
|
619
|
-
async function
|
|
620
|
-
return (await
|
|
621
|
+
var tn = 450;
|
|
622
|
+
async function nn(e, t, n) {
|
|
623
|
+
return (await V(G(g(e, t), X("postId", "==", n)))).docs.flatMap((e) => le(e.data().images, `${x(t, n)}/comment-images/`));
|
|
621
624
|
}
|
|
622
|
-
async function
|
|
625
|
+
async function rn(e, t) {
|
|
623
626
|
let n = [...new Set([...t].filter(Boolean))];
|
|
624
627
|
await Promise.all(n.map((t) => He(qe(e, t)).catch(() => {})));
|
|
625
628
|
}
|
|
626
|
-
async function
|
|
627
|
-
let n = await
|
|
628
|
-
for (let t = 0; t < n.docs.length; t +=
|
|
629
|
+
async function an(e, t) {
|
|
630
|
+
let n = await V(t);
|
|
631
|
+
for (let t = 0; t < n.docs.length; t += tn) {
|
|
629
632
|
let r = Oe(e);
|
|
630
|
-
n.docs.slice(t, t +
|
|
633
|
+
n.docs.slice(t, t + tn).forEach((e) => r.delete(e.ref)), await r.commit();
|
|
631
634
|
}
|
|
632
635
|
}
|
|
633
|
-
async function an(e, t, n) {
|
|
634
|
-
await rn(e, K(b(e, t), X("postId", "==", n)));
|
|
635
|
-
}
|
|
636
636
|
async function on(e, t, n) {
|
|
637
|
-
await
|
|
637
|
+
await an(e, G(b(e, t), X("postId", "==", n)));
|
|
638
638
|
}
|
|
639
|
-
async function sn(e, t, n
|
|
640
|
-
|
|
639
|
+
async function sn(e, t, n) {
|
|
640
|
+
await an(e, G(b(e, t), X("commentId", "==", n), X("target", "==", "comment")));
|
|
641
|
+
}
|
|
642
|
+
async function cn(e, t, n, r) {
|
|
643
|
+
let i = y(e, n, r), a = s(e, n, r), [o, c] = await Promise.all([Se(i), Se(a)]);
|
|
641
644
|
if (!o.exists()) return;
|
|
642
|
-
let l = o.data(), u = c.exists() ? String(c.data().content ?? "") : "", d = await
|
|
645
|
+
let l = o.data(), u = c.exists() ? String(c.data().content ?? "") : "", d = await nn(e, n, r), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
|
|
643
646
|
for (let e of l.attachments ?? []) {
|
|
644
647
|
if (!e?.path) continue;
|
|
645
648
|
f.add(e.path);
|
|
646
|
-
let t =
|
|
649
|
+
let t = Qt(e.path);
|
|
647
650
|
t && t !== r && p.add(t);
|
|
648
651
|
}
|
|
649
|
-
for (let e of
|
|
650
|
-
let t =
|
|
652
|
+
for (let e of Xt(u)) {
|
|
653
|
+
let t = Zt(e);
|
|
651
654
|
if (!t) continue;
|
|
652
655
|
f.add(t);
|
|
653
656
|
let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
|
|
654
657
|
n !== t && n.includes("/images/thumbnails/") && f.add(n);
|
|
655
658
|
let i = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
|
|
656
659
|
i && !t.includes("/thumbnails/") && f.add(`${i[1]}thumbnails/${i[2]}.jpg`);
|
|
657
|
-
let a =
|
|
660
|
+
let a = Qt(t);
|
|
658
661
|
a && a !== r && p.add(a);
|
|
659
662
|
}
|
|
660
|
-
await
|
|
661
|
-
for (let e of p) await
|
|
662
|
-
await
|
|
663
|
+
await en(t, x(n, r));
|
|
664
|
+
for (let e of p) await en(t, x(n, e));
|
|
665
|
+
await rn(t, d), await rn(t, f), await an(e, G(g(e, n), X("postId", "==", r))), await on(e, n, r), await _e(a), await _e(i);
|
|
663
666
|
}
|
|
664
667
|
//#endregion
|
|
665
668
|
//#region src/utils/postBody.ts
|
|
666
|
-
function
|
|
669
|
+
function ln(e) {
|
|
667
670
|
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(/ /gi, " ").replace(/ /g, " ").replace(/&[a-z]+;/gi, " ").replace(/&#\d+;/g, " ").replace(/[\u200B-\u200D\uFEFF\u00AD]/g, "").replace(/\s+/g, " ").trim();
|
|
668
671
|
}
|
|
669
|
-
function
|
|
670
|
-
let n =
|
|
672
|
+
function un(e, t = 40) {
|
|
673
|
+
let n = ln(e);
|
|
671
674
|
if (!n) return "";
|
|
672
675
|
if (n.length <= t) return n;
|
|
673
676
|
let r = n.slice(0, t), i = r.lastIndexOf(" ");
|
|
674
677
|
return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
|
|
675
678
|
}
|
|
676
|
-
function
|
|
677
|
-
return
|
|
679
|
+
function dn(e) {
|
|
680
|
+
return ln(e).length > 0;
|
|
678
681
|
}
|
|
679
|
-
function
|
|
682
|
+
function fn(e, t) {
|
|
680
683
|
return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
|
|
681
684
|
}
|
|
682
|
-
function
|
|
683
|
-
return !
|
|
685
|
+
function pn(e) {
|
|
686
|
+
return !dn(e);
|
|
684
687
|
}
|
|
685
688
|
//#endregion
|
|
686
689
|
//#region src/utils/postPreview.ts
|
|
687
|
-
function
|
|
690
|
+
function mn(e) {
|
|
688
691
|
return e.replace(/&/g, "&").replace(/"/g, "\"").replace(/'/g, "'");
|
|
689
692
|
}
|
|
690
|
-
function
|
|
693
|
+
function hn(e) {
|
|
691
694
|
if (e) try {
|
|
692
|
-
let t = new URL(
|
|
695
|
+
let t = new URL(mn(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
|
|
693
696
|
if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
|
|
694
697
|
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;
|
|
695
698
|
} catch {
|
|
696
699
|
return;
|
|
697
700
|
}
|
|
698
701
|
}
|
|
699
|
-
function
|
|
700
|
-
let t =
|
|
702
|
+
function gn(e) {
|
|
703
|
+
let t = hn(e.videoUrl);
|
|
701
704
|
return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
702
705
|
}
|
|
703
|
-
function
|
|
704
|
-
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 ?
|
|
706
|
+
function _n(e, t = []) {
|
|
707
|
+
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 ? mn(r[1]) : a, s = o ? hn(o) : void 0, c = n ? mn(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
|
|
705
708
|
return {
|
|
706
709
|
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(/ /g, " ").replace(/&/g, "&").replace(/[^\S\n]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{2,}/g, "\n").trim().slice(0, 160),
|
|
707
710
|
...c ? { previewImage: c } : {},
|
|
@@ -710,44 +713,44 @@ function gn(e, t = []) {
|
|
|
710
713
|
}
|
|
711
714
|
//#endregion
|
|
712
715
|
//#region src/utils/saveBoardVisibility.ts
|
|
713
|
-
function
|
|
716
|
+
function vn(e) {
|
|
714
717
|
return e === "hidden" ? "hidden" : "public";
|
|
715
718
|
}
|
|
716
|
-
async function
|
|
719
|
+
async function yn(e, t, n, r) {
|
|
717
720
|
let i;
|
|
718
721
|
for (;;) {
|
|
719
|
-
let a = await
|
|
722
|
+
let a = await V(G(t, X("boardId", "==", n), W("__name__"), ...i ? [J(i)] : [], H(400)));
|
|
720
723
|
if (a.empty) break;
|
|
721
724
|
let o = Oe(e), s = 0;
|
|
722
725
|
for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
|
|
723
726
|
if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
|
|
724
727
|
}
|
|
725
728
|
}
|
|
726
|
-
async function yn(e, t, n, r) {
|
|
727
|
-
await vn(e, o(e, t), n, r), await vn(e, g(e, t), n, r);
|
|
728
|
-
}
|
|
729
729
|
async function bn(e, t, n, r) {
|
|
730
|
-
|
|
731
|
-
|
|
730
|
+
await yn(e, o(e, t), n, r), await yn(e, g(e, t), n, r);
|
|
731
|
+
}
|
|
732
|
+
async function xn(e, t, n, r) {
|
|
733
|
+
let i = w(e, t, n), a = vn(r.visibility);
|
|
734
|
+
await De(e, async (e) => {
|
|
732
735
|
let t = await e.get(i), n = t.data(), o = n?.visibilityTransition || "";
|
|
733
736
|
if (o && o !== a) throw Error("Finish the pending visibility change before changing it again.");
|
|
734
|
-
return !t.exists() || !o &&
|
|
737
|
+
return !t.exists() || !o && vn(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
|
|
735
738
|
...r,
|
|
736
|
-
visibility: a === "public" ? "public" :
|
|
739
|
+
visibility: a === "public" ? "public" : vn(n?.visibility),
|
|
737
740
|
visibilityTransition: a
|
|
738
741
|
}, { merge: !0 }), !0);
|
|
739
|
-
}) && (await
|
|
742
|
+
}) && (await bn(e, t, n, a !== "hidden"), await De(e, async (e) => {
|
|
740
743
|
if ((await e.get(i)).data()?.visibilityTransition !== a) throw Error("The visibility transition changed. Reload and retry.");
|
|
741
744
|
e.update(i, {
|
|
742
745
|
visibility: a,
|
|
743
746
|
visibilityTransition: "",
|
|
744
|
-
updatedAt:
|
|
747
|
+
updatedAt: K()
|
|
745
748
|
});
|
|
746
749
|
}));
|
|
747
750
|
}
|
|
748
751
|
//#endregion
|
|
749
752
|
//#region src/utils/moderation-prompt.ts
|
|
750
|
-
var
|
|
753
|
+
var Sn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", Cn = {
|
|
751
754
|
ko: "Korean",
|
|
752
755
|
en: "English",
|
|
753
756
|
ja: "Japanese",
|
|
@@ -759,12 +762,12 @@ var xn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
|
|
|
759
762
|
ar: "Arabic",
|
|
760
763
|
id: "Indonesian"
|
|
761
764
|
};
|
|
762
|
-
function
|
|
763
|
-
let t =
|
|
765
|
+
function wn(e) {
|
|
766
|
+
let t = Cn[e] ?? "English", n = de(e).name;
|
|
764
767
|
return t === n ? t : `${t} (${n})`;
|
|
765
768
|
}
|
|
766
|
-
function
|
|
767
|
-
let t =
|
|
769
|
+
function Tn(e) {
|
|
770
|
+
let t = wn(e);
|
|
768
771
|
return `You are a strict moderator reviewing content for a message board.
|
|
769
772
|
If the text below contains profanity, vulgar slang, sexual harassment, hate speech, threats, spam, or repetitive/flooding advertisements, you MUST reject it (flagged=true).
|
|
770
773
|
|
|
@@ -791,17 +794,17 @@ Output JSON only:
|
|
|
791
794
|
Do not quote the offensive words at length; clearly state the type (profanity/hate/spam, etc.).
|
|
792
795
|
- If flagged=false, category is "none" and reason is ""`;
|
|
793
796
|
}
|
|
794
|
-
function
|
|
795
|
-
return e === "ko" ?
|
|
797
|
+
function En(e = "ko") {
|
|
798
|
+
return e === "ko" ? Sn : Tn(e);
|
|
796
799
|
}
|
|
797
|
-
function
|
|
800
|
+
function Dn(e, t = "ko") {
|
|
798
801
|
let n = `"""${e.slice(0, 4e3)}"""`;
|
|
799
802
|
return t === "ko" ? `심사할 텍스트:\n${n}` : `Text to review:\n${n}`;
|
|
800
803
|
}
|
|
801
|
-
function
|
|
804
|
+
function On(e = "ko") {
|
|
802
805
|
return e === "ko" ? "이 이미지를 심사해 주세요." : "Please review this image.";
|
|
803
806
|
}
|
|
804
|
-
var
|
|
807
|
+
var kn = {
|
|
805
808
|
abuse: "욕설·비속어·모욕",
|
|
806
809
|
spam: "스팸·광고",
|
|
807
810
|
adult: "선정적·성인 내용",
|
|
@@ -809,21 +812,21 @@ var On = {
|
|
|
809
812
|
other: "부적절한 내용",
|
|
810
813
|
none: ""
|
|
811
814
|
};
|
|
812
|
-
function
|
|
813
|
-
return !e || e === "none" ? "" : e in
|
|
815
|
+
function An(e, t = "ko") {
|
|
816
|
+
return !e || e === "none" ? "" : e in kn ? j(t, `moderationPrompt.categories.${e}`) : e;
|
|
814
817
|
}
|
|
815
|
-
function
|
|
818
|
+
function jn(e) {
|
|
816
819
|
let t = e.locale ?? "ko";
|
|
817
820
|
if (e.via === "local" && e.localHit) {
|
|
818
821
|
let n = e.localHit.trim();
|
|
819
|
-
return n.length > 0 && n.length <= 12 ?
|
|
822
|
+
return n.length > 0 && n.length <= 12 ? j(t, "moderationPrompt.localHit", { hit: n }) : j(t, "moderationPrompt.localGeneric");
|
|
820
823
|
}
|
|
821
824
|
let n = (e.reason || "").trim();
|
|
822
825
|
if (n) return n;
|
|
823
|
-
let r = e.category ?
|
|
824
|
-
return r ?
|
|
826
|
+
let r = e.category ? An(e.category, t) : "";
|
|
827
|
+
return r ? j(t, "moderationPrompt.categoryBlocked", { category: r }) : j(t, "moderationPrompt.genericBlocked");
|
|
825
828
|
}
|
|
826
|
-
var
|
|
829
|
+
var Mn = [
|
|
827
830
|
"씨발",
|
|
828
831
|
"시발",
|
|
829
832
|
"시이발",
|
|
@@ -849,10 +852,10 @@ var jn = [
|
|
|
849
852
|
"bitch",
|
|
850
853
|
"asshole"
|
|
851
854
|
];
|
|
852
|
-
function
|
|
855
|
+
function Nn(e) {
|
|
853
856
|
return new RegExp(e.join("|"), "i");
|
|
854
857
|
}
|
|
855
|
-
var
|
|
858
|
+
var Pn = /* @__PURE__ */ new Set([
|
|
856
859
|
"none",
|
|
857
860
|
"abuse",
|
|
858
861
|
"spam",
|
|
@@ -860,7 +863,7 @@ var Nn = /* @__PURE__ */ new Set([
|
|
|
860
863
|
"violence",
|
|
861
864
|
"other"
|
|
862
865
|
]);
|
|
863
|
-
function
|
|
866
|
+
function Fn(e) {
|
|
864
867
|
let t = e.trim();
|
|
865
868
|
if (!t) return null;
|
|
866
869
|
let n;
|
|
@@ -878,7 +881,7 @@ function Pn(e) {
|
|
|
878
881
|
if (typeof n != "object" || !n) return null;
|
|
879
882
|
let r = n;
|
|
880
883
|
if (typeof r.flagged != "boolean") return null;
|
|
881
|
-
let i = typeof r.category == "string" &&
|
|
884
|
+
let i = typeof r.category == "string" && Pn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
|
|
882
885
|
return {
|
|
883
886
|
flagged: r.flagged,
|
|
884
887
|
category: i,
|
|
@@ -887,11 +890,11 @@ function Pn(e) {
|
|
|
887
890
|
}
|
|
888
891
|
//#endregion
|
|
889
892
|
//#region src/composables/useMemiBoardAutoTranslate.ts
|
|
890
|
-
var
|
|
891
|
-
function
|
|
893
|
+
var In = 3e4, Ln = 45e3, Rn = 12e3, zn = 3;
|
|
894
|
+
function Bn(e) {
|
|
892
895
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
893
896
|
}
|
|
894
|
-
async function
|
|
897
|
+
async function Vn(e, t, n) {
|
|
895
898
|
let r = Array(e.length), i = 0;
|
|
896
899
|
async function a() {
|
|
897
900
|
for (; i < e.length;) {
|
|
@@ -901,7 +904,7 @@ async function Bn(e, t, n) {
|
|
|
901
904
|
}
|
|
902
905
|
return await Promise.all(Array.from({ length: Math.min(t, e.length) }, () => a())), r;
|
|
903
906
|
}
|
|
904
|
-
function
|
|
907
|
+
function Hn(e, t) {
|
|
905
908
|
return new Promise((n, r) => {
|
|
906
909
|
let i = setTimeout(() => r(/* @__PURE__ */ Error(`translation timed out after ${t / 1e3}s`)), t);
|
|
907
910
|
e.then((e) => {
|
|
@@ -911,14 +914,14 @@ function Vn(e, t) {
|
|
|
911
914
|
});
|
|
912
915
|
});
|
|
913
916
|
}
|
|
914
|
-
function
|
|
917
|
+
function Un() {
|
|
915
918
|
let e = Me(), { moderation: t } = v();
|
|
916
919
|
async function n(n) {
|
|
917
920
|
D();
|
|
918
921
|
let r = Xe(e, {
|
|
919
922
|
backend: new Je(),
|
|
920
923
|
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
921
|
-
}), i = await
|
|
924
|
+
}), i = await Hn(Ze(r, {
|
|
922
925
|
model: t.model ?? "gemini-3.5-flash-lite",
|
|
923
926
|
systemInstruction: [
|
|
924
927
|
"Identify the predominant language of the supplied message-board text.",
|
|
@@ -931,7 +934,7 @@ function Hn() {
|
|
|
931
934
|
responseMimeType: "application/json",
|
|
932
935
|
responseSchema: Ye.object({ properties: { locale: Ye.enumString({ enum: T.map((e) => e.code) }) } })
|
|
933
936
|
}
|
|
934
|
-
}).generateContent(JSON.stringify({ text: n.slice(0,
|
|
937
|
+
}).generateContent(JSON.stringify({ text: n.slice(0, Rn) })), In), a = P(JSON.parse(i.response.text())?.locale);
|
|
935
938
|
if (!a) throw Error("Could not identify the original language. Please try translating again.");
|
|
936
939
|
return a;
|
|
937
940
|
}
|
|
@@ -959,12 +962,12 @@ function Hn() {
|
|
|
959
962
|
async function i(e, t, n, i) {
|
|
960
963
|
let a = Object.keys(e.fields), o = [
|
|
961
964
|
`Purpose: ${i}`,
|
|
962
|
-
`Source language: ${
|
|
963
|
-
`Translate into: ${n.map((e) => `${e} = ${
|
|
965
|
+
`Source language: ${wn(t)} (${t})`,
|
|
966
|
+
`Translate into: ${n.map((e) => `${e} = ${wn(e)}`).join(", ")}`,
|
|
964
967
|
e.context ? `Context (do not translate): ${e.context}` : "",
|
|
965
968
|
"Text (JSON):",
|
|
966
969
|
JSON.stringify(e.fields)
|
|
967
|
-
].filter(Boolean).join("\n"), s = await
|
|
970
|
+
].filter(Boolean).join("\n"), s = await Hn(r(n, a).generateContent(o), In), c = JSON.parse(s.response.text()), l = {};
|
|
968
971
|
for (let e of n) {
|
|
969
972
|
let t = c?.[e];
|
|
970
973
|
if (!t) continue;
|
|
@@ -1010,14 +1013,14 @@ function Hn() {
|
|
|
1010
1013
|
D();
|
|
1011
1014
|
let n = t.source ?? "ko", r = (t.targets ?? T.map((e) => e.code)).filter((e) => e !== n), i = e.trim();
|
|
1012
1015
|
if (!i || !r.length) return {};
|
|
1013
|
-
if (i.length > 12e3) throw Error(`translation is limited to ${
|
|
1014
|
-
let a = await
|
|
1016
|
+
if (i.length > 12e3) throw Error(`translation is limited to ${Rn} characters`);
|
|
1017
|
+
let a = await Vn(r, zn, async (e) => {
|
|
1015
1018
|
let t = [
|
|
1016
|
-
`Source language: ${
|
|
1017
|
-
`Translate into: ${e} = ${
|
|
1019
|
+
`Source language: ${wn(n)} (${n})`,
|
|
1020
|
+
`Translate into: ${e} = ${wn(e)}`,
|
|
1018
1021
|
"HTML:",
|
|
1019
1022
|
i
|
|
1020
|
-
].join("\n"), r =
|
|
1023
|
+
].join("\n"), r = Bn((await Hn(o().generateContent(t), Ln)).response.text());
|
|
1021
1024
|
if (!r) throw Error(`empty translation for ${e}`);
|
|
1022
1025
|
return [e, r];
|
|
1023
1026
|
});
|
|
@@ -1031,7 +1034,7 @@ function Hn() {
|
|
|
1031
1034
|
}
|
|
1032
1035
|
//#endregion
|
|
1033
1036
|
//#region src/composables/useMemiBoardSettings.ts
|
|
1034
|
-
var
|
|
1037
|
+
var Wn = [
|
|
1035
1038
|
{
|
|
1036
1039
|
id: "free",
|
|
1037
1040
|
label: "자유",
|
|
@@ -1059,17 +1062,17 @@ var Un = [
|
|
|
1059
1062
|
visibility: "public",
|
|
1060
1063
|
order: 2
|
|
1061
1064
|
}
|
|
1062
|
-
],
|
|
1063
|
-
function
|
|
1065
|
+
], Gn = Wn;
|
|
1066
|
+
function Kn(e) {
|
|
1064
1067
|
return e === "hidden" ? "hidden" : "public";
|
|
1065
1068
|
}
|
|
1066
|
-
function
|
|
1069
|
+
function qn(e, t, n) {
|
|
1067
1070
|
return {
|
|
1068
1071
|
id: e,
|
|
1069
1072
|
label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
|
|
1070
1073
|
order: typeof t.order == "number" ? t.order : n,
|
|
1071
1074
|
description: (typeof t.description == "string" ? t.description : "") || "",
|
|
1072
|
-
visibility:
|
|
1075
|
+
visibility: Kn(t.visibility),
|
|
1073
1076
|
visibilityTransition: t.visibilityTransition === "hidden" || t.visibilityTransition === "public" ? t.visibilityTransition : void 0,
|
|
1074
1077
|
listView: t.listView ?? "default",
|
|
1075
1078
|
editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
|
|
@@ -1077,7 +1080,7 @@ function Kn(e, t, n) {
|
|
|
1077
1080
|
commentWriteRole: t.commentWriteRole ?? "user",
|
|
1078
1081
|
allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : [],
|
|
1079
1082
|
allowedManagerUids: Array.isArray(t.allowedManagerUids) ? t.allowedManagerUids : [],
|
|
1080
|
-
locale:
|
|
1083
|
+
locale: P(t.locale) ?? "",
|
|
1081
1084
|
autoTranslate: t.autoTranslate === !0,
|
|
1082
1085
|
autoTranslatePosts: t.autoTranslatePosts === !0,
|
|
1083
1086
|
translationLocales: mt(t.translationLocales),
|
|
@@ -1085,8 +1088,8 @@ function Kn(e, t, n) {
|
|
|
1085
1088
|
i18nSource: ut(t.i18nSource)
|
|
1086
1089
|
};
|
|
1087
1090
|
}
|
|
1088
|
-
function
|
|
1089
|
-
let e = () =>
|
|
1091
|
+
function Jn() {
|
|
1092
|
+
let e = () => N(), t = Z(), r = Me(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = Wt(), { t: l, locale: u } = M(), { translateEntries: d } = Un(), f = F(() => G(S(t, e()), W("order", "asc"))), { data: m, pending: h } = ke(f, { ssrKey: p(e(), "boards") }), g = F(() => m.value.map((e, t) => qn(e.id, e, t))), _ = g, v = F(() => g.value.filter((e) => e.visibility !== "hidden")), y = v;
|
|
1090
1093
|
function b(e, t) {
|
|
1091
1094
|
if (!e) return;
|
|
1092
1095
|
let n = g.value.find((t) => t.id === e);
|
|
@@ -1102,41 +1105,41 @@ function qn() {
|
|
|
1102
1105
|
function D(e) {
|
|
1103
1106
|
return e ? g.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
|
|
1104
1107
|
}
|
|
1105
|
-
let
|
|
1106
|
-
function
|
|
1108
|
+
let O = D;
|
|
1109
|
+
function k(e) {
|
|
1107
1110
|
return D(e) === "hidden";
|
|
1108
1111
|
}
|
|
1109
|
-
let
|
|
1110
|
-
function
|
|
1112
|
+
let ee = k;
|
|
1113
|
+
function A(e) {
|
|
1111
1114
|
if (e) return g.value.find((t) => t.id === e);
|
|
1112
1115
|
}
|
|
1113
|
-
|
|
1114
|
-
function
|
|
1115
|
-
return
|
|
1116
|
+
Nt((e) => A(e));
|
|
1117
|
+
function te(e) {
|
|
1118
|
+
return At(c.value?.uid, a.value, s.value, e ? A(e) : void 0);
|
|
1116
1119
|
}
|
|
1117
|
-
let
|
|
1118
|
-
function
|
|
1120
|
+
let ne = F(() => g.value.filter((e) => te(e.id)));
|
|
1121
|
+
function re(e, t) {
|
|
1119
1122
|
return {
|
|
1120
1123
|
label: e.label.trim(),
|
|
1121
1124
|
description: (e.description ?? "").trim(),
|
|
1122
|
-
visibility:
|
|
1125
|
+
visibility: Kn(e.visibility),
|
|
1123
1126
|
listView: e.listView ?? "default",
|
|
1124
1127
|
editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
|
|
1125
1128
|
writeRole: e.writeRole ?? "user",
|
|
1126
1129
|
commentWriteRole: e.commentWriteRole ?? "user",
|
|
1127
1130
|
allowedStaffUids: e.allowedStaffUids ?? [],
|
|
1128
1131
|
allowedManagerUids: e.allowedManagerUids ?? [],
|
|
1129
|
-
locale:
|
|
1132
|
+
locale: P(e.locale) ?? "",
|
|
1130
1133
|
autoTranslate: e.autoTranslate === !0,
|
|
1131
1134
|
autoTranslatePosts: e.autoTranslatePosts === !0,
|
|
1132
1135
|
translationLocales: mt(e.translationLocales),
|
|
1133
1136
|
...e.i18n ? { i18n: e.i18n } : {},
|
|
1134
1137
|
...e.i18nSource ? { i18nSource: e.i18nSource } : {},
|
|
1135
1138
|
order: t,
|
|
1136
|
-
updatedAt:
|
|
1139
|
+
updatedAt: K()
|
|
1137
1140
|
};
|
|
1138
1141
|
}
|
|
1139
|
-
async function
|
|
1142
|
+
async function ie(e) {
|
|
1140
1143
|
if (!n()) return e;
|
|
1141
1144
|
let t = e.label.trim(), r = (e.description ?? "").trim();
|
|
1142
1145
|
if (!t) return e;
|
|
@@ -1173,40 +1176,40 @@ function qn() {
|
|
|
1173
1176
|
}
|
|
1174
1177
|
};
|
|
1175
1178
|
}
|
|
1176
|
-
async function
|
|
1179
|
+
async function j(n, r = n.order ?? 0) {
|
|
1177
1180
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
1178
1181
|
let a = n.id.trim(), o = n.label.trim();
|
|
1179
1182
|
if (!a || !o) throw Error(l("boardSettings.idAndNameRequired"));
|
|
1180
|
-
let s =
|
|
1183
|
+
let s = Kn(n.visibility), c = re({
|
|
1181
1184
|
...n,
|
|
1182
1185
|
label: o,
|
|
1183
1186
|
visibility: s
|
|
1184
1187
|
}, r);
|
|
1185
|
-
await
|
|
1188
|
+
await xn(t, e(), a, c);
|
|
1186
1189
|
}
|
|
1187
|
-
let
|
|
1188
|
-
async function
|
|
1190
|
+
let ae = j;
|
|
1191
|
+
async function oe(e) {
|
|
1189
1192
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
1190
1193
|
for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(l("boardSettings.idAndNameRequired"));
|
|
1191
|
-
for (let [t, n] of e.entries()) await
|
|
1194
|
+
for (let [t, n] of e.entries()) await j(n, t);
|
|
1192
1195
|
}
|
|
1193
|
-
let
|
|
1194
|
-
async function
|
|
1196
|
+
let se = oe;
|
|
1197
|
+
async function ce(n) {
|
|
1195
1198
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
1196
1199
|
let a = n.trim();
|
|
1197
1200
|
if (!a) throw Error(l("boardSettings.deleteIdRequired"));
|
|
1198
1201
|
for (;;) {
|
|
1199
|
-
let n = await
|
|
1202
|
+
let n = await V(G(o(t, e()), X("boardId", "==", a), H(25)));
|
|
1200
1203
|
if (n.empty) break;
|
|
1201
|
-
for (let i of n.docs) await
|
|
1204
|
+
for (let i of n.docs) await cn(t, We(r), e(), i.id);
|
|
1202
1205
|
}
|
|
1203
|
-
await
|
|
1206
|
+
await _e(w(t, e(), n));
|
|
1204
1207
|
}
|
|
1205
|
-
let
|
|
1206
|
-
async function
|
|
1208
|
+
let le = ce;
|
|
1209
|
+
async function ue() {
|
|
1207
1210
|
return Promise.resolve();
|
|
1208
1211
|
}
|
|
1209
|
-
async function
|
|
1212
|
+
async function de(e) {
|
|
1210
1213
|
let t = e.trim();
|
|
1211
1214
|
if (!t) throw Error(l("boardSettings.nameRequired"));
|
|
1212
1215
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
@@ -1214,7 +1217,7 @@ function qn() {
|
|
|
1214
1217
|
if (n) return n.id;
|
|
1215
1218
|
let r = E(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(g.value.map((e) => e.id));
|
|
1216
1219
|
for (; s.has(a);) a = `${r}-${o++}`;
|
|
1217
|
-
return await
|
|
1220
|
+
return await j({
|
|
1218
1221
|
id: a,
|
|
1219
1222
|
label: t,
|
|
1220
1223
|
visibility: "public",
|
|
@@ -1231,46 +1234,46 @@ function qn() {
|
|
|
1231
1234
|
boardLabel: b,
|
|
1232
1235
|
boardDescription: C,
|
|
1233
1236
|
boardVisibility: D,
|
|
1234
|
-
isBoardHidden:
|
|
1235
|
-
getBoard:
|
|
1236
|
-
canManageBoard:
|
|
1237
|
-
managedBoards:
|
|
1237
|
+
isBoardHidden: k,
|
|
1238
|
+
getBoard: A,
|
|
1239
|
+
canManageBoard: te,
|
|
1240
|
+
managedBoards: ne,
|
|
1238
1241
|
categories: _,
|
|
1239
1242
|
publicCategories: y,
|
|
1240
1243
|
categoryLabel: x,
|
|
1241
1244
|
categoryDescription: T,
|
|
1242
|
-
categoryVisibility:
|
|
1243
|
-
isCategoryHidden:
|
|
1245
|
+
categoryVisibility: O,
|
|
1246
|
+
isCategoryHidden: ee,
|
|
1244
1247
|
settingsPending: h,
|
|
1245
|
-
ensureSettings:
|
|
1246
|
-
addBoard:
|
|
1247
|
-
addCategory:
|
|
1248
|
-
saveBoard:
|
|
1249
|
-
saveCategory:
|
|
1250
|
-
translateBoard:
|
|
1251
|
-
saveBoards:
|
|
1252
|
-
saveCategories:
|
|
1253
|
-
deleteBoard:
|
|
1254
|
-
deleteCategory:
|
|
1255
|
-
DEFAULT_BOARDS:
|
|
1256
|
-
DEFAULT_CATEGORIES:
|
|
1248
|
+
ensureSettings: ue,
|
|
1249
|
+
addBoard: de,
|
|
1250
|
+
addCategory: de,
|
|
1251
|
+
saveBoard: j,
|
|
1252
|
+
saveCategory: ae,
|
|
1253
|
+
translateBoard: ie,
|
|
1254
|
+
saveBoards: oe,
|
|
1255
|
+
saveCategories: se,
|
|
1256
|
+
deleteBoard: ce,
|
|
1257
|
+
deleteCategory: le,
|
|
1258
|
+
DEFAULT_BOARDS: Wn,
|
|
1259
|
+
DEFAULT_CATEGORIES: Gn
|
|
1257
1260
|
};
|
|
1258
1261
|
}
|
|
1259
1262
|
//#endregion
|
|
1260
1263
|
//#region src/composables/useMemiBoardPosts.ts
|
|
1261
|
-
var
|
|
1262
|
-
function
|
|
1264
|
+
var Yn = /* @__PURE__ */ new Map();
|
|
1265
|
+
function Xn(e) {
|
|
1263
1266
|
if (!e || typeof e != "object") return !1;
|
|
1264
1267
|
let t = "code" in e ? String(e.code) : "";
|
|
1265
1268
|
return t === "permission-denied" || t === "firestore/permission-denied";
|
|
1266
1269
|
}
|
|
1267
|
-
function
|
|
1268
|
-
let n =
|
|
1269
|
-
if (!n) throw Error(
|
|
1270
|
+
function Zn(e, t) {
|
|
1271
|
+
let n = R(e)?.trim();
|
|
1272
|
+
if (!n) throw Error(j(t, "posts.boardIdRequired"));
|
|
1270
1273
|
return n;
|
|
1271
1274
|
}
|
|
1272
|
-
function
|
|
1273
|
-
let t = Z(), n = Me(), { isBoardHidden: r, getBoard: i } =
|
|
1275
|
+
function Qn(e) {
|
|
1276
|
+
let t = Z(), n = Me(), { isBoardHidden: r, getBoard: i } = Jn(), { user: a, canManageBoard: c } = Wt(), { t: l, locale: u } = M(), d = () => N(), f = () => Zn(e, u.value), p = () => o(t, d()), m = (e) => y(t, d(), e), h = (e) => s(t, d(), e);
|
|
1274
1277
|
function g(e, t, n) {
|
|
1275
1278
|
return {
|
|
1276
1279
|
id: e,
|
|
@@ -1289,7 +1292,7 @@ function Zn(e) {
|
|
|
1289
1292
|
return i(f())?.editorType === "image";
|
|
1290
1293
|
}
|
|
1291
1294
|
function b(e) {
|
|
1292
|
-
let t = v(), n =
|
|
1295
|
+
let t = v(), n = dn(e.content), r = fn(e.content, e.attachments);
|
|
1293
1296
|
if (t) {
|
|
1294
1297
|
if (!r) throw Error(l("posts.photoRequired"));
|
|
1295
1298
|
return;
|
|
@@ -1298,15 +1301,15 @@ function Zn(e) {
|
|
|
1298
1301
|
if (!e.title?.trim()) throw Error(l("posts.titleRequired"));
|
|
1299
1302
|
}
|
|
1300
1303
|
function x() {
|
|
1301
|
-
return
|
|
1304
|
+
return ye(p()).id;
|
|
1302
1305
|
}
|
|
1303
1306
|
function S(e) {
|
|
1304
|
-
return
|
|
1307
|
+
return Yt(t, d(), f(), e, a.value?.uid, c(f()));
|
|
1305
1308
|
}
|
|
1306
1309
|
async function C(e = {}) {
|
|
1307
1310
|
let t = e.pageSize ?? 20, n = [X("boardId", "==", f()), X("isPublished", "==", !0)];
|
|
1308
|
-
e.publicOnly !== !1 && n.push(X("listed", "==", !0)), n.push(
|
|
1309
|
-
let r = await
|
|
1311
|
+
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));
|
|
1312
|
+
let r = await V(G(p(), ...n)), i = r.docs.slice(0, t);
|
|
1310
1313
|
return {
|
|
1311
1314
|
posts: i.map((e) => ({
|
|
1312
1315
|
id: e.id,
|
|
@@ -1317,7 +1320,7 @@ function Zn(e) {
|
|
|
1317
1320
|
};
|
|
1318
1321
|
}
|
|
1319
1322
|
async function w(e) {
|
|
1320
|
-
let [t, n] = await Promise.all([
|
|
1323
|
+
let [t, n] = await Promise.all([Se(m(e)), Se(h(e))]);
|
|
1321
1324
|
return t.exists() ? g(t.id, t.data(), n.exists() ? n.data() : void 0) : null;
|
|
1322
1325
|
}
|
|
1323
1326
|
async function T(e) {
|
|
@@ -1331,20 +1334,20 @@ function Zn(e) {
|
|
|
1331
1334
|
post: e
|
|
1332
1335
|
} : { status: "not-found" };
|
|
1333
1336
|
} catch (e) {
|
|
1334
|
-
return
|
|
1337
|
+
return Xn(e) ? { status: "permission-denied" } : {
|
|
1335
1338
|
status: "error",
|
|
1336
1339
|
message: e instanceof Error ? e.message : String(e)
|
|
1337
1340
|
};
|
|
1338
1341
|
}
|
|
1339
1342
|
} catch (e) {
|
|
1340
|
-
return
|
|
1343
|
+
return Xn(e) ? { status: "permission-denied" } : {
|
|
1341
1344
|
status: "error",
|
|
1342
1345
|
message: e instanceof Error ? e.message : String(e)
|
|
1343
1346
|
};
|
|
1344
1347
|
}
|
|
1345
1348
|
}
|
|
1346
|
-
async function
|
|
1347
|
-
let t = e.trim(), n =
|
|
1349
|
+
async function O(e) {
|
|
1350
|
+
let t = e.trim(), n = Yn.get(`${f()}/${t}`);
|
|
1348
1351
|
if (n) return {
|
|
1349
1352
|
status: "ok",
|
|
1350
1353
|
id: n
|
|
@@ -1356,16 +1359,16 @@ function Zn(e) {
|
|
|
1356
1359
|
id: e.id
|
|
1357
1360
|
} : { status: r(f()) ? "permission-denied" : "not-found" };
|
|
1358
1361
|
} catch (e) {
|
|
1359
|
-
return
|
|
1362
|
+
return Xn(e) ? { status: "permission-denied" } : {
|
|
1360
1363
|
status: "error",
|
|
1361
1364
|
message: e instanceof Error ? e.message : String(e)
|
|
1362
1365
|
};
|
|
1363
1366
|
}
|
|
1364
1367
|
}
|
|
1365
|
-
async function
|
|
1368
|
+
async function k(e) {
|
|
1366
1369
|
return `${E(e.trim()) || "post"}-${x()}`;
|
|
1367
1370
|
}
|
|
1368
|
-
async function
|
|
1371
|
+
async function ee(e) {
|
|
1369
1372
|
if (!e.createdAt) return {
|
|
1370
1373
|
previous: null,
|
|
1371
1374
|
next: null
|
|
@@ -1375,8 +1378,8 @@ function Zn(e) {
|
|
|
1375
1378
|
X("boardId", "==", f()),
|
|
1376
1379
|
X("isPublished", "==", !0),
|
|
1377
1380
|
...e.listed === !1 ? [] : [X("listed", "==", !0)],
|
|
1378
|
-
|
|
1379
|
-
], [n, r] = await Promise.all([
|
|
1381
|
+
W("createdAt", "desc")
|
|
1382
|
+
], [n, r] = await Promise.all([V(G(p(), ...t, J(e.createdAt), H(1))), V(G(p(), ...t, xe(e.createdAt), Ee(1)))]), i = (e) => {
|
|
1380
1383
|
let t = e.docs[0];
|
|
1381
1384
|
return t ? {
|
|
1382
1385
|
id: t.id,
|
|
@@ -1394,11 +1397,11 @@ function Zn(e) {
|
|
|
1394
1397
|
};
|
|
1395
1398
|
}
|
|
1396
1399
|
}
|
|
1397
|
-
async function
|
|
1400
|
+
async function A(e) {
|
|
1398
1401
|
b(e);
|
|
1399
1402
|
let n = e.postId || x(), r = v(), i, a;
|
|
1400
|
-
r ? (i = n, a =
|
|
1401
|
-
let o =
|
|
1403
|
+
r ? (i = n, a = un(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await k(a));
|
|
1404
|
+
let o = _n(e.content, e.attachments), s = _(), c = Oe(t);
|
|
1402
1405
|
return c.set(m(n), {
|
|
1403
1406
|
boardId: f(),
|
|
1404
1407
|
slug: i,
|
|
@@ -1416,8 +1419,8 @@ function Zn(e) {
|
|
|
1416
1419
|
authorPhoto: e.authorPhoto,
|
|
1417
1420
|
moderationStatus: "approved",
|
|
1418
1421
|
moderationModel: e.moderationModel ?? null,
|
|
1419
|
-
createdAt:
|
|
1420
|
-
updatedAt:
|
|
1422
|
+
createdAt: K(),
|
|
1423
|
+
updatedAt: K(),
|
|
1421
1424
|
...e.translations ? {
|
|
1422
1425
|
i18n: e.translations.i18n,
|
|
1423
1426
|
i18nSource: e.translations.i18nSource
|
|
@@ -1428,91 +1431,91 @@ function Zn(e) {
|
|
|
1428
1431
|
i18n: e.translations.contentI18n,
|
|
1429
1432
|
i18nSource: e.translations.contentI18nSource
|
|
1430
1433
|
} : {}
|
|
1431
|
-
}), await c.commit(),
|
|
1434
|
+
}), await c.commit(), Yn.set(`${f()}/${i}`, n), i;
|
|
1432
1435
|
}
|
|
1433
|
-
async function
|
|
1436
|
+
async function te(e, t) {
|
|
1434
1437
|
b(t);
|
|
1435
|
-
let n = v() ?
|
|
1438
|
+
let n = v() ? un(t.content) : t.title.trim(), r = _n(t.content, t.attachments), i = _();
|
|
1436
1439
|
await Promise.all([Y(m(e), {
|
|
1437
1440
|
title: n,
|
|
1438
1441
|
...r,
|
|
1439
|
-
previewImage: r.previewImage ? r.previewImage :
|
|
1440
|
-
videoUrl: r.videoUrl ? r.videoUrl :
|
|
1442
|
+
previewImage: r.previewImage ? r.previewImage : ve(),
|
|
1443
|
+
videoUrl: r.videoUrl ? r.videoUrl : ve(),
|
|
1441
1444
|
tags: t.tags ?? [],
|
|
1442
1445
|
listed: i,
|
|
1443
1446
|
attachments: t.attachments ?? [],
|
|
1444
|
-
updatedAt:
|
|
1447
|
+
updatedAt: K(),
|
|
1445
1448
|
...t.translations ? {
|
|
1446
1449
|
i18n: t.translations.i18n,
|
|
1447
1450
|
i18nSource: t.translations.i18nSource
|
|
1448
1451
|
} : {}
|
|
1449
|
-
}),
|
|
1452
|
+
}), q(h(e), {
|
|
1450
1453
|
content: t.content,
|
|
1451
1454
|
...t.translations ? t.translations.contentI18n ? {
|
|
1452
1455
|
i18n: t.translations.contentI18n,
|
|
1453
1456
|
i18nSource: t.translations.contentI18nSource
|
|
1454
1457
|
} : {
|
|
1455
|
-
i18n:
|
|
1456
|
-
i18nSource:
|
|
1458
|
+
i18n: ve(),
|
|
1459
|
+
i18nSource: ve()
|
|
1457
1460
|
} : {}
|
|
1458
1461
|
}, { merge: !0 })]);
|
|
1459
1462
|
}
|
|
1460
|
-
async function
|
|
1463
|
+
async function ne(e, t) {
|
|
1461
1464
|
D(), await Promise.all([Y(m(e), {
|
|
1462
1465
|
i18n: t.i18n,
|
|
1463
1466
|
i18nSource: t.i18nSource,
|
|
1464
|
-
updatedAt:
|
|
1465
|
-
}),
|
|
1467
|
+
updatedAt: K()
|
|
1468
|
+
}), q(h(e), t.contentI18n ? {
|
|
1466
1469
|
i18n: t.contentI18n,
|
|
1467
1470
|
i18nSource: t.contentI18nSource
|
|
1468
1471
|
} : {
|
|
1469
|
-
i18n:
|
|
1470
|
-
i18nSource:
|
|
1472
|
+
i18n: ve(),
|
|
1473
|
+
i18nSource: ve()
|
|
1471
1474
|
}, { merge: !0 })]);
|
|
1472
1475
|
}
|
|
1473
|
-
async function
|
|
1476
|
+
async function re(e) {
|
|
1474
1477
|
await Y(m(e), {
|
|
1475
1478
|
isPublished: !0,
|
|
1476
|
-
publishedAt:
|
|
1477
|
-
updatedAt:
|
|
1479
|
+
publishedAt: K(),
|
|
1480
|
+
updatedAt: K()
|
|
1478
1481
|
});
|
|
1479
1482
|
}
|
|
1480
|
-
async function
|
|
1483
|
+
async function ie(e, t) {
|
|
1481
1484
|
await Y(m(e), t ? {
|
|
1482
1485
|
pinned: !0,
|
|
1483
|
-
pinnedAt:
|
|
1486
|
+
pinnedAt: K()
|
|
1484
1487
|
} : {
|
|
1485
|
-
pinned:
|
|
1486
|
-
pinnedAt:
|
|
1488
|
+
pinned: ve(),
|
|
1489
|
+
pinnedAt: ve()
|
|
1487
1490
|
});
|
|
1488
1491
|
}
|
|
1489
|
-
async function
|
|
1490
|
-
await
|
|
1491
|
-
for (let [t, n] of
|
|
1492
|
+
async function j(e) {
|
|
1493
|
+
await cn(t, We(n), d(), e);
|
|
1494
|
+
for (let [t, n] of Yn) n === e && Yn.delete(t);
|
|
1492
1495
|
}
|
|
1493
1496
|
return {
|
|
1494
1497
|
createPostId: x,
|
|
1495
1498
|
getPosts: C,
|
|
1496
1499
|
getPost: w,
|
|
1497
1500
|
getPostBySlug: T,
|
|
1498
|
-
resolvePostIdBySlug:
|
|
1499
|
-
resolveUniqueSlug:
|
|
1500
|
-
getAdjacentPosts:
|
|
1501
|
-
createPost:
|
|
1502
|
-
updatePost:
|
|
1503
|
-
savePostTranslations:
|
|
1504
|
-
publishPost:
|
|
1505
|
-
setPostPinned:
|
|
1506
|
-
deletePost:
|
|
1501
|
+
resolvePostIdBySlug: O,
|
|
1502
|
+
resolveUniqueSlug: k,
|
|
1503
|
+
getAdjacentPosts: ee,
|
|
1504
|
+
createPost: A,
|
|
1505
|
+
updatePost: te,
|
|
1506
|
+
savePostTranslations: ne,
|
|
1507
|
+
publishPost: re,
|
|
1508
|
+
setPostPinned: ie,
|
|
1509
|
+
deletePost: j
|
|
1507
1510
|
};
|
|
1508
1511
|
}
|
|
1509
|
-
var
|
|
1510
|
-
function
|
|
1511
|
-
let n = Z(), { isAdmin: r, user: i, canManageBoard: a } =
|
|
1512
|
+
var $n = 10, er = 10;
|
|
1513
|
+
function tr(e, t = {}) {
|
|
1514
|
+
let n = Z(), { isAdmin: r, user: i, canManageBoard: a } = Wt(), s = () => N(), c = t.pageSize ?? $n, l = F(() => i.value?.uid ?? ""), u = F(() => Zn(e)), d = () => o(n, s()), f = F(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = L([]), m = L([]), h = L([]), g = L([]), _ = L(!0), v = L(!0), y = L(!0), b = L(!1), x = L(""), S = null, C = null, w, T, E;
|
|
1512
1515
|
function D(e) {
|
|
1513
1516
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1514
1517
|
}
|
|
1515
|
-
let
|
|
1518
|
+
let O = F(() => {
|
|
1516
1519
|
let e = new Set(g.value.map((e) => e.id)), t = /* @__PURE__ */ new Map();
|
|
1517
1520
|
for (let n of [
|
|
1518
1521
|
...m.value,
|
|
@@ -1521,12 +1524,12 @@ function er(e, t = {}) {
|
|
|
1521
1524
|
]) n.id && !e.has(n.id) && t.set(n.id, n);
|
|
1522
1525
|
return [...t.values()].sort((e, t) => D(t) - D(e) || String(t.id).localeCompare(String(e.id)));
|
|
1523
1526
|
});
|
|
1524
|
-
function
|
|
1527
|
+
function k() {
|
|
1525
1528
|
let e = [X("boardId", "==", u.value), X("isPublished", "==", !0)];
|
|
1526
1529
|
return f.value && e.push(X("listed", "==", !0)), e;
|
|
1527
1530
|
}
|
|
1528
|
-
function
|
|
1529
|
-
w?.(), w =
|
|
1531
|
+
function ee() {
|
|
1532
|
+
w?.(), w = U(G(d(), ...k(), W("createdAt", "desc"), W(B(), "desc"), H(c)), (e) => {
|
|
1530
1533
|
p.value = e.docs.map((e) => ({
|
|
1531
1534
|
id: e.id,
|
|
1532
1535
|
...e.data()
|
|
@@ -1535,8 +1538,8 @@ function er(e, t = {}) {
|
|
|
1535
1538
|
console.error("[memi-board:postList] onSnapshot failed", e), x.value = e.message || String(e), v.value = !1;
|
|
1536
1539
|
});
|
|
1537
1540
|
}
|
|
1538
|
-
function
|
|
1539
|
-
E?.(), E =
|
|
1541
|
+
function A() {
|
|
1542
|
+
E?.(), E = U(G(d(), ...k(), X("pinned", "==", !0), W("pinnedAt", "desc"), H(er)), (e) => {
|
|
1540
1543
|
g.value = e.docs.map((e) => ({
|
|
1541
1544
|
id: e.id,
|
|
1542
1545
|
...e.data()
|
|
@@ -1545,14 +1548,14 @@ function er(e, t = {}) {
|
|
|
1545
1548
|
console.error("[memi-board:postList] notice onSnapshot failed", e), g.value = [], _.value = !1;
|
|
1546
1549
|
});
|
|
1547
1550
|
}
|
|
1548
|
-
function
|
|
1551
|
+
function te() {
|
|
1549
1552
|
T?.();
|
|
1550
1553
|
let e = l.value;
|
|
1551
1554
|
if (!e) {
|
|
1552
1555
|
h.value = [];
|
|
1553
1556
|
return;
|
|
1554
1557
|
}
|
|
1555
|
-
T =
|
|
1558
|
+
T = U(G(d(), X("boardId", "==", u.value), X("authorUid", "==", e), X("isPublished", "==", !1), W("createdAt", "desc"), H(20)), (e) => {
|
|
1556
1559
|
h.value = e.docs.map((e) => ({
|
|
1557
1560
|
id: e.id,
|
|
1558
1561
|
...e.data()
|
|
@@ -1561,17 +1564,17 @@ function er(e, t = {}) {
|
|
|
1561
1564
|
console.error("[memi-board:postList] own draft onSnapshot failed", e);
|
|
1562
1565
|
});
|
|
1563
1566
|
}
|
|
1564
|
-
async function
|
|
1567
|
+
async function ne() {
|
|
1565
1568
|
if (!(b.value || !y.value || v.value)) {
|
|
1566
1569
|
b.value = !0, x.value = "";
|
|
1567
1570
|
try {
|
|
1568
1571
|
let e = C ?? S, t = [
|
|
1569
|
-
...
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
+
...k(),
|
|
1573
|
+
W("createdAt", "desc"),
|
|
1574
|
+
W(B(), "desc"),
|
|
1572
1575
|
...e ? [J(e)] : [],
|
|
1573
|
-
|
|
1574
|
-
], n = await
|
|
1576
|
+
H(c + 1)
|
|
1577
|
+
], n = await V(G(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
|
|
1575
1578
|
id: e.id,
|
|
1576
1579
|
...e.data()
|
|
1577
1580
|
})), a = new Set([...m.value, ...p.value].map((e) => e.id));
|
|
@@ -1583,29 +1586,29 @@ function er(e, t = {}) {
|
|
|
1583
1586
|
}
|
|
1584
1587
|
}
|
|
1585
1588
|
}
|
|
1586
|
-
function
|
|
1587
|
-
w?.(), p.value = [], m.value = [], S = null, C = null, y.value = !0, x.value = "", v.value = !0, g.value = [], _.value = !0,
|
|
1589
|
+
function re() {
|
|
1590
|
+
w?.(), p.value = [], m.value = [], S = null, C = null, y.value = !0, x.value = "", v.value = !0, g.value = [], _.value = !0, ee(), A(), te();
|
|
1588
1591
|
}
|
|
1589
|
-
return
|
|
1592
|
+
return z([
|
|
1590
1593
|
u,
|
|
1591
1594
|
f,
|
|
1592
1595
|
l
|
|
1593
|
-
],
|
|
1596
|
+
], re, { immediate: !0 }), I(() => {
|
|
1594
1597
|
w?.(), E?.(), T?.();
|
|
1595
1598
|
}), {
|
|
1596
|
-
posts:
|
|
1599
|
+
posts: O,
|
|
1597
1600
|
notices: g,
|
|
1598
|
-
postsPending:
|
|
1601
|
+
postsPending: F(() => v.value || _.value),
|
|
1599
1602
|
hasMore: y,
|
|
1600
1603
|
loadingMore: b,
|
|
1601
1604
|
loadError: x,
|
|
1602
|
-
loadMore:
|
|
1605
|
+
loadMore: ne
|
|
1603
1606
|
};
|
|
1604
1607
|
}
|
|
1605
|
-
function
|
|
1606
|
-
let n = Z(), r = () =>
|
|
1608
|
+
function nr(e, t) {
|
|
1609
|
+
let n = Z(), r = () => N(), i = F(() => Zn(e)), a = F(() => typeof t == "string" ? t : t.value), o = F(() => y(n, r(), a.value)), c = F(() => s(n, r(), a.value)), { data: l, pending: u } = je(o), { data: d, pending: f } = je(c);
|
|
1607
1610
|
return {
|
|
1608
|
-
post:
|
|
1611
|
+
post: F(() => {
|
|
1609
1612
|
if (!l.value || l.value.boardId !== i.value) return null;
|
|
1610
1613
|
let e = d.value;
|
|
1611
1614
|
return {
|
|
@@ -1618,14 +1621,14 @@ function tr(e, t) {
|
|
|
1618
1621
|
contentI18nSource: dt(e?.i18nSource)
|
|
1619
1622
|
};
|
|
1620
1623
|
}),
|
|
1621
|
-
pending:
|
|
1624
|
+
pending: F(() => u.value || f.value)
|
|
1622
1625
|
};
|
|
1623
1626
|
}
|
|
1624
1627
|
//#endregion
|
|
1625
1628
|
//#region src/composables/useMemiBoardUserPosts.ts
|
|
1626
|
-
var
|
|
1627
|
-
function
|
|
1628
|
-
let n = Z(), r = () =>
|
|
1629
|
+
var rr = 10;
|
|
1630
|
+
function ir(e, t = {}) {
|
|
1631
|
+
let n = Z(), r = () => N(), i = () => o(n, r()), a = t.pageSize ?? rr, s = F(() => R(e)?.trim() || ""), c = L([]), l = L([]), u = L(!0), d = L(!0), f = L(!1), p = L(""), m = null, h = null, g;
|
|
1629
1632
|
function _(e) {
|
|
1630
1633
|
return {
|
|
1631
1634
|
id: e.id,
|
|
@@ -1635,7 +1638,7 @@ function rr(e, t = {}) {
|
|
|
1635
1638
|
function v(e) {
|
|
1636
1639
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1637
1640
|
}
|
|
1638
|
-
let y =
|
|
1641
|
+
let y = F(() => {
|
|
1639
1642
|
let e = /* @__PURE__ */ new Map();
|
|
1640
1643
|
for (let t of [...l.value, ...c.value]) t.id && e.set(t.id, t);
|
|
1641
1644
|
return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
|
|
@@ -1652,7 +1655,7 @@ function rr(e, t = {}) {
|
|
|
1652
1655
|
u.value = !1;
|
|
1653
1656
|
return;
|
|
1654
1657
|
}
|
|
1655
|
-
g =
|
|
1658
|
+
g = U(G(i(), ...b(), W("createdAt", "desc"), W(B(), "desc"), H(a)), (e) => {
|
|
1656
1659
|
c.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a), u.value = !1;
|
|
1657
1660
|
}, (e) => {
|
|
1658
1661
|
console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
|
|
@@ -1664,11 +1667,11 @@ function rr(e, t = {}) {
|
|
|
1664
1667
|
try {
|
|
1665
1668
|
let e = h ?? m, t = [
|
|
1666
1669
|
...b(),
|
|
1667
|
-
|
|
1668
|
-
|
|
1670
|
+
W("createdAt", "desc"),
|
|
1671
|
+
W(B(), "desc"),
|
|
1669
1672
|
...e ? [J(e)] : [],
|
|
1670
|
-
|
|
1671
|
-
], n = await
|
|
1673
|
+
H(a + 1)
|
|
1674
|
+
], n = await V(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), s = new Set([...l.value, ...c.value].map((e) => e.id));
|
|
1672
1675
|
l.value.push(...o.filter((e) => !s.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > a;
|
|
1673
1676
|
} catch (e) {
|
|
1674
1677
|
p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
|
|
@@ -1680,7 +1683,7 @@ function rr(e, t = {}) {
|
|
|
1680
1683
|
function C() {
|
|
1681
1684
|
g?.(), c.value = [], l.value = [], m = null, h = null, d.value = !0, p.value = "", u.value = !0, x();
|
|
1682
1685
|
}
|
|
1683
|
-
return
|
|
1686
|
+
return z(s, C, { immediate: !0 }), I(() => g?.()), {
|
|
1684
1687
|
posts: y,
|
|
1685
1688
|
postsPending: u,
|
|
1686
1689
|
hasMore: d,
|
|
@@ -1691,9 +1694,9 @@ function rr(e, t = {}) {
|
|
|
1691
1694
|
}
|
|
1692
1695
|
//#endregion
|
|
1693
1696
|
//#region src/composables/useMemiBoardUserComments.ts
|
|
1694
|
-
var
|
|
1695
|
-
function
|
|
1696
|
-
let n = Z(), r = () =>
|
|
1697
|
+
var ar = 10;
|
|
1698
|
+
function or(e, t = {}) {
|
|
1699
|
+
let n = Z(), r = () => N(), i = () => g(n, r()), a = t.pageSize ?? ar, o = F(() => R(e)?.trim() || ""), s = L([]), c = L([]), l = L(!0), u = L(!0), d = L(!1), f = L(""), p = null, m = null, h;
|
|
1697
1700
|
function _(e) {
|
|
1698
1701
|
return {
|
|
1699
1702
|
id: e.id,
|
|
@@ -1703,7 +1706,7 @@ function ar(e, t = {}) {
|
|
|
1703
1706
|
function v(e) {
|
|
1704
1707
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1705
1708
|
}
|
|
1706
|
-
let y =
|
|
1709
|
+
let y = F(() => {
|
|
1707
1710
|
let e = /* @__PURE__ */ new Map();
|
|
1708
1711
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1709
1712
|
return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
|
|
@@ -1716,7 +1719,7 @@ function ar(e, t = {}) {
|
|
|
1716
1719
|
l.value = !1;
|
|
1717
1720
|
return;
|
|
1718
1721
|
}
|
|
1719
|
-
h =
|
|
1722
|
+
h = U(G(i(), ...b(), W("createdAt", "desc"), W(B(), "desc"), H(a)), (e) => {
|
|
1720
1723
|
s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
|
|
1721
1724
|
}, (e) => {
|
|
1722
1725
|
console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
@@ -1728,11 +1731,11 @@ function ar(e, t = {}) {
|
|
|
1728
1731
|
try {
|
|
1729
1732
|
let e = m ?? p, t = [
|
|
1730
1733
|
...b(),
|
|
1731
|
-
|
|
1732
|
-
|
|
1734
|
+
W("createdAt", "desc"),
|
|
1735
|
+
W(B(), "desc"),
|
|
1733
1736
|
...e ? [J(e)] : [],
|
|
1734
|
-
|
|
1735
|
-
], n = await
|
|
1737
|
+
H(a + 1)
|
|
1738
|
+
], n = await V(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1736
1739
|
c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
|
|
1737
1740
|
} catch (e) {
|
|
1738
1741
|
f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
|
|
@@ -1744,7 +1747,7 @@ function ar(e, t = {}) {
|
|
|
1744
1747
|
function C() {
|
|
1745
1748
|
h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
|
|
1746
1749
|
}
|
|
1747
|
-
return
|
|
1750
|
+
return z(o, C, { immediate: !0 }), I(() => h?.()), {
|
|
1748
1751
|
comments: y,
|
|
1749
1752
|
commentsPending: l,
|
|
1750
1753
|
hasMore: u,
|
|
@@ -1755,12 +1758,12 @@ function ar(e, t = {}) {
|
|
|
1755
1758
|
}
|
|
1756
1759
|
//#endregion
|
|
1757
1760
|
//#region src/composables/useMemiBoardCommentFeed.ts
|
|
1758
|
-
var
|
|
1759
|
-
function
|
|
1760
|
-
let n = Z(), r = () =>
|
|
1761
|
-
let e = Math.floor(Number(
|
|
1762
|
-
return Number.isFinite(e) && e > 0 ? e :
|
|
1763
|
-
}), o =
|
|
1761
|
+
var sr = 10;
|
|
1762
|
+
function cr(e = "latest", t = {}) {
|
|
1763
|
+
let n = Z(), r = () => N(), i = () => g(n, r()), a = F(() => {
|
|
1764
|
+
let e = Math.floor(Number(R(t.pageSize)));
|
|
1765
|
+
return Number.isFinite(e) && e > 0 ? e : sr;
|
|
1766
|
+
}), o = F(() => R(e) === "likes" ? "likes" : "latest"), s = L([]), c = L([]), l = L(!0), u = L(!0), d = L(!1), f = L(""), p = null, m = null, h;
|
|
1764
1767
|
function _(e) {
|
|
1765
1768
|
return {
|
|
1766
1769
|
id: e.id,
|
|
@@ -1777,7 +1780,7 @@ function sr(e = "latest", t = {}) {
|
|
|
1777
1780
|
}
|
|
1778
1781
|
return v(t) - v(e) || String(t.id).localeCompare(String(e.id));
|
|
1779
1782
|
}
|
|
1780
|
-
let b =
|
|
1783
|
+
let b = F(() => {
|
|
1781
1784
|
let e = /* @__PURE__ */ new Map();
|
|
1782
1785
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1783
1786
|
return [...e.values()].sort(y);
|
|
@@ -1785,17 +1788,17 @@ function sr(e = "latest", t = {}) {
|
|
|
1785
1788
|
function x() {
|
|
1786
1789
|
return o.value === "likes" ? [
|
|
1787
1790
|
X("listed", "==", !0),
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
+
W("likeCount", "desc"),
|
|
1792
|
+
W("createdAt", "desc"),
|
|
1793
|
+
W(B(), "desc")
|
|
1791
1794
|
] : [
|
|
1792
1795
|
X("listed", "==", !0),
|
|
1793
|
-
|
|
1794
|
-
|
|
1796
|
+
W("createdAt", "desc"),
|
|
1797
|
+
W(B(), "desc")
|
|
1795
1798
|
];
|
|
1796
1799
|
}
|
|
1797
1800
|
function S() {
|
|
1798
|
-
h?.(), h =
|
|
1801
|
+
h?.(), h = U(G(i(), ...x(), H(a.value)), (e) => {
|
|
1799
1802
|
s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
|
|
1800
1803
|
}, (e) => {
|
|
1801
1804
|
console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
@@ -1805,7 +1808,7 @@ function sr(e = "latest", t = {}) {
|
|
|
1805
1808
|
if (!(d.value || !u.value || l.value)) {
|
|
1806
1809
|
d.value = !0, f.value = "";
|
|
1807
1810
|
try {
|
|
1808
|
-
let e = m ?? p, t = await
|
|
1811
|
+
let e = m ?? p, t = await V(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));
|
|
1809
1812
|
c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
|
|
1810
1813
|
} catch (e) {
|
|
1811
1814
|
f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
|
|
@@ -1817,7 +1820,7 @@ function sr(e = "latest", t = {}) {
|
|
|
1817
1820
|
function w() {
|
|
1818
1821
|
h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, S();
|
|
1819
1822
|
}
|
|
1820
|
-
return
|
|
1823
|
+
return z([o, a], w, { immediate: !0 }), I(() => h?.()), {
|
|
1821
1824
|
comments: b,
|
|
1822
1825
|
commentsPending: l,
|
|
1823
1826
|
hasMore: u,
|
|
@@ -1829,35 +1832,35 @@ function sr(e = "latest", t = {}) {
|
|
|
1829
1832
|
}
|
|
1830
1833
|
//#endregion
|
|
1831
1834
|
//#region src/composables/useMemiBoardAuthorMemo.ts
|
|
1832
|
-
var
|
|
1835
|
+
var lr = 100, ur = /* @__PURE__ */ new Map();
|
|
1833
1836
|
function $(e) {
|
|
1834
|
-
let t =
|
|
1835
|
-
return t || (t =
|
|
1837
|
+
let t = ur.get(e);
|
|
1838
|
+
return t || (t = me({
|
|
1836
1839
|
text: "",
|
|
1837
1840
|
sentiment: null,
|
|
1838
1841
|
loaded: !1,
|
|
1839
1842
|
pending: !1,
|
|
1840
1843
|
saving: !1,
|
|
1841
1844
|
error: ""
|
|
1842
|
-
}),
|
|
1845
|
+
}), ur.set(e, t)), t;
|
|
1843
1846
|
}
|
|
1844
|
-
function
|
|
1845
|
-
let t = Z(), n = () =>
|
|
1847
|
+
function dr(e) {
|
|
1848
|
+
let t = Z(), n = () => N(), { user: r } = Wt(), { t: i, formatNumber: a } = M(), o = F(() => R(e)), s = F(() => `${r.value?.uid ?? ""}:${o.value}`), c = F(() => {
|
|
1846
1849
|
let e = r.value?.uid, i = o.value;
|
|
1847
1850
|
return !e || !i ? null : f(t, n(), e, i);
|
|
1848
|
-
}), l =
|
|
1851
|
+
}), l = F({
|
|
1849
1852
|
get: () => $(s.value).text,
|
|
1850
1853
|
set: (e) => {
|
|
1851
1854
|
$(s.value).text = e;
|
|
1852
1855
|
}
|
|
1853
|
-
}), u =
|
|
1856
|
+
}), u = F(() => $(s.value).sentiment), d = F(() => $(s.value).loaded), p = F(() => $(s.value).pending), m = F(() => $(s.value).saving), h = F(() => $(s.value).error);
|
|
1854
1857
|
async function g() {
|
|
1855
1858
|
let e = c.value;
|
|
1856
1859
|
if (!e) return;
|
|
1857
1860
|
let t = $(s.value);
|
|
1858
1861
|
t.pending = !0, t.error = "";
|
|
1859
1862
|
try {
|
|
1860
|
-
let n = (await
|
|
1863
|
+
let n = (await Se(e)).data();
|
|
1861
1864
|
t.text = n ? n.text ?? "" : "", t.sentiment = n ? n.sentiment ?? null : null, t.loaded = !0;
|
|
1862
1865
|
} catch (e) {
|
|
1863
1866
|
t.error = e.message || String(e), console.error("[memi-board:authorMemo] load failed", e);
|
|
@@ -1873,10 +1876,10 @@ function ur(e) {
|
|
|
1873
1876
|
let o = $(s.value);
|
|
1874
1877
|
o.saving = !0, o.error = "";
|
|
1875
1878
|
try {
|
|
1876
|
-
await
|
|
1879
|
+
await q(n, {
|
|
1877
1880
|
text: r,
|
|
1878
1881
|
sentiment: t,
|
|
1879
|
-
updatedAt:
|
|
1882
|
+
updatedAt: K()
|
|
1880
1883
|
}), o.text = r, o.sentiment = t, o.loaded = !0;
|
|
1881
1884
|
} catch (e) {
|
|
1882
1885
|
throw o.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
|
|
@@ -1890,7 +1893,7 @@ function ur(e) {
|
|
|
1890
1893
|
let t = $(s.value);
|
|
1891
1894
|
t.saving = !0, t.error = "";
|
|
1892
1895
|
try {
|
|
1893
|
-
await
|
|
1896
|
+
await _e(e), t.text = "", t.sentiment = null, t.loaded = !0;
|
|
1894
1897
|
} catch (e) {
|
|
1895
1898
|
throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
|
|
1896
1899
|
} finally {
|
|
@@ -1910,200 +1913,431 @@ function ur(e) {
|
|
|
1910
1913
|
};
|
|
1911
1914
|
}
|
|
1912
1915
|
//#endregion
|
|
1916
|
+
//#region src/composables/useMemiBoardWritingAssistant.ts
|
|
1917
|
+
var fr = 10, pr = 864e5, mr = 200, hr = {
|
|
1918
|
+
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
1919
|
+
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
1920
|
+
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
1921
|
+
summarize: "핵심 정보는 보존하면서 원문의 약 절반 길이로 간결하게 줄여라.",
|
|
1922
|
+
"translate-en": "자연스러운 영어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
1923
|
+
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
1924
|
+
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
1925
|
+
};
|
|
1926
|
+
function gr(e) {
|
|
1927
|
+
return {
|
|
1928
|
+
proofread: "Fix only spelling, spacing, and grammar errors. Do not change the meaning or tone.",
|
|
1929
|
+
polish: "Refine the text into more natural, readable sentences while keeping the meaning and the author's tone.",
|
|
1930
|
+
continue: "Continue writing one or two paragraphs that match the preceding context and tone, without exaggeration.",
|
|
1931
|
+
summarize: "Shorten the text concisely to about half of its original length while preserving the key information.",
|
|
1932
|
+
"translate-en": "Translate into natural English. Keep proper nouns and technical terms accurate.",
|
|
1933
|
+
"translate-ko": "Translate into natural Korean. Keep proper nouns and technical terms accurate.",
|
|
1934
|
+
title: `Create one concise title in ${e} that represents the body. Output only the title, without quotes or explanation.`
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
function _r(e, t, n) {
|
|
1938
|
+
let r = t === "ko", i = wn(t);
|
|
1939
|
+
if (e.action !== "custom") {
|
|
1940
|
+
if (r) return hr[e.action];
|
|
1941
|
+
let t = gr(i)[e.action];
|
|
1942
|
+
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}.`;
|
|
1943
|
+
}
|
|
1944
|
+
let a = e.customInstruction?.trim().slice(0, mr);
|
|
1945
|
+
if (!a) throw Error(n("writingAssistant.customRequired"));
|
|
1946
|
+
return r ? `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${a}` : `Rewrite the text applying the following style instruction while keeping the meaning: ${a}`;
|
|
1947
|
+
}
|
|
1948
|
+
function vr(e) {
|
|
1949
|
+
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
1950
|
+
}
|
|
1951
|
+
function yr(e) {
|
|
1952
|
+
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
1953
|
+
}
|
|
1954
|
+
function br(e = {}) {
|
|
1955
|
+
let t = M(), n = F(() => P(R(e.locale)) ?? t.locale.value), r = (e, t) => j(n.value, e, t), i = Me(), a = Z(), o = Ae(), s = v(), { translateEntries: c, translateHtml: l, detectSourceLocale: u } = Un();
|
|
1956
|
+
function d(e, t) {
|
|
1957
|
+
let n = yr(e.aiWritingWindowAt), r = n != null && t - n < pr, i = Math.max(0, Math.floor(Number(e.aiWritingCount) || 0)), a = Math.max(0, Math.floor(Number(e.aiWritingPending) || 0));
|
|
1958
|
+
return {
|
|
1959
|
+
active: r,
|
|
1960
|
+
windowAt: n,
|
|
1961
|
+
count: r ? i : 0,
|
|
1962
|
+
pending: r ? a : 0
|
|
1963
|
+
};
|
|
1964
|
+
}
|
|
1965
|
+
function f(e, t) {
|
|
1966
|
+
let n = e + pr, i = Math.max(1, Math.ceil((n - t) / 36e5));
|
|
1967
|
+
return Error(r("writingAssistant.dailyLimit", {
|
|
1968
|
+
limit: 10,
|
|
1969
|
+
hours: i
|
|
1970
|
+
}));
|
|
1971
|
+
}
|
|
1972
|
+
async function p(e) {
|
|
1973
|
+
let t = o.value?.uid;
|
|
1974
|
+
if (!t) throw Error(r("writingAssistant.loginRequired"));
|
|
1975
|
+
await De(a, async (n) => {
|
|
1976
|
+
let i = h(a, N(), t), o = await n.get(i);
|
|
1977
|
+
if (!o.exists()) throw Error(r("writingAssistant.userMissing"));
|
|
1978
|
+
let s = o.data(), c = e(d(s, Date.now()), s);
|
|
1979
|
+
c && n.update(i, {
|
|
1980
|
+
...c,
|
|
1981
|
+
updatedAt: K()
|
|
1982
|
+
});
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
async function m() {
|
|
1986
|
+
await p((e) => {
|
|
1987
|
+
if (e.active && e.windowAt != null && e.count + e.pending >= 10) throw f(e.windowAt, Date.now());
|
|
1988
|
+
return e.active ? { aiWritingPending: e.pending + 1 } : {
|
|
1989
|
+
aiWritingCount: 0,
|
|
1990
|
+
aiWritingPending: 1,
|
|
1991
|
+
aiWritingWindowAt: K()
|
|
1992
|
+
};
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
async function g() {
|
|
1996
|
+
await p((e) => !e.active || e.pending < 1 || e.count >= 10 ? null : {
|
|
1997
|
+
aiWritingCount: e.count + 1,
|
|
1998
|
+
aiWritingPending: e.pending - 1
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
async function _() {
|
|
2002
|
+
await p((e) => !e.active || e.pending < 1 ? null : { aiWritingPending: e.pending - 1 });
|
|
2003
|
+
}
|
|
2004
|
+
async function y(e) {
|
|
2005
|
+
await m();
|
|
2006
|
+
try {
|
|
2007
|
+
let t = await e();
|
|
2008
|
+
try {
|
|
2009
|
+
await g();
|
|
2010
|
+
} catch {}
|
|
2011
|
+
return t;
|
|
2012
|
+
} catch (e) {
|
|
2013
|
+
throw await _().catch(() => {}), e;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
async function b(e) {
|
|
2017
|
+
(e.action === "translate-en" || e.action === "translate-ko") && D();
|
|
2018
|
+
let t = n.value, a = t === "ko", o = _r(e, t, r);
|
|
2019
|
+
if (!e.content.trim()) throw Error(r("writingAssistant.contentRequired"));
|
|
2020
|
+
return y(async () => {
|
|
2021
|
+
let t = s.moderation ?? {}, n = Xe(i, {
|
|
2022
|
+
backend: new Je(),
|
|
2023
|
+
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
2024
|
+
}), c = Ze(n, {
|
|
2025
|
+
model: t.model ?? "gemini-3.5-flash-lite",
|
|
2026
|
+
systemInstruction: (a ? [
|
|
2027
|
+
"너는 게시판 글쓰기 편집 도우미다.",
|
|
2028
|
+
"사용자가 요청한 편집 결과만 출력하고 설명, 인사, 마크다운 코드 펜스를 붙이지 마라.",
|
|
2029
|
+
e.action === "title" || e.selection ? "출력은 일반 텍스트로 작성하라." : "입력의 HTML 구조와 링크, 이미지 태그를 보존하고 결과도 HTML 조각으로 출력하라."
|
|
2030
|
+
] : [
|
|
2031
|
+
"You are an editing assistant for writing message board posts.",
|
|
2032
|
+
"Output only the requested edit result. Do not add explanations, greetings, or markdown code fences.",
|
|
2033
|
+
e.action === "title" || e.selection ? "Write the output as plain text." : "Preserve the HTML structure, links, and image tags of the input, and output the result as an HTML fragment as well."
|
|
2034
|
+
]).join("\n"),
|
|
2035
|
+
generationConfig: {
|
|
2036
|
+
temperature: e.action === "continue" || e.action === "title" || e.action === "custom" ? .6 : .2,
|
|
2037
|
+
maxOutputTokens: 2048
|
|
2038
|
+
}
|
|
2039
|
+
}), l = e.content.trim(), u = (a ? [
|
|
2040
|
+
`작업: ${o}`,
|
|
2041
|
+
e.title ? `현재 제목: ${e.title}` : "",
|
|
2042
|
+
`본문:\n${l.slice(0, 12e3)}`
|
|
2043
|
+
] : [
|
|
2044
|
+
`Task: ${o}`,
|
|
2045
|
+
e.title ? `Current title: ${e.title}` : "",
|
|
2046
|
+
`Body:\n${l.slice(0, 12e3)}`
|
|
2047
|
+
]).filter(Boolean).join("\n\n"), d = vr((await c.generateContent(u)).response.text());
|
|
2048
|
+
if (!d) throw Error(r("writingAssistant.emptyResult"));
|
|
2049
|
+
return d;
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2052
|
+
async function x(e) {
|
|
2053
|
+
D();
|
|
2054
|
+
let t = e.targets?.length ? e.targets : pt(), n = e.title?.trim() ?? "", i = e.summary?.trim() ?? "", a = e.content ?? "", o = {};
|
|
2055
|
+
n && (o.title = n), i && (o.summary = i);
|
|
2056
|
+
let s = !!ln(a);
|
|
2057
|
+
if (!Object.keys(o).length && !s) throw Error(r("writingAssistant.translateEmpty"));
|
|
2058
|
+
if (s && a.length > 12e3) throw Error(r("writingAssistant.translateTooLong", {
|
|
2059
|
+
limit: Rn,
|
|
2060
|
+
count: t.length
|
|
2061
|
+
}));
|
|
2062
|
+
return y(async () => {
|
|
2063
|
+
let d = e.source ?? await u([
|
|
2064
|
+
ln(a),
|
|
2065
|
+
n,
|
|
2066
|
+
i
|
|
2067
|
+
].filter(Boolean).join("\n")), f = [...t, d], [p, m] = await Promise.all([Object.keys(o).length ? c([{
|
|
2068
|
+
id: "post",
|
|
2069
|
+
fields: o,
|
|
2070
|
+
context: "message board post title and short summary"
|
|
2071
|
+
}], {
|
|
2072
|
+
source: d,
|
|
2073
|
+
targets: t,
|
|
2074
|
+
purpose: "message board post title and short summary"
|
|
2075
|
+
}) : Promise.resolve({}), s ? l(a, {
|
|
2076
|
+
source: d,
|
|
2077
|
+
targets: t
|
|
2078
|
+
}) : Promise.resolve({})]), h = ft(d, o, p.post);
|
|
2079
|
+
if (Object.keys(o).length && !ht(h, Object.keys(o), f)) throw Error(r("writingAssistant.translateIncomplete"));
|
|
2080
|
+
let g = {
|
|
2081
|
+
i18n: h,
|
|
2082
|
+
i18nSource: {
|
|
2083
|
+
locale: d,
|
|
2084
|
+
title: n,
|
|
2085
|
+
summary: i
|
|
2086
|
+
}
|
|
2087
|
+
};
|
|
2088
|
+
if (s) {
|
|
2089
|
+
let e = {};
|
|
2090
|
+
for (let [t, n] of Object.entries(m)) {
|
|
2091
|
+
let r = P(t);
|
|
2092
|
+
r && typeof n == "string" && n.trim() && (e[r] = { content: n.trim() });
|
|
2093
|
+
}
|
|
2094
|
+
let t = ft(d, { content: a }, e);
|
|
2095
|
+
if (!ht(t, ["content"], f)) throw Error(r("writingAssistant.translateIncomplete"));
|
|
2096
|
+
g.contentI18n = t, g.contentI18nSource = {
|
|
2097
|
+
locale: d,
|
|
2098
|
+
hash: ct(a)
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
return g;
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2104
|
+
async function S(e) {
|
|
2105
|
+
D();
|
|
2106
|
+
let t = e.body.trim();
|
|
2107
|
+
if (!t) throw Error(r("writingAssistant.translateEmpty"));
|
|
2108
|
+
let n = e.targets?.length ? e.targets : pt();
|
|
2109
|
+
return y(async () => {
|
|
2110
|
+
let e = await u(t), i = await c([{
|
|
2111
|
+
id: "comment",
|
|
2112
|
+
fields: { body: t },
|
|
2113
|
+
context: "message board comment or reply, plain text"
|
|
2114
|
+
}], {
|
|
2115
|
+
source: e,
|
|
2116
|
+
targets: n,
|
|
2117
|
+
purpose: "message board comments and replies"
|
|
2118
|
+
}), a = ft(e, { body: t }, i.comment);
|
|
2119
|
+
if (!ht(a, ["body"], [...n, e])) throw Error(r("writingAssistant.translateIncomplete"));
|
|
2120
|
+
return {
|
|
2121
|
+
i18n: a,
|
|
2122
|
+
i18nSource: {
|
|
2123
|
+
locale: e,
|
|
2124
|
+
body: t
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
return {
|
|
2130
|
+
assist: b,
|
|
2131
|
+
translatePost: x,
|
|
2132
|
+
translateComment: S
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
//#endregion
|
|
1913
2136
|
//#region src/utils/subscribeCommentRange.ts
|
|
1914
|
-
function
|
|
1915
|
-
return
|
|
2137
|
+
function xr(e, t, n, r, i, a) {
|
|
2138
|
+
return U(G(g(e, t), X("postId", "==", n), ...r.rootId ? [X("rootId", "==", r.rootId), X("isReply", "==", !0)] : [X("parentId", "==", null)], W("createdAt", "asc"), W(B(), "asc"), ...r.hasMore && r.cursor ? [be(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
|
|
1916
2139
|
...e.data(),
|
|
1917
2140
|
id: e.id
|
|
1918
2141
|
}))), a);
|
|
1919
2142
|
}
|
|
1920
2143
|
//#endregion
|
|
1921
2144
|
//#region src/composables/useMemiBoardComments.ts
|
|
1922
|
-
var
|
|
1923
|
-
function
|
|
2145
|
+
var Sr = 10, Cr = 5, wr = 1e3;
|
|
2146
|
+
function Tr(e, { t, formatNumber: n }) {
|
|
1924
2147
|
let r = e.trim();
|
|
1925
2148
|
if (!r) throw Error(t("comments.bodyRequired"));
|
|
1926
|
-
if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(
|
|
2149
|
+
if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(wr) }));
|
|
1927
2150
|
return r;
|
|
1928
2151
|
}
|
|
1929
|
-
function
|
|
1930
|
-
let
|
|
1931
|
-
function
|
|
2152
|
+
function Er(e, t, r = {}) {
|
|
2153
|
+
let i = Z(), a = Me(), o = () => N(), { isBoardHidden: s, getBoard: c } = Jn(), { translateComment: l } = br(), u;
|
|
2154
|
+
async function f(e, t) {
|
|
2155
|
+
return n() ? t?.i18nSource.body === e ? t : c(_.value)?.autoTranslatePosts === !0 ? (u?.i18nSource.body !== e && (u = await l({
|
|
2156
|
+
body: e,
|
|
2157
|
+
targets: pt(c(_.value))
|
|
2158
|
+
})), u) : {} : {};
|
|
2159
|
+
}
|
|
2160
|
+
let p = M(), { t: m } = p, h = () => g(i, o()), _ = F(() => R(e)), v = F(() => R(t)), b = () => !s(_.value), S = L([]), C = L(r.subscribe !== !1), w = L([]), T = L(!1), E = L(r.subscribe !== !1), D = L(r.subscribe !== !1), O = null, k = 0, ee = 0, A;
|
|
2161
|
+
function te(e) {
|
|
1932
2162
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1933
2163
|
}
|
|
1934
|
-
let
|
|
2164
|
+
let ne = F(() => {
|
|
1935
2165
|
let e = /* @__PURE__ */ new Map();
|
|
1936
|
-
for (let t of [...
|
|
1937
|
-
return [...e.values()].sort((e, t) =>
|
|
2166
|
+
for (let t of [...S.value, ...w.value]) t.id && e.set(t.id, t);
|
|
2167
|
+
return [...e.values()].sort((e, t) => te(e) - te(t) || String(e.id).localeCompare(String(t.id)));
|
|
1938
2168
|
});
|
|
1939
|
-
|
|
1940
|
-
let t = ++
|
|
1941
|
-
if (
|
|
1942
|
-
|
|
2169
|
+
z([v, _], async ([e]) => {
|
|
2170
|
+
let t = ++k;
|
|
2171
|
+
if (ee++, T.value = !1, w.value = [], S.value = [], O = null, A?.(), A = void 0, E.value = r.subscribe !== !1, r.subscribe !== !1) {
|
|
2172
|
+
C.value = !0, D.value = !0;
|
|
1943
2173
|
try {
|
|
1944
|
-
let n =
|
|
2174
|
+
let n = V(G(h(), X("postId", "==", e), W("createdAt", "desc"), W(B(), "desc")));
|
|
1945
2175
|
if (await Promise.all([n.then((e) => {
|
|
1946
|
-
if (t !==
|
|
2176
|
+
if (t !== k) return;
|
|
1947
2177
|
let n = e.docs.map((e) => ({
|
|
1948
2178
|
id: e.id,
|
|
1949
2179
|
...e.data()
|
|
1950
2180
|
}));
|
|
1951
|
-
|
|
1952
|
-
}),
|
|
2181
|
+
S.value = n.filter((e) => e.parentId === void 0);
|
|
2182
|
+
}), ie()]), t !== k) return;
|
|
1953
2183
|
} finally {
|
|
1954
|
-
t ===
|
|
2184
|
+
t === k && (C.value = !1, D.value = !1);
|
|
1955
2185
|
}
|
|
1956
2186
|
}
|
|
1957
2187
|
}, { immediate: !0 });
|
|
1958
|
-
function
|
|
1959
|
-
|
|
1960
|
-
let e = ++
|
|
1961
|
-
|
|
1962
|
-
cursor:
|
|
1963
|
-
hasMore:
|
|
2188
|
+
function re() {
|
|
2189
|
+
A?.();
|
|
2190
|
+
let e = ++ee;
|
|
2191
|
+
A = xr(i, o(), v.value, {
|
|
2192
|
+
cursor: O,
|
|
2193
|
+
hasMore: E.value
|
|
1964
2194
|
}, (t) => {
|
|
1965
|
-
e ===
|
|
2195
|
+
e === ee && (w.value = t);
|
|
1966
2196
|
}, (e) => {
|
|
1967
2197
|
console.error("[memi-board:comments] onSnapshot failed", e);
|
|
1968
2198
|
});
|
|
1969
2199
|
}
|
|
1970
|
-
async function
|
|
1971
|
-
if (
|
|
1972
|
-
let e =
|
|
1973
|
-
|
|
2200
|
+
async function ie() {
|
|
2201
|
+
if (T.value || !E.value) return;
|
|
2202
|
+
let e = k;
|
|
2203
|
+
T.value = !0;
|
|
1974
2204
|
try {
|
|
1975
2205
|
let t = [
|
|
1976
|
-
X("postId", "==",
|
|
2206
|
+
X("postId", "==", v.value),
|
|
1977
2207
|
X("parentId", "==", null),
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
...
|
|
1981
|
-
|
|
1982
|
-
], n = await
|
|
1983
|
-
if (e !==
|
|
1984
|
-
let r = n.docs.slice(0,
|
|
2208
|
+
W("createdAt", "asc"),
|
|
2209
|
+
W(B(), "asc"),
|
|
2210
|
+
...O ? [J(O)] : [],
|
|
2211
|
+
H(11)
|
|
2212
|
+
], n = await V(G(h(), ...t));
|
|
2213
|
+
if (e !== k) return;
|
|
2214
|
+
let r = n.docs.slice(0, Sr), i = r.map((e) => ({
|
|
1985
2215
|
id: e.id,
|
|
1986
2216
|
...e.data()
|
|
1987
|
-
})), a = new Set(
|
|
1988
|
-
|
|
2217
|
+
})), a = new Set(w.value.map((e) => e.id));
|
|
2218
|
+
w.value.push(...i.filter((e) => !a.has(e.id))), O = r.at(-1) ?? O, E.value = n.size > Sr, re();
|
|
1989
2219
|
} finally {
|
|
1990
|
-
e ===
|
|
2220
|
+
e === k && (T.value = !1);
|
|
1991
2221
|
}
|
|
1992
2222
|
}
|
|
1993
|
-
|
|
1994
|
-
|
|
2223
|
+
I(() => {
|
|
2224
|
+
k++, ee++, A?.();
|
|
1995
2225
|
});
|
|
1996
|
-
function
|
|
1997
|
-
return
|
|
2226
|
+
function j() {
|
|
2227
|
+
return ye(h()).id;
|
|
1998
2228
|
}
|
|
1999
|
-
function
|
|
2000
|
-
if (!e) return
|
|
2001
|
-
if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(
|
|
2002
|
-
return d(
|
|
2229
|
+
function ae(e) {
|
|
2230
|
+
if (!e) return ye(h());
|
|
2231
|
+
if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(m("commentForm.uploadFailed"));
|
|
2232
|
+
return d(i, o(), e);
|
|
2003
2233
|
}
|
|
2004
|
-
function
|
|
2005
|
-
let n = `${x(
|
|
2006
|
-
return
|
|
2234
|
+
function oe(e, t) {
|
|
2235
|
+
let n = `${x(o(), v.value)}/comment-images/${e}/`;
|
|
2236
|
+
return ce(t).filter((e) => e.path.startsWith(n));
|
|
2007
2237
|
}
|
|
2008
|
-
function
|
|
2009
|
-
let n =
|
|
2238
|
+
async function se(e, t) {
|
|
2239
|
+
let n = oe(t, e.images), r = Tr(e.body, p);
|
|
2010
2240
|
return {
|
|
2011
|
-
postId:
|
|
2012
|
-
boardId:
|
|
2013
|
-
listed:
|
|
2014
|
-
body:
|
|
2241
|
+
postId: v.value,
|
|
2242
|
+
boardId: _.value,
|
|
2243
|
+
listed: b(),
|
|
2244
|
+
body: r,
|
|
2245
|
+
...await f(r, e.translations),
|
|
2015
2246
|
authorUid: e.authorUid,
|
|
2016
2247
|
authorName: e.authorName,
|
|
2017
2248
|
authorPhoto: e.authorPhoto,
|
|
2018
2249
|
moderationStatus: "approved",
|
|
2019
2250
|
replyCount: 0,
|
|
2020
2251
|
likeCount: 0,
|
|
2021
|
-
createdAt:
|
|
2022
|
-
updatedAt:
|
|
2252
|
+
createdAt: K(),
|
|
2253
|
+
updatedAt: K(),
|
|
2023
2254
|
...n.length ? { images: n } : {}
|
|
2024
2255
|
};
|
|
2025
2256
|
}
|
|
2026
|
-
async function
|
|
2257
|
+
async function ue(e) {
|
|
2027
2258
|
if (!e.length) return;
|
|
2028
|
-
let t = We(
|
|
2259
|
+
let t = We(a);
|
|
2029
2260
|
await Promise.all(e.map((e) => He(qe(t, e)).catch(() => {})));
|
|
2030
2261
|
}
|
|
2031
|
-
async function
|
|
2032
|
-
let t = Oe(
|
|
2262
|
+
async function de(e) {
|
|
2263
|
+
let t = Oe(i), n = ae(e.id);
|
|
2033
2264
|
t.set(n, {
|
|
2034
|
-
...
|
|
2265
|
+
...await se(e, n.id),
|
|
2035
2266
|
parentId: null,
|
|
2036
2267
|
rootId: n.id,
|
|
2037
2268
|
depth: 0,
|
|
2038
2269
|
replyToUid: null,
|
|
2039
2270
|
replyToName: null,
|
|
2040
2271
|
isReply: !1
|
|
2041
|
-
}), t.update(y(
|
|
2272
|
+
}), t.update(y(i, o(), v.value), { commentCount: Te(1) }), await t.commit();
|
|
2042
2273
|
}
|
|
2043
|
-
async function
|
|
2044
|
-
if (!e.parent.id) throw Error(
|
|
2045
|
-
let t = Oe(
|
|
2046
|
-
if (!
|
|
2047
|
-
let
|
|
2274
|
+
async function fe(e) {
|
|
2275
|
+
if (!e.parent.id) throw Error(m("comments.replyTargetNotFound"));
|
|
2276
|
+
let t = Oe(i), n = ae(e.id), r = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
|
|
2277
|
+
if (!r) throw Error(m("comments.threadNotFound"));
|
|
2278
|
+
let a = Math.min((e.parent.depth ?? 0) + 1, 2);
|
|
2048
2279
|
t.set(n, {
|
|
2049
|
-
...
|
|
2280
|
+
...await se(e, n.id),
|
|
2050
2281
|
parentId: e.parent.id,
|
|
2051
|
-
rootId:
|
|
2052
|
-
depth:
|
|
2282
|
+
rootId: r,
|
|
2283
|
+
depth: a,
|
|
2053
2284
|
replyToUid: e.parent.authorUid,
|
|
2054
2285
|
replyToName: e.parent.authorName,
|
|
2055
2286
|
isReply: !0
|
|
2056
|
-
}), t.update(d(
|
|
2287
|
+
}), t.update(d(i, o(), r), { replyCount: Te(1) }), t.update(y(i, o(), v.value), { commentCount: Te(1) }), await t.commit();
|
|
2057
2288
|
}
|
|
2058
|
-
async function
|
|
2289
|
+
async function P(e) {
|
|
2059
2290
|
if (!e.id) return;
|
|
2060
|
-
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(
|
|
2061
|
-
let t =
|
|
2062
|
-
await
|
|
2063
|
-
let n = Oe(
|
|
2064
|
-
n.delete(d(
|
|
2065
|
-
}
|
|
2066
|
-
async function
|
|
2067
|
-
let
|
|
2068
|
-
body:
|
|
2069
|
-
updatedAt:
|
|
2291
|
+
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(m("comments.hasRepliesCannotDelete"));
|
|
2292
|
+
let t = le(e.images, `${x(o(), v.value)}/comment-images/${e.id}/`);
|
|
2293
|
+
await sn(i, o(), e.id);
|
|
2294
|
+
let n = Oe(i);
|
|
2295
|
+
n.delete(d(i, o(), e.id)), e.parentId && e.rootId && n.update(d(i, o(), e.rootId), { replyCount: Te(-1) }), n.update(y(i, o(), v.value), { commentCount: Te(-1) }), await n.commit(), await ue(t), w.value = w.value.filter((t) => t.id !== e.id), S.value = S.value.filter((t) => t.id !== e.id);
|
|
2296
|
+
}
|
|
2297
|
+
async function pe(e, t, n, r) {
|
|
2298
|
+
let a = Tr(t, p), s = {
|
|
2299
|
+
body: a,
|
|
2300
|
+
updatedAt: K()
|
|
2070
2301
|
};
|
|
2071
2302
|
if (n !== void 0) {
|
|
2072
|
-
let t =
|
|
2073
|
-
|
|
2303
|
+
let t = oe(e, n);
|
|
2304
|
+
s.images = t.length ? t : ve();
|
|
2074
2305
|
}
|
|
2075
|
-
await Y(d(
|
|
2306
|
+
await Y(d(i, o(), e), {
|
|
2307
|
+
...s,
|
|
2308
|
+
...await f(a, r)
|
|
2309
|
+
});
|
|
2076
2310
|
}
|
|
2077
|
-
async function
|
|
2078
|
-
await Y(d(
|
|
2311
|
+
async function me(e, t, n) {
|
|
2312
|
+
await Y(d(i, o(), e), {
|
|
2079
2313
|
isBlinded: t,
|
|
2080
|
-
moderatedAt:
|
|
2314
|
+
moderatedAt: K(),
|
|
2081
2315
|
moderatedBy: n
|
|
2082
2316
|
});
|
|
2083
2317
|
}
|
|
2084
2318
|
return {
|
|
2085
|
-
comments:
|
|
2086
|
-
commentsPending:
|
|
2087
|
-
hasMore:
|
|
2088
|
-
loadingMore:
|
|
2089
|
-
loadMore:
|
|
2090
|
-
newCommentId:
|
|
2091
|
-
addComment:
|
|
2092
|
-
addReply:
|
|
2093
|
-
updateComment:
|
|
2094
|
-
setCommentBlinded:
|
|
2095
|
-
deleteComment:
|
|
2319
|
+
comments: ne,
|
|
2320
|
+
commentsPending: F(() => D.value || C.value),
|
|
2321
|
+
hasMore: E,
|
|
2322
|
+
loadingMore: T,
|
|
2323
|
+
loadMore: ie,
|
|
2324
|
+
newCommentId: j,
|
|
2325
|
+
addComment: de,
|
|
2326
|
+
addReply: fe,
|
|
2327
|
+
updateComment: pe,
|
|
2328
|
+
setCommentBlinded: me,
|
|
2329
|
+
deleteComment: P
|
|
2096
2330
|
};
|
|
2097
2331
|
}
|
|
2098
|
-
function
|
|
2099
|
-
let r = Z(), i = () =>
|
|
2332
|
+
function Dr(e, t, n) {
|
|
2333
|
+
let r = Z(), i = () => N(), a = () => g(r, i()), o = t.trim(), s = L([]), c = L(!1), l = L(!1), u = L(!0), d = null, f, p = 0, m = 0;
|
|
2100
2334
|
function h(e) {
|
|
2101
2335
|
return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
|
|
2102
2336
|
}
|
|
2103
2337
|
function _() {
|
|
2104
2338
|
f?.();
|
|
2105
2339
|
let e = ++m;
|
|
2106
|
-
f =
|
|
2340
|
+
f = xr(r, i(), o, {
|
|
2107
2341
|
rootId: n,
|
|
2108
2342
|
cursor: d,
|
|
2109
2343
|
hasMore: u.value
|
|
@@ -2122,17 +2356,17 @@ function _r(e, t, n) {
|
|
|
2122
2356
|
X("postId", "==", o),
|
|
2123
2357
|
X("rootId", "==", n),
|
|
2124
2358
|
X("isReply", "==", !0),
|
|
2125
|
-
|
|
2126
|
-
|
|
2359
|
+
W("createdAt", "asc"),
|
|
2360
|
+
W(B(), "asc"),
|
|
2127
2361
|
...d ? [J(d)] : [],
|
|
2128
|
-
|
|
2129
|
-
], r = await
|
|
2362
|
+
H(6)
|
|
2363
|
+
], r = await V(G(a(), ...t));
|
|
2130
2364
|
if (e !== p) return;
|
|
2131
|
-
let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0,
|
|
2365
|
+
let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0, Cr), f = c.map((e) => ({
|
|
2132
2366
|
id: e.id,
|
|
2133
2367
|
...e.data()
|
|
2134
2368
|
})).filter((e) => !i.has(e.id));
|
|
2135
|
-
s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size >
|
|
2369
|
+
s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size > Cr, _();
|
|
2136
2370
|
} finally {
|
|
2137
2371
|
e === p && (c.value = !1);
|
|
2138
2372
|
}
|
|
@@ -2143,7 +2377,7 @@ function _r(e, t, n) {
|
|
|
2143
2377
|
async function b() {
|
|
2144
2378
|
y(), await v();
|
|
2145
2379
|
}
|
|
2146
|
-
return
|
|
2380
|
+
return I(() => {
|
|
2147
2381
|
p++, m++, f?.();
|
|
2148
2382
|
}), {
|
|
2149
2383
|
replies: s,
|
|
@@ -2156,22 +2390,22 @@ function _r(e, t, n) {
|
|
|
2156
2390
|
}
|
|
2157
2391
|
//#endregion
|
|
2158
2392
|
//#region src/composables/useMemiBoardLikes.ts
|
|
2159
|
-
function
|
|
2160
|
-
let n = () =>
|
|
2393
|
+
function Or(e, t) {
|
|
2394
|
+
let n = () => N(), r = Z(), i = Ae(), { t: a } = M(), o = L(!1), s = L(!1), c;
|
|
2161
2395
|
function l(e) {
|
|
2162
|
-
return
|
|
2396
|
+
return pe(r, n(), t, e);
|
|
2163
2397
|
}
|
|
2164
|
-
|
|
2398
|
+
z(i, (e) => {
|
|
2165
2399
|
if (c?.(), c = void 0, !e) {
|
|
2166
2400
|
o.value = !1;
|
|
2167
2401
|
return;
|
|
2168
2402
|
}
|
|
2169
|
-
c =
|
|
2403
|
+
c = U(l(e.uid), (e) => {
|
|
2170
2404
|
o.value = e.exists();
|
|
2171
2405
|
}, (e) => {
|
|
2172
2406
|
console.error("[memi-board:likes] onSnapshot failed", e);
|
|
2173
2407
|
});
|
|
2174
|
-
}, { immediate: !0 }),
|
|
2408
|
+
}, { immediate: !0 }), I(() => c?.());
|
|
2175
2409
|
async function u() {
|
|
2176
2410
|
let c = i.value?.uid;
|
|
2177
2411
|
if (!c) throw Error(a("likes.signInRequired"));
|
|
@@ -2179,12 +2413,12 @@ function vr(e, t) {
|
|
|
2179
2413
|
s.value = !0;
|
|
2180
2414
|
try {
|
|
2181
2415
|
let i = l(c), a = y(r, n(), t);
|
|
2182
|
-
return await
|
|
2416
|
+
return await De(r, async (n) => (await n.get(i)).exists() ? (n.delete(i), n.update(a, { likeCount: Te(-1) }), !1) : (n.set(i, {
|
|
2183
2417
|
uid: c,
|
|
2184
2418
|
postId: t,
|
|
2185
2419
|
boardId: e,
|
|
2186
|
-
createdAt:
|
|
2187
|
-
}), n.update(a, { likeCount:
|
|
2420
|
+
createdAt: K()
|
|
2421
|
+
}), n.update(a, { likeCount: Te(1) }), !0));
|
|
2188
2422
|
} finally {
|
|
2189
2423
|
s.value = !1;
|
|
2190
2424
|
}
|
|
@@ -2195,11 +2429,11 @@ function vr(e, t) {
|
|
|
2195
2429
|
toggleLike: u
|
|
2196
2430
|
};
|
|
2197
2431
|
}
|
|
2198
|
-
var
|
|
2199
|
-
function
|
|
2200
|
-
let n = () =>
|
|
2201
|
-
|
|
2202
|
-
u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u =
|
|
2432
|
+
var kr = Symbol.for("memi-board:comment-likes");
|
|
2433
|
+
function Ar(e, t) {
|
|
2434
|
+
let n = () => N(), r = Z(), i = Ae(), { t: a } = M(), o = F(() => R(e)), s = F(() => R(t)), c = L(/* @__PURE__ */ new Set()), l = L(null), u;
|
|
2435
|
+
z([i, s], ([e, t]) => {
|
|
2436
|
+
u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = U(G(b(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
|
|
2203
2437
|
let t = /* @__PURE__ */ new Set();
|
|
2204
2438
|
for (let n of e.docs) {
|
|
2205
2439
|
let e = n.data().commentId;
|
|
@@ -2209,7 +2443,7 @@ function br(e, t) {
|
|
|
2209
2443
|
}, (e) => {
|
|
2210
2444
|
console.error("[memi-board:comment-likes] onSnapshot failed", e);
|
|
2211
2445
|
}));
|
|
2212
|
-
}, { immediate: !0 }),
|
|
2446
|
+
}, { immediate: !0 }), I(() => u?.());
|
|
2213
2447
|
function f(e) {
|
|
2214
2448
|
return !!e && c.value.has(e);
|
|
2215
2449
|
}
|
|
@@ -2223,7 +2457,7 @@ function br(e, t) {
|
|
|
2223
2457
|
if (l.value) return f(e);
|
|
2224
2458
|
l.value = e;
|
|
2225
2459
|
try {
|
|
2226
|
-
let i =
|
|
2460
|
+
let i = pe(r, n(), e, t), l = d(r, n(), e), u = await De(r, async (n) => {
|
|
2227
2461
|
let r = await n.get(i), c = await n.get(l);
|
|
2228
2462
|
if (!c.exists()) throw Error(a("likes.commentNotFound"));
|
|
2229
2463
|
let u = Number(c.data()?.likeCount ?? 0);
|
|
@@ -2233,7 +2467,7 @@ function br(e, t) {
|
|
|
2233
2467
|
boardId: o.value,
|
|
2234
2468
|
commentId: e,
|
|
2235
2469
|
target: "comment",
|
|
2236
|
-
createdAt:
|
|
2470
|
+
createdAt: K()
|
|
2237
2471
|
}), n.update(l, { likeCount: u + 1 }), !0);
|
|
2238
2472
|
}), f = new Set(c.value);
|
|
2239
2473
|
return u ? f.add(e) : f.delete(e), c.value = f, u;
|
|
@@ -2249,7 +2483,7 @@ function br(e, t) {
|
|
|
2249
2483
|
}
|
|
2250
2484
|
//#endregion
|
|
2251
2485
|
//#region src/composables/useMemiBoardReports.ts
|
|
2252
|
-
var
|
|
2486
|
+
var jr = 200, Mr = [
|
|
2253
2487
|
{
|
|
2254
2488
|
value: "spam",
|
|
2255
2489
|
label: "스팸·광고"
|
|
@@ -2271,34 +2505,34 @@ var xr = 200, Sr = [
|
|
|
2271
2505
|
label: "기타"
|
|
2272
2506
|
}
|
|
2273
2507
|
];
|
|
2274
|
-
function
|
|
2275
|
-
return
|
|
2508
|
+
function Nr(e, t) {
|
|
2509
|
+
return Mr.some((t) => t.value === e) ? j(t, `reports.reason.${e}`) : e || j(t, "reports.fallbackLabel");
|
|
2276
2510
|
}
|
|
2277
|
-
function
|
|
2278
|
-
let n = () =>
|
|
2279
|
-
|
|
2511
|
+
function Pr(e, t) {
|
|
2512
|
+
let n = () => N(), r = Z(), i = Ae(), { t: a } = M(), o = L(!1), s = L(!1), c;
|
|
2513
|
+
z(i, (e) => {
|
|
2280
2514
|
if (c?.(), c = void 0, !e) {
|
|
2281
2515
|
o.value = !1;
|
|
2282
2516
|
return;
|
|
2283
2517
|
}
|
|
2284
|
-
c =
|
|
2518
|
+
c = U(u(r, n(), t, e.uid), (e) => {
|
|
2285
2519
|
o.value = e.exists();
|
|
2286
2520
|
}, (e) => {
|
|
2287
2521
|
console.error("[memi-board:reports] onSnapshot failed", e);
|
|
2288
2522
|
});
|
|
2289
|
-
}, { immediate: !0 }),
|
|
2523
|
+
}, { immediate: !0 }), I(() => c?.());
|
|
2290
2524
|
async function l(c) {
|
|
2291
2525
|
let l = i.value?.uid;
|
|
2292
2526
|
if (!l) throw Error(a("reports.signInRequired"));
|
|
2293
2527
|
if (s.value) return;
|
|
2294
2528
|
if (c.authorUid && c.authorUid === l) throw Error(a("reports.cannotReportOwn"));
|
|
2295
|
-
let d =
|
|
2529
|
+
let d = Mr.some((e) => e.value === c.reason) ? c.reason : null;
|
|
2296
2530
|
if (!d) throw Error(a("reports.reasonRequired"));
|
|
2297
2531
|
let f = (c.detail || "").trim();
|
|
2298
2532
|
if (f.length > 200) throw Error(a("reports.detailTooLong", { max: 200 }));
|
|
2299
2533
|
s.value = !0;
|
|
2300
2534
|
try {
|
|
2301
|
-
await
|
|
2535
|
+
await q(u(r, n(), t, l), {
|
|
2302
2536
|
uid: l,
|
|
2303
2537
|
target: "post",
|
|
2304
2538
|
postId: t,
|
|
@@ -2309,7 +2543,7 @@ function wr(e, t) {
|
|
|
2309
2543
|
postTitle: (c.postTitle || "").trim().slice(0, 200),
|
|
2310
2544
|
authorUid: c.authorUid || "",
|
|
2311
2545
|
authorName: c.authorName ?? null,
|
|
2312
|
-
createdAt:
|
|
2546
|
+
createdAt: K()
|
|
2313
2547
|
}), o.value = !0;
|
|
2314
2548
|
} finally {
|
|
2315
2549
|
s.value = !1;
|
|
@@ -2321,9 +2555,9 @@ function wr(e, t) {
|
|
|
2321
2555
|
submitReport: l
|
|
2322
2556
|
};
|
|
2323
2557
|
}
|
|
2324
|
-
var
|
|
2325
|
-
function
|
|
2326
|
-
let t = () =>
|
|
2558
|
+
var Fr = 20;
|
|
2559
|
+
function Ir(e = {}) {
|
|
2560
|
+
let t = () => N(), n = Z(), { isAdmin: r, canManageContent: i, canManageBoard: a } = Wt(), o = e.pageSize ?? Fr, s = F(() => R(e.boardId)?.trim() || ""), c = L([]), d = L(!0), f = L(!1), p = L(!1), m = L(""), h = null, g;
|
|
2327
2561
|
function _(e) {
|
|
2328
2562
|
return {
|
|
2329
2563
|
id: e.id,
|
|
@@ -2337,18 +2571,18 @@ function Er(e = {}) {
|
|
|
2337
2571
|
}
|
|
2338
2572
|
d.value = !0;
|
|
2339
2573
|
let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")];
|
|
2340
|
-
g =
|
|
2574
|
+
g = U(G(l(n, t()), ...e, W("createdAt", "desc"), W(B(), "desc"), H(o)), (e) => {
|
|
2341
2575
|
c.value = e.docs.map(_).filter((e) => a(e.boardId)), h = e.docs.at(-1) ?? null, p.value = e.docs.length >= o, d.value = !1;
|
|
2342
2576
|
}, (e) => {
|
|
2343
2577
|
console.error("[memi-board:report-queue] onSnapshot failed", e), m.value = e.message || String(e), d.value = !1;
|
|
2344
2578
|
});
|
|
2345
2579
|
}
|
|
2346
|
-
|
|
2580
|
+
z([i, s], v, { immediate: !0 }), I(() => g?.());
|
|
2347
2581
|
async function y() {
|
|
2348
2582
|
if (!f.value && p.value && h && i.value) {
|
|
2349
2583
|
f.value = !0, m.value = "";
|
|
2350
2584
|
try {
|
|
2351
|
-
let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await
|
|
2585
|
+
let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await V(G(l(n, t()), ...e, W("createdAt", "desc"), W(B(), "desc"), J(h), H(o + 1))), i = r.docs.slice(0, o), u = new Set(c.value.map((e) => e.id));
|
|
2352
2586
|
c.value.push(...i.map(_).filter((e) => !u.has(e.id) && a(e.boardId))), h = i.at(-1) ?? h, p.value = r.docs.length > o;
|
|
2353
2587
|
} catch (e) {
|
|
2354
2588
|
m.value = e.message || String(e);
|
|
@@ -2360,7 +2594,7 @@ function Er(e = {}) {
|
|
|
2360
2594
|
async function b(e, r) {
|
|
2361
2595
|
e.id && a(e.boardId) && await Y(u(n, t(), e.postId, e.uid), {
|
|
2362
2596
|
status: r,
|
|
2363
|
-
reviewedAt:
|
|
2597
|
+
reviewedAt: K(),
|
|
2364
2598
|
reviewedBy: Ae().value?.uid || ""
|
|
2365
2599
|
});
|
|
2366
2600
|
}
|
|
@@ -2377,8 +2611,8 @@ function Er(e = {}) {
|
|
|
2377
2611
|
}
|
|
2378
2612
|
//#endregion
|
|
2379
2613
|
//#region src/composables/useMemiBoardViews.ts
|
|
2380
|
-
function
|
|
2381
|
-
let e = () =>
|
|
2614
|
+
function Lr() {
|
|
2615
|
+
let e = () => N(), t = Z();
|
|
2382
2616
|
function n(t, n) {
|
|
2383
2617
|
let { postsCollection: r } = e();
|
|
2384
2618
|
return `memi-board:viewed:${r}:${t}:${n}`;
|
|
@@ -2401,7 +2635,7 @@ function Dr() {
|
|
|
2401
2635
|
if (s && c && !r(s, c)) {
|
|
2402
2636
|
i(s, c);
|
|
2403
2637
|
try {
|
|
2404
|
-
await Y(y(t, e(), c), { viewCount:
|
|
2638
|
+
await Y(y(t, e(), c), { viewCount: Te(1) });
|
|
2405
2639
|
} catch (e) {
|
|
2406
2640
|
try {
|
|
2407
2641
|
sessionStorage.removeItem(n(s, c));
|
|
@@ -2417,20 +2651,20 @@ function Dr() {
|
|
|
2417
2651
|
}
|
|
2418
2652
|
//#endregion
|
|
2419
2653
|
//#region src/composables/useMemiBoardModeration.ts
|
|
2420
|
-
var
|
|
2654
|
+
var Rr = {
|
|
2421
2655
|
flagged: !1,
|
|
2422
2656
|
category: "none",
|
|
2423
2657
|
reason: "",
|
|
2424
2658
|
via: "empty"
|
|
2425
2659
|
};
|
|
2426
|
-
function
|
|
2427
|
-
let t =
|
|
2660
|
+
function zr(e = {}) {
|
|
2661
|
+
let t = M(), n = F(() => P(R(e.locale)) ?? t.locale.value), r = v().moderation ?? {}, i = Me(), a = (e) => j(n.value, e), { isWriteRestricted: o, restrictedMessage: s, recordContentModerationBlock: c } = Wt(), l = Nn([...Mn, ...r.localBlocklist ?? []]);
|
|
2428
2662
|
function u(e) {
|
|
2429
2663
|
let t = e.match(l);
|
|
2430
2664
|
return t ? {
|
|
2431
2665
|
flagged: !0,
|
|
2432
2666
|
category: "abuse",
|
|
2433
|
-
reason:
|
|
2667
|
+
reason: jn({
|
|
2434
2668
|
via: "local",
|
|
2435
2669
|
localHit: t[0] || "",
|
|
2436
2670
|
category: "abuse"
|
|
@@ -2445,7 +2679,7 @@ function kr(e = {}) {
|
|
|
2445
2679
|
});
|
|
2446
2680
|
return Ze(a, {
|
|
2447
2681
|
model: e,
|
|
2448
|
-
systemInstruction:
|
|
2682
|
+
systemInstruction: En(n.value),
|
|
2449
2683
|
generationConfig: {
|
|
2450
2684
|
temperature: 0,
|
|
2451
2685
|
maxOutputTokens: 256,
|
|
@@ -2474,7 +2708,7 @@ function kr(e = {}) {
|
|
|
2474
2708
|
};
|
|
2475
2709
|
}
|
|
2476
2710
|
function p(e, t = "") {
|
|
2477
|
-
let n =
|
|
2711
|
+
let n = jn({
|
|
2478
2712
|
reason: e.reason,
|
|
2479
2713
|
category: e.category,
|
|
2480
2714
|
via: e.via
|
|
@@ -2502,26 +2736,26 @@ function kr(e = {}) {
|
|
|
2502
2736
|
};
|
|
2503
2737
|
let i = e.trim();
|
|
2504
2738
|
if (!i) return {
|
|
2505
|
-
...
|
|
2739
|
+
...Rr,
|
|
2506
2740
|
via: "empty"
|
|
2507
2741
|
};
|
|
2508
2742
|
if (t?.skipFilter) return {
|
|
2509
|
-
...
|
|
2743
|
+
...Rr,
|
|
2510
2744
|
via: "admin-override"
|
|
2511
2745
|
};
|
|
2512
2746
|
let c = u(i);
|
|
2513
2747
|
if (c) return m(c);
|
|
2514
2748
|
if (r.enabled === !1) return {
|
|
2515
|
-
...
|
|
2749
|
+
...Rr,
|
|
2516
2750
|
via: "disabled"
|
|
2517
2751
|
};
|
|
2518
2752
|
try {
|
|
2519
|
-
let e =
|
|
2753
|
+
let e = Fn((await d().generateContent(Dn(i, n.value))).response.text());
|
|
2520
2754
|
if (!e) return f();
|
|
2521
2755
|
let t = {
|
|
2522
2756
|
flagged: e.flagged,
|
|
2523
2757
|
category: e.category,
|
|
2524
|
-
reason:
|
|
2758
|
+
reason: jn({
|
|
2525
2759
|
reason: e.reason,
|
|
2526
2760
|
category: e.category,
|
|
2527
2761
|
via: "ai"
|
|
@@ -2541,22 +2775,22 @@ function kr(e = {}) {
|
|
|
2541
2775
|
via: "restricted"
|
|
2542
2776
|
};
|
|
2543
2777
|
if (r.enabled === !1 || !r.moderateImages) return {
|
|
2544
|
-
...
|
|
2778
|
+
...Rr,
|
|
2545
2779
|
via: "disabled"
|
|
2546
2780
|
};
|
|
2547
2781
|
try {
|
|
2548
2782
|
let t = await new Promise((t, n) => {
|
|
2549
2783
|
let r = new FileReader();
|
|
2550
2784
|
r.onload = () => t(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(e);
|
|
2551
|
-
}), r =
|
|
2785
|
+
}), r = Fn((await d().generateContent([{ inlineData: {
|
|
2552
2786
|
mimeType: e.type || "image/jpeg",
|
|
2553
2787
|
data: t
|
|
2554
|
-
} },
|
|
2788
|
+
} }, On(n.value)])).response.text());
|
|
2555
2789
|
if (!r) return f();
|
|
2556
2790
|
let i = {
|
|
2557
2791
|
flagged: r.flagged,
|
|
2558
2792
|
category: r.category,
|
|
2559
|
-
reason:
|
|
2793
|
+
reason: jn({
|
|
2560
2794
|
reason: r.reason,
|
|
2561
2795
|
category: r.category,
|
|
2562
2796
|
via: "ai"
|
|
@@ -2575,7 +2809,7 @@ function kr(e = {}) {
|
|
|
2575
2809
|
}
|
|
2576
2810
|
//#endregion
|
|
2577
2811
|
//#region src/composables/useMemiBoardUsers.ts
|
|
2578
|
-
var
|
|
2812
|
+
var Br = [
|
|
2579
2813
|
"owner",
|
|
2580
2814
|
"admin",
|
|
2581
2815
|
"manager",
|
|
@@ -2583,16 +2817,16 @@ var Ar = [
|
|
|
2583
2817
|
"user"
|
|
2584
2818
|
].map((e) => ({
|
|
2585
2819
|
value: e,
|
|
2586
|
-
label:
|
|
2587
|
-
description:
|
|
2820
|
+
label: j("ko", `common.role.${e}`),
|
|
2821
|
+
description: j("ko", `boardUsers.roleDescription.${e}`)
|
|
2588
2822
|
}));
|
|
2589
|
-
function
|
|
2590
|
-
let t = () =>
|
|
2823
|
+
function Vr(e = {}) {
|
|
2824
|
+
let t = () => N(), n = Z(), { t: r } = M(), i = F(() => R(e.enabled) ?? !0 ? c(n, t()) : null), a = ke(i, { ssrKey: p(t(), "users-management") });
|
|
2591
2825
|
async function o(e, i) {
|
|
2592
|
-
if (!
|
|
2826
|
+
if (!Br.some((e) => e.value === i)) throw Error(r("boardUsers.unsupportedRole"));
|
|
2593
2827
|
await Y(h(n, t(), e), {
|
|
2594
2828
|
role: i,
|
|
2595
|
-
updatedAt:
|
|
2829
|
+
updatedAt: K()
|
|
2596
2830
|
});
|
|
2597
2831
|
}
|
|
2598
2832
|
return {
|
|
@@ -2603,8 +2837,8 @@ function jr(e = {}) {
|
|
|
2603
2837
|
}
|
|
2604
2838
|
//#endregion
|
|
2605
2839
|
//#region src/composables/useMemiBoardUserProfile.ts
|
|
2606
|
-
function
|
|
2607
|
-
let t = Z(), n = () =>
|
|
2840
|
+
function Hr(e) {
|
|
2841
|
+
let t = Z(), n = () => N(), r = F(() => R(e)), i = F(() => {
|
|
2608
2842
|
let e = r.value;
|
|
2609
2843
|
return e ? h(t, n(), e) : null;
|
|
2610
2844
|
}), { data: a, pending: o } = je(i);
|
|
@@ -2615,7 +2849,7 @@ function Mr(e) {
|
|
|
2615
2849
|
}
|
|
2616
2850
|
//#endregion
|
|
2617
2851
|
//#region src/utils/section.ts
|
|
2618
|
-
var
|
|
2852
|
+
var Ur = [
|
|
2619
2853
|
3,
|
|
2620
2854
|
4,
|
|
2621
2855
|
5,
|
|
@@ -2625,43 +2859,43 @@ var Nr = [
|
|
|
2625
2859
|
9,
|
|
2626
2860
|
12
|
|
2627
2861
|
];
|
|
2628
|
-
function
|
|
2862
|
+
function Wr(e) {
|
|
2629
2863
|
return [
|
|
2630
2864
|
{
|
|
2631
2865
|
value: "list",
|
|
2632
|
-
label:
|
|
2866
|
+
label: j(e, "sectionUtil.kind.list")
|
|
2633
2867
|
},
|
|
2634
2868
|
{
|
|
2635
2869
|
value: "post",
|
|
2636
|
-
label:
|
|
2870
|
+
label: j(e, "sectionUtil.kind.post")
|
|
2637
2871
|
},
|
|
2638
2872
|
{
|
|
2639
2873
|
value: "comments",
|
|
2640
|
-
label:
|
|
2874
|
+
label: j(e, "sectionUtil.kind.comments")
|
|
2641
2875
|
}
|
|
2642
2876
|
];
|
|
2643
2877
|
}
|
|
2644
|
-
function
|
|
2878
|
+
function Gr(e) {
|
|
2645
2879
|
return [{
|
|
2646
2880
|
value: "latest",
|
|
2647
|
-
label:
|
|
2881
|
+
label: j(e, "sectionUtil.sort.latest")
|
|
2648
2882
|
}, {
|
|
2649
2883
|
value: "likes",
|
|
2650
|
-
label:
|
|
2884
|
+
label: j(e, "sectionUtil.sort.likes")
|
|
2651
2885
|
}];
|
|
2652
2886
|
}
|
|
2653
|
-
var
|
|
2654
|
-
function
|
|
2887
|
+
var Kr = Wr("ko"), qr = Gr("ko");
|
|
2888
|
+
function Jr(e) {
|
|
2655
2889
|
return e === "list" ? 5 : 4;
|
|
2656
2890
|
}
|
|
2657
|
-
function
|
|
2891
|
+
function Yr(e, t) {
|
|
2658
2892
|
let n = Math.floor(Number(t));
|
|
2659
|
-
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) :
|
|
2893
|
+
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : Jr(e);
|
|
2660
2894
|
}
|
|
2661
|
-
function
|
|
2895
|
+
function Xr(e) {
|
|
2662
2896
|
return e === 12 ? null : 12 - e;
|
|
2663
2897
|
}
|
|
2664
|
-
function
|
|
2898
|
+
function Zr(e) {
|
|
2665
2899
|
return {
|
|
2666
2900
|
3: "col-span-12 md:col-span-3",
|
|
2667
2901
|
4: "col-span-12 md:col-span-4",
|
|
@@ -2673,36 +2907,36 @@ function Vr(e) {
|
|
|
2673
2907
|
12: "col-span-12"
|
|
2674
2908
|
}[e];
|
|
2675
2909
|
}
|
|
2676
|
-
function
|
|
2910
|
+
function Qr(e) {
|
|
2677
2911
|
return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
|
|
2678
2912
|
}
|
|
2679
|
-
function
|
|
2913
|
+
function $r(e) {
|
|
2680
2914
|
let t = e.boardId || e.category || "free";
|
|
2681
2915
|
return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
|
|
2682
2916
|
}
|
|
2683
|
-
function
|
|
2917
|
+
function ei(e) {
|
|
2684
2918
|
return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
|
|
2685
2919
|
}
|
|
2686
|
-
function
|
|
2920
|
+
function ti(e) {
|
|
2687
2921
|
if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
|
|
2688
2922
|
}
|
|
2689
|
-
function
|
|
2923
|
+
function ni(e) {
|
|
2690
2924
|
return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
2691
2925
|
}
|
|
2692
|
-
function
|
|
2693
|
-
return vt(e, t).trim() || yt(e, t).trim() ||
|
|
2926
|
+
function ri(e, t) {
|
|
2927
|
+
return vt(e, t).trim() || yt(e, t).trim() || j(t, "sectionUtil.untitledPost");
|
|
2694
2928
|
}
|
|
2695
|
-
function
|
|
2929
|
+
function ii(e) {
|
|
2696
2930
|
return e === "image" || e === "video" ? "media" : "list";
|
|
2697
2931
|
}
|
|
2698
|
-
function
|
|
2699
|
-
return
|
|
2932
|
+
function ai(e, t) {
|
|
2933
|
+
return j(t, ii(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
|
|
2700
2934
|
}
|
|
2701
|
-
function
|
|
2935
|
+
function oi(e, t) {
|
|
2702
2936
|
return e ? t(e)?.listView ?? "default" : "default";
|
|
2703
2937
|
}
|
|
2704
|
-
function
|
|
2705
|
-
let n = e.map((e) =>
|
|
2938
|
+
function si(e, t) {
|
|
2939
|
+
let n = e.map((e) => oi(e.boardId, t));
|
|
2706
2940
|
if (!n.length) return "default";
|
|
2707
2941
|
if (n.every((e) => e === n[0])) return n[0];
|
|
2708
2942
|
let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
|
|
@@ -2710,27 +2944,27 @@ function Zr(e, t) {
|
|
|
2710
2944
|
}
|
|
2711
2945
|
//#endregion
|
|
2712
2946
|
//#region src/composables/useMemiBoardSections.ts
|
|
2713
|
-
var
|
|
2714
|
-
function
|
|
2947
|
+
var ci = [];
|
|
2948
|
+
function li(e) {
|
|
2715
2949
|
let t = Number(e.cols);
|
|
2716
|
-
if (
|
|
2950
|
+
if (Ur.includes(t)) return t;
|
|
2717
2951
|
let n = e.width;
|
|
2718
2952
|
return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
|
|
2719
2953
|
}
|
|
2720
|
-
function
|
|
2954
|
+
function ui(e) {
|
|
2721
2955
|
let t = e.height ?? e.size;
|
|
2722
2956
|
return t === "sm" || t === "lg" ? t : "md";
|
|
2723
2957
|
}
|
|
2724
|
-
function
|
|
2958
|
+
function di(e) {
|
|
2725
2959
|
return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
|
|
2726
2960
|
}
|
|
2727
|
-
function
|
|
2961
|
+
function fi(e) {
|
|
2728
2962
|
return e.sort === "likes" ? "likes" : "latest";
|
|
2729
2963
|
}
|
|
2730
|
-
function
|
|
2964
|
+
function pi(e) {
|
|
2731
2965
|
return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
|
|
2732
2966
|
}
|
|
2733
|
-
function
|
|
2967
|
+
function mi(e, t) {
|
|
2734
2968
|
let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
|
|
2735
2969
|
for (let e of n) {
|
|
2736
2970
|
let n = String(e || "").trim();
|
|
@@ -2738,29 +2972,29 @@ function ii(e, t) {
|
|
|
2738
2972
|
}
|
|
2739
2973
|
return r;
|
|
2740
2974
|
}
|
|
2741
|
-
function
|
|
2742
|
-
return
|
|
2975
|
+
function hi(e, t) {
|
|
2976
|
+
return j(t, "sections.defaultTitle", { n: e + 1 });
|
|
2743
2977
|
}
|
|
2744
|
-
function
|
|
2745
|
-
let r =
|
|
2978
|
+
function gi(e, t, n) {
|
|
2979
|
+
let r = di(e), i = Yr(r, e.count), a = Q(e.i18n), o = ut(e.i18nSource);
|
|
2746
2980
|
return {
|
|
2747
2981
|
id: String(e.id || `box-${t + 1}`),
|
|
2748
|
-
title: String(e.title ||
|
|
2982
|
+
title: String(e.title || hi(t, n)),
|
|
2749
2983
|
showTitle: e.showTitle !== !1,
|
|
2750
2984
|
kind: r,
|
|
2751
|
-
boardId:
|
|
2985
|
+
boardId: pi(e),
|
|
2752
2986
|
count: i,
|
|
2753
|
-
postIds:
|
|
2754
|
-
sort:
|
|
2755
|
-
cols:
|
|
2756
|
-
height:
|
|
2987
|
+
postIds: mi(e, i),
|
|
2988
|
+
sort: fi(e),
|
|
2989
|
+
cols: li(e),
|
|
2990
|
+
height: ui(e),
|
|
2757
2991
|
order: t,
|
|
2758
2992
|
...a ? { i18n: a } : {},
|
|
2759
2993
|
...o ? { i18nSource: o } : {}
|
|
2760
2994
|
};
|
|
2761
2995
|
}
|
|
2762
|
-
function
|
|
2763
|
-
let { locale: e } =
|
|
2996
|
+
function _i() {
|
|
2997
|
+
let { locale: e } = M(), { translateEntries: t } = Un(), r = Z(), i = ye(r, "settings", "homeLayout"), { data: a, pending: o } = je(i), s = F(() => (Array.isArray(a.value?.blocks) ? a.value.blocks : ci).map((t, n) => gi(t, n, e.value)));
|
|
2764
2998
|
async function c(r) {
|
|
2765
2999
|
if (!n()) return r;
|
|
2766
3000
|
let i = e.value, a = r.filter((e) => {
|
|
@@ -2792,18 +3026,18 @@ function si() {
|
|
|
2792
3026
|
});
|
|
2793
3027
|
}
|
|
2794
3028
|
function l(t, n) {
|
|
2795
|
-
let r = t, i =
|
|
3029
|
+
let r = t, i = di(r), a = Yr(i, t.count), o = t.title.trim() || hi(n, e.value);
|
|
2796
3030
|
return {
|
|
2797
3031
|
id: t.id,
|
|
2798
3032
|
title: o,
|
|
2799
3033
|
showTitle: t.showTitle !== !1,
|
|
2800
3034
|
kind: i,
|
|
2801
|
-
boardId:
|
|
3035
|
+
boardId: pi(r),
|
|
2802
3036
|
count: a,
|
|
2803
|
-
postIds:
|
|
2804
|
-
sort:
|
|
2805
|
-
cols:
|
|
2806
|
-
height:
|
|
3037
|
+
postIds: mi(r, a),
|
|
3038
|
+
sort: fi(r),
|
|
3039
|
+
cols: li(r),
|
|
3040
|
+
height: ui(r),
|
|
2807
3041
|
order: n,
|
|
2808
3042
|
...t.i18n ? { i18n: t.i18n } : {},
|
|
2809
3043
|
...t.i18nSource?.title === o ? { i18nSource: t.i18nSource } : {}
|
|
@@ -2816,10 +3050,10 @@ function si() {
|
|
|
2816
3050
|
} catch (e) {
|
|
2817
3051
|
console.warn("[memi-board] section translation skipped", e);
|
|
2818
3052
|
}
|
|
2819
|
-
await
|
|
3053
|
+
await q(i, {
|
|
2820
3054
|
columns: 12,
|
|
2821
3055
|
blocks: t.map((e, t) => l(e, t)),
|
|
2822
|
-
updatedAt:
|
|
3056
|
+
updatedAt: K()
|
|
2823
3057
|
});
|
|
2824
3058
|
}
|
|
2825
3059
|
return {
|
|
@@ -2827,28 +3061,28 @@ function si() {
|
|
|
2827
3061
|
pending: o,
|
|
2828
3062
|
sections: s,
|
|
2829
3063
|
blocks: s,
|
|
2830
|
-
hasSavedLayout:
|
|
3064
|
+
hasSavedLayout: F(() => Array.isArray(a.value?.blocks)),
|
|
2831
3065
|
saveSections: u,
|
|
2832
3066
|
saveBlocks: u
|
|
2833
3067
|
};
|
|
2834
3068
|
}
|
|
2835
3069
|
//#endregion
|
|
2836
3070
|
//#region src/composables/useMemiBoardMiniPosts.ts
|
|
2837
|
-
function
|
|
2838
|
-
let n = Z(), r = () =>
|
|
2839
|
-
let i = Math.max(1, Math.floor(Number(
|
|
2840
|
-
return a && s.unshift(X("boardId", "==", a)),
|
|
3071
|
+
function vi(e, t) {
|
|
3072
|
+
let n = Z(), r = () => N(), i = R(e)?.trim() || "all", a = F(() => {
|
|
3073
|
+
let i = Math.max(1, Math.floor(Number(R(t)) || 5)), a = R(e)?.trim() || "", s = [X("isPublished", "==", !0), X("listed", "==", !0)];
|
|
3074
|
+
return a && s.unshift(X("boardId", "==", a)), G(o(n, r()), ...s, W("createdAt", "desc"), H(i));
|
|
2841
3075
|
}), { data: s, pending: c, error: l } = ke(a, { ssrKey: p(r(), `mini-list/${i}`) });
|
|
2842
3076
|
return {
|
|
2843
|
-
posts:
|
|
3077
|
+
posts: F(() => s.value ?? []),
|
|
2844
3078
|
pending: c,
|
|
2845
3079
|
error: l
|
|
2846
3080
|
};
|
|
2847
3081
|
}
|
|
2848
|
-
function
|
|
2849
|
-
let t = Z(), n = () =>
|
|
3082
|
+
function yi(e) {
|
|
3083
|
+
let t = Z(), n = () => N(), r = F(() => [...new Set(R(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = F(() => r.value.length ? G(o(t, n()), X(B(), "in", r.value)) : null), { data: s, pending: c, error: l } = ke(a, { ssrKey: p(n(), `mini-picked/${i}`) });
|
|
2850
3084
|
return {
|
|
2851
|
-
posts:
|
|
3085
|
+
posts: F(() => {
|
|
2852
3086
|
let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
|
|
2853
3087
|
for (let n of r.value) {
|
|
2854
3088
|
let r = e.get(n);
|
|
@@ -2862,7 +3096,13 @@ function li(e) {
|
|
|
2862
3096
|
}
|
|
2863
3097
|
//#endregion
|
|
2864
3098
|
//#region src/data/versionHistory.ts
|
|
2865
|
-
var
|
|
3099
|
+
var bi = [
|
|
3100
|
+
{
|
|
3101
|
+
version: "0.52.2",
|
|
3102
|
+
date: "2026-10-30",
|
|
3103
|
+
highlights: ["댓글·답글 작성 및 수정창에서도 AI로 문장을 다듬고 번역할 수 있어요", "글 자동 번역을 켜면 댓글·답글도 번역해 보는 언어에 맞춰 보여줘요"],
|
|
3104
|
+
highlightsEn: ["Use AI writing assistance and translation when writing or editing comments and replies", "Automatic post translation now also translates comments and replies for each viewer’s language"]
|
|
3105
|
+
},
|
|
2866
3106
|
{
|
|
2867
3107
|
version: "0.52.1",
|
|
2868
3108
|
date: "2026-10-30",
|
|
@@ -3397,208 +3637,17 @@ var ui = [
|
|
|
3397
3637
|
note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다.",
|
|
3398
3638
|
noteEn: "Real security requires registering the host's Firebase rules."
|
|
3399
3639
|
}
|
|
3400
|
-
]
|
|
3401
|
-
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
3402
|
-
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
3403
|
-
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
3404
|
-
summarize: "핵심 정보는 보존하면서 원문의 약 절반 길이로 간결하게 줄여라.",
|
|
3405
|
-
"translate-en": "자연스러운 영어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
3406
|
-
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
3407
|
-
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
3408
|
-
};
|
|
3409
|
-
function hi(e) {
|
|
3410
|
-
return {
|
|
3411
|
-
proofread: "Fix only spelling, spacing, and grammar errors. Do not change the meaning or tone.",
|
|
3412
|
-
polish: "Refine the text into more natural, readable sentences while keeping the meaning and the author's tone.",
|
|
3413
|
-
continue: "Continue writing one or two paragraphs that match the preceding context and tone, without exaggeration.",
|
|
3414
|
-
summarize: "Shorten the text concisely to about half of its original length while preserving the key information.",
|
|
3415
|
-
"translate-en": "Translate into natural English. Keep proper nouns and technical terms accurate.",
|
|
3416
|
-
"translate-ko": "Translate into natural Korean. Keep proper nouns and technical terms accurate.",
|
|
3417
|
-
title: `Create one concise title in ${e} that represents the body. Output only the title, without quotes or explanation.`
|
|
3418
|
-
};
|
|
3419
|
-
}
|
|
3420
|
-
function gi(e, t, n) {
|
|
3421
|
-
let r = t === "ko", i = Cn(t);
|
|
3422
|
-
if (e.action !== "custom") {
|
|
3423
|
-
if (r) return mi[e.action];
|
|
3424
|
-
let t = hi(i)[e.action];
|
|
3425
|
-
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}.`;
|
|
3426
|
-
}
|
|
3427
|
-
let a = e.customInstruction?.trim().slice(0, pi);
|
|
3428
|
-
if (!a) throw Error(n("writingAssistant.customRequired"));
|
|
3429
|
-
return r ? `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${a}` : `Rewrite the text applying the following style instruction while keeping the meaning: ${a}`;
|
|
3430
|
-
}
|
|
3431
|
-
function _i(e) {
|
|
3432
|
-
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
3433
|
-
}
|
|
3434
|
-
function vi(e) {
|
|
3435
|
-
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
3436
|
-
}
|
|
3437
|
-
function yi(e = {}) {
|
|
3438
|
-
let t = j(), n = P(() => N(L(e.locale)) ?? t.locale.value), r = (e, t) => A(n.value, e, t), i = Me(), a = Z(), o = Ae(), s = v(), { translateEntries: c, translateHtml: l, detectSourceLocale: u } = Hn();
|
|
3439
|
-
function d(e, t) {
|
|
3440
|
-
let n = vi(e.aiWritingWindowAt), r = n != null && t - n < fi, i = Math.max(0, Math.floor(Number(e.aiWritingCount) || 0)), a = Math.max(0, Math.floor(Number(e.aiWritingPending) || 0));
|
|
3441
|
-
return {
|
|
3442
|
-
active: r,
|
|
3443
|
-
windowAt: n,
|
|
3444
|
-
count: r ? i : 0,
|
|
3445
|
-
pending: r ? a : 0
|
|
3446
|
-
};
|
|
3447
|
-
}
|
|
3448
|
-
function f(e, t) {
|
|
3449
|
-
let n = e + fi, i = Math.max(1, Math.ceil((n - t) / 36e5));
|
|
3450
|
-
return Error(r("writingAssistant.dailyLimit", {
|
|
3451
|
-
limit: 10,
|
|
3452
|
-
hours: i
|
|
3453
|
-
}));
|
|
3454
|
-
}
|
|
3455
|
-
async function p(e) {
|
|
3456
|
-
let t = o.value?.uid;
|
|
3457
|
-
if (!t) throw Error(r("writingAssistant.loginRequired"));
|
|
3458
|
-
await Ee(a, async (n) => {
|
|
3459
|
-
let i = h(a, M(), t), o = await n.get(i);
|
|
3460
|
-
if (!o.exists()) throw Error(r("writingAssistant.userMissing"));
|
|
3461
|
-
let s = o.data(), c = e(d(s, Date.now()), s);
|
|
3462
|
-
c && n.update(i, {
|
|
3463
|
-
...c,
|
|
3464
|
-
updatedAt: q()
|
|
3465
|
-
});
|
|
3466
|
-
});
|
|
3467
|
-
}
|
|
3468
|
-
async function m() {
|
|
3469
|
-
await p((e) => {
|
|
3470
|
-
if (e.active && e.windowAt != null && e.count + e.pending >= 10) throw f(e.windowAt, Date.now());
|
|
3471
|
-
return e.active ? { aiWritingPending: e.pending + 1 } : {
|
|
3472
|
-
aiWritingCount: 0,
|
|
3473
|
-
aiWritingPending: 1,
|
|
3474
|
-
aiWritingWindowAt: q()
|
|
3475
|
-
};
|
|
3476
|
-
});
|
|
3477
|
-
}
|
|
3478
|
-
async function g() {
|
|
3479
|
-
await p((e) => !e.active || e.pending < 1 || e.count >= 10 ? null : {
|
|
3480
|
-
aiWritingCount: e.count + 1,
|
|
3481
|
-
aiWritingPending: e.pending - 1
|
|
3482
|
-
});
|
|
3483
|
-
}
|
|
3484
|
-
async function _() {
|
|
3485
|
-
await p((e) => !e.active || e.pending < 1 ? null : { aiWritingPending: e.pending - 1 });
|
|
3486
|
-
}
|
|
3487
|
-
async function y(e) {
|
|
3488
|
-
await m();
|
|
3489
|
-
try {
|
|
3490
|
-
let t = await e();
|
|
3491
|
-
try {
|
|
3492
|
-
await g();
|
|
3493
|
-
} catch {}
|
|
3494
|
-
return t;
|
|
3495
|
-
} catch (e) {
|
|
3496
|
-
throw await _().catch(() => {}), e;
|
|
3497
|
-
}
|
|
3498
|
-
}
|
|
3499
|
-
async function b(e) {
|
|
3500
|
-
(e.action === "translate-en" || e.action === "translate-ko") && D();
|
|
3501
|
-
let t = n.value, a = t === "ko", o = gi(e, t, r);
|
|
3502
|
-
if (!e.content.trim()) throw Error(r("writingAssistant.contentRequired"));
|
|
3503
|
-
return y(async () => {
|
|
3504
|
-
let t = s.moderation ?? {}, n = Xe(i, {
|
|
3505
|
-
backend: new Je(),
|
|
3506
|
-
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
3507
|
-
}), c = Ze(n, {
|
|
3508
|
-
model: t.model ?? "gemini-3.5-flash-lite",
|
|
3509
|
-
systemInstruction: (a ? [
|
|
3510
|
-
"너는 게시판 글쓰기 편집 도우미다.",
|
|
3511
|
-
"사용자가 요청한 편집 결과만 출력하고 설명, 인사, 마크다운 코드 펜스를 붙이지 마라.",
|
|
3512
|
-
e.action === "title" || e.selection ? "출력은 일반 텍스트로 작성하라." : "입력의 HTML 구조와 링크, 이미지 태그를 보존하고 결과도 HTML 조각으로 출력하라."
|
|
3513
|
-
] : [
|
|
3514
|
-
"You are an editing assistant for writing message board posts.",
|
|
3515
|
-
"Output only the requested edit result. Do not add explanations, greetings, or markdown code fences.",
|
|
3516
|
-
e.action === "title" || e.selection ? "Write the output as plain text." : "Preserve the HTML structure, links, and image tags of the input, and output the result as an HTML fragment as well."
|
|
3517
|
-
]).join("\n"),
|
|
3518
|
-
generationConfig: {
|
|
3519
|
-
temperature: e.action === "continue" || e.action === "title" || e.action === "custom" ? .6 : .2,
|
|
3520
|
-
maxOutputTokens: 2048
|
|
3521
|
-
}
|
|
3522
|
-
}), l = e.content.trim(), u = (a ? [
|
|
3523
|
-
`작업: ${o}`,
|
|
3524
|
-
e.title ? `현재 제목: ${e.title}` : "",
|
|
3525
|
-
`본문:\n${l.slice(0, 12e3)}`
|
|
3526
|
-
] : [
|
|
3527
|
-
`Task: ${o}`,
|
|
3528
|
-
e.title ? `Current title: ${e.title}` : "",
|
|
3529
|
-
`Body:\n${l.slice(0, 12e3)}`
|
|
3530
|
-
]).filter(Boolean).join("\n\n"), d = _i((await c.generateContent(u)).response.text());
|
|
3531
|
-
if (!d) throw Error(r("writingAssistant.emptyResult"));
|
|
3532
|
-
return d;
|
|
3533
|
-
});
|
|
3534
|
-
}
|
|
3535
|
-
async function x(e) {
|
|
3536
|
-
D();
|
|
3537
|
-
let t = e.targets?.length ? e.targets : pt(), n = e.title?.trim() ?? "", i = e.summary?.trim() ?? "", a = e.content ?? "", o = {};
|
|
3538
|
-
n && (o.title = n), i && (o.summary = i);
|
|
3539
|
-
let s = !!cn(a);
|
|
3540
|
-
if (!Object.keys(o).length && !s) throw Error(r("writingAssistant.translateEmpty"));
|
|
3541
|
-
if (s && a.length > 12e3) throw Error(r("writingAssistant.translateTooLong", {
|
|
3542
|
-
limit: Ln,
|
|
3543
|
-
count: t.length
|
|
3544
|
-
}));
|
|
3545
|
-
return y(async () => {
|
|
3546
|
-
let d = e.source ?? await u([
|
|
3547
|
-
cn(a),
|
|
3548
|
-
n,
|
|
3549
|
-
i
|
|
3550
|
-
].filter(Boolean).join("\n")), f = [...t, d], [p, m] = await Promise.all([Object.keys(o).length ? c([{
|
|
3551
|
-
id: "post",
|
|
3552
|
-
fields: o,
|
|
3553
|
-
context: "message board post title and short summary"
|
|
3554
|
-
}], {
|
|
3555
|
-
source: d,
|
|
3556
|
-
targets: t,
|
|
3557
|
-
purpose: "message board post title and short summary"
|
|
3558
|
-
}) : Promise.resolve({}), s ? l(a, {
|
|
3559
|
-
source: d,
|
|
3560
|
-
targets: t
|
|
3561
|
-
}) : Promise.resolve({})]), h = ft(d, o, p.post);
|
|
3562
|
-
if (Object.keys(o).length && !ht(h, Object.keys(o), f)) throw Error(r("writingAssistant.translateIncomplete"));
|
|
3563
|
-
let g = {
|
|
3564
|
-
i18n: h,
|
|
3565
|
-
i18nSource: {
|
|
3566
|
-
locale: d,
|
|
3567
|
-
title: n,
|
|
3568
|
-
summary: i
|
|
3569
|
-
}
|
|
3570
|
-
};
|
|
3571
|
-
if (s) {
|
|
3572
|
-
let e = {};
|
|
3573
|
-
for (let [t, n] of Object.entries(m)) {
|
|
3574
|
-
let r = N(t);
|
|
3575
|
-
r && typeof n == "string" && n.trim() && (e[r] = { content: n.trim() });
|
|
3576
|
-
}
|
|
3577
|
-
let t = ft(d, { content: a }, e);
|
|
3578
|
-
if (!ht(t, ["content"], f)) throw Error(r("writingAssistant.translateIncomplete"));
|
|
3579
|
-
g.contentI18n = t, g.contentI18nSource = {
|
|
3580
|
-
locale: d,
|
|
3581
|
-
hash: ct(a)
|
|
3582
|
-
};
|
|
3583
|
-
}
|
|
3584
|
-
return g;
|
|
3585
|
-
});
|
|
3586
|
-
}
|
|
3587
|
-
return {
|
|
3588
|
-
assist: b,
|
|
3589
|
-
translatePost: x
|
|
3590
|
-
};
|
|
3591
|
-
}
|
|
3640
|
+
];
|
|
3592
3641
|
//#endregion
|
|
3593
3642
|
//#region src/utils/renderMarkdown.ts
|
|
3594
|
-
function
|
|
3643
|
+
function xi(e) {
|
|
3595
3644
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3596
3645
|
}
|
|
3597
|
-
function
|
|
3646
|
+
function Si(e) {
|
|
3598
3647
|
let t = e;
|
|
3599
3648
|
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;
|
|
3600
3649
|
}
|
|
3601
|
-
function
|
|
3650
|
+
function Ci(e) {
|
|
3602
3651
|
if (!e?.trim()) return "";
|
|
3603
3652
|
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
|
|
3604
3653
|
function c() {
|
|
@@ -3607,7 +3656,7 @@ function Si(e) {
|
|
|
3607
3656
|
return;
|
|
3608
3657
|
}
|
|
3609
3658
|
let e = o;
|
|
3610
|
-
n.push(`<${e}>${s.map((e) => `<li>${
|
|
3659
|
+
n.push(`<${e}>${s.map((e) => `<li>${Si(e)}</li>`).join("")}</${e}>`), o = null, s = [];
|
|
3611
3660
|
}
|
|
3612
3661
|
for (; r < t.length;) {
|
|
3613
3662
|
let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
|
|
@@ -3616,7 +3665,7 @@ function Si(e) {
|
|
|
3616
3665
|
continue;
|
|
3617
3666
|
}
|
|
3618
3667
|
if (i) {
|
|
3619
|
-
a.push(
|
|
3668
|
+
a.push(xi(e)), r++;
|
|
3620
3669
|
continue;
|
|
3621
3670
|
}
|
|
3622
3671
|
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
|
|
@@ -3627,24 +3676,24 @@ function Si(e) {
|
|
|
3627
3676
|
if (u) {
|
|
3628
3677
|
c();
|
|
3629
3678
|
let e = u[1].length;
|
|
3630
|
-
n.push(`<h${e} class="font-semibold mt-4 mb-2">${xi(
|
|
3679
|
+
n.push(`<h${e} class="font-semibold mt-4 mb-2">${Si(xi(u[2]))}</h${e}>`), r++;
|
|
3631
3680
|
continue;
|
|
3632
3681
|
}
|
|
3633
3682
|
if (e.startsWith("> ")) {
|
|
3634
3683
|
c();
|
|
3635
3684
|
let e = [];
|
|
3636
|
-
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(
|
|
3637
|
-
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${
|
|
3685
|
+
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(xi((t[r] ?? "").slice(2))), r++;
|
|
3686
|
+
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Si(e.join("<br />"))}</blockquote>`);
|
|
3638
3687
|
continue;
|
|
3639
3688
|
}
|
|
3640
3689
|
let d = e.match(/^[-*+]\s+(.+)$/);
|
|
3641
3690
|
if (d) {
|
|
3642
|
-
o && o !== "ul" && c(), o = "ul", s.push(
|
|
3691
|
+
o && o !== "ul" && c(), o = "ul", s.push(xi(d[1])), r++;
|
|
3643
3692
|
continue;
|
|
3644
3693
|
}
|
|
3645
3694
|
let f = e.match(/^\d+\.\s+(.+)$/);
|
|
3646
3695
|
if (f) {
|
|
3647
|
-
o && o !== "ol" && c(), o = "ol", s.push(
|
|
3696
|
+
o && o !== "ol" && c(), o = "ol", s.push(xi(f[1])), r++;
|
|
3648
3697
|
continue;
|
|
3649
3698
|
}
|
|
3650
3699
|
if (!e.trim()) {
|
|
@@ -3656,22 +3705,22 @@ function Si(e) {
|
|
|
3656
3705
|
for (; r < t.length;) {
|
|
3657
3706
|
let e = t[r] ?? "";
|
|
3658
3707
|
if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
|
|
3659
|
-
p.push(
|
|
3708
|
+
p.push(xi(e)), r++;
|
|
3660
3709
|
}
|
|
3661
|
-
n.push(`<p class="my-2 leading-relaxed">${
|
|
3710
|
+
n.push(`<p class="my-2 leading-relaxed">${Si(p.join("<br />"))}</p>`);
|
|
3662
3711
|
}
|
|
3663
3712
|
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");
|
|
3664
3713
|
}
|
|
3665
3714
|
//#endregion
|
|
3666
3715
|
//#region src/utils/orphanCleanup.ts
|
|
3667
|
-
function
|
|
3716
|
+
function wi(e, t, n, r) {
|
|
3668
3717
|
return typeof t.postId != "string" || !t.postId || t.postId.includes("/") ? !1 : !n.has(t.postId) || e === "like" && t.target === "comment" && typeof t.commentId == "string" && !!t.commentId && !t.commentId.includes("/") && !r.has(t.commentId);
|
|
3669
3718
|
}
|
|
3670
|
-
function
|
|
3719
|
+
function Ti(e, t) {
|
|
3671
3720
|
let n = Date.parse(e);
|
|
3672
3721
|
return Number.isFinite(n) && t - n >= 864e5;
|
|
3673
3722
|
}
|
|
3674
|
-
function
|
|
3723
|
+
function Ei(e, t) {
|
|
3675
3724
|
if (!e.startsWith(`${t}/`)) return null;
|
|
3676
3725
|
let n = e.slice(t.length + 1).split("/");
|
|
3677
3726
|
if (n.some((e) => !e || e === "." || e === "..")) return null;
|
|
@@ -3681,18 +3730,18 @@ function Ti(e, t) {
|
|
|
3681
3730
|
commentId: a
|
|
3682
3731
|
} : null;
|
|
3683
3732
|
}
|
|
3684
|
-
function
|
|
3733
|
+
function Di(e, t, n) {
|
|
3685
3734
|
let r = `${t === "comment" ? n.commentsCollection : n.likesCollection}/`, i = e.startsWith(r) ? e.slice(r.length) : "";
|
|
3686
3735
|
return !!i && !i.includes("/") && i !== "." && i !== "..";
|
|
3687
3736
|
}
|
|
3688
3737
|
//#endregion
|
|
3689
3738
|
//#region src/composables/useMemiBoardCleanup.ts
|
|
3690
|
-
function
|
|
3691
|
-
let e = Z(), t = Me(), { isAdmin: n, rolePending: r } =
|
|
3739
|
+
function Oi() {
|
|
3740
|
+
let e = Z(), t = Me(), { isAdmin: n, rolePending: r } = Wt(), { t: i } = M(), a = L([]), o = L(!1), s = L(!1), c = L(""), l = L(""), u = [], d = "", f = /* @__PURE__ */ new Map();
|
|
3692
3741
|
function p() {
|
|
3693
3742
|
let e = Le(t).currentUser?.uid;
|
|
3694
3743
|
if (!e) throw Error(i("settings.noAccess"));
|
|
3695
|
-
return JSON.stringify([e,
|
|
3744
|
+
return JSON.stringify([e, N()]);
|
|
3696
3745
|
}
|
|
3697
3746
|
function m(e) {
|
|
3698
3747
|
if (h(), p() !== e) throw Error(i("settings.cleanup.contextChanged"));
|
|
@@ -3701,24 +3750,24 @@ function Di() {
|
|
|
3701
3750
|
if (!n.value || r.value || !Le(t).currentUser) throw Error(i("settings.noAccess"));
|
|
3702
3751
|
}
|
|
3703
3752
|
async function g() {
|
|
3704
|
-
let t =
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3753
|
+
let t = N(), [n, r, i] = await Promise.all([
|
|
3754
|
+
we(ge(e, t.postsCollection)),
|
|
3755
|
+
we(ge(e, t.commentsCollection)),
|
|
3756
|
+
we(ge(e, t.likesCollection))
|
|
3708
3757
|
]), a = /* @__PURE__ */ new Set();
|
|
3709
3758
|
function o(e) {
|
|
3710
3759
|
if (typeof e == "string") {
|
|
3711
3760
|
e.startsWith(`${t.postsCollection}/`) && a.add(e);
|
|
3712
|
-
let n =
|
|
3761
|
+
let n = Zt(e);
|
|
3713
3762
|
n && a.add(n);
|
|
3714
3763
|
for (let t of e.matchAll(/https?:\/\/[^\s"'<>]+/g)) {
|
|
3715
|
-
let e =
|
|
3764
|
+
let e = Zt(t[0].replace(/&/g, "&"));
|
|
3716
3765
|
e && a.add(e);
|
|
3717
3766
|
}
|
|
3718
3767
|
} else Array.isArray(e) ? e.forEach(o) : e && typeof e == "object" && Object.getPrototypeOf(e) === Object.prototype && Object.values(e).forEach(o);
|
|
3719
3768
|
}
|
|
3720
3769
|
n.docs.forEach((e) => o(e.data())), r.docs.forEach((e) => o(e.data()));
|
|
3721
|
-
for (let e of n.docs) (await
|
|
3770
|
+
for (let e of n.docs) (await we(ge(e.ref, "body"))).docs.forEach((e) => o(e.data()));
|
|
3722
3771
|
for (let e of [...a]) {
|
|
3723
3772
|
let t = e.match(/^(.*\/images\/)([^/]+)\.[^/.]+$/);
|
|
3724
3773
|
t && a.add(`${t[1]}thumbnails/${t[2]}.jpg`);
|
|
@@ -3742,7 +3791,7 @@ function Di() {
|
|
|
3742
3791
|
let r = [];
|
|
3743
3792
|
for (let [e, t] of [["comment", n.commentDocs], ["like", n.likes]]) for (let i of t) {
|
|
3744
3793
|
let t = i.data();
|
|
3745
|
-
|
|
3794
|
+
wi(e, t, n.posts, n.comments) && r.push({
|
|
3746
3795
|
kind: e,
|
|
3747
3796
|
path: i.ref.path,
|
|
3748
3797
|
postId: t.postId,
|
|
@@ -3760,12 +3809,12 @@ function Di() {
|
|
|
3760
3809
|
});
|
|
3761
3810
|
o.push(...e.prefixes);
|
|
3762
3811
|
for (let t of e.items) {
|
|
3763
|
-
let e =
|
|
3812
|
+
let e = Ei(t.fullPath, n.cfg.postsCollection);
|
|
3764
3813
|
if (!e) continue;
|
|
3765
3814
|
let { postId: i, commentId: a } = e;
|
|
3766
3815
|
if (n.referenced.has(t.fullPath) || n.posts.has(i) && (!a || n.comments.has(a))) continue;
|
|
3767
3816
|
let o = await Ue(t);
|
|
3768
|
-
|
|
3817
|
+
Ti(o.updated, Date.now()) && (f.set(t.fullPath, o.generation), r.push({
|
|
3769
3818
|
kind: "file",
|
|
3770
3819
|
path: t.fullPath,
|
|
3771
3820
|
postId: i,
|
|
@@ -3798,23 +3847,23 @@ function Di() {
|
|
|
3798
3847
|
try {
|
|
3799
3848
|
let i = !1;
|
|
3800
3849
|
if (n.kind === "file") {
|
|
3801
|
-
if (!
|
|
3850
|
+
if (!Ei(n.path, o.cfg.postsCollection)) throw Error("Invalid cleanup path");
|
|
3802
3851
|
let r = We(t), a = qe(r, n.path), [s, c, l] = await Promise.all([
|
|
3803
|
-
|
|
3804
|
-
n.commentId ?
|
|
3852
|
+
Ce(ye(e, o.cfg.postsCollection, n.postId)),
|
|
3853
|
+
n.commentId ? Ce(ye(e, o.cfg.commentsCollection, n.commentId)) : null,
|
|
3805
3854
|
Ue(a)
|
|
3806
3855
|
]);
|
|
3807
|
-
m(d), l.generation === f.get(n.path) && !o.referenced.has(n.path) &&
|
|
3856
|
+
m(d), l.generation === f.get(n.path) && !o.referenced.has(n.path) && Ti(l.updated, Date.now()) && (!s.exists() || n.commentId && !c?.exists()) && (await He(a), i = !0);
|
|
3808
3857
|
} else {
|
|
3809
3858
|
let t = n.kind;
|
|
3810
|
-
if (!
|
|
3811
|
-
i = await
|
|
3812
|
-
let i = await r.get(
|
|
3859
|
+
if (!Di(n.path, t, o.cfg)) throw Error("Invalid cleanup path");
|
|
3860
|
+
i = await De(e, async (r) => {
|
|
3861
|
+
let i = await r.get(ye(e, n.path));
|
|
3813
3862
|
if (!i.exists()) return !0;
|
|
3814
3863
|
let a = i.data();
|
|
3815
3864
|
if (typeof a.postId != "string" || !a.postId || a.postId.includes("/")) return !1;
|
|
3816
|
-
let s = await r.get(
|
|
3817
|
-
return
|
|
3865
|
+
let s = await r.get(ye(e, o.cfg.postsCollection, a.postId)), c = n.kind === "like" && a.target === "comment" && typeof a.commentId == "string" && a.commentId && !a.commentId.includes("/") ? await r.get(ye(e, o.cfg.commentsCollection, a.commentId)) : null;
|
|
3866
|
+
return wi(t, a, new Set(s.exists() ? [a.postId] : []), new Set(c?.exists() ? [a.commentId] : [])) ? (m(d), r.delete(i.ref), !0) : !1;
|
|
3818
3867
|
});
|
|
3819
3868
|
}
|
|
3820
3869
|
i ? r++ : p++, a.value = a.value.filter((e) => e.path !== n.path);
|
|
@@ -3834,16 +3883,16 @@ function Di() {
|
|
|
3834
3883
|
}
|
|
3835
3884
|
}
|
|
3836
3885
|
return {
|
|
3837
|
-
items:
|
|
3838
|
-
busy:
|
|
3839
|
-
scanned:
|
|
3840
|
-
error:
|
|
3841
|
-
result:
|
|
3886
|
+
items: he(a),
|
|
3887
|
+
busy: he(o),
|
|
3888
|
+
scanned: he(s),
|
|
3889
|
+
error: he(c),
|
|
3890
|
+
result: he(l),
|
|
3842
3891
|
scan: _,
|
|
3843
3892
|
remove: v
|
|
3844
3893
|
};
|
|
3845
3894
|
}
|
|
3846
3895
|
//#endregion
|
|
3847
|
-
export {
|
|
3896
|
+
export { lr as AUTHOR_MEMO_MAX_LENGTH, Ur as BOARD_SECTION_COLS, Kr as BOARD_SECTION_KINDS, qr as BOARD_SECTION_SORTS, Br as BOARD_USER_ROLES, wr as COMMENT_BODY_MAX_LENGTH, It as DEFAULT_BLOCK_BAN_DECAY_MS, Ft as DEFAULT_BLOCK_BAN_THRESHOLD, Wn as DEFAULT_BOARDS, Gn as DEFAULT_CATEGORIES, i as DEFAULT_COMMENTS_COLLECTION, r as DEFAULT_LIKES_COLLECTION, te as DEFAULT_MEMI_BOARD_LOCALE, m as DEFAULT_POSTS_COLLECTION, re as DEFAULT_REPORTS_COLLECTION, e as DEFAULT_SETTINGS_COLLECTION, ne as DEFAULT_USERS_COLLECTION, A as FALLBACK_MEMI_BOARD_LOCALE, Rn as HTML_MAX_CHARS, T as MEMI_BOARD_LOCALES, jr as REPORT_DETAIL_MAX_LENGTH, Mr as REPORT_REASONS, fr as WRITING_ASSISTANT_DAILY_LIMIT, $e as asHttpUrl, xt as boardCopyIsTranslated, at as boardListOgDescription, it as boardListOgTitle, rt as boardPostOgDescription, nt as boardPostOgTitle, Wr as boardSectionKinds, Gr as boardSectionSorts, p as boardSsrKey, pt as boardTranslationLocales, h as boardUserDoc, c as boardUsersCol, _n as buildPostPreview, At as canManageBoardByRole, jt as canWriteCommentByRole, Yr as clampSectionCount, d as commentDoc, g as commentsCol, fe as configureMemiBoard, ht as coversLocales, Jr as defaultSectionCount, St as displayCommentBody, bt as displayPostContent, yt as displayPostSummary, vt as displayPostTitle, _t as displayStoredField, Lt as effectiveModerationBlockCount, Xt as extractEditorImageUrls, Dt as fetchPublicListForSeo, Et as fetchPublicPostForSeo, O as formatDate, ie as formatFullDate, ue as formatRelativeDate, Bt as formatRestrictedUntilLabel, k as formatTimestampDetails, fn as hasBodyImage, dn as hasBodyText, ct as hashText, Jt as imeSafeSubmitClick, qt as imeSafeSubmitPointerDown, kt as isAssignedStaff, pn as isContentEmpty, Xn as isFirestorePermissionDenied, _ as isMemiBoardI18nEnabled, ee as isMemiBoardLocaleLoaded, n as isMemiBoardTranslationEnabled, zt as isModerationWriteRestricted, pe as likeDoc, t as likeDocId, b as likesCol, oe as loadMemiBoardLocale, gt as localizedText, kr as memiBoardCommentLikesKey, ae as memiBoardHostLocaleKey, de as memiBoardLocaleInfo, ft as mergeSourceFields, oi as miniBoardView, ti as miniCommentLink, ei as miniMoreLink, ni as miniPostImage, $r as miniPostLink, ri as miniPostTitle, si as miniPostsView, ii as miniViewGroup, ai as miniViewLabel, Rt as moderationWriteRestrictedUntilMs, ot as normalizeBasePath, gi as normalizeBoardSection, P as normalizeMemiBoardLocale, Xr as pairSectionCols, ln as plainTextFromHtml, s as postBodyDoc, y as postDoc, Qt as postNamespaceFromStoragePath, x as postStorageFolder, o as postsCol, ut as readI18nSource, Q as readLocalizedFields, Ci as renderMarkdownToHtml, u as reportDoc, se as reportDocId, Nr as reportReasonLabel, l as reportsCol, C as resolveBoardPathConfig, Ct as resolvePublicSeoDb, Zr as sectionColClass, Qr as sectionMinHeight, S as settingsCol, w as settingsDoc, E as slugify, Zt as storagePathFromDownloadUrl, un as titleFromBody, tt as toAbsoluteUrl, et as toBoardOgImageUrl, j as translate, N as useBoardPathConfig, Wt as useMemiBoardAuth, dr as useMemiBoardAuthorMemo, Un as useMemiBoardAutoTranslate, Oi as useMemiBoardCleanup, cr as useMemiBoardCommentFeed, Ar as useMemiBoardCommentLikes, Er as useMemiBoardComments, v as useMemiBoardConfig, M as useMemiBoardI18n, Or as useMemiBoardLikes, vi as useMemiBoardMiniLatest, yi as useMemiBoardMiniPicked, zr as useMemiBoardModeration, nr as useMemiBoardPost, tr as useMemiBoardPostList, Qn as useMemiBoardPosts, Dr as useMemiBoardReplies, Ir as useMemiBoardReportQueue, Pr as useMemiBoardReports, _i as useMemiBoardSections, Jn as useMemiBoardSettings, or as useMemiBoardUserComments, ir as useMemiBoardUserPosts, Hr as useMemiBoardUserProfile, Vr as useMemiBoardUsers, Lr as useMemiBoardViews, br as useMemiBoardWritingAssistant, bi as versionHistory, gn as videoListCoverUrl, hn as youtubeId };
|
|
3848
3897
|
|
|
3849
3898
|
//# sourceMappingURL=index.js.map
|