memi-board 0.52.4 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -6
- package/dist/{ar-3hd6xh6U.js → ar-DBv_xFzj.js} +3 -2
- package/dist/ar-DBv_xFzj.js.map +1 -0
- package/dist/{commentImages-4IOk2u0O.js → commentImages-t4lu_hxD.js} +130 -99
- package/dist/commentImages-t4lu_hxD.js.map +1 -0
- package/dist/composables/useMemiBoardModeration.d.ts +1 -3
- package/dist/composables/useMemiBoardPosts.d.ts +6 -0
- package/dist/{de-DXtmk-4H.js → de-DiqhMTJO.js} +3 -2
- package/dist/de-DiqhMTJO.js.map +1 -0
- package/dist/{en-CyZH4Ct1.js → en-hMF_prdm.js} +33 -3
- package/dist/en-hMF_prdm.js.map +1 -0
- package/dist/{es-BtRbHicT.js → es-RfbaViQj.js} +3 -2
- package/dist/es-RfbaViQj.js.map +1 -0
- package/dist/{fr-vnizG3rD.js → fr-BlRWQtSh.js} +3 -2
- package/dist/fr-BlRWQtSh.js.map +1 -0
- package/dist/{id-Cf8yw8n_.js → id-C0-e3Gwc.js} +3 -2
- package/dist/id-C0-e3Gwc.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1172 -1059
- package/dist/index.js.map +1 -1
- package/dist/{ja-D-Nrtjk-.js → ja-q1DilxZV.js} +3 -2
- package/dist/ja-q1DilxZV.js.map +1 -0
- package/dist/{pt-CSsshr7u.js → pt-sB9letRc.js} +3 -2
- package/dist/pt-sB9letRc.js.map +1 -0
- package/dist/runtime/components/Attachments.vue +82 -22
- package/dist/runtime/components/CategorySettings.vue +4 -0
- package/dist/runtime/components/CustomFieldEditor.vue +86 -0
- package/dist/runtime/components/Detail.vue +15 -1
- package/dist/runtime/components/Editor.vue +49 -12
- package/dist/runtime/components/Settings.vue +190 -13
- package/dist/storage.js +36 -36
- package/dist/types.d.ts +23 -1
- package/dist/utils/customFields.d.ts +33 -0
- package/dist/utils/slugify.d.ts +2 -0
- package/dist/{zh-BzrsqVN2.js → zh-Dag8WCjt.js} +3 -2
- package/dist/zh-Dag8WCjt.js.map +1 -0
- package/docs/firebase-setup.md +64 -0
- package/docs/host-integration.md +4 -0
- package/package.json +1 -1
- package/dist/ar-3hd6xh6U.js.map +0 -1
- package/dist/commentImages-4IOk2u0O.js.map +0 -1
- package/dist/de-DXtmk-4H.js.map +0 -1
- package/dist/en-CyZH4Ct1.js.map +0 -1
- package/dist/es-BtRbHicT.js.map +0 -1
- package/dist/fr-vnizG3rD.js.map +0 -1
- package/dist/id-Cf8yw8n_.js.map +0 -1
- package/dist/ja-D-Nrtjk-.js.map +0 -1
- package/dist/pt-CSsshr7u.js.map +0 -1
- package/dist/zh-BzrsqVN2.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,
|
|
2
|
-
import { computed as I, onScopeDispose as L, reactive as
|
|
3
|
-
import { collection as
|
|
4
|
-
import { useCollection as ke, useCurrentUser as Ae, useDocument as je, useFirebaseApp as Me, useFirebaseAuth as Ne, useFirestore 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, Q as g, R as _, S as v, T as y, U as b, V as x, W as S, X as C, Y as w, Z as T, _ as E, b as D, c as O, d as k, f as A, g as ee, h as j, i as M, j as te, k as ne, l as re, m as ie, o as ae, p as N, q as oe, r as se, s as ce, t as le, u as ue, v as P, w as de, x as F, y as fe, z as pe } from "./commentImages-t4lu_hxD.js";
|
|
2
|
+
import { computed as I, onScopeDispose as L, reactive as me, readonly as he, ref as R, toValue as z, watch as B } from "vue";
|
|
3
|
+
import { collection as ge, deleteDoc as _e, deleteField as V, doc as ve, documentId as H, endAt as ye, endBefore as be, getDoc as xe, getDocFromServer as Se, getDocs as U, getDocsFromServer as Ce, increment as we, limit as W, limitToLast as Te, onSnapshot as G, orderBy as K, query as q, runTransaction as Ee, serverTimestamp as J, setDoc as De, startAfter as Y, updateDoc as X, where as Z, writeBatch as Oe } from "firebase/firestore";
|
|
4
|
+
import { useCollection as ke, useCurrentUser as Ae, useDocument as je, useFirebaseApp as Me, useFirebaseAuth as Ne, useFirestore as Q } 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) {
|
|
@@ -78,11 +78,11 @@ function lt(e, t) {
|
|
|
78
78
|
let n = e?.[t];
|
|
79
79
|
return typeof n == "string" ? n.trim() : "";
|
|
80
80
|
}
|
|
81
|
-
function
|
|
81
|
+
function $(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 = D(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,19 +92,19 @@ 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 = D(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 = D(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) {
|
|
106
106
|
let r = {};
|
|
107
|
-
if (n) for (let e of
|
|
107
|
+
if (n) for (let e of P) {
|
|
108
108
|
let t = n[e.code];
|
|
109
109
|
if (!t) continue;
|
|
110
110
|
let i = {};
|
|
@@ -122,28 +122,28 @@ 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) => D(e)).filter((e) => !!e)), n = P.map((e) => e.code);
|
|
126
126
|
return t.size ? n.filter((e) => t.has(e)) : n;
|
|
127
127
|
}
|
|
128
128
|
function mt(e) {
|
|
129
129
|
if (!Array.isArray(e)) return [];
|
|
130
130
|
let t = pt({ translationLocales: e.filter((e) => typeof e == "string") });
|
|
131
|
-
return t.length ===
|
|
131
|
+
return t.length === P.length ? [] : t;
|
|
132
132
|
}
|
|
133
|
-
function ht(e, t, n =
|
|
133
|
+
function ht(e, t, n = P.map((e) => e.code)) {
|
|
134
134
|
return !e || !t.length ? !1 : n.every((n) => t.every((t) => !!lt(e[n], t)));
|
|
135
135
|
}
|
|
136
|
-
function gt(e, t, r, i
|
|
137
|
-
if (!
|
|
138
|
-
let
|
|
139
|
-
if (!
|
|
140
|
-
let
|
|
141
|
-
if (
|
|
142
|
-
if (
|
|
143
|
-
let t = lt(e?.en,
|
|
136
|
+
function gt(e, t, n, r, i) {
|
|
137
|
+
if (!de()) return r;
|
|
138
|
+
let a = D(t), o = D(i);
|
|
139
|
+
if (!a || o && a === o) return r;
|
|
140
|
+
let s = lt(e?.[a], n);
|
|
141
|
+
if (s) return s;
|
|
142
|
+
if (a !== "en" && o !== "en") {
|
|
143
|
+
let t = lt(e?.en, n);
|
|
144
144
|
if (t) return t;
|
|
145
145
|
}
|
|
146
|
-
return
|
|
146
|
+
return r;
|
|
147
147
|
}
|
|
148
148
|
function _t(e, t, n, r, i) {
|
|
149
149
|
return r ? !t || t[n] !== r ? r : gt(e, i, n, r, t.locale) : "";
|
|
@@ -169,19 +169,19 @@ function St(e, t) {
|
|
|
169
169
|
//#region src/composables/fetchPublicSeo.ts
|
|
170
170
|
function Ct() {
|
|
171
171
|
return {
|
|
172
|
-
db:
|
|
173
|
-
paths:
|
|
172
|
+
db: Q(),
|
|
173
|
+
paths: y()
|
|
174
174
|
};
|
|
175
175
|
}
|
|
176
176
|
async function wt(e, t, n) {
|
|
177
177
|
try {
|
|
178
|
-
let r = await xe(
|
|
178
|
+
let r = await xe(g(e.db, e.paths, t));
|
|
179
179
|
if (!r.exists()) return {
|
|
180
180
|
label: t,
|
|
181
181
|
description: "",
|
|
182
182
|
hidden: !1
|
|
183
183
|
};
|
|
184
|
-
let i = r.data() ?? {}, a = typeof i.label == "string" && i.label.trim() ? i.label.trim() : t, o = typeof i.description == "string" ? i.description.trim() : "", s =
|
|
184
|
+
let i = r.data() ?? {}, a = typeof i.label == "string" && i.label.trim() ? i.label.trim() : t, o = typeof i.description == "string" ? i.description.trim() : "", s = $(i.i18n), c = ut(i.i18nSource);
|
|
185
185
|
return {
|
|
186
186
|
label: _t(s, c, "label", a, n) || a,
|
|
187
187
|
description: _t(s, c, "description", o, n),
|
|
@@ -207,27 +207,27 @@ function Tt(e) {
|
|
|
207
207
|
async function Et(e, t, n, r) {
|
|
208
208
|
let i = e.trim(), a = t.trim();
|
|
209
209
|
if (!i || !a) return null;
|
|
210
|
-
let
|
|
211
|
-
|
|
212
|
-
let
|
|
213
|
-
if (
|
|
210
|
+
let o = n ?? Ct();
|
|
211
|
+
o.paths = C(o.paths), r && await ie(r);
|
|
212
|
+
let s = await wt(o, i, r);
|
|
213
|
+
if (s.hidden) return null;
|
|
214
214
|
try {
|
|
215
|
-
let e = (await
|
|
215
|
+
let e = (await U(q(u(o.db, o.paths), Z("boardId", "==", i), Z("slug", "==", a), Z("listed", "==", !0), Z("isPublished", "==", !0), W(1)))).docs[0];
|
|
216
216
|
if (!e) return null;
|
|
217
|
-
let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "",
|
|
217
|
+
let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "", c = typeof t.summary == "string" ? t.summary : "", l = $(t.i18n), d = ut(t.i18nSource), f = vt({
|
|
218
218
|
title: n,
|
|
219
|
-
i18n:
|
|
219
|
+
i18n: l,
|
|
220
220
|
i18nSource: d
|
|
221
221
|
}, r).trim();
|
|
222
222
|
return f ? {
|
|
223
223
|
id: e.id,
|
|
224
224
|
slug: typeof t.slug == "string" ? t.slug : a,
|
|
225
225
|
category: i,
|
|
226
|
-
categoryLabel:
|
|
226
|
+
categoryLabel: s.label,
|
|
227
227
|
title: f,
|
|
228
228
|
summary: yt({
|
|
229
|
-
summary:
|
|
230
|
-
i18n:
|
|
229
|
+
summary: c,
|
|
230
|
+
i18n: l,
|
|
231
231
|
i18nSource: d
|
|
232
232
|
}, r).trim().slice(0, 200),
|
|
233
233
|
previewImage: et(t.previewImage),
|
|
@@ -239,7 +239,7 @@ async function Et(e, t, n, r) {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
async function Dt(e, t, n) {
|
|
242
|
-
n && await
|
|
242
|
+
n && await ie(n);
|
|
243
243
|
let r = e?.trim() || null, i = t ?? Ct();
|
|
244
244
|
if (i.paths = C(i.paths), r) {
|
|
245
245
|
let e = await wt(i, r, n);
|
|
@@ -256,7 +256,7 @@ async function Dt(e, t, n) {
|
|
|
256
256
|
kind: "category",
|
|
257
257
|
category: r,
|
|
258
258
|
categoryLabel: e.label,
|
|
259
|
-
description: e.description ||
|
|
259
|
+
description: e.description || j(n, "seo.boardDescription", { name: e.label }),
|
|
260
260
|
ogImage: a,
|
|
261
261
|
recentTitles: t
|
|
262
262
|
};
|
|
@@ -264,8 +264,8 @@ async function Dt(e, t, n) {
|
|
|
264
264
|
return {
|
|
265
265
|
kind: "all",
|
|
266
266
|
category: null,
|
|
267
|
-
categoryLabel:
|
|
268
|
-
description:
|
|
267
|
+
categoryLabel: j(n, "seo.allCategory"),
|
|
268
|
+
description: j(n, "seo.allDescription"),
|
|
269
269
|
ogImage: null,
|
|
270
270
|
recentTitles: []
|
|
271
271
|
};
|
|
@@ -273,11 +273,11 @@ async function Dt(e, t, n) {
|
|
|
273
273
|
async function Ot(e, t, n) {
|
|
274
274
|
let r = [], i = null;
|
|
275
275
|
try {
|
|
276
|
-
let a = await
|
|
276
|
+
let a = await U(q(u(e.db, e.paths), Z("boardId", "==", t), Z("listed", "==", !0), Z("isPublished", "==", !0), K("createdAt", "desc"), W(12)));
|
|
277
277
|
for (let e of a.docs) {
|
|
278
278
|
let t = e.data() ?? {}, a = vt({
|
|
279
279
|
title: typeof t.title == "string" ? t.title : "",
|
|
280
|
-
i18n:
|
|
280
|
+
i18n: $(t.i18n),
|
|
281
281
|
i18nSource: ut(t.i18nSource)
|
|
282
282
|
}, n).trim();
|
|
283
283
|
a && r.length < 5 && r.push(a), i ||= et(t.previewImage);
|
|
@@ -337,10 +337,10 @@ function zt(e, t, n = Date.now(), r = 10, i = It) {
|
|
|
337
337
|
}
|
|
338
338
|
function Bt(e, t = Date.now(), n) {
|
|
339
339
|
let r = Math.max(0, e - t), i = Math.ceil(r / 36e5);
|
|
340
|
-
if (i <= 0) return
|
|
341
|
-
if (i < 24) return
|
|
340
|
+
if (i <= 0) return j(n, "moderationStrike.liftSoon");
|
|
341
|
+
if (i < 24) return j(n, "moderationStrike.liftInHours", { hours: i });
|
|
342
342
|
let a = Math.floor(i / 24), o = i % 24;
|
|
343
|
-
return o === 0 ?
|
|
343
|
+
return o === 0 ? j(n, "moderationStrike.liftInDays", { days: a }) : j(n, "moderationStrike.liftInDaysHours", {
|
|
344
344
|
days: a,
|
|
345
345
|
hours: o
|
|
346
346
|
});
|
|
@@ -369,191 +369,191 @@ function Ut() {
|
|
|
369
369
|
}), e[Ht];
|
|
370
370
|
}
|
|
371
371
|
function Wt() {
|
|
372
|
-
let e =
|
|
373
|
-
function
|
|
372
|
+
let e = i(), { t, locale: n } = O(), r = Ut(), o = Q(), s = Ne(), l = Ae(), { role: u, rolePending: d, rawBlockCount: f, blockAtMs: p } = r;
|
|
373
|
+
function m() {
|
|
374
374
|
let t = e.moderation?.blockBanThreshold;
|
|
375
375
|
return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
|
|
376
376
|
}
|
|
377
|
-
function
|
|
377
|
+
function h() {
|
|
378
378
|
let t = e.moderation?.blockBanDecayMs;
|
|
379
379
|
return typeof t == "number" && t > 0 ? t : It;
|
|
380
380
|
}
|
|
381
|
-
function m(e) {
|
|
382
|
-
return h(i, P(), e);
|
|
383
|
-
}
|
|
384
381
|
function g(e) {
|
|
385
|
-
|
|
382
|
+
return a(o, y(), e);
|
|
383
|
+
}
|
|
384
|
+
function _(e) {
|
|
385
|
+
if (u.value = [
|
|
386
386
|
"owner",
|
|
387
387
|
"admin",
|
|
388
388
|
"manager",
|
|
389
389
|
"staff",
|
|
390
390
|
"user"
|
|
391
391
|
].includes(String(e?.role)) ? e?.role : "user", !e) {
|
|
392
|
-
|
|
392
|
+
f.value = 0, p.value = null;
|
|
393
393
|
return;
|
|
394
394
|
}
|
|
395
|
-
|
|
395
|
+
f.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), p.value = Vt(e.moderationBlockAt);
|
|
396
396
|
}
|
|
397
|
-
async function
|
|
398
|
-
let t =
|
|
397
|
+
async function v(e) {
|
|
398
|
+
let t = g(e.uid), n = c(o, y(), e.uid), r = await xe(t);
|
|
399
399
|
if (!r.exists()) return await Promise.all([De(t, {
|
|
400
400
|
role: "user",
|
|
401
401
|
displayName: e.displayName,
|
|
402
402
|
photoURL: e.photoURL,
|
|
403
|
-
joinedAt:
|
|
404
|
-
lastVisitAt:
|
|
405
|
-
updatedAt:
|
|
406
|
-
}), De(n, { email: e.email })]),
|
|
407
|
-
let
|
|
408
|
-
|
|
409
|
-
let
|
|
410
|
-
lastVisitAt:
|
|
411
|
-
updatedAt:
|
|
403
|
+
joinedAt: J(),
|
|
404
|
+
lastVisitAt: J(),
|
|
405
|
+
updatedAt: J()
|
|
406
|
+
}), De(n, { email: e.email })]), _({ moderationBlockCount: 0 }), "user";
|
|
407
|
+
let i = r.data();
|
|
408
|
+
_(i);
|
|
409
|
+
let a = typeof i.displayName == "string" && i.displayName.trim(), s = typeof i.photoURL == "string" && i.photoURL.trim(), l = {
|
|
410
|
+
lastVisitAt: J(),
|
|
411
|
+
updatedAt: J()
|
|
412
412
|
};
|
|
413
|
-
return !
|
|
413
|
+
return !a && e.displayName && (l.displayName = e.displayName), !s && e.photoURL && (l.photoURL = e.photoURL), await Promise.all([X(t, l), De(n, { email: e.email }, { merge: !0 })]), [
|
|
414
414
|
"owner",
|
|
415
415
|
"admin",
|
|
416
416
|
"manager",
|
|
417
417
|
"staff",
|
|
418
418
|
"user"
|
|
419
|
-
].includes(String(
|
|
419
|
+
].includes(String(i.role)) ? i.role : "user";
|
|
420
420
|
}
|
|
421
|
-
async function
|
|
422
|
-
let e =
|
|
421
|
+
async function b() {
|
|
422
|
+
let e = l.value?.uid;
|
|
423
423
|
if (!e) {
|
|
424
|
-
|
|
424
|
+
_(void 0);
|
|
425
425
|
return;
|
|
426
426
|
}
|
|
427
|
-
let t = await xe(
|
|
428
|
-
|
|
427
|
+
let t = await xe(g(e));
|
|
428
|
+
_(t.exists() ? t.data() : void 0);
|
|
429
429
|
}
|
|
430
|
-
r.watchStarted || (r.watchStarted = !0, B(
|
|
431
|
-
if (
|
|
432
|
-
|
|
430
|
+
r.watchStarted || (r.watchStarted = !0, B(l, async (e) => {
|
|
431
|
+
if (d.value = !0, !e) {
|
|
432
|
+
u.value = "user", _(void 0), d.value = !1;
|
|
433
433
|
return;
|
|
434
434
|
}
|
|
435
435
|
try {
|
|
436
|
-
|
|
436
|
+
u.value = await v(e);
|
|
437
437
|
} catch (e) {
|
|
438
|
-
console.error("[memi-board] ensureUserDoc failed", e),
|
|
438
|
+
console.error("[memi-board] ensureUserDoc failed", e), u.value = "user", _(void 0);
|
|
439
439
|
} finally {
|
|
440
|
-
|
|
440
|
+
d.value = !1;
|
|
441
441
|
}
|
|
442
442
|
}, { immediate: !0 }));
|
|
443
|
-
let
|
|
444
|
-
let e =
|
|
445
|
-
return e <= 0 ? !1 : zt(
|
|
446
|
-
}),
|
|
447
|
-
let e =
|
|
443
|
+
let x = I(() => !!l.value), S = I(() => u.value === "owner"), C = I(() => u.value === "manager"), w = I(() => S.value || u.value === "admin"), T = I(() => C.value || u.value === "staff"), E = I(() => w.value || T.value), D = I(() => Lt(f.value, p.value, Date.now(), h())), k = I(() => {
|
|
444
|
+
let e = m();
|
|
445
|
+
return e <= 0 ? !1 : zt(f.value, p.value, Date.now(), e, h());
|
|
446
|
+
}), A = I(() => {
|
|
447
|
+
let e = m();
|
|
448
448
|
if (e <= 0) return null;
|
|
449
|
-
let t = Rt(
|
|
449
|
+
let t = Rt(f.value, p.value, Date.now(), e, h());
|
|
450
450
|
return t == null ? null : Bt(t, Date.now(), n.value);
|
|
451
|
-
}),
|
|
452
|
-
if (!
|
|
453
|
-
let e =
|
|
451
|
+
}), ee = I(() => {
|
|
452
|
+
if (!k.value) return null;
|
|
453
|
+
let e = A.value;
|
|
454
454
|
return e ? t("auth.writeRestrictedUntil", { until: e }) : t("auth.writeRestricted");
|
|
455
455
|
});
|
|
456
|
-
async function
|
|
457
|
-
let e =
|
|
456
|
+
async function j() {
|
|
457
|
+
let e = l.value?.uid, r = m();
|
|
458
458
|
if (!e || r <= 0) return {
|
|
459
459
|
effectiveCount: 0,
|
|
460
460
|
restricted: !1,
|
|
461
461
|
messageSuffix: ""
|
|
462
462
|
};
|
|
463
|
-
let i =
|
|
464
|
-
a.exists() ? await
|
|
463
|
+
let i = g(e), a = await xe(i);
|
|
464
|
+
a.exists() ? await X(i, {
|
|
465
465
|
moderationBlockCount: we(1),
|
|
466
|
-
moderationBlockAt:
|
|
467
|
-
updatedAt:
|
|
466
|
+
moderationBlockAt: J(),
|
|
467
|
+
updatedAt: J()
|
|
468
468
|
}) : await De(i, {
|
|
469
469
|
role: "user",
|
|
470
|
-
displayName:
|
|
470
|
+
displayName: l.value?.displayName ?? null,
|
|
471
471
|
moderationBlockCount: 1,
|
|
472
|
-
moderationBlockAt:
|
|
473
|
-
updatedAt:
|
|
472
|
+
moderationBlockAt: J(),
|
|
473
|
+
updatedAt: J()
|
|
474
474
|
});
|
|
475
|
-
let o = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1,
|
|
476
|
-
|
|
477
|
-
let
|
|
478
|
-
count:
|
|
475
|
+
let o = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, s = Date.now();
|
|
476
|
+
f.value = o, p.value = s;
|
|
477
|
+
let c = Lt(o, s, s, h()), u = zt(o, s, s, r, h()), d = t("auth.strikeSuffix", {
|
|
478
|
+
count: c,
|
|
479
479
|
threshold: r
|
|
480
480
|
});
|
|
481
|
-
if (
|
|
482
|
-
let e = Rt(o,
|
|
483
|
-
|
|
484
|
-
count:
|
|
481
|
+
if (u) {
|
|
482
|
+
let e = Rt(o, s, s, r, h()), i = e == null ? null : Bt(e, s, n.value);
|
|
483
|
+
d = i ? t("auth.strikeRestrictedUntil", {
|
|
484
|
+
count: c,
|
|
485
485
|
until: i
|
|
486
|
-
}) : t("auth.strikeRestricted", { count:
|
|
486
|
+
}) : t("auth.strikeRestricted", { count: c });
|
|
487
487
|
}
|
|
488
488
|
return {
|
|
489
|
-
effectiveCount:
|
|
490
|
-
restricted:
|
|
491
|
-
messageSuffix:
|
|
489
|
+
effectiveCount: c,
|
|
490
|
+
restricted: u,
|
|
491
|
+
messageSuffix: d
|
|
492
492
|
};
|
|
493
493
|
}
|
|
494
|
-
function
|
|
495
|
-
if (!
|
|
496
|
-
return
|
|
497
|
-
}
|
|
498
|
-
async function j() {
|
|
499
|
-
return ze(A(), new Pe());
|
|
494
|
+
function M() {
|
|
495
|
+
if (!s) throw Error(t("auth.notInitialized"));
|
|
496
|
+
return s;
|
|
500
497
|
}
|
|
501
498
|
async function te() {
|
|
499
|
+
return ze(M(), new Pe());
|
|
500
|
+
}
|
|
501
|
+
async function ne() {
|
|
502
502
|
let e = new Fe("apple.com");
|
|
503
|
-
return e.addScope("email"), e.addScope("name"), ze(
|
|
503
|
+
return e.addScope("email"), e.addScope("name"), ze(M(), e);
|
|
504
504
|
}
|
|
505
|
-
async function
|
|
506
|
-
return Re(
|
|
505
|
+
async function re(e, t) {
|
|
506
|
+
return Re(M(), e, t);
|
|
507
507
|
}
|
|
508
|
-
async function
|
|
509
|
-
let r = await Ie(
|
|
508
|
+
async function ie(e, t, n) {
|
|
509
|
+
let r = await Ie(M(), e, t);
|
|
510
510
|
return n && await Ve(r.user, { displayName: n }), r;
|
|
511
511
|
}
|
|
512
|
-
async function
|
|
513
|
-
await Be(
|
|
512
|
+
async function ae() {
|
|
513
|
+
await Be(M());
|
|
514
514
|
}
|
|
515
|
-
function
|
|
516
|
-
return At(
|
|
517
|
-
}
|
|
518
|
-
function ae(e) {
|
|
519
|
-
return s.value ? C.value ? !0 : S.value && !!e && (Pt(e)?.allowedManagerUids ?? []).includes(s.value.uid) : !1;
|
|
515
|
+
function N(e) {
|
|
516
|
+
return At(l.value?.uid, w.value, T.value, e ? Pt(e) : void 0);
|
|
520
517
|
}
|
|
521
518
|
function oe(e) {
|
|
522
|
-
return
|
|
519
|
+
return l.value ? w.value ? !0 : C.value && !!e && (Pt(e)?.allowedManagerUids ?? []).includes(l.value.uid) : !1;
|
|
523
520
|
}
|
|
524
521
|
function se(e) {
|
|
525
|
-
return
|
|
522
|
+
return x.value && (l.value?.uid === e.authorUid || N(e.boardId));
|
|
526
523
|
}
|
|
527
524
|
function ce(e) {
|
|
528
|
-
return
|
|
525
|
+
return x.value && l.value?.uid === e.authorUid;
|
|
526
|
+
}
|
|
527
|
+
function le(e) {
|
|
528
|
+
return x.value && (l.value?.uid === e.authorUid || N(e.boardId));
|
|
529
529
|
}
|
|
530
530
|
return {
|
|
531
|
-
user:
|
|
532
|
-
role:
|
|
533
|
-
isOwner:
|
|
534
|
-
isManager:
|
|
535
|
-
canConfigureBoard:
|
|
536
|
-
isSignedIn:
|
|
537
|
-
isAdmin:
|
|
538
|
-
isStaff:
|
|
539
|
-
canManageContent:
|
|
540
|
-
canManageBoard:
|
|
541
|
-
rolePending:
|
|
542
|
-
moderationBlockCount:
|
|
543
|
-
isWriteRestricted:
|
|
544
|
-
restrictedUntilLabel:
|
|
545
|
-
restrictedMessage:
|
|
546
|
-
signInWithGoogle:
|
|
547
|
-
signInWithApple:
|
|
548
|
-
signInWithEmail:
|
|
549
|
-
signUpWithEmail:
|
|
550
|
-
signOut:
|
|
551
|
-
canEdit:
|
|
552
|
-
canDelete:
|
|
553
|
-
canEditComment:
|
|
554
|
-
canDeleteComment:
|
|
555
|
-
recordContentModerationBlock:
|
|
556
|
-
refreshBoardUser:
|
|
531
|
+
user: l,
|
|
532
|
+
role: u,
|
|
533
|
+
isOwner: S,
|
|
534
|
+
isManager: C,
|
|
535
|
+
canConfigureBoard: oe,
|
|
536
|
+
isSignedIn: x,
|
|
537
|
+
isAdmin: w,
|
|
538
|
+
isStaff: T,
|
|
539
|
+
canManageContent: E,
|
|
540
|
+
canManageBoard: N,
|
|
541
|
+
rolePending: d,
|
|
542
|
+
moderationBlockCount: D,
|
|
543
|
+
isWriteRestricted: k,
|
|
544
|
+
restrictedUntilLabel: A,
|
|
545
|
+
restrictedMessage: ee,
|
|
546
|
+
signInWithGoogle: te,
|
|
547
|
+
signInWithApple: ne,
|
|
548
|
+
signInWithEmail: re,
|
|
549
|
+
signUpWithEmail: ie,
|
|
550
|
+
signOut: ae,
|
|
551
|
+
canEdit: se,
|
|
552
|
+
canDelete: se,
|
|
553
|
+
canEditComment: ce,
|
|
554
|
+
canDeleteComment: le,
|
|
555
|
+
recordContentModerationBlock: j,
|
|
556
|
+
refreshBoardUser: b
|
|
557
557
|
};
|
|
558
558
|
}
|
|
559
559
|
//#endregion
|
|
@@ -580,8 +580,8 @@ function Jt(e) {
|
|
|
580
580
|
//#endregion
|
|
581
581
|
//#region src/utils/findReadablePost.ts
|
|
582
582
|
async function Yt(e, t, n, r, i, a) {
|
|
583
|
-
let
|
|
584
|
-
return a ? (await
|
|
583
|
+
let o = [Z("boardId", "==", n), Z("slug", "==", r)];
|
|
584
|
+
return a ? (await U(q(u(e, t), ...o, W(1)))).docs[0] : (await Promise.all([U(q(u(e, t), ...o, Z("listed", "==", !0), Z("isPublished", "==", !0), W(1))), ...i ? [U(q(u(e, t), ...o, Z("authorUid", "==", i), W(1)))] : []])).flatMap((e) => e.docs)[0];
|
|
585
585
|
}
|
|
586
586
|
//#endregion
|
|
587
587
|
//#region src/utils/extractEditorImageUrls.ts
|
|
@@ -620,29 +620,29 @@ async function en(e, t) {
|
|
|
620
620
|
}
|
|
621
621
|
var tn = 450;
|
|
622
622
|
async function nn(e, t, n) {
|
|
623
|
-
return (await
|
|
623
|
+
return (await U(q(pe(e, t), Z("postId", "==", n)))).docs.flatMap((e) => le(e.data().images, `${o(t, n)}/comment-images/`));
|
|
624
624
|
}
|
|
625
625
|
async function rn(e, t) {
|
|
626
626
|
let n = [...new Set([...t].filter(Boolean))];
|
|
627
627
|
await Promise.all(n.map((t) => He(qe(e, t)).catch(() => {})));
|
|
628
628
|
}
|
|
629
629
|
async function an(e, t) {
|
|
630
|
-
let n = await
|
|
630
|
+
let n = await U(t);
|
|
631
631
|
for (let t = 0; t < n.docs.length; t += tn) {
|
|
632
632
|
let r = Oe(e);
|
|
633
633
|
n.docs.slice(t, t + tn).forEach((e) => r.delete(e.ref)), await r.commit();
|
|
634
634
|
}
|
|
635
635
|
}
|
|
636
636
|
async function on(e, t, n) {
|
|
637
|
-
await an(e,
|
|
637
|
+
await an(e, q(s(e, t), Z("postId", "==", n)));
|
|
638
638
|
}
|
|
639
639
|
async function sn(e, t, n) {
|
|
640
|
-
await an(e,
|
|
640
|
+
await an(e, q(s(e, t), Z("commentId", "==", n), Z("target", "==", "comment")));
|
|
641
641
|
}
|
|
642
642
|
async function cn(e, t, n, r) {
|
|
643
|
-
let i =
|
|
644
|
-
if (!
|
|
645
|
-
let l =
|
|
643
|
+
let i = S(e, n, r), a = b(e, n, r), [s, c] = await Promise.all([xe(i), xe(a)]);
|
|
644
|
+
if (!s.exists()) return;
|
|
645
|
+
let l = s.data(), u = c.exists() ? String(c.data().content ?? "") : "", d = await nn(e, n, r), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
|
|
646
646
|
for (let e of l.attachments ?? []) {
|
|
647
647
|
if (!e?.path) continue;
|
|
648
648
|
f.add(e.path);
|
|
@@ -660,9 +660,9 @@ async function cn(e, t, n, r) {
|
|
|
660
660
|
let a = Qt(t);
|
|
661
661
|
a && a !== r && p.add(a);
|
|
662
662
|
}
|
|
663
|
-
await en(t,
|
|
664
|
-
for (let e of p) await en(t,
|
|
665
|
-
await rn(t, d), await rn(t, f), await an(e,
|
|
663
|
+
await en(t, o(n, r));
|
|
664
|
+
for (let e of p) await en(t, o(n, e));
|
|
665
|
+
await rn(t, d), await rn(t, f), await an(e, q(pe(e, n), Z("postId", "==", r))), await on(e, n, r), await _e(a), await _e(i);
|
|
666
666
|
}
|
|
667
667
|
//#endregion
|
|
668
668
|
//#region src/utils/postBody.ts
|
|
@@ -712,45 +712,129 @@ function _n(e, t = []) {
|
|
|
712
712
|
};
|
|
713
713
|
}
|
|
714
714
|
//#endregion
|
|
715
|
+
//#region src/utils/customFields.ts
|
|
716
|
+
var vn = 8, yn = 40, bn = 80, xn = 200, Sn = /^[a-z][A-Za-z0-9_]{0,31}$/;
|
|
717
|
+
function Cn(e) {
|
|
718
|
+
return typeof e == "string" ? e.trim() : "";
|
|
719
|
+
}
|
|
720
|
+
function wn(e) {
|
|
721
|
+
return (typeof e == "string" ? e.trim() : "").slice(0, 40);
|
|
722
|
+
}
|
|
723
|
+
function Tn(e) {
|
|
724
|
+
return (typeof e == "string" ? e.trim() : "").slice(0, 80);
|
|
725
|
+
}
|
|
726
|
+
function En(e, t, n) {
|
|
727
|
+
return n ? {
|
|
728
|
+
key: e,
|
|
729
|
+
label: t,
|
|
730
|
+
placeholder: n
|
|
731
|
+
} : {
|
|
732
|
+
key: e,
|
|
733
|
+
label: t
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function Dn(e) {
|
|
737
|
+
if (!Array.isArray(e)) return [];
|
|
738
|
+
let t = /* @__PURE__ */ new Set(), n = [];
|
|
739
|
+
for (let r of e) {
|
|
740
|
+
if (!r || typeof r != "object") continue;
|
|
741
|
+
let e = r, i = Cn(e.key), a = wn(e.label);
|
|
742
|
+
if (Sn.test(i) && a && !t.has(i) && (t.add(i), n.push(En(i, a, Tn(e.placeholder))), n.length >= 8)) break;
|
|
743
|
+
}
|
|
744
|
+
return n;
|
|
745
|
+
}
|
|
746
|
+
function On(e) {
|
|
747
|
+
let t = (e ?? []).filter((e) => Cn(e?.key) || wn(e?.label) || Tn(e?.placeholder));
|
|
748
|
+
if (t.length > 8) return {
|
|
749
|
+
fields: [],
|
|
750
|
+
issue: { code: "tooMany" }
|
|
751
|
+
};
|
|
752
|
+
let n = /* @__PURE__ */ new Set(), r = [];
|
|
753
|
+
for (let e of t) {
|
|
754
|
+
let t = Cn(e.key), i = wn(e.label), a = Tn(e.placeholder);
|
|
755
|
+
if (!Sn.test(t)) return {
|
|
756
|
+
fields: [],
|
|
757
|
+
issue: { code: "invalidKey" }
|
|
758
|
+
};
|
|
759
|
+
if (n.has(t)) return {
|
|
760
|
+
fields: [],
|
|
761
|
+
issue: {
|
|
762
|
+
code: "duplicateKey",
|
|
763
|
+
key: t
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
if (!i) return {
|
|
767
|
+
fields: [],
|
|
768
|
+
issue: {
|
|
769
|
+
code: "labelRequired",
|
|
770
|
+
key: t
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
n.add(t), r.push(En(t, i, a));
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
fields: r,
|
|
777
|
+
issue: null
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function kn(e) {
|
|
781
|
+
if (!e || typeof e != "object" || Array.isArray(e)) return {};
|
|
782
|
+
let t = {};
|
|
783
|
+
for (let [n, r] of Object.entries(e)) {
|
|
784
|
+
if (!Sn.test(n) || typeof r != "string") continue;
|
|
785
|
+
let e = r.trim().slice(0, 200);
|
|
786
|
+
e && (t[n] = e);
|
|
787
|
+
}
|
|
788
|
+
return t;
|
|
789
|
+
}
|
|
790
|
+
function An(e, t) {
|
|
791
|
+
let n = {};
|
|
792
|
+
for (let r of t) {
|
|
793
|
+
let t = (e[r.key] ?? "").trim().slice(0, 200);
|
|
794
|
+
t && (n[r.key] = t);
|
|
795
|
+
}
|
|
796
|
+
return n;
|
|
797
|
+
}
|
|
798
|
+
//#endregion
|
|
715
799
|
//#region src/utils/saveBoardVisibility.ts
|
|
716
|
-
function
|
|
800
|
+
function jn(e) {
|
|
717
801
|
return e === "hidden" ? "hidden" : "public";
|
|
718
802
|
}
|
|
719
|
-
async function
|
|
803
|
+
async function Mn(e, t, n, r) {
|
|
720
804
|
let i;
|
|
721
805
|
for (;;) {
|
|
722
|
-
let a = await
|
|
806
|
+
let a = await U(q(t, Z("boardId", "==", n), K("__name__"), ...i ? [Y(i)] : [], W(400)));
|
|
723
807
|
if (a.empty) break;
|
|
724
808
|
let o = Oe(e), s = 0;
|
|
725
809
|
for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
|
|
726
810
|
if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
|
|
727
811
|
}
|
|
728
812
|
}
|
|
729
|
-
async function
|
|
730
|
-
await
|
|
813
|
+
async function Nn(e, t, n, r) {
|
|
814
|
+
await Mn(e, u(e, t), n, r), await Mn(e, pe(e, t), n, r);
|
|
731
815
|
}
|
|
732
|
-
async function
|
|
733
|
-
let i =
|
|
816
|
+
async function Pn(e, t, n, r) {
|
|
817
|
+
let i = g(e, t, n), a = jn(r.visibility);
|
|
734
818
|
await Ee(e, async (e) => {
|
|
735
819
|
let t = await e.get(i), n = t.data(), o = n?.visibilityTransition || "";
|
|
736
820
|
if (o && o !== a) throw Error("Finish the pending visibility change before changing it again.");
|
|
737
|
-
return !t.exists() || !o &&
|
|
821
|
+
return !t.exists() || !o && jn(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
|
|
738
822
|
...r,
|
|
739
|
-
visibility: a === "public" ? "public" :
|
|
823
|
+
visibility: a === "public" ? "public" : jn(n?.visibility),
|
|
740
824
|
visibilityTransition: a
|
|
741
825
|
}, { merge: !0 }), !0);
|
|
742
|
-
}) && (await
|
|
826
|
+
}) && (await Nn(e, t, n, a !== "hidden"), await Ee(e, async (e) => {
|
|
743
827
|
if ((await e.get(i)).data()?.visibilityTransition !== a) throw Error("The visibility transition changed. Reload and retry.");
|
|
744
828
|
e.update(i, {
|
|
745
829
|
visibility: a,
|
|
746
830
|
visibilityTransition: "",
|
|
747
|
-
updatedAt:
|
|
831
|
+
updatedAt: J()
|
|
748
832
|
});
|
|
749
833
|
}));
|
|
750
834
|
}
|
|
751
835
|
//#endregion
|
|
752
836
|
//#region src/utils/moderation-prompt.ts
|
|
753
|
-
var
|
|
837
|
+
var Fn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\n아래 텍스트에 욕설·비속어·성희롱·혐오·위협·스팸·도배성 광고가 있으면 반드시 거부(flagged=true)합니다.\n\nflagged=true 예:\n- 욕설/비속어: 씨발, 시발, 병신, 지랄, 좆, 개새끼, 존나, fuck, shit, bitch 등\n- 성적 모욕, 혐오 발언, 협박\n- 게시판 주제와 무관한 도배성 광고/스팸\n\nflagged=false:\n- 게시판 주제에 맞는 정상적인 글/댓글 (강한 의견이나 정당한 비판은 허용)\n\nJSON만 출력:\n{\"flagged\":boolean,\"category\":\"none\"|\"abuse\"|\"spam\"|\"adult\"|\"violence\"|\"other\",\"reason\":string}\n- flagged=true면 category를 고르고, reason은 한국어로 **무엇이 문제인지** 구체적으로 1문장\n (예: \"욕설(비속어)이 포함되어 게시할 수 없습니다.\", \"광고·스팸성 문구가 있어 게시할 수 없습니다.\")\n 욕설 단어 전체를 그대로 길게 인용하지 말고, 유형(욕설/혐오/스팸 등)을 분명히 밝힌다.\n- flagged=false면 category는 \"none\", reason은 \"\"", In = {
|
|
754
838
|
ko: "Korean",
|
|
755
839
|
en: "English",
|
|
756
840
|
ja: "Japanese",
|
|
@@ -762,12 +846,12 @@ var Sn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
|
|
|
762
846
|
ar: "Arabic",
|
|
763
847
|
id: "Indonesian"
|
|
764
848
|
};
|
|
765
|
-
function
|
|
766
|
-
let t =
|
|
849
|
+
function Ln(e) {
|
|
850
|
+
let t = In[e] ?? "English", n = fe(e).name;
|
|
767
851
|
return t === n ? t : `${t} (${n})`;
|
|
768
852
|
}
|
|
769
|
-
function
|
|
770
|
-
let t =
|
|
853
|
+
function Rn(e) {
|
|
854
|
+
let t = Ln(e);
|
|
771
855
|
return `You are a strict moderator reviewing content for a message board.
|
|
772
856
|
If the text below contains profanity, vulgar slang, sexual harassment, hate speech, threats, spam, or repetitive/flooding advertisements, you MUST reject it (flagged=true).
|
|
773
857
|
|
|
@@ -794,17 +878,17 @@ Output JSON only:
|
|
|
794
878
|
Do not quote the offensive words at length; clearly state the type (profanity/hate/spam, etc.).
|
|
795
879
|
- If flagged=false, category is "none" and reason is ""`;
|
|
796
880
|
}
|
|
797
|
-
function
|
|
798
|
-
return e === "ko" ?
|
|
881
|
+
function zn(e = "ko") {
|
|
882
|
+
return e === "ko" ? Fn : Rn(e);
|
|
799
883
|
}
|
|
800
|
-
function
|
|
884
|
+
function Bn(e, t = "ko") {
|
|
801
885
|
let n = `"""${e.slice(0, 4e3)}"""`;
|
|
802
886
|
return t === "ko" ? `심사할 텍스트:\n${n}` : `Text to review:\n${n}`;
|
|
803
887
|
}
|
|
804
|
-
function
|
|
888
|
+
function Vn(e = "ko") {
|
|
805
889
|
return e === "ko" ? "이 이미지를 심사해 주세요." : "Please review this image.";
|
|
806
890
|
}
|
|
807
|
-
var
|
|
891
|
+
var Hn = {
|
|
808
892
|
abuse: "욕설·비속어·모욕",
|
|
809
893
|
spam: "스팸·광고",
|
|
810
894
|
adult: "선정적·성인 내용",
|
|
@@ -812,21 +896,21 @@ var kn = {
|
|
|
812
896
|
other: "부적절한 내용",
|
|
813
897
|
none: ""
|
|
814
898
|
};
|
|
815
|
-
function
|
|
816
|
-
return !e || e === "none" ? "" : e in
|
|
899
|
+
function Un(e, t = "ko") {
|
|
900
|
+
return !e || e === "none" ? "" : e in Hn ? j(t, `moderationPrompt.categories.${e}`) : e;
|
|
817
901
|
}
|
|
818
|
-
function
|
|
902
|
+
function Wn(e) {
|
|
819
903
|
let t = e.locale ?? "ko";
|
|
820
904
|
if (e.via === "local" && e.localHit) {
|
|
821
905
|
let n = e.localHit.trim();
|
|
822
|
-
return n.length > 0 && n.length <= 12 ?
|
|
906
|
+
return n.length > 0 && n.length <= 12 ? j(t, "moderationPrompt.localHit", { hit: n }) : j(t, "moderationPrompt.localGeneric");
|
|
823
907
|
}
|
|
824
908
|
let n = (e.reason || "").trim();
|
|
825
909
|
if (n) return n;
|
|
826
|
-
let r = e.category ?
|
|
827
|
-
return r ?
|
|
910
|
+
let r = e.category ? Un(e.category, t) : "";
|
|
911
|
+
return r ? j(t, "moderationPrompt.categoryBlocked", { category: r }) : j(t, "moderationPrompt.genericBlocked");
|
|
828
912
|
}
|
|
829
|
-
var
|
|
913
|
+
var Gn = [
|
|
830
914
|
"씨발",
|
|
831
915
|
"시발",
|
|
832
916
|
"시이발",
|
|
@@ -852,10 +936,10 @@ var Mn = [
|
|
|
852
936
|
"bitch",
|
|
853
937
|
"asshole"
|
|
854
938
|
];
|
|
855
|
-
function
|
|
939
|
+
function Kn(e) {
|
|
856
940
|
return new RegExp(e.join("|"), "i");
|
|
857
941
|
}
|
|
858
|
-
var
|
|
942
|
+
var qn = /* @__PURE__ */ new Set([
|
|
859
943
|
"none",
|
|
860
944
|
"abuse",
|
|
861
945
|
"spam",
|
|
@@ -863,7 +947,7 @@ var Pn = /* @__PURE__ */ new Set([
|
|
|
863
947
|
"violence",
|
|
864
948
|
"other"
|
|
865
949
|
]);
|
|
866
|
-
function
|
|
950
|
+
function Jn(e) {
|
|
867
951
|
let t = e.trim();
|
|
868
952
|
if (!t) return null;
|
|
869
953
|
let n;
|
|
@@ -881,7 +965,7 @@ function Fn(e) {
|
|
|
881
965
|
if (typeof n != "object" || !n) return null;
|
|
882
966
|
let r = n;
|
|
883
967
|
if (typeof r.flagged != "boolean") return null;
|
|
884
|
-
let i = typeof r.category == "string" &&
|
|
968
|
+
let i = typeof r.category == "string" && qn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
|
|
885
969
|
return {
|
|
886
970
|
flagged: r.flagged,
|
|
887
971
|
category: i,
|
|
@@ -890,11 +974,11 @@ function Fn(e) {
|
|
|
890
974
|
}
|
|
891
975
|
//#endregion
|
|
892
976
|
//#region src/composables/useMemiBoardAutoTranslate.ts
|
|
893
|
-
var
|
|
894
|
-
function
|
|
977
|
+
var Yn = 3e4, Xn = 45e3, Zn = 12e3, Qn = 3;
|
|
978
|
+
function $n(e) {
|
|
895
979
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
896
980
|
}
|
|
897
|
-
async function
|
|
981
|
+
async function er(e, t, n) {
|
|
898
982
|
let r = Array(e.length), i = 0;
|
|
899
983
|
async function a() {
|
|
900
984
|
for (; i < e.length;) {
|
|
@@ -904,7 +988,7 @@ async function Vn(e, t, n) {
|
|
|
904
988
|
}
|
|
905
989
|
return await Promise.all(Array.from({ length: Math.min(t, e.length) }, () => a())), r;
|
|
906
990
|
}
|
|
907
|
-
function
|
|
991
|
+
function tr(e, t) {
|
|
908
992
|
return new Promise((n, r) => {
|
|
909
993
|
let i = setTimeout(() => r(/* @__PURE__ */ Error(`translation timed out after ${t / 1e3}s`)), t);
|
|
910
994
|
e.then((e) => {
|
|
@@ -914,14 +998,14 @@ function Hn(e, t) {
|
|
|
914
998
|
});
|
|
915
999
|
});
|
|
916
1000
|
}
|
|
917
|
-
function
|
|
918
|
-
let e = Me(), { moderation: t } =
|
|
1001
|
+
function nr() {
|
|
1002
|
+
let e = Me(), { moderation: t } = i();
|
|
919
1003
|
async function n(n) {
|
|
920
|
-
|
|
1004
|
+
F();
|
|
921
1005
|
let r = Xe(e, {
|
|
922
1006
|
backend: new Je(),
|
|
923
1007
|
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
924
|
-
}), i = await
|
|
1008
|
+
}), i = await tr(Ze(r, {
|
|
925
1009
|
model: t.model ?? "gemini-3.5-flash-lite",
|
|
926
1010
|
systemInstruction: [
|
|
927
1011
|
"Identify the predominant language of the supplied message-board text.",
|
|
@@ -932,9 +1016,9 @@ function Un() {
|
|
|
932
1016
|
temperature: 0,
|
|
933
1017
|
maxOutputTokens: 128,
|
|
934
1018
|
responseMimeType: "application/json",
|
|
935
|
-
responseSchema: Ye.object({ properties: { locale: Ye.enumString({ enum:
|
|
1019
|
+
responseSchema: Ye.object({ properties: { locale: Ye.enumString({ enum: P.map((e) => e.code) }) } })
|
|
936
1020
|
}
|
|
937
|
-
}).generateContent(JSON.stringify({ text: n.slice(0,
|
|
1021
|
+
}).generateContent(JSON.stringify({ text: n.slice(0, Zn) })), Yn), a = D(JSON.parse(i.response.text())?.locale);
|
|
938
1022
|
if (!a) throw Error("Could not identify the original language. Please try translating again.");
|
|
939
1023
|
return a;
|
|
940
1024
|
}
|
|
@@ -959,15 +1043,15 @@ function Un() {
|
|
|
959
1043
|
}
|
|
960
1044
|
});
|
|
961
1045
|
}
|
|
962
|
-
async function
|
|
1046
|
+
async function a(e, t, n, i) {
|
|
963
1047
|
let a = Object.keys(e.fields), o = [
|
|
964
1048
|
`Purpose: ${i}`,
|
|
965
|
-
`Source language: ${
|
|
966
|
-
`Translate into: ${n.map((e) => `${e} = ${
|
|
1049
|
+
`Source language: ${Ln(t)} (${t})`,
|
|
1050
|
+
`Translate into: ${n.map((e) => `${e} = ${Ln(e)}`).join(", ")}`,
|
|
967
1051
|
e.context ? `Context (do not translate): ${e.context}` : "",
|
|
968
1052
|
"Text (JSON):",
|
|
969
1053
|
JSON.stringify(e.fields)
|
|
970
|
-
].filter(Boolean).join("\n"), s = await
|
|
1054
|
+
].filter(Boolean).join("\n"), s = await tr(r(n, a).generateContent(o), Yn), c = JSON.parse(s.response.text()), l = {};
|
|
971
1055
|
for (let e of n) {
|
|
972
1056
|
let t = c?.[e];
|
|
973
1057
|
if (!t) continue;
|
|
@@ -980,17 +1064,17 @@ function Un() {
|
|
|
980
1064
|
}
|
|
981
1065
|
return l;
|
|
982
1066
|
}
|
|
983
|
-
async function
|
|
984
|
-
|
|
985
|
-
let n = t.source ?? "ko", r = (t.targets ??
|
|
1067
|
+
async function o(e, t = {}) {
|
|
1068
|
+
F();
|
|
1069
|
+
let n = t.source ?? "ko", r = (t.targets ?? P.map((e) => e.code)).filter((e) => e !== n), i = t.purpose ?? "website UI labels", o = e.map((e) => ({
|
|
986
1070
|
...e,
|
|
987
1071
|
fields: Object.fromEntries(Object.entries(e.fields).map(([e, t]) => [e, t.trim()]).filter(([, e]) => e))
|
|
988
1072
|
})).filter((e) => Object.keys(e.fields).length);
|
|
989
1073
|
if (!o.length || !r.length) return {};
|
|
990
|
-
let s = await Promise.all(o.map((e) =>
|
|
1074
|
+
let s = await Promise.all(o.map((e) => a(e, n, r, i)));
|
|
991
1075
|
return Object.fromEntries(o.map((e, t) => [e.id, s[t]]));
|
|
992
1076
|
}
|
|
993
|
-
function
|
|
1077
|
+
function s() {
|
|
994
1078
|
let n = Xe(e, {
|
|
995
1079
|
backend: new Je(),
|
|
996
1080
|
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
@@ -1009,32 +1093,32 @@ function Un() {
|
|
|
1009
1093
|
}
|
|
1010
1094
|
});
|
|
1011
1095
|
}
|
|
1012
|
-
async function
|
|
1013
|
-
|
|
1014
|
-
let n = t.source ?? "ko", r = (t.targets ??
|
|
1096
|
+
async function c(e, t = {}) {
|
|
1097
|
+
F();
|
|
1098
|
+
let n = t.source ?? "ko", r = (t.targets ?? P.map((e) => e.code)).filter((e) => e !== n), i = e.trim();
|
|
1015
1099
|
if (!i || !r.length) return {};
|
|
1016
|
-
if (i.length > 12e3) throw Error(`translation is limited to ${
|
|
1017
|
-
let a = await
|
|
1100
|
+
if (i.length > 12e3) throw Error(`translation is limited to ${Zn} characters`);
|
|
1101
|
+
let a = await er(r, Qn, async (e) => {
|
|
1018
1102
|
let t = [
|
|
1019
|
-
`Source language: ${
|
|
1020
|
-
`Translate into: ${e} = ${
|
|
1103
|
+
`Source language: ${Ln(n)} (${n})`,
|
|
1104
|
+
`Translate into: ${e} = ${Ln(e)}`,
|
|
1021
1105
|
"HTML:",
|
|
1022
1106
|
i
|
|
1023
|
-
].join("\n"), r =
|
|
1107
|
+
].join("\n"), r = $n((await tr(s().generateContent(t), Xn)).response.text());
|
|
1024
1108
|
if (!r) throw Error(`empty translation for ${e}`);
|
|
1025
1109
|
return [e, r];
|
|
1026
1110
|
});
|
|
1027
1111
|
return Object.fromEntries(a);
|
|
1028
1112
|
}
|
|
1029
1113
|
return {
|
|
1030
|
-
translateEntries:
|
|
1031
|
-
translateHtml:
|
|
1114
|
+
translateEntries: o,
|
|
1115
|
+
translateHtml: c,
|
|
1032
1116
|
detectSourceLocale: n
|
|
1033
1117
|
};
|
|
1034
1118
|
}
|
|
1035
1119
|
//#endregion
|
|
1036
1120
|
//#region src/composables/useMemiBoardSettings.ts
|
|
1037
|
-
var
|
|
1121
|
+
var rr = [
|
|
1038
1122
|
{
|
|
1039
1123
|
id: "free",
|
|
1040
1124
|
label: "자유",
|
|
@@ -1062,17 +1146,17 @@ var Wn = [
|
|
|
1062
1146
|
visibility: "public",
|
|
1063
1147
|
order: 2
|
|
1064
1148
|
}
|
|
1065
|
-
],
|
|
1066
|
-
function
|
|
1149
|
+
], ir = rr;
|
|
1150
|
+
function ar(e) {
|
|
1067
1151
|
return e === "hidden" ? "hidden" : "public";
|
|
1068
1152
|
}
|
|
1069
|
-
function
|
|
1153
|
+
function or(e, t, n) {
|
|
1070
1154
|
return {
|
|
1071
1155
|
id: e,
|
|
1072
1156
|
label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
|
|
1073
1157
|
order: typeof t.order == "number" ? t.order : n,
|
|
1074
1158
|
description: (typeof t.description == "string" ? t.description : "") || "",
|
|
1075
|
-
visibility:
|
|
1159
|
+
visibility: ar(t.visibility),
|
|
1076
1160
|
visibilityTransition: t.visibilityTransition === "hidden" || t.visibilityTransition === "public" ? t.visibilityTransition : void 0,
|
|
1077
1161
|
listView: t.listView ?? "default",
|
|
1078
1162
|
editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
|
|
@@ -1080,144 +1164,151 @@ function qn(e, t, n) {
|
|
|
1080
1164
|
commentWriteRole: t.commentWriteRole ?? "user",
|
|
1081
1165
|
allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : [],
|
|
1082
1166
|
allowedManagerUids: Array.isArray(t.allowedManagerUids) ? t.allowedManagerUids : [],
|
|
1083
|
-
locale:
|
|
1167
|
+
locale: D(t.locale) ?? "",
|
|
1084
1168
|
autoTranslate: t.autoTranslate === !0,
|
|
1085
1169
|
autoTranslatePosts: t.autoTranslatePosts === !0,
|
|
1086
1170
|
translationLocales: mt(t.translationLocales),
|
|
1087
|
-
|
|
1171
|
+
customFields: Dn(t.customFields),
|
|
1172
|
+
i18n: $(t.i18n),
|
|
1088
1173
|
i18nSource: ut(t.i18nSource)
|
|
1089
1174
|
};
|
|
1090
1175
|
}
|
|
1091
|
-
function
|
|
1092
|
-
let e = () =>
|
|
1093
|
-
function
|
|
1176
|
+
function sr() {
|
|
1177
|
+
let e = () => y(), t = Q(), n = Me(), { isSignedIn: r, isAdmin: i, isStaff: a, user: o } = Wt(), { t: s, locale: c } = O(), { translateEntries: l } = nr(), d = I(() => q(T(t, e()), K("order", "asc"))), { data: f, pending: p } = ke(d, { ssrKey: h(e(), "boards") }), m = I(() => f.value.map((e, t) => or(e.id, e, t))), _ = m, v = I(() => m.value.filter((e) => e.visibility !== "hidden")), b = v;
|
|
1178
|
+
function x(e, t) {
|
|
1094
1179
|
if (!e) return;
|
|
1095
|
-
let n =
|
|
1096
|
-
return n ? _t(n.i18n, n.i18nSource, "label", n.label, t ??
|
|
1180
|
+
let n = m.value.find((t) => t.id === e);
|
|
1181
|
+
return n ? _t(n.i18n, n.i18nSource, "label", n.label, t ?? c.value) || n.label : e;
|
|
1097
1182
|
}
|
|
1098
|
-
let
|
|
1183
|
+
let S = x;
|
|
1099
1184
|
function C(e, t) {
|
|
1100
1185
|
if (!e) return;
|
|
1101
|
-
let n =
|
|
1102
|
-
if (n && r) return _t(n.i18n, n.i18nSource, "description", r, t ??
|
|
1186
|
+
let n = m.value.find((t) => t.id === e), r = n?.description?.trim();
|
|
1187
|
+
if (n && r) return _t(n.i18n, n.i18nSource, "description", r, t ?? c.value) || void 0;
|
|
1103
1188
|
}
|
|
1104
|
-
let
|
|
1105
|
-
function
|
|
1106
|
-
return e ?
|
|
1189
|
+
let w = C;
|
|
1190
|
+
function E(e) {
|
|
1191
|
+
return e ? m.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
|
|
1107
1192
|
}
|
|
1108
|
-
let
|
|
1109
|
-
function O(e) {
|
|
1110
|
-
return D(e) === "hidden";
|
|
1111
|
-
}
|
|
1112
|
-
let k = O;
|
|
1193
|
+
let k = E;
|
|
1113
1194
|
function A(e) {
|
|
1114
|
-
|
|
1195
|
+
return E(e) === "hidden";
|
|
1115
1196
|
}
|
|
1116
|
-
|
|
1197
|
+
let ee = A;
|
|
1117
1198
|
function j(e) {
|
|
1118
|
-
|
|
1199
|
+
if (e) return m.value.find((t) => t.id === e);
|
|
1200
|
+
}
|
|
1201
|
+
Nt((e) => j(e));
|
|
1202
|
+
function M(e) {
|
|
1203
|
+
return At(o.value?.uid, i.value, a.value, e ? j(e) : void 0);
|
|
1119
1204
|
}
|
|
1120
|
-
let te = I(() =>
|
|
1121
|
-
function ne(e
|
|
1205
|
+
let te = I(() => m.value.filter((e) => M(e.id)));
|
|
1206
|
+
function ne(e) {
|
|
1207
|
+
return e.code === "duplicateKey" ? s("settings.customFields.duplicateKey", { key: e.key }) : e.code === "labelRequired" ? s("settings.customFields.labelRequired", { key: e.key }) : e.code === "tooMany" ? s("settings.customFields.limit") : s("settings.customFields.invalidKey");
|
|
1208
|
+
}
|
|
1209
|
+
function re(e, t) {
|
|
1210
|
+
let n = On(e.customFields);
|
|
1211
|
+
if (n.issue) throw Error(ne(n.issue));
|
|
1122
1212
|
return {
|
|
1123
1213
|
label: e.label.trim(),
|
|
1124
1214
|
description: (e.description ?? "").trim(),
|
|
1125
|
-
visibility:
|
|
1215
|
+
visibility: ar(e.visibility),
|
|
1126
1216
|
listView: e.listView ?? "default",
|
|
1127
1217
|
editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
|
|
1128
1218
|
writeRole: e.writeRole ?? "user",
|
|
1129
1219
|
commentWriteRole: e.commentWriteRole ?? "user",
|
|
1130
1220
|
allowedStaffUids: e.allowedStaffUids ?? [],
|
|
1131
1221
|
allowedManagerUids: e.allowedManagerUids ?? [],
|
|
1132
|
-
locale:
|
|
1222
|
+
locale: D(e.locale) ?? "",
|
|
1133
1223
|
autoTranslate: e.autoTranslate === !0,
|
|
1134
1224
|
autoTranslatePosts: e.autoTranslatePosts === !0,
|
|
1135
1225
|
translationLocales: mt(e.translationLocales),
|
|
1226
|
+
customFields: n.fields,
|
|
1136
1227
|
...e.i18n ? { i18n: e.i18n } : {},
|
|
1137
1228
|
...e.i18nSource ? { i18nSource: e.i18nSource } : {},
|
|
1138
1229
|
order: t,
|
|
1139
|
-
updatedAt:
|
|
1230
|
+
updatedAt: J()
|
|
1140
1231
|
};
|
|
1141
1232
|
}
|
|
1142
|
-
async function
|
|
1143
|
-
if (!
|
|
1144
|
-
let t = e.label.trim(),
|
|
1233
|
+
async function ie(e) {
|
|
1234
|
+
if (!de()) return e;
|
|
1235
|
+
let t = e.label.trim(), n = (e.description ?? "").trim();
|
|
1145
1236
|
if (!t) return e;
|
|
1146
1237
|
if (xt({
|
|
1147
1238
|
...e,
|
|
1148
1239
|
label: t,
|
|
1149
|
-
description:
|
|
1240
|
+
description: n
|
|
1150
1241
|
})) return {
|
|
1151
1242
|
...e,
|
|
1152
1243
|
label: t,
|
|
1153
|
-
description:
|
|
1244
|
+
description: n
|
|
1154
1245
|
};
|
|
1155
|
-
let
|
|
1156
|
-
|
|
1157
|
-
let
|
|
1246
|
+
let r = c.value, i = pt(e), a = { label: t };
|
|
1247
|
+
n && (a.description = n);
|
|
1248
|
+
let o = ft(r, a, (await l([{
|
|
1158
1249
|
id: e.id || "board",
|
|
1159
|
-
fields:
|
|
1250
|
+
fields: a,
|
|
1160
1251
|
context: e.id
|
|
1161
1252
|
}], {
|
|
1162
|
-
source:
|
|
1163
|
-
targets:
|
|
1253
|
+
source: r,
|
|
1254
|
+
targets: i,
|
|
1164
1255
|
purpose: "board name and short description shown in navigation and page headers"
|
|
1165
1256
|
}))[e.id || "board"]);
|
|
1166
|
-
if (!ht(
|
|
1257
|
+
if (!ht(o, Object.keys(a), [...i, r])) throw Error(s("settings.autoTranslate.failed", { count: i.length }));
|
|
1167
1258
|
return {
|
|
1168
1259
|
...e,
|
|
1169
1260
|
label: t,
|
|
1170
|
-
description:
|
|
1171
|
-
i18n:
|
|
1261
|
+
description: n,
|
|
1262
|
+
i18n: o,
|
|
1172
1263
|
i18nSource: {
|
|
1173
|
-
locale:
|
|
1264
|
+
locale: r,
|
|
1174
1265
|
label: t,
|
|
1175
|
-
description:
|
|
1266
|
+
description: n
|
|
1176
1267
|
}
|
|
1177
1268
|
};
|
|
1178
1269
|
}
|
|
1179
|
-
async function
|
|
1180
|
-
if (!
|
|
1270
|
+
async function N(n, i = n.order ?? 0) {
|
|
1271
|
+
if (!r.value) throw Error(s("boardSettings.signInRequired"));
|
|
1181
1272
|
let a = n.id.trim(), o = n.label.trim();
|
|
1182
|
-
if (!a || !o) throw Error(
|
|
1183
|
-
let
|
|
1273
|
+
if (!a || !o) throw Error(s("boardSettings.idAndNameRequired"));
|
|
1274
|
+
let c = ar(n.visibility), l = re({
|
|
1184
1275
|
...n,
|
|
1185
1276
|
label: o,
|
|
1186
|
-
visibility:
|
|
1187
|
-
},
|
|
1188
|
-
await
|
|
1189
|
-
}
|
|
1190
|
-
let
|
|
1191
|
-
async function
|
|
1192
|
-
if (!
|
|
1193
|
-
for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(
|
|
1194
|
-
for (let [t, n] of e.entries()) await
|
|
1195
|
-
}
|
|
1196
|
-
let
|
|
1197
|
-
async function
|
|
1198
|
-
if (!
|
|
1199
|
-
let a =
|
|
1200
|
-
if (!a) throw Error(
|
|
1277
|
+
visibility: c
|
|
1278
|
+
}, i);
|
|
1279
|
+
await Pn(t, e(), a, l);
|
|
1280
|
+
}
|
|
1281
|
+
let oe = N;
|
|
1282
|
+
async function se(e) {
|
|
1283
|
+
if (!r.value) throw Error(s("boardSettings.signInRequired"));
|
|
1284
|
+
for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(s("boardSettings.idAndNameRequired"));
|
|
1285
|
+
for (let [t, n] of e.entries()) await N(n, t);
|
|
1286
|
+
}
|
|
1287
|
+
let ce = se;
|
|
1288
|
+
async function le(i) {
|
|
1289
|
+
if (!r.value) throw Error(s("boardSettings.signInRequired"));
|
|
1290
|
+
let a = i.trim();
|
|
1291
|
+
if (!a) throw Error(s("boardSettings.deleteIdRequired"));
|
|
1201
1292
|
for (;;) {
|
|
1202
|
-
let
|
|
1203
|
-
if (
|
|
1204
|
-
for (let i of
|
|
1293
|
+
let r = await U(q(u(t, e()), Z("boardId", "==", a), W(25)));
|
|
1294
|
+
if (r.empty) break;
|
|
1295
|
+
for (let i of r.docs) await cn(t, We(n), e(), i.id);
|
|
1205
1296
|
}
|
|
1206
|
-
await
|
|
1297
|
+
await _e(g(t, e(), i));
|
|
1207
1298
|
}
|
|
1208
|
-
let
|
|
1209
|
-
async function
|
|
1299
|
+
let ue = le;
|
|
1300
|
+
async function P() {
|
|
1210
1301
|
return Promise.resolve();
|
|
1211
1302
|
}
|
|
1212
|
-
async function
|
|
1213
|
-
let t = e.trim();
|
|
1214
|
-
if (!t) throw Error(
|
|
1215
|
-
if (!
|
|
1216
|
-
let n =
|
|
1303
|
+
async function F(e) {
|
|
1304
|
+
let t = e.trim().slice(0, 40);
|
|
1305
|
+
if (!t) throw Error(s("boardSettings.nameRequired"));
|
|
1306
|
+
if (!r.value) throw Error(s("boardSettings.signInRequired"));
|
|
1307
|
+
let n = m.value.find((e) => e.label === t);
|
|
1217
1308
|
if (n) return n.id;
|
|
1218
|
-
let
|
|
1219
|
-
for (;
|
|
1220
|
-
return await
|
|
1309
|
+
let i = ae(t) || `board-${Date.now()}`, a = i, o = 2, c = new Set(m.value.map((e) => e.id));
|
|
1310
|
+
for (; c.has(a);) a = `${i}-${o++}`;
|
|
1311
|
+
return await N({
|
|
1221
1312
|
id: a,
|
|
1222
1313
|
label: t,
|
|
1223
1314
|
visibility: "public",
|
|
@@ -1225,91 +1316,91 @@ function Jn() {
|
|
|
1225
1316
|
editorType: "default",
|
|
1226
1317
|
writeRole: "user",
|
|
1227
1318
|
commentWriteRole: "user",
|
|
1228
|
-
order:
|
|
1319
|
+
order: m.value.length
|
|
1229
1320
|
}), a;
|
|
1230
1321
|
}
|
|
1231
1322
|
return {
|
|
1232
|
-
boards:
|
|
1323
|
+
boards: m,
|
|
1233
1324
|
publicBoards: v,
|
|
1234
|
-
boardLabel:
|
|
1325
|
+
boardLabel: x,
|
|
1235
1326
|
boardDescription: C,
|
|
1236
|
-
boardVisibility:
|
|
1237
|
-
isBoardHidden:
|
|
1238
|
-
getBoard:
|
|
1239
|
-
canManageBoard:
|
|
1327
|
+
boardVisibility: E,
|
|
1328
|
+
isBoardHidden: A,
|
|
1329
|
+
getBoard: j,
|
|
1330
|
+
canManageBoard: M,
|
|
1240
1331
|
managedBoards: te,
|
|
1241
1332
|
categories: _,
|
|
1242
|
-
publicCategories:
|
|
1243
|
-
categoryLabel:
|
|
1244
|
-
categoryDescription:
|
|
1245
|
-
categoryVisibility:
|
|
1246
|
-
isCategoryHidden:
|
|
1247
|
-
settingsPending:
|
|
1248
|
-
ensureSettings:
|
|
1249
|
-
addBoard:
|
|
1250
|
-
addCategory:
|
|
1251
|
-
saveBoard:
|
|
1252
|
-
saveCategory:
|
|
1253
|
-
translateBoard:
|
|
1254
|
-
saveBoards:
|
|
1255
|
-
saveCategories:
|
|
1256
|
-
deleteBoard:
|
|
1257
|
-
deleteCategory:
|
|
1258
|
-
DEFAULT_BOARDS:
|
|
1259
|
-
DEFAULT_CATEGORIES:
|
|
1333
|
+
publicCategories: b,
|
|
1334
|
+
categoryLabel: S,
|
|
1335
|
+
categoryDescription: w,
|
|
1336
|
+
categoryVisibility: k,
|
|
1337
|
+
isCategoryHidden: ee,
|
|
1338
|
+
settingsPending: p,
|
|
1339
|
+
ensureSettings: P,
|
|
1340
|
+
addBoard: F,
|
|
1341
|
+
addCategory: F,
|
|
1342
|
+
saveBoard: N,
|
|
1343
|
+
saveCategory: oe,
|
|
1344
|
+
translateBoard: ie,
|
|
1345
|
+
saveBoards: se,
|
|
1346
|
+
saveCategories: ce,
|
|
1347
|
+
deleteBoard: le,
|
|
1348
|
+
deleteCategory: ue,
|
|
1349
|
+
DEFAULT_BOARDS: rr,
|
|
1350
|
+
DEFAULT_CATEGORIES: ir
|
|
1260
1351
|
};
|
|
1261
1352
|
}
|
|
1262
1353
|
//#endregion
|
|
1263
1354
|
//#region src/composables/useMemiBoardPosts.ts
|
|
1264
|
-
var
|
|
1265
|
-
function
|
|
1355
|
+
var cr = /* @__PURE__ */ new Map();
|
|
1356
|
+
function lr(e) {
|
|
1266
1357
|
if (!e || typeof e != "object") return !1;
|
|
1267
1358
|
let t = "code" in e ? String(e.code) : "";
|
|
1268
1359
|
return t === "permission-denied" || t === "firestore/permission-denied";
|
|
1269
1360
|
}
|
|
1270
|
-
function
|
|
1361
|
+
function ur(e, t) {
|
|
1271
1362
|
let n = z(e)?.trim();
|
|
1272
|
-
if (!n) throw Error(
|
|
1363
|
+
if (!n) throw Error(j(t, "posts.boardIdRequired"));
|
|
1273
1364
|
return n;
|
|
1274
1365
|
}
|
|
1275
|
-
function
|
|
1276
|
-
let t =
|
|
1277
|
-
function
|
|
1366
|
+
function dr(e) {
|
|
1367
|
+
let t = Q(), n = Me(), { isBoardHidden: r, getBoard: i } = sr(), { user: a, canManageBoard: o } = Wt(), { t: s, locale: c } = O(), l = () => y(), d = () => ur(e, c.value), f = () => u(t, l()), p = (e) => S(t, l(), e), m = (e) => b(t, l(), e);
|
|
1368
|
+
function h(e, t, n) {
|
|
1278
1369
|
return {
|
|
1279
1370
|
id: e,
|
|
1280
1371
|
...t,
|
|
1281
|
-
i18n:
|
|
1372
|
+
i18n: $(t.i18n),
|
|
1282
1373
|
i18nSource: ut(t.i18nSource),
|
|
1283
1374
|
content: typeof n?.content == "string" ? n.content : "",
|
|
1284
|
-
contentI18n:
|
|
1375
|
+
contentI18n: $(n?.i18n),
|
|
1285
1376
|
contentI18nSource: dt(n?.i18nSource)
|
|
1286
1377
|
};
|
|
1287
1378
|
}
|
|
1288
|
-
function
|
|
1289
|
-
return !r(
|
|
1379
|
+
function g() {
|
|
1380
|
+
return !r(d());
|
|
1290
1381
|
}
|
|
1291
|
-
function
|
|
1292
|
-
return i(
|
|
1382
|
+
function _() {
|
|
1383
|
+
return i(d())?.editorType === "image";
|
|
1293
1384
|
}
|
|
1294
|
-
function
|
|
1295
|
-
let t =
|
|
1385
|
+
function v(e) {
|
|
1386
|
+
let t = _(), n = dn(e.content), r = fn(e.content, e.attachments);
|
|
1296
1387
|
if (t) {
|
|
1297
|
-
if (!r) throw Error(
|
|
1388
|
+
if (!r) throw Error(s("posts.photoRequired"));
|
|
1298
1389
|
return;
|
|
1299
1390
|
}
|
|
1300
|
-
if (!n && !r) throw Error(
|
|
1301
|
-
if (!e.title?.trim()) throw Error(
|
|
1391
|
+
if (!n && !r) throw Error(s("posts.bodyRequired"));
|
|
1392
|
+
if (!e.title?.trim()) throw Error(s("posts.titleRequired"));
|
|
1302
1393
|
}
|
|
1303
1394
|
function x() {
|
|
1304
|
-
return ve(
|
|
1395
|
+
return ve(f()).id;
|
|
1305
1396
|
}
|
|
1306
|
-
function
|
|
1307
|
-
return Yt(t,
|
|
1397
|
+
function C(e) {
|
|
1398
|
+
return Yt(t, l(), d(), e, a.value?.uid, o(d()));
|
|
1308
1399
|
}
|
|
1309
|
-
async function
|
|
1310
|
-
let t = e.pageSize ?? 20, n = [
|
|
1311
|
-
e.publicOnly !== !1 && n.push(
|
|
1312
|
-
let r = await
|
|
1400
|
+
async function w(e = {}) {
|
|
1401
|
+
let t = e.pageSize ?? 20, n = [Z("boardId", "==", d()), Z("isPublished", "==", !0)];
|
|
1402
|
+
e.publicOnly !== !1 && n.push(Z("listed", "==", !0)), n.push(K("createdAt", "desc")), e.cursor && n.push(Y(e.cursor)), n.push(W(t + 1));
|
|
1403
|
+
let r = await U(q(f(), ...n)), i = r.docs.slice(0, t);
|
|
1313
1404
|
return {
|
|
1314
1405
|
posts: i.map((e) => ({
|
|
1315
1406
|
id: e.id,
|
|
@@ -1319,67 +1410,67 @@ function Qn(e) {
|
|
|
1319
1410
|
hasMore: r.docs.length > t
|
|
1320
1411
|
};
|
|
1321
1412
|
}
|
|
1322
|
-
async function w(e) {
|
|
1323
|
-
let [t, n] = await Promise.all([xe(m(e)), xe(h(e))]);
|
|
1324
|
-
return t.exists() ? g(t.id, t.data(), n.exists() ? n.data() : void 0) : null;
|
|
1325
|
-
}
|
|
1326
1413
|
async function T(e) {
|
|
1414
|
+
let [t, n] = await Promise.all([xe(p(e)), xe(m(e))]);
|
|
1415
|
+
return t.exists() ? h(t.id, t.data(), n.exists() ? n.data() : void 0) : null;
|
|
1416
|
+
}
|
|
1417
|
+
async function E(e) {
|
|
1327
1418
|
try {
|
|
1328
|
-
let t = await
|
|
1419
|
+
let t = await C(e.trim());
|
|
1329
1420
|
if (!t) return { status: "not-found" };
|
|
1330
1421
|
try {
|
|
1331
|
-
let e = await
|
|
1422
|
+
let e = await T(t.id);
|
|
1332
1423
|
return e ? {
|
|
1333
1424
|
status: "ok",
|
|
1334
1425
|
post: e
|
|
1335
1426
|
} : { status: "not-found" };
|
|
1336
1427
|
} catch (e) {
|
|
1337
|
-
return
|
|
1428
|
+
return lr(e) ? { status: "permission-denied" } : {
|
|
1338
1429
|
status: "error",
|
|
1339
1430
|
message: e instanceof Error ? e.message : String(e)
|
|
1340
1431
|
};
|
|
1341
1432
|
}
|
|
1342
1433
|
} catch (e) {
|
|
1343
|
-
return
|
|
1434
|
+
return lr(e) ? { status: "permission-denied" } : {
|
|
1344
1435
|
status: "error",
|
|
1345
1436
|
message: e instanceof Error ? e.message : String(e)
|
|
1346
1437
|
};
|
|
1347
1438
|
}
|
|
1348
1439
|
}
|
|
1349
|
-
async function
|
|
1350
|
-
let t = e.trim(), n =
|
|
1440
|
+
async function D(e) {
|
|
1441
|
+
let t = e.trim(), n = cr.get(`${d()}/${t}`);
|
|
1351
1442
|
if (n) return {
|
|
1352
1443
|
status: "ok",
|
|
1353
1444
|
id: n
|
|
1354
1445
|
};
|
|
1355
1446
|
try {
|
|
1356
|
-
let e = await
|
|
1447
|
+
let e = await C(t);
|
|
1357
1448
|
return e ? {
|
|
1358
1449
|
status: "ok",
|
|
1359
1450
|
id: e.id
|
|
1360
|
-
} : { status: r(
|
|
1451
|
+
} : { status: r(d()) ? "permission-denied" : "not-found" };
|
|
1361
1452
|
} catch (e) {
|
|
1362
|
-
return
|
|
1453
|
+
return lr(e) ? { status: "permission-denied" } : {
|
|
1363
1454
|
status: "error",
|
|
1364
1455
|
message: e instanceof Error ? e.message : String(e)
|
|
1365
1456
|
};
|
|
1366
1457
|
}
|
|
1367
1458
|
}
|
|
1368
|
-
async function O(e) {
|
|
1369
|
-
return `${E(e.trim()) || "post"}-${x()}`;
|
|
1370
|
-
}
|
|
1371
1459
|
async function k(e) {
|
|
1460
|
+
return `${ae(e.trim()) || "post"}-${x()}`;
|
|
1461
|
+
}
|
|
1462
|
+
async function A(e) {
|
|
1372
1463
|
if (!e.createdAt) return {
|
|
1373
1464
|
previous: null,
|
|
1374
1465
|
next: null
|
|
1375
1466
|
};
|
|
1376
1467
|
try {
|
|
1377
1468
|
let t = [
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
...e.listed === !1 ? [] : [
|
|
1381
|
-
|
|
1382
|
-
], [n, r] = await Promise.all([
|
|
1469
|
+
Z("boardId", "==", d()),
|
|
1470
|
+
Z("isPublished", "==", !0),
|
|
1471
|
+
...e.listed === !1 ? [] : [Z("listed", "==", !0)],
|
|
1472
|
+
K("createdAt", "desc")
|
|
1473
|
+
], [n, r] = await Promise.all([U(q(f(), ...t, Y(e.createdAt), W(1))), U(q(f(), ...t, be(e.createdAt), Te(1)))]), i = (e) => {
|
|
1383
1474
|
let t = e.docs[0];
|
|
1384
1475
|
return t ? {
|
|
1385
1476
|
id: t.id,
|
|
@@ -1397,13 +1488,13 @@ function Qn(e) {
|
|
|
1397
1488
|
};
|
|
1398
1489
|
}
|
|
1399
1490
|
}
|
|
1400
|
-
async function
|
|
1401
|
-
|
|
1402
|
-
let n = e.postId || x(), r =
|
|
1403
|
-
r ? (i = n, a = un(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await
|
|
1404
|
-
let o = _n(e.content, e.attachments), s =
|
|
1405
|
-
return c.set(
|
|
1406
|
-
boardId:
|
|
1491
|
+
async function ee(e) {
|
|
1492
|
+
v(e);
|
|
1493
|
+
let n = e.postId || x(), r = _(), i, a;
|
|
1494
|
+
r ? (i = n, a = un(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await k(a));
|
|
1495
|
+
let o = _n(e.content, e.attachments), s = g(), c = Oe(t);
|
|
1496
|
+
return c.set(p(n), {
|
|
1497
|
+
boardId: d(),
|
|
1407
1498
|
slug: i,
|
|
1408
1499
|
title: a,
|
|
1409
1500
|
...o,
|
|
@@ -1419,127 +1510,129 @@ function Qn(e) {
|
|
|
1419
1510
|
authorPhoto: e.authorPhoto,
|
|
1420
1511
|
moderationStatus: "approved",
|
|
1421
1512
|
moderationModel: e.moderationModel ?? null,
|
|
1422
|
-
createdAt:
|
|
1423
|
-
updatedAt:
|
|
1513
|
+
createdAt: J(),
|
|
1514
|
+
updatedAt: J(),
|
|
1424
1515
|
...e.translations ? {
|
|
1425
1516
|
i18n: e.translations.i18n,
|
|
1426
1517
|
i18nSource: e.translations.i18nSource
|
|
1427
|
-
} : {}
|
|
1428
|
-
|
|
1518
|
+
} : {},
|
|
1519
|
+
...e.extend && Object.keys(e.extend).length ? { extend: kn(e.extend) } : {}
|
|
1520
|
+
}), c.set(m(n), {
|
|
1429
1521
|
content: e.content,
|
|
1430
1522
|
...e.translations?.contentI18n ? {
|
|
1431
1523
|
i18n: e.translations.contentI18n,
|
|
1432
1524
|
i18nSource: e.translations.contentI18nSource
|
|
1433
1525
|
} : {}
|
|
1434
|
-
}), await c.commit(),
|
|
1526
|
+
}), await c.commit(), cr.set(`${d()}/${i}`, n), i;
|
|
1435
1527
|
}
|
|
1436
1528
|
async function j(e, t) {
|
|
1437
|
-
|
|
1438
|
-
let n =
|
|
1439
|
-
await Promise.all([
|
|
1529
|
+
v(t);
|
|
1530
|
+
let n = _() ? un(t.content) : t.title.trim(), r = _n(t.content, t.attachments), i = g(), a = t.extend ? kn(t.extend) : void 0;
|
|
1531
|
+
await Promise.all([X(p(e), {
|
|
1440
1532
|
title: n,
|
|
1441
1533
|
...r,
|
|
1442
|
-
previewImage: r.previewImage ? r.previewImage :
|
|
1443
|
-
videoUrl: r.videoUrl ? r.videoUrl :
|
|
1534
|
+
previewImage: r.previewImage ? r.previewImage : V(),
|
|
1535
|
+
videoUrl: r.videoUrl ? r.videoUrl : V(),
|
|
1444
1536
|
tags: t.tags ?? [],
|
|
1445
1537
|
listed: i,
|
|
1446
1538
|
attachments: t.attachments ?? [],
|
|
1447
|
-
updatedAt:
|
|
1539
|
+
updatedAt: J(),
|
|
1448
1540
|
...t.translations ? {
|
|
1449
1541
|
i18n: t.translations.i18n,
|
|
1450
1542
|
i18nSource: t.translations.i18nSource
|
|
1451
|
-
} : {}
|
|
1452
|
-
|
|
1543
|
+
} : {},
|
|
1544
|
+
...a ? { extend: Object.keys(a).length ? a : V() } : {}
|
|
1545
|
+
}), De(m(e), {
|
|
1453
1546
|
content: t.content,
|
|
1454
1547
|
...t.translations ? t.translations.contentI18n ? {
|
|
1455
1548
|
i18n: t.translations.contentI18n,
|
|
1456
1549
|
i18nSource: t.translations.contentI18nSource
|
|
1457
1550
|
} : {
|
|
1458
|
-
i18n:
|
|
1459
|
-
i18nSource:
|
|
1551
|
+
i18n: V(),
|
|
1552
|
+
i18nSource: V()
|
|
1460
1553
|
} : {}
|
|
1461
1554
|
}, { merge: !0 })]);
|
|
1462
1555
|
}
|
|
1463
|
-
async function
|
|
1464
|
-
|
|
1556
|
+
async function M(e, t) {
|
|
1557
|
+
F(), await Promise.all([X(p(e), {
|
|
1465
1558
|
i18n: t.i18n,
|
|
1466
1559
|
i18nSource: t.i18nSource,
|
|
1467
|
-
updatedAt:
|
|
1468
|
-
}), De(
|
|
1560
|
+
updatedAt: J()
|
|
1561
|
+
}), De(m(e), t.contentI18n ? {
|
|
1469
1562
|
i18n: t.contentI18n,
|
|
1470
1563
|
i18nSource: t.contentI18nSource
|
|
1471
1564
|
} : {
|
|
1472
|
-
i18n:
|
|
1473
|
-
i18nSource:
|
|
1565
|
+
i18n: V(),
|
|
1566
|
+
i18nSource: V()
|
|
1474
1567
|
}, { merge: !0 })]);
|
|
1475
1568
|
}
|
|
1476
|
-
async function
|
|
1477
|
-
await
|
|
1569
|
+
async function te(e) {
|
|
1570
|
+
await X(p(e), {
|
|
1478
1571
|
isPublished: !0,
|
|
1479
|
-
publishedAt:
|
|
1480
|
-
updatedAt:
|
|
1572
|
+
publishedAt: J(),
|
|
1573
|
+
updatedAt: J()
|
|
1481
1574
|
});
|
|
1482
1575
|
}
|
|
1483
|
-
async function
|
|
1484
|
-
await
|
|
1576
|
+
async function ne(e, t) {
|
|
1577
|
+
await X(p(e), t ? {
|
|
1485
1578
|
pinned: !0,
|
|
1486
|
-
pinnedAt:
|
|
1579
|
+
pinnedAt: J()
|
|
1487
1580
|
} : {
|
|
1488
|
-
pinned:
|
|
1489
|
-
pinnedAt:
|
|
1581
|
+
pinned: V(),
|
|
1582
|
+
pinnedAt: V()
|
|
1490
1583
|
});
|
|
1491
1584
|
}
|
|
1492
|
-
async function
|
|
1493
|
-
await cn(t, We(n),
|
|
1494
|
-
for (let [t, n] of
|
|
1585
|
+
async function re(e) {
|
|
1586
|
+
await cn(t, We(n), l(), e);
|
|
1587
|
+
for (let [t, n] of cr) n === e && cr.delete(t);
|
|
1495
1588
|
}
|
|
1496
1589
|
return {
|
|
1497
1590
|
createPostId: x,
|
|
1498
|
-
getPosts:
|
|
1499
|
-
getPost:
|
|
1500
|
-
getPostBySlug:
|
|
1501
|
-
resolvePostIdBySlug:
|
|
1502
|
-
resolveUniqueSlug:
|
|
1503
|
-
getAdjacentPosts:
|
|
1504
|
-
createPost:
|
|
1591
|
+
getPosts: w,
|
|
1592
|
+
getPost: T,
|
|
1593
|
+
getPostBySlug: E,
|
|
1594
|
+
resolvePostIdBySlug: D,
|
|
1595
|
+
resolveUniqueSlug: k,
|
|
1596
|
+
getAdjacentPosts: A,
|
|
1597
|
+
createPost: ee,
|
|
1505
1598
|
updatePost: j,
|
|
1506
|
-
savePostTranslations:
|
|
1507
|
-
publishPost:
|
|
1508
|
-
setPostPinned:
|
|
1509
|
-
deletePost:
|
|
1599
|
+
savePostTranslations: M,
|
|
1600
|
+
publishPost: te,
|
|
1601
|
+
setPostPinned: ne,
|
|
1602
|
+
deletePost: re
|
|
1510
1603
|
};
|
|
1511
1604
|
}
|
|
1512
|
-
var
|
|
1513
|
-
function
|
|
1514
|
-
let n =
|
|
1515
|
-
function
|
|
1605
|
+
var fr = 10, pr = 10;
|
|
1606
|
+
function mr(e, t = {}) {
|
|
1607
|
+
let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = Wt(), o = () => y(), s = t.pageSize ?? fr, c = I(() => i.value?.uid ?? ""), l = I(() => ur(e)), d = () => u(n, o()), f = I(() => t.publicOnly === void 0 ? !(r.value || a(l.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = R([]), m = R([]), h = R([]), g = R([]), _ = R(!0), v = R(!0), b = R(!0), x = R(!1), S = R(""), C = null, w = null, T, E, D;
|
|
1608
|
+
function O(e) {
|
|
1516
1609
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1517
1610
|
}
|
|
1518
|
-
let
|
|
1611
|
+
let k = I(() => {
|
|
1519
1612
|
let e = new Set(g.value.map((e) => e.id)), t = /* @__PURE__ */ new Map();
|
|
1520
1613
|
for (let n of [
|
|
1521
1614
|
...m.value,
|
|
1522
1615
|
...p.value,
|
|
1523
1616
|
...h.value
|
|
1524
1617
|
]) n.id && !e.has(n.id) && t.set(n.id, n);
|
|
1525
|
-
return [...t.values()].sort((e, t) =>
|
|
1618
|
+
return [...t.values()].sort((e, t) => O(t) - O(e) || String(t.id).localeCompare(String(e.id)));
|
|
1526
1619
|
});
|
|
1527
|
-
function
|
|
1528
|
-
let e = [
|
|
1529
|
-
return f.value && e.push(
|
|
1620
|
+
function A() {
|
|
1621
|
+
let e = [Z("boardId", "==", l.value), Z("isPublished", "==", !0)];
|
|
1622
|
+
return f.value && e.push(Z("listed", "==", !0)), e;
|
|
1530
1623
|
}
|
|
1531
|
-
function
|
|
1532
|
-
|
|
1624
|
+
function ee() {
|
|
1625
|
+
T?.(), T = G(q(d(), ...A(), K("createdAt", "desc"), K(H(), "desc"), W(s)), (e) => {
|
|
1533
1626
|
p.value = e.docs.map((e) => ({
|
|
1534
1627
|
id: e.id,
|
|
1535
1628
|
...e.data()
|
|
1536
|
-
})),
|
|
1629
|
+
})), C = e.docs.at(-1) ?? null, w || (b.value = e.docs.length >= s), v.value = !1;
|
|
1537
1630
|
}, (e) => {
|
|
1538
|
-
console.error("[memi-board:postList] onSnapshot failed", e),
|
|
1631
|
+
console.error("[memi-board:postList] onSnapshot failed", e), S.value = e.message || String(e), v.value = !1;
|
|
1539
1632
|
});
|
|
1540
1633
|
}
|
|
1541
|
-
function
|
|
1542
|
-
|
|
1634
|
+
function j() {
|
|
1635
|
+
D?.(), D = G(q(d(), ...A(), Z("pinned", "==", !0), K("pinnedAt", "desc"), W(pr)), (e) => {
|
|
1543
1636
|
g.value = e.docs.map((e) => ({
|
|
1544
1637
|
id: e.id,
|
|
1545
1638
|
...e.data()
|
|
@@ -1548,14 +1641,14 @@ function tr(e, t = {}) {
|
|
|
1548
1641
|
console.error("[memi-board:postList] notice onSnapshot failed", e), g.value = [], _.value = !1;
|
|
1549
1642
|
});
|
|
1550
1643
|
}
|
|
1551
|
-
function
|
|
1552
|
-
|
|
1553
|
-
let e =
|
|
1644
|
+
function M() {
|
|
1645
|
+
E?.();
|
|
1646
|
+
let e = c.value;
|
|
1554
1647
|
if (!e) {
|
|
1555
1648
|
h.value = [];
|
|
1556
1649
|
return;
|
|
1557
1650
|
}
|
|
1558
|
-
|
|
1651
|
+
E = G(q(d(), Z("boardId", "==", l.value), Z("authorUid", "==", e), Z("isPublished", "==", !1), K("createdAt", "desc"), W(20)), (e) => {
|
|
1559
1652
|
h.value = e.docs.map((e) => ({
|
|
1560
1653
|
id: e.id,
|
|
1561
1654
|
...e.data()
|
|
@@ -1565,70 +1658,70 @@ function tr(e, t = {}) {
|
|
|
1565
1658
|
});
|
|
1566
1659
|
}
|
|
1567
1660
|
async function te() {
|
|
1568
|
-
if (!(
|
|
1569
|
-
|
|
1661
|
+
if (!(x.value || !b.value || v.value)) {
|
|
1662
|
+
x.value = !0, S.value = "";
|
|
1570
1663
|
try {
|
|
1571
|
-
let e =
|
|
1572
|
-
...
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
...e ? [
|
|
1576
|
-
|
|
1577
|
-
], n = await
|
|
1664
|
+
let e = w ?? C, t = [
|
|
1665
|
+
...A(),
|
|
1666
|
+
K("createdAt", "desc"),
|
|
1667
|
+
K(H(), "desc"),
|
|
1668
|
+
...e ? [Y(e)] : [],
|
|
1669
|
+
W(s + 1)
|
|
1670
|
+
], n = await U(q(d(), ...t)), r = n.docs.slice(0, s), i = r.map((e) => ({
|
|
1578
1671
|
id: e.id,
|
|
1579
1672
|
...e.data()
|
|
1580
1673
|
})), a = new Set([...m.value, ...p.value].map((e) => e.id));
|
|
1581
|
-
m.value.push(...i.filter((e) => !a.has(e.id))),
|
|
1674
|
+
m.value.push(...i.filter((e) => !a.has(e.id))), w = r.at(-1) ?? w, b.value = n.docs.length > s;
|
|
1582
1675
|
} catch (e) {
|
|
1583
|
-
|
|
1676
|
+
S.value = e.message || String(e), console.error("[memi-board:postList] loadMore failed", e);
|
|
1584
1677
|
} finally {
|
|
1585
|
-
|
|
1678
|
+
x.value = !1;
|
|
1586
1679
|
}
|
|
1587
1680
|
}
|
|
1588
1681
|
}
|
|
1589
1682
|
function ne() {
|
|
1590
|
-
|
|
1683
|
+
T?.(), p.value = [], m.value = [], C = null, w = null, b.value = !0, S.value = "", v.value = !0, g.value = [], _.value = !0, ee(), j(), M();
|
|
1591
1684
|
}
|
|
1592
1685
|
return B([
|
|
1593
|
-
|
|
1686
|
+
l,
|
|
1594
1687
|
f,
|
|
1595
|
-
|
|
1688
|
+
c
|
|
1596
1689
|
], ne, { immediate: !0 }), L(() => {
|
|
1597
|
-
|
|
1690
|
+
T?.(), D?.(), E?.();
|
|
1598
1691
|
}), {
|
|
1599
|
-
posts:
|
|
1692
|
+
posts: k,
|
|
1600
1693
|
notices: g,
|
|
1601
1694
|
postsPending: I(() => v.value || _.value),
|
|
1602
|
-
hasMore:
|
|
1603
|
-
loadingMore:
|
|
1604
|
-
loadError:
|
|
1695
|
+
hasMore: b,
|
|
1696
|
+
loadingMore: x,
|
|
1697
|
+
loadError: S,
|
|
1605
1698
|
loadMore: te
|
|
1606
1699
|
};
|
|
1607
1700
|
}
|
|
1608
|
-
function
|
|
1609
|
-
let n =
|
|
1701
|
+
function hr(e, t) {
|
|
1702
|
+
let n = Q(), r = () => y(), i = I(() => ur(e)), a = I(() => typeof t == "string" ? t : t.value), o = I(() => S(n, r(), a.value)), s = I(() => b(n, r(), a.value)), { data: c, pending: l } = je(o), { data: u, pending: d } = je(s);
|
|
1610
1703
|
return {
|
|
1611
1704
|
post: I(() => {
|
|
1612
|
-
if (!
|
|
1613
|
-
let e =
|
|
1705
|
+
if (!c.value || c.value.boardId !== i.value) return null;
|
|
1706
|
+
let e = u.value;
|
|
1614
1707
|
return {
|
|
1615
|
-
...
|
|
1708
|
+
...c.value,
|
|
1616
1709
|
id: a.value,
|
|
1617
|
-
i18n:
|
|
1618
|
-
i18nSource: ut(
|
|
1619
|
-
content:
|
|
1620
|
-
contentI18n:
|
|
1710
|
+
i18n: $(c.value.i18n),
|
|
1711
|
+
i18nSource: ut(c.value.i18nSource),
|
|
1712
|
+
content: u.value?.content ?? "",
|
|
1713
|
+
contentI18n: $(e?.i18n),
|
|
1621
1714
|
contentI18nSource: dt(e?.i18nSource)
|
|
1622
1715
|
};
|
|
1623
1716
|
}),
|
|
1624
|
-
pending: I(() =>
|
|
1717
|
+
pending: I(() => l.value || d.value)
|
|
1625
1718
|
};
|
|
1626
1719
|
}
|
|
1627
1720
|
//#endregion
|
|
1628
1721
|
//#region src/composables/useMemiBoardUserPosts.ts
|
|
1629
|
-
var
|
|
1630
|
-
function
|
|
1631
|
-
let n =
|
|
1722
|
+
var gr = 10;
|
|
1723
|
+
function _r(e, t = {}) {
|
|
1724
|
+
let n = Q(), r = () => y(), i = () => u(n, r()), a = t.pageSize ?? gr, o = I(() => z(e)?.trim() || ""), s = R([]), c = R([]), l = R(!0), d = R(!0), f = R(!1), p = R(""), m = null, h = null, g;
|
|
1632
1725
|
function _(e) {
|
|
1633
1726
|
return {
|
|
1634
1727
|
id: e.id,
|
|
@@ -1638,41 +1731,41 @@ function ir(e, t = {}) {
|
|
|
1638
1731
|
function v(e) {
|
|
1639
1732
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1640
1733
|
}
|
|
1641
|
-
let
|
|
1734
|
+
let b = I(() => {
|
|
1642
1735
|
let e = /* @__PURE__ */ new Map();
|
|
1643
|
-
for (let t of [...
|
|
1736
|
+
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1644
1737
|
return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
|
|
1645
1738
|
});
|
|
1646
|
-
function
|
|
1739
|
+
function x() {
|
|
1647
1740
|
return [
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1741
|
+
Z("authorUid", "==", o.value),
|
|
1742
|
+
Z("isPublished", "==", !0),
|
|
1743
|
+
Z("listed", "==", !0)
|
|
1651
1744
|
];
|
|
1652
1745
|
}
|
|
1653
|
-
function
|
|
1654
|
-
if (g?.(), !
|
|
1655
|
-
|
|
1746
|
+
function S() {
|
|
1747
|
+
if (g?.(), !o.value) {
|
|
1748
|
+
l.value = !1;
|
|
1656
1749
|
return;
|
|
1657
1750
|
}
|
|
1658
|
-
g =
|
|
1659
|
-
|
|
1751
|
+
g = G(q(i(), ...x(), K("createdAt", "desc"), K(H(), "desc"), W(a)), (e) => {
|
|
1752
|
+
s.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a), l.value = !1;
|
|
1660
1753
|
}, (e) => {
|
|
1661
|
-
console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e),
|
|
1754
|
+
console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), l.value = !1;
|
|
1662
1755
|
});
|
|
1663
1756
|
}
|
|
1664
|
-
async function
|
|
1665
|
-
if (!f.value && d.value && !
|
|
1757
|
+
async function C() {
|
|
1758
|
+
if (!f.value && d.value && !l.value && o.value) {
|
|
1666
1759
|
f.value = !0, p.value = "";
|
|
1667
1760
|
try {
|
|
1668
1761
|
let e = h ?? m, t = [
|
|
1669
|
-
...
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
...e ? [
|
|
1673
|
-
|
|
1674
|
-
], n = await
|
|
1675
|
-
|
|
1762
|
+
...x(),
|
|
1763
|
+
K("createdAt", "desc"),
|
|
1764
|
+
K(H(), "desc"),
|
|
1765
|
+
...e ? [Y(e)] : [],
|
|
1766
|
+
W(a + 1)
|
|
1767
|
+
], n = await U(q(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1768
|
+
c.value.push(...o.filter((e) => !l.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > a;
|
|
1676
1769
|
} catch (e) {
|
|
1677
1770
|
p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
|
|
1678
1771
|
} finally {
|
|
@@ -1680,47 +1773,47 @@ function ir(e, t = {}) {
|
|
|
1680
1773
|
}
|
|
1681
1774
|
}
|
|
1682
1775
|
}
|
|
1683
|
-
function
|
|
1684
|
-
g?.(),
|
|
1776
|
+
function w() {
|
|
1777
|
+
g?.(), s.value = [], c.value = [], m = null, h = null, d.value = !0, p.value = "", l.value = !0, S();
|
|
1685
1778
|
}
|
|
1686
|
-
return B(
|
|
1687
|
-
posts:
|
|
1688
|
-
postsPending:
|
|
1779
|
+
return B(o, w, { immediate: !0 }), L(() => g?.()), {
|
|
1780
|
+
posts: b,
|
|
1781
|
+
postsPending: l,
|
|
1689
1782
|
hasMore: d,
|
|
1690
1783
|
loadingMore: f,
|
|
1691
1784
|
loadError: p,
|
|
1692
|
-
loadMore:
|
|
1785
|
+
loadMore: C
|
|
1693
1786
|
};
|
|
1694
1787
|
}
|
|
1695
1788
|
//#endregion
|
|
1696
1789
|
//#region src/composables/useMemiBoardUserComments.ts
|
|
1697
|
-
var
|
|
1698
|
-
function
|
|
1699
|
-
let n =
|
|
1700
|
-
function
|
|
1790
|
+
var vr = 10;
|
|
1791
|
+
function yr(e, t = {}) {
|
|
1792
|
+
let n = Q(), r = () => y(), i = () => pe(n, r()), a = t.pageSize ?? vr, o = I(() => z(e)?.trim() || ""), s = R([]), c = R([]), l = R(!0), u = R(!0), d = R(!1), f = R(""), p = null, m = null, h;
|
|
1793
|
+
function g(e) {
|
|
1701
1794
|
return {
|
|
1702
1795
|
id: e.id,
|
|
1703
1796
|
...e.data()
|
|
1704
1797
|
};
|
|
1705
1798
|
}
|
|
1706
|
-
function
|
|
1799
|
+
function _(e) {
|
|
1707
1800
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1708
1801
|
}
|
|
1709
|
-
let
|
|
1802
|
+
let v = I(() => {
|
|
1710
1803
|
let e = /* @__PURE__ */ new Map();
|
|
1711
1804
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1712
|
-
return [...e.values()].sort((e, t) =>
|
|
1805
|
+
return [...e.values()].sort((e, t) => _(t) - _(e) || String(t.id).localeCompare(String(e.id)));
|
|
1713
1806
|
});
|
|
1714
1807
|
function b() {
|
|
1715
|
-
return [
|
|
1808
|
+
return [Z("authorUid", "==", o.value), Z("listed", "==", !0)];
|
|
1716
1809
|
}
|
|
1717
1810
|
function x() {
|
|
1718
1811
|
if (h?.(), !o.value) {
|
|
1719
1812
|
l.value = !1;
|
|
1720
1813
|
return;
|
|
1721
1814
|
}
|
|
1722
|
-
h =
|
|
1723
|
-
s.value = e.docs.map(
|
|
1815
|
+
h = G(q(i(), ...b(), K("createdAt", "desc"), K(H(), "desc"), W(a)), (e) => {
|
|
1816
|
+
s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
|
|
1724
1817
|
}, (e) => {
|
|
1725
1818
|
console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
1726
1819
|
});
|
|
@@ -1731,11 +1824,11 @@ function or(e, t = {}) {
|
|
|
1731
1824
|
try {
|
|
1732
1825
|
let e = m ?? p, t = [
|
|
1733
1826
|
...b(),
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
...e ? [
|
|
1737
|
-
|
|
1738
|
-
], n = await
|
|
1827
|
+
K("createdAt", "desc"),
|
|
1828
|
+
K(H(), "desc"),
|
|
1829
|
+
...e ? [Y(e)] : [],
|
|
1830
|
+
W(a + 1)
|
|
1831
|
+
], n = await U(q(i(), ...t)), r = n.docs.slice(0, a), o = r.map(g), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1739
1832
|
c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
|
|
1740
1833
|
} catch (e) {
|
|
1741
1834
|
f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
|
|
@@ -1748,7 +1841,7 @@ function or(e, t = {}) {
|
|
|
1748
1841
|
h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
|
|
1749
1842
|
}
|
|
1750
1843
|
return B(o, C, { immediate: !0 }), L(() => h?.()), {
|
|
1751
|
-
comments:
|
|
1844
|
+
comments: v,
|
|
1752
1845
|
commentsPending: l,
|
|
1753
1846
|
hasMore: u,
|
|
1754
1847
|
loadingMore: d,
|
|
@@ -1758,48 +1851,48 @@ function or(e, t = {}) {
|
|
|
1758
1851
|
}
|
|
1759
1852
|
//#endregion
|
|
1760
1853
|
//#region src/composables/useMemiBoardCommentFeed.ts
|
|
1761
|
-
var
|
|
1762
|
-
function
|
|
1763
|
-
let n =
|
|
1854
|
+
var br = 10;
|
|
1855
|
+
function xr(e = "latest", t = {}) {
|
|
1856
|
+
let n = Q(), r = () => y(), i = () => pe(n, r()), a = I(() => {
|
|
1764
1857
|
let e = Math.floor(Number(z(t.pageSize)));
|
|
1765
|
-
return Number.isFinite(e) && e > 0 ? e :
|
|
1858
|
+
return Number.isFinite(e) && e > 0 ? e : br;
|
|
1766
1859
|
}), o = I(() => z(e) === "likes" ? "likes" : "latest"), s = R([]), c = R([]), l = R(!0), u = R(!0), d = R(!1), f = R(""), p = null, m = null, h;
|
|
1767
|
-
function
|
|
1860
|
+
function g(e) {
|
|
1768
1861
|
return {
|
|
1769
1862
|
id: e.id,
|
|
1770
1863
|
...e.data()
|
|
1771
1864
|
};
|
|
1772
1865
|
}
|
|
1773
|
-
function
|
|
1866
|
+
function _(e) {
|
|
1774
1867
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1775
1868
|
}
|
|
1776
|
-
function
|
|
1869
|
+
function v(e, t) {
|
|
1777
1870
|
if (o.value === "likes") {
|
|
1778
1871
|
let n = (t.likeCount ?? 0) - (e.likeCount ?? 0);
|
|
1779
1872
|
if (n) return n;
|
|
1780
1873
|
}
|
|
1781
|
-
return
|
|
1874
|
+
return _(t) - _(e) || String(t.id).localeCompare(String(e.id));
|
|
1782
1875
|
}
|
|
1783
1876
|
let b = I(() => {
|
|
1784
1877
|
let e = /* @__PURE__ */ new Map();
|
|
1785
1878
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1786
|
-
return [...e.values()].sort(
|
|
1879
|
+
return [...e.values()].sort(v);
|
|
1787
1880
|
});
|
|
1788
1881
|
function x() {
|
|
1789
1882
|
return o.value === "likes" ? [
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1883
|
+
Z("listed", "==", !0),
|
|
1884
|
+
K("likeCount", "desc"),
|
|
1885
|
+
K("createdAt", "desc"),
|
|
1886
|
+
K(H(), "desc")
|
|
1794
1887
|
] : [
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1888
|
+
Z("listed", "==", !0),
|
|
1889
|
+
K("createdAt", "desc"),
|
|
1890
|
+
K(H(), "desc")
|
|
1798
1891
|
];
|
|
1799
1892
|
}
|
|
1800
1893
|
function S() {
|
|
1801
|
-
h?.(), h =
|
|
1802
|
-
s.value = e.docs.map(
|
|
1894
|
+
h?.(), h = G(q(i(), ...x(), W(a.value)), (e) => {
|
|
1895
|
+
s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
|
|
1803
1896
|
}, (e) => {
|
|
1804
1897
|
console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
1805
1898
|
});
|
|
@@ -1808,7 +1901,7 @@ function cr(e = "latest", t = {}) {
|
|
|
1808
1901
|
if (!(d.value || !u.value || l.value)) {
|
|
1809
1902
|
d.value = !0, f.value = "";
|
|
1810
1903
|
try {
|
|
1811
|
-
let e = m ?? p, t = await
|
|
1904
|
+
let e = m ?? p, t = await U(q(i(), ...x(), ...e ? [Y(e)] : [], W(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(g), o = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1812
1905
|
c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
|
|
1813
1906
|
} catch (e) {
|
|
1814
1907
|
f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
|
|
@@ -1832,32 +1925,32 @@ function cr(e = "latest", t = {}) {
|
|
|
1832
1925
|
}
|
|
1833
1926
|
//#endregion
|
|
1834
1927
|
//#region src/composables/useMemiBoardAuthorMemo.ts
|
|
1835
|
-
var
|
|
1836
|
-
function
|
|
1837
|
-
let t =
|
|
1838
|
-
return t || (t =
|
|
1928
|
+
var Sr = 100, Cr = /* @__PURE__ */ new Map();
|
|
1929
|
+
function wr(e) {
|
|
1930
|
+
let t = Cr.get(e);
|
|
1931
|
+
return t || (t = me({
|
|
1839
1932
|
text: "",
|
|
1840
1933
|
sentiment: null,
|
|
1841
1934
|
loaded: !1,
|
|
1842
1935
|
pending: !1,
|
|
1843
1936
|
saving: !1,
|
|
1844
1937
|
error: ""
|
|
1845
|
-
}),
|
|
1938
|
+
}), Cr.set(e, t)), t;
|
|
1846
1939
|
}
|
|
1847
|
-
function
|
|
1848
|
-
let t =
|
|
1940
|
+
function Tr(e) {
|
|
1941
|
+
let t = Q(), n = () => y(), { user: r } = Wt(), { t: i, formatNumber: a } = O(), o = I(() => z(e)), s = I(() => `${r.value?.uid ?? ""}:${o.value}`), c = I(() => {
|
|
1849
1942
|
let e = r.value?.uid, i = o.value;
|
|
1850
|
-
return !e || !i ? null :
|
|
1943
|
+
return !e || !i ? null : p(t, n(), e, i);
|
|
1851
1944
|
}), l = I({
|
|
1852
|
-
get: () =>
|
|
1945
|
+
get: () => wr(s.value).text,
|
|
1853
1946
|
set: (e) => {
|
|
1854
|
-
|
|
1947
|
+
wr(s.value).text = e;
|
|
1855
1948
|
}
|
|
1856
|
-
}), u = I(() =>
|
|
1949
|
+
}), u = I(() => wr(s.value).sentiment), d = I(() => wr(s.value).loaded), f = I(() => wr(s.value).pending), m = I(() => wr(s.value).saving), h = I(() => wr(s.value).error);
|
|
1857
1950
|
async function g() {
|
|
1858
1951
|
let e = c.value;
|
|
1859
1952
|
if (!e) return;
|
|
1860
|
-
let t =
|
|
1953
|
+
let t = wr(s.value);
|
|
1861
1954
|
t.pending = !0, t.error = "";
|
|
1862
1955
|
try {
|
|
1863
1956
|
let n = (await xe(e)).data();
|
|
@@ -1873,13 +1966,13 @@ function dr(e) {
|
|
|
1873
1966
|
if (!n) return;
|
|
1874
1967
|
let r = e.trim();
|
|
1875
1968
|
if (r.length > 100) throw Error(i("authorMemo.tooLong", { max: a(100) }));
|
|
1876
|
-
let o =
|
|
1969
|
+
let o = wr(s.value);
|
|
1877
1970
|
o.saving = !0, o.error = "";
|
|
1878
1971
|
try {
|
|
1879
1972
|
await De(n, {
|
|
1880
1973
|
text: r,
|
|
1881
1974
|
sentiment: t,
|
|
1882
|
-
updatedAt:
|
|
1975
|
+
updatedAt: J()
|
|
1883
1976
|
}), o.text = r, o.sentiment = t, o.loaded = !0;
|
|
1884
1977
|
} catch (e) {
|
|
1885
1978
|
throw o.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
|
|
@@ -1890,10 +1983,10 @@ function dr(e) {
|
|
|
1890
1983
|
async function v() {
|
|
1891
1984
|
let e = c.value;
|
|
1892
1985
|
if (!e) return;
|
|
1893
|
-
let t =
|
|
1986
|
+
let t = wr(s.value);
|
|
1894
1987
|
t.saving = !0, t.error = "";
|
|
1895
1988
|
try {
|
|
1896
|
-
await
|
|
1989
|
+
await _e(e), t.text = "", t.sentiment = null, t.loaded = !0;
|
|
1897
1990
|
} catch (e) {
|
|
1898
1991
|
throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
|
|
1899
1992
|
} finally {
|
|
@@ -1904,7 +1997,7 @@ function dr(e) {
|
|
|
1904
1997
|
text: l,
|
|
1905
1998
|
sentiment: u,
|
|
1906
1999
|
loaded: d,
|
|
1907
|
-
pending:
|
|
2000
|
+
pending: f,
|
|
1908
2001
|
saving: m,
|
|
1909
2002
|
error: h,
|
|
1910
2003
|
load: g,
|
|
@@ -1914,7 +2007,7 @@ function dr(e) {
|
|
|
1914
2007
|
}
|
|
1915
2008
|
//#endregion
|
|
1916
2009
|
//#region src/composables/useMemiBoardWritingAssistant.ts
|
|
1917
|
-
var
|
|
2010
|
+
var Er = 20, Dr = 864e5, Or = 200, kr = {
|
|
1918
2011
|
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
1919
2012
|
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
1920
2013
|
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
@@ -1923,7 +2016,7 @@ var fr = 20, pr = 864e5, mr = 200, hr = {
|
|
|
1923
2016
|
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
1924
2017
|
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
1925
2018
|
};
|
|
1926
|
-
function
|
|
2019
|
+
function Ar(e) {
|
|
1927
2020
|
return {
|
|
1928
2021
|
proofread: "Fix only spelling, spacing, and grammar errors. Do not change the meaning or tone.",
|
|
1929
2022
|
polish: "Refine the text into more natural, readable sentences while keeping the meaning and the author's tone.",
|
|
@@ -1934,27 +2027,27 @@ function gr(e) {
|
|
|
1934
2027
|
title: `Create one concise title in ${e} that represents the body. Output only the title, without quotes or explanation.`
|
|
1935
2028
|
};
|
|
1936
2029
|
}
|
|
1937
|
-
function
|
|
1938
|
-
let r = t === "ko", i =
|
|
2030
|
+
function jr(e, t, n) {
|
|
2031
|
+
let r = t === "ko", i = Ln(t);
|
|
1939
2032
|
if (e.action !== "custom") {
|
|
1940
|
-
if (r) return
|
|
1941
|
-
let t =
|
|
2033
|
+
if (r) return kr[e.action];
|
|
2034
|
+
let t = Ar(i)[e.action];
|
|
1942
2035
|
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
2036
|
}
|
|
1944
|
-
let a = e.customInstruction?.trim().slice(0,
|
|
2037
|
+
let a = e.customInstruction?.trim().slice(0, Or);
|
|
1945
2038
|
if (!a) throw Error(n("writingAssistant.customRequired"));
|
|
1946
2039
|
return r ? `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${a}` : `Rewrite the text applying the following style instruction while keeping the meaning: ${a}`;
|
|
1947
2040
|
}
|
|
1948
|
-
function
|
|
2041
|
+
function Mr(e) {
|
|
1949
2042
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
1950
2043
|
}
|
|
1951
|
-
function
|
|
2044
|
+
function Nr(e) {
|
|
1952
2045
|
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
1953
2046
|
}
|
|
1954
|
-
function
|
|
1955
|
-
let t =
|
|
1956
|
-
function
|
|
1957
|
-
let n =
|
|
2047
|
+
function Pr(e = {}) {
|
|
2048
|
+
let t = O(), n = I(() => D(z(e.locale)) ?? t.locale.value), r = (e, t) => j(n.value, e, t), o = Me(), s = Q(), c = Ae(), l = i(), { translateEntries: u, translateHtml: d, detectSourceLocale: f } = nr();
|
|
2049
|
+
function p(e, t) {
|
|
2050
|
+
let n = Nr(e.aiWritingWindowAt), r = n != null && t - n < Dr, i = Math.max(0, Math.floor(Number(e.aiWritingCount) || 0)), a = Math.max(0, Math.floor(Number(e.aiWritingPending) || 0));
|
|
1958
2051
|
return {
|
|
1959
2052
|
active: r,
|
|
1960
2053
|
windowAt: n,
|
|
@@ -1962,68 +2055,68 @@ function br(e = {}) {
|
|
|
1962
2055
|
pending: r ? a : 0
|
|
1963
2056
|
};
|
|
1964
2057
|
}
|
|
1965
|
-
function
|
|
1966
|
-
let n = e +
|
|
2058
|
+
function m(e, t) {
|
|
2059
|
+
let n = e + Dr, i = Math.max(1, Math.ceil((n - t) / 36e5));
|
|
1967
2060
|
return Error(r("writingAssistant.dailyLimit", {
|
|
1968
2061
|
limit: 20,
|
|
1969
2062
|
hours: i
|
|
1970
2063
|
}));
|
|
1971
2064
|
}
|
|
1972
|
-
async function
|
|
1973
|
-
let t =
|
|
2065
|
+
async function h(e) {
|
|
2066
|
+
let t = c.value?.uid;
|
|
1974
2067
|
if (!t) throw Error(r("writingAssistant.loginRequired"));
|
|
1975
|
-
await Ee(
|
|
1976
|
-
let i =
|
|
2068
|
+
await Ee(s, async (n) => {
|
|
2069
|
+
let i = a(s, y(), t), o = await n.get(i);
|
|
1977
2070
|
if (!o.exists()) throw Error(r("writingAssistant.userMissing"));
|
|
1978
|
-
let
|
|
1979
|
-
|
|
1980
|
-
...
|
|
1981
|
-
updatedAt:
|
|
2071
|
+
let c = o.data(), l = e(p(c, Date.now()), c);
|
|
2072
|
+
l && n.update(i, {
|
|
2073
|
+
...l,
|
|
2074
|
+
updatedAt: J()
|
|
1982
2075
|
});
|
|
1983
2076
|
});
|
|
1984
2077
|
}
|
|
1985
|
-
async function
|
|
1986
|
-
await
|
|
1987
|
-
if (e.active && e.windowAt != null && e.count + e.pending >= 20) throw
|
|
2078
|
+
async function g() {
|
|
2079
|
+
await h((e) => {
|
|
2080
|
+
if (e.active && e.windowAt != null && e.count + e.pending >= 20) throw m(e.windowAt, Date.now());
|
|
1988
2081
|
return e.active ? { aiWritingPending: e.pending + 1 } : {
|
|
1989
2082
|
aiWritingCount: 0,
|
|
1990
2083
|
aiWritingPending: 1,
|
|
1991
|
-
aiWritingWindowAt:
|
|
2084
|
+
aiWritingWindowAt: J()
|
|
1992
2085
|
};
|
|
1993
2086
|
});
|
|
1994
2087
|
}
|
|
1995
|
-
async function
|
|
1996
|
-
await
|
|
2088
|
+
async function _() {
|
|
2089
|
+
await h((e) => !e.active || e.pending < 1 || e.count >= 20 ? null : {
|
|
1997
2090
|
aiWritingCount: e.count + 1,
|
|
1998
2091
|
aiWritingPending: e.pending - 1
|
|
1999
2092
|
});
|
|
2000
2093
|
}
|
|
2001
|
-
async function
|
|
2002
|
-
await
|
|
2094
|
+
async function v() {
|
|
2095
|
+
await h((e) => !e.active || e.pending < 1 ? null : { aiWritingPending: e.pending - 1 });
|
|
2003
2096
|
}
|
|
2004
|
-
async function
|
|
2005
|
-
await
|
|
2097
|
+
async function b(e) {
|
|
2098
|
+
await g();
|
|
2006
2099
|
try {
|
|
2007
2100
|
let t = await e();
|
|
2008
2101
|
try {
|
|
2009
|
-
await
|
|
2102
|
+
await _();
|
|
2010
2103
|
} catch {}
|
|
2011
2104
|
return t;
|
|
2012
2105
|
} catch (e) {
|
|
2013
|
-
throw await
|
|
2106
|
+
throw await v().catch(() => {}), e;
|
|
2014
2107
|
}
|
|
2015
2108
|
}
|
|
2016
|
-
async function
|
|
2017
|
-
(e.action === "translate-en" || e.action === "translate-ko") &&
|
|
2018
|
-
let t = n.value,
|
|
2109
|
+
async function x(e) {
|
|
2110
|
+
(e.action === "translate-en" || e.action === "translate-ko") && F();
|
|
2111
|
+
let t = n.value, i = t === "ko", a = jr(e, t, r);
|
|
2019
2112
|
if (!e.content.trim()) throw Error(r("writingAssistant.contentRequired"));
|
|
2020
|
-
return
|
|
2021
|
-
let t =
|
|
2113
|
+
return b(async () => {
|
|
2114
|
+
let t = l.moderation ?? {}, n = Xe(o, {
|
|
2022
2115
|
backend: new Je(),
|
|
2023
2116
|
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
2024
|
-
}),
|
|
2117
|
+
}), s = Ze(n, {
|
|
2025
2118
|
model: t.model ?? "gemini-3.5-flash-lite",
|
|
2026
|
-
systemInstruction: (
|
|
2119
|
+
systemInstruction: (i ? [
|
|
2027
2120
|
"너는 게시판 글쓰기 편집 도우미다.",
|
|
2028
2121
|
"사용자가 요청한 편집 결과만 출력하고 설명, 인사, 마크다운 코드 펜스를 붙이지 마라.",
|
|
2029
2122
|
e.action === "title" || e.selection ? "출력은 일반 텍스트로 작성하라." : "입력의 HTML 구조와 링크, 이미지 태그를 보존하고 결과도 HTML 조각으로 출력하라."
|
|
@@ -2036,51 +2129,51 @@ function br(e = {}) {
|
|
|
2036
2129
|
temperature: e.action === "continue" || e.action === "title" || e.action === "custom" ? .6 : .2,
|
|
2037
2130
|
maxOutputTokens: 2048
|
|
2038
2131
|
}
|
|
2039
|
-
}),
|
|
2040
|
-
`작업: ${
|
|
2132
|
+
}), c = e.content.trim(), u = (i ? [
|
|
2133
|
+
`작업: ${a}`,
|
|
2041
2134
|
e.title ? `현재 제목: ${e.title}` : "",
|
|
2042
|
-
`본문:\n${
|
|
2135
|
+
`본문:\n${c.slice(0, 12e3)}`
|
|
2043
2136
|
] : [
|
|
2044
|
-
`Task: ${
|
|
2137
|
+
`Task: ${a}`,
|
|
2045
2138
|
e.title ? `Current title: ${e.title}` : "",
|
|
2046
|
-
`Body:\n${
|
|
2047
|
-
]).filter(Boolean).join("\n\n"), d =
|
|
2139
|
+
`Body:\n${c.slice(0, 12e3)}`
|
|
2140
|
+
]).filter(Boolean).join("\n\n"), d = Mr((await s.generateContent(u)).response.text());
|
|
2048
2141
|
if (!d) throw Error(r("writingAssistant.emptyResult"));
|
|
2049
2142
|
return d;
|
|
2050
2143
|
});
|
|
2051
2144
|
}
|
|
2052
|
-
async function
|
|
2053
|
-
|
|
2145
|
+
async function S(e) {
|
|
2146
|
+
F();
|
|
2054
2147
|
let t = e.targets?.length ? e.targets : pt(), n = e.title?.trim() ?? "", i = e.summary?.trim() ?? "", a = e.content ?? "", o = {};
|
|
2055
2148
|
n && (o.title = n), i && (o.summary = i);
|
|
2056
2149
|
let s = !!ln(a);
|
|
2057
2150
|
if (!Object.keys(o).length && !s) throw Error(r("writingAssistant.translateEmpty"));
|
|
2058
2151
|
if (s && a.length > 12e3) throw Error(r("writingAssistant.translateTooLong", {
|
|
2059
|
-
limit:
|
|
2152
|
+
limit: Zn,
|
|
2060
2153
|
count: t.length
|
|
2061
2154
|
}));
|
|
2062
|
-
return
|
|
2063
|
-
let
|
|
2155
|
+
return b(async () => {
|
|
2156
|
+
let c = e.source ?? await f([
|
|
2064
2157
|
ln(a),
|
|
2065
2158
|
n,
|
|
2066
2159
|
i
|
|
2067
|
-
].filter(Boolean).join("\n")),
|
|
2160
|
+
].filter(Boolean).join("\n")), l = [...t, c], [p, m] = await Promise.all([Object.keys(o).length ? u([{
|
|
2068
2161
|
id: "post",
|
|
2069
2162
|
fields: o,
|
|
2070
2163
|
context: "message board post title and short summary"
|
|
2071
2164
|
}], {
|
|
2072
|
-
source:
|
|
2165
|
+
source: c,
|
|
2073
2166
|
targets: t,
|
|
2074
2167
|
purpose: "message board post title and short summary"
|
|
2075
|
-
}) : Promise.resolve({}), s ?
|
|
2076
|
-
source:
|
|
2168
|
+
}) : Promise.resolve({}), s ? d(a, {
|
|
2169
|
+
source: c,
|
|
2077
2170
|
targets: t
|
|
2078
|
-
}) : Promise.resolve({})]), h = ft(
|
|
2079
|
-
if (Object.keys(o).length && !ht(h, Object.keys(o),
|
|
2171
|
+
}) : Promise.resolve({})]), h = ft(c, o, p.post);
|
|
2172
|
+
if (Object.keys(o).length && !ht(h, Object.keys(o), l)) throw Error(r("writingAssistant.translateIncomplete"));
|
|
2080
2173
|
let g = {
|
|
2081
2174
|
i18n: h,
|
|
2082
2175
|
i18nSource: {
|
|
2083
|
-
locale:
|
|
2176
|
+
locale: c,
|
|
2084
2177
|
title: n,
|
|
2085
2178
|
summary: i
|
|
2086
2179
|
}
|
|
@@ -2088,26 +2181,26 @@ function br(e = {}) {
|
|
|
2088
2181
|
if (s) {
|
|
2089
2182
|
let e = {};
|
|
2090
2183
|
for (let [t, n] of Object.entries(m)) {
|
|
2091
|
-
let r =
|
|
2184
|
+
let r = D(t);
|
|
2092
2185
|
r && typeof n == "string" && n.trim() && (e[r] = { content: n.trim() });
|
|
2093
2186
|
}
|
|
2094
|
-
let t = ft(
|
|
2095
|
-
if (!ht(t, ["content"],
|
|
2187
|
+
let t = ft(c, { content: a }, e);
|
|
2188
|
+
if (!ht(t, ["content"], l)) throw Error(r("writingAssistant.translateIncomplete"));
|
|
2096
2189
|
g.contentI18n = t, g.contentI18nSource = {
|
|
2097
|
-
locale:
|
|
2190
|
+
locale: c,
|
|
2098
2191
|
hash: ct(a)
|
|
2099
2192
|
};
|
|
2100
2193
|
}
|
|
2101
2194
|
return g;
|
|
2102
2195
|
});
|
|
2103
2196
|
}
|
|
2104
|
-
async function
|
|
2105
|
-
|
|
2197
|
+
async function C(e) {
|
|
2198
|
+
F();
|
|
2106
2199
|
let t = e.body.trim();
|
|
2107
2200
|
if (!t) throw Error(r("writingAssistant.translateEmpty"));
|
|
2108
2201
|
let n = e.targets?.length ? e.targets : pt();
|
|
2109
|
-
return
|
|
2110
|
-
let e = await
|
|
2202
|
+
return b(async () => {
|
|
2203
|
+
let e = await f(t), i = await u([{
|
|
2111
2204
|
id: "comment",
|
|
2112
2205
|
fields: { body: t },
|
|
2113
2206
|
context: "message board comment or reply, plain text"
|
|
@@ -2127,226 +2220,226 @@ function br(e = {}) {
|
|
|
2127
2220
|
});
|
|
2128
2221
|
}
|
|
2129
2222
|
return {
|
|
2130
|
-
assist:
|
|
2131
|
-
translatePost:
|
|
2132
|
-
translateComment:
|
|
2223
|
+
assist: x,
|
|
2224
|
+
translatePost: S,
|
|
2225
|
+
translateComment: C
|
|
2133
2226
|
};
|
|
2134
2227
|
}
|
|
2135
2228
|
//#endregion
|
|
2136
2229
|
//#region src/utils/subscribeCommentRange.ts
|
|
2137
|
-
function
|
|
2138
|
-
return
|
|
2230
|
+
function Fr(e, t, n, r, i, a) {
|
|
2231
|
+
return G(q(pe(e, t), Z("postId", "==", n), ...r.rootId ? [Z("rootId", "==", r.rootId), Z("isReply", "==", !0)] : [Z("parentId", "==", null)], K("createdAt", "asc"), K(H(), "asc"), ...r.hasMore && r.cursor ? [ye(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
|
|
2139
2232
|
...e.data(),
|
|
2140
2233
|
id: e.id
|
|
2141
2234
|
}))), a);
|
|
2142
2235
|
}
|
|
2143
2236
|
//#endregion
|
|
2144
2237
|
//#region src/composables/useMemiBoardComments.ts
|
|
2145
|
-
var
|
|
2146
|
-
function
|
|
2238
|
+
var Ir = 10, Lr = 5, Rr = 1e3;
|
|
2239
|
+
function zr(e, { t, formatNumber: n }) {
|
|
2147
2240
|
let r = e.trim();
|
|
2148
2241
|
if (!r) throw Error(t("comments.bodyRequired"));
|
|
2149
|
-
if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(
|
|
2242
|
+
if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(Rr) }));
|
|
2150
2243
|
return r;
|
|
2151
2244
|
}
|
|
2152
|
-
function
|
|
2153
|
-
let
|
|
2154
|
-
async function
|
|
2155
|
-
if (
|
|
2245
|
+
function Br(e, t, n = {}) {
|
|
2246
|
+
let r = Q(), i = Me(), a = () => y(), { isBoardHidden: s, getBoard: c } = sr(), { translateComment: l } = Pr(), u, d = R(!1);
|
|
2247
|
+
async function f(e, t) {
|
|
2248
|
+
if (d.value = !1, !de()) return {};
|
|
2156
2249
|
if (t?.i18nSource.body === e) return t;
|
|
2157
|
-
if (c(
|
|
2250
|
+
if (c(g.value)?.autoTranslatePosts !== !0) return {};
|
|
2158
2251
|
if (u?.i18nSource.body !== e) try {
|
|
2159
2252
|
u = await l({
|
|
2160
2253
|
body: e,
|
|
2161
|
-
targets: pt(c(
|
|
2254
|
+
targets: pt(c(g.value))
|
|
2162
2255
|
});
|
|
2163
2256
|
} catch (e) {
|
|
2164
|
-
return import.meta.dev && console.warn("[memi-board] comment auto-translation skipped", e),
|
|
2257
|
+
return import.meta.dev && console.warn("[memi-board] comment auto-translation skipped", e), d.value = !0, {};
|
|
2165
2258
|
}
|
|
2166
2259
|
return u;
|
|
2167
2260
|
}
|
|
2168
|
-
let
|
|
2169
|
-
function
|
|
2261
|
+
let p = O(), { t: m } = p, h = () => pe(r, a()), g = I(() => z(e)), v = I(() => z(t)), b = () => !s(g.value), x = R([]), C = R(n.subscribe !== !1), w = R([]), T = R(!1), E = R(n.subscribe !== !1), D = R(n.subscribe !== !1), k = null, A = 0, ee = 0, j;
|
|
2262
|
+
function M(e) {
|
|
2170
2263
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
2171
2264
|
}
|
|
2172
|
-
let
|
|
2265
|
+
let te = I(() => {
|
|
2173
2266
|
let e = /* @__PURE__ */ new Map();
|
|
2174
|
-
for (let t of [...
|
|
2175
|
-
return [...e.values()].sort((e, t) =>
|
|
2267
|
+
for (let t of [...x.value, ...w.value]) t.id && e.set(t.id, t);
|
|
2268
|
+
return [...e.values()].sort((e, t) => M(e) - M(t) || String(e.id).localeCompare(String(t.id)));
|
|
2176
2269
|
});
|
|
2177
|
-
B([
|
|
2178
|
-
let t = ++
|
|
2179
|
-
if (
|
|
2180
|
-
|
|
2270
|
+
B([v, g], async ([e]) => {
|
|
2271
|
+
let t = ++A;
|
|
2272
|
+
if (ee++, T.value = !1, w.value = [], x.value = [], k = null, j?.(), j = void 0, E.value = n.subscribe !== !1, n.subscribe !== !1) {
|
|
2273
|
+
C.value = !0, D.value = !0;
|
|
2181
2274
|
try {
|
|
2182
|
-
let n =
|
|
2275
|
+
let n = U(q(h(), Z("postId", "==", e), K("createdAt", "desc"), K(H(), "desc")));
|
|
2183
2276
|
if (await Promise.all([n.then((e) => {
|
|
2184
|
-
if (t !==
|
|
2277
|
+
if (t !== A) return;
|
|
2185
2278
|
let n = e.docs.map((e) => ({
|
|
2186
2279
|
id: e.id,
|
|
2187
2280
|
...e.data()
|
|
2188
2281
|
}));
|
|
2189
|
-
|
|
2190
|
-
}),
|
|
2282
|
+
x.value = n.filter((e) => e.parentId === void 0);
|
|
2283
|
+
}), re()]), t !== A) return;
|
|
2191
2284
|
} finally {
|
|
2192
|
-
t ===
|
|
2285
|
+
t === A && (C.value = !1, D.value = !1);
|
|
2193
2286
|
}
|
|
2194
2287
|
}
|
|
2195
2288
|
}, { immediate: !0 });
|
|
2196
|
-
function
|
|
2289
|
+
function ne() {
|
|
2197
2290
|
j?.();
|
|
2198
|
-
let e = ++
|
|
2199
|
-
j =
|
|
2200
|
-
cursor:
|
|
2201
|
-
hasMore:
|
|
2291
|
+
let e = ++ee;
|
|
2292
|
+
j = Fr(r, a(), v.value, {
|
|
2293
|
+
cursor: k,
|
|
2294
|
+
hasMore: E.value
|
|
2202
2295
|
}, (t) => {
|
|
2203
|
-
e ===
|
|
2296
|
+
e === ee && (w.value = t);
|
|
2204
2297
|
}, (e) => {
|
|
2205
2298
|
console.error("[memi-board:comments] onSnapshot failed", e);
|
|
2206
2299
|
});
|
|
2207
2300
|
}
|
|
2208
|
-
async function
|
|
2209
|
-
if (
|
|
2210
|
-
let e =
|
|
2211
|
-
|
|
2301
|
+
async function re() {
|
|
2302
|
+
if (T.value || !E.value) return;
|
|
2303
|
+
let e = A;
|
|
2304
|
+
T.value = !0;
|
|
2212
2305
|
try {
|
|
2213
2306
|
let t = [
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
...
|
|
2219
|
-
|
|
2220
|
-
], n = await
|
|
2221
|
-
if (e !==
|
|
2222
|
-
let r = n.docs.slice(0,
|
|
2307
|
+
Z("postId", "==", v.value),
|
|
2308
|
+
Z("parentId", "==", null),
|
|
2309
|
+
K("createdAt", "asc"),
|
|
2310
|
+
K(H(), "asc"),
|
|
2311
|
+
...k ? [Y(k)] : [],
|
|
2312
|
+
W(11)
|
|
2313
|
+
], n = await U(q(h(), ...t));
|
|
2314
|
+
if (e !== A) return;
|
|
2315
|
+
let r = n.docs.slice(0, Ir), i = r.map((e) => ({
|
|
2223
2316
|
id: e.id,
|
|
2224
2317
|
...e.data()
|
|
2225
|
-
})), a = new Set(
|
|
2226
|
-
|
|
2318
|
+
})), a = new Set(w.value.map((e) => e.id));
|
|
2319
|
+
w.value.push(...i.filter((e) => !a.has(e.id))), k = r.at(-1) ?? k, E.value = n.size > Ir, ne();
|
|
2227
2320
|
} finally {
|
|
2228
|
-
e ===
|
|
2321
|
+
e === A && (T.value = !1);
|
|
2229
2322
|
}
|
|
2230
2323
|
}
|
|
2231
2324
|
L(() => {
|
|
2232
|
-
|
|
2325
|
+
A++, ee++, j?.();
|
|
2233
2326
|
});
|
|
2234
2327
|
function ie() {
|
|
2235
|
-
return ve(
|
|
2328
|
+
return ve(h()).id;
|
|
2236
2329
|
}
|
|
2237
2330
|
function ae(e) {
|
|
2238
|
-
if (!e) return ve(
|
|
2239
|
-
if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(
|
|
2240
|
-
return
|
|
2331
|
+
if (!e) return ve(h());
|
|
2332
|
+
if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(m("commentForm.uploadFailed"));
|
|
2333
|
+
return _(r, a(), e);
|
|
2241
2334
|
}
|
|
2242
|
-
function
|
|
2243
|
-
let n = `${
|
|
2335
|
+
function N(e, t) {
|
|
2336
|
+
let n = `${o(a(), v.value)}/comment-images/${e}/`;
|
|
2244
2337
|
return se(t).filter((e) => e.path.startsWith(n));
|
|
2245
2338
|
}
|
|
2246
|
-
async function
|
|
2247
|
-
let n =
|
|
2339
|
+
async function oe(e, t) {
|
|
2340
|
+
let n = N(t, e.images), r = zr(e.body, p);
|
|
2248
2341
|
return {
|
|
2249
|
-
postId:
|
|
2250
|
-
boardId:
|
|
2251
|
-
listed:
|
|
2342
|
+
postId: v.value,
|
|
2343
|
+
boardId: g.value,
|
|
2344
|
+
listed: b(),
|
|
2252
2345
|
body: r,
|
|
2253
|
-
...await
|
|
2346
|
+
...await f(r, e.translations),
|
|
2254
2347
|
authorUid: e.authorUid,
|
|
2255
2348
|
authorName: e.authorName,
|
|
2256
2349
|
authorPhoto: e.authorPhoto,
|
|
2257
2350
|
moderationStatus: "approved",
|
|
2258
2351
|
replyCount: 0,
|
|
2259
2352
|
likeCount: 0,
|
|
2260
|
-
createdAt:
|
|
2261
|
-
updatedAt:
|
|
2353
|
+
createdAt: J(),
|
|
2354
|
+
updatedAt: J(),
|
|
2262
2355
|
...n.length ? { images: n } : {}
|
|
2263
2356
|
};
|
|
2264
2357
|
}
|
|
2265
|
-
async function
|
|
2358
|
+
async function ce(e) {
|
|
2266
2359
|
if (!e.length) return;
|
|
2267
|
-
let t = We(
|
|
2360
|
+
let t = We(i);
|
|
2268
2361
|
await Promise.all(e.map((e) => He(qe(t, e)).catch(() => {})));
|
|
2269
2362
|
}
|
|
2270
|
-
async function
|
|
2271
|
-
let t = Oe(
|
|
2363
|
+
async function ue(e) {
|
|
2364
|
+
let t = Oe(r), n = ae(e.id);
|
|
2272
2365
|
t.set(n, {
|
|
2273
|
-
...await
|
|
2366
|
+
...await oe(e, n.id),
|
|
2274
2367
|
parentId: null,
|
|
2275
2368
|
rootId: n.id,
|
|
2276
2369
|
depth: 0,
|
|
2277
2370
|
replyToUid: null,
|
|
2278
2371
|
replyToName: null,
|
|
2279
2372
|
isReply: !1
|
|
2280
|
-
}), t.update(
|
|
2373
|
+
}), t.update(S(r, a(), v.value), { commentCount: we(1) }), await t.commit();
|
|
2281
2374
|
}
|
|
2282
|
-
async function
|
|
2283
|
-
if (!e.parent.id) throw Error(
|
|
2284
|
-
let t = Oe(
|
|
2285
|
-
if (!
|
|
2286
|
-
let
|
|
2375
|
+
async function P(e) {
|
|
2376
|
+
if (!e.parent.id) throw Error(m("comments.replyTargetNotFound"));
|
|
2377
|
+
let t = Oe(r), n = ae(e.id), i = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
|
|
2378
|
+
if (!i) throw Error(m("comments.threadNotFound"));
|
|
2379
|
+
let o = Math.min((e.parent.depth ?? 0) + 1, 2);
|
|
2287
2380
|
t.set(n, {
|
|
2288
|
-
...await
|
|
2381
|
+
...await oe(e, n.id),
|
|
2289
2382
|
parentId: e.parent.id,
|
|
2290
|
-
rootId:
|
|
2291
|
-
depth:
|
|
2383
|
+
rootId: i,
|
|
2384
|
+
depth: o,
|
|
2292
2385
|
replyToUid: e.parent.authorUid,
|
|
2293
2386
|
replyToName: e.parent.authorName,
|
|
2294
2387
|
isReply: !0
|
|
2295
|
-
}), t.update(
|
|
2388
|
+
}), t.update(_(r, a(), i), { replyCount: we(1) }), t.update(S(r, a(), v.value), { commentCount: we(1) }), await t.commit();
|
|
2296
2389
|
}
|
|
2297
|
-
async function
|
|
2390
|
+
async function F(e) {
|
|
2298
2391
|
if (!e.id) return;
|
|
2299
|
-
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(
|
|
2300
|
-
let t =
|
|
2301
|
-
await sn(
|
|
2302
|
-
let n = Oe(
|
|
2303
|
-
n.delete(
|
|
2304
|
-
}
|
|
2305
|
-
async function
|
|
2306
|
-
let
|
|
2307
|
-
body:
|
|
2308
|
-
updatedAt:
|
|
2392
|
+
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(m("comments.hasRepliesCannotDelete"));
|
|
2393
|
+
let t = le(e.images, `${o(a(), v.value)}/comment-images/${e.id}/`);
|
|
2394
|
+
await sn(r, a(), e.id);
|
|
2395
|
+
let n = Oe(r);
|
|
2396
|
+
n.delete(_(r, a(), e.id)), e.parentId && e.rootId && n.update(_(r, a(), e.rootId), { replyCount: we(-1) }), n.update(S(r, a(), v.value), { commentCount: we(-1) }), await n.commit(), await ce(t), w.value = w.value.filter((t) => t.id !== e.id), x.value = x.value.filter((t) => t.id !== e.id);
|
|
2397
|
+
}
|
|
2398
|
+
async function fe(e, t, n, i) {
|
|
2399
|
+
let o = zr(t, p), s = {
|
|
2400
|
+
body: o,
|
|
2401
|
+
updatedAt: J()
|
|
2309
2402
|
};
|
|
2310
2403
|
if (n !== void 0) {
|
|
2311
|
-
let t =
|
|
2312
|
-
s.images = t.length ? t :
|
|
2404
|
+
let t = N(e, n);
|
|
2405
|
+
s.images = t.length ? t : V();
|
|
2313
2406
|
}
|
|
2314
|
-
await
|
|
2407
|
+
await X(_(r, a(), e), {
|
|
2315
2408
|
...s,
|
|
2316
|
-
...await
|
|
2409
|
+
...await f(o, i)
|
|
2317
2410
|
});
|
|
2318
2411
|
}
|
|
2319
2412
|
async function me(e, t, n) {
|
|
2320
|
-
await
|
|
2413
|
+
await X(_(r, a(), e), {
|
|
2321
2414
|
isBlinded: t,
|
|
2322
|
-
moderatedAt:
|
|
2415
|
+
moderatedAt: J(),
|
|
2323
2416
|
moderatedBy: n
|
|
2324
2417
|
});
|
|
2325
2418
|
}
|
|
2326
2419
|
return {
|
|
2327
|
-
comments:
|
|
2328
|
-
commentsPending: I(() =>
|
|
2329
|
-
hasMore:
|
|
2330
|
-
loadingMore:
|
|
2331
|
-
loadMore:
|
|
2420
|
+
comments: te,
|
|
2421
|
+
commentsPending: I(() => D.value || C.value),
|
|
2422
|
+
hasMore: E,
|
|
2423
|
+
loadingMore: T,
|
|
2424
|
+
loadMore: re,
|
|
2332
2425
|
newCommentId: ie,
|
|
2333
|
-
translationSkipped:
|
|
2334
|
-
addComment:
|
|
2335
|
-
addReply:
|
|
2336
|
-
updateComment:
|
|
2426
|
+
translationSkipped: d,
|
|
2427
|
+
addComment: ue,
|
|
2428
|
+
addReply: P,
|
|
2429
|
+
updateComment: fe,
|
|
2337
2430
|
setCommentBlinded: me,
|
|
2338
|
-
deleteComment:
|
|
2431
|
+
deleteComment: F
|
|
2339
2432
|
};
|
|
2340
2433
|
}
|
|
2341
|
-
function
|
|
2342
|
-
let r =
|
|
2434
|
+
function Vr(e, t, n) {
|
|
2435
|
+
let r = Q(), i = () => y(), a = () => pe(r, i()), o = t.trim(), s = R([]), c = R(!1), l = R(!1), u = R(!0), d = null, f, p = 0, m = 0;
|
|
2343
2436
|
function h(e) {
|
|
2344
2437
|
return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
|
|
2345
2438
|
}
|
|
2346
|
-
function
|
|
2439
|
+
function g() {
|
|
2347
2440
|
f?.();
|
|
2348
2441
|
let e = ++m;
|
|
2349
|
-
f =
|
|
2442
|
+
f = Fr(r, i(), o, {
|
|
2350
2443
|
rootId: n,
|
|
2351
2444
|
cursor: d,
|
|
2352
2445
|
hasMore: u.value
|
|
@@ -2356,35 +2449,35 @@ function Dr(e, t, n) {
|
|
|
2356
2449
|
console.error("[memi-board:replies] onSnapshot failed", e);
|
|
2357
2450
|
});
|
|
2358
2451
|
}
|
|
2359
|
-
async function
|
|
2452
|
+
async function _() {
|
|
2360
2453
|
if (c.value || !u.value) return;
|
|
2361
2454
|
let e = p;
|
|
2362
2455
|
c.value = !0;
|
|
2363
2456
|
try {
|
|
2364
2457
|
let t = [
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
...d ? [
|
|
2371
|
-
|
|
2372
|
-
], r = await
|
|
2458
|
+
Z("postId", "==", o),
|
|
2459
|
+
Z("rootId", "==", n),
|
|
2460
|
+
Z("isReply", "==", !0),
|
|
2461
|
+
K("createdAt", "asc"),
|
|
2462
|
+
K(H(), "asc"),
|
|
2463
|
+
...d ? [Y(d)] : [],
|
|
2464
|
+
W(6)
|
|
2465
|
+
], r = await U(q(a(), ...t));
|
|
2373
2466
|
if (e !== p) return;
|
|
2374
|
-
let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0,
|
|
2467
|
+
let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0, Lr), f = c.map((e) => ({
|
|
2375
2468
|
id: e.id,
|
|
2376
2469
|
...e.data()
|
|
2377
2470
|
})).filter((e) => !i.has(e.id));
|
|
2378
|
-
s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size >
|
|
2471
|
+
s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size > Lr, g();
|
|
2379
2472
|
} finally {
|
|
2380
2473
|
e === p && (c.value = !1);
|
|
2381
2474
|
}
|
|
2382
2475
|
}
|
|
2383
|
-
function
|
|
2476
|
+
function v() {
|
|
2384
2477
|
p++, m++, c.value = !1, f?.(), f = void 0, s.value = [], d = null, l.value = !1, u.value = !0;
|
|
2385
2478
|
}
|
|
2386
2479
|
async function b() {
|
|
2387
|
-
|
|
2480
|
+
v(), await _();
|
|
2388
2481
|
}
|
|
2389
2482
|
return L(() => {
|
|
2390
2483
|
p++, m++, f?.();
|
|
@@ -2393,106 +2486,106 @@ function Dr(e, t, n) {
|
|
|
2393
2486
|
loading: c,
|
|
2394
2487
|
loaded: l,
|
|
2395
2488
|
hasMore: u,
|
|
2396
|
-
loadMore:
|
|
2489
|
+
loadMore: _,
|
|
2397
2490
|
refresh: b
|
|
2398
2491
|
};
|
|
2399
2492
|
}
|
|
2400
2493
|
//#endregion
|
|
2401
2494
|
//#region src/composables/useMemiBoardLikes.ts
|
|
2402
|
-
function
|
|
2403
|
-
let
|
|
2404
|
-
function
|
|
2405
|
-
return
|
|
2495
|
+
function Hr(e, n) {
|
|
2496
|
+
let r = () => y(), i = Q(), a = Ae(), { t: o } = O(), s = R(!1), c = R(!1), l;
|
|
2497
|
+
function u(e) {
|
|
2498
|
+
return t(i, r(), n, e);
|
|
2406
2499
|
}
|
|
2407
|
-
B(
|
|
2408
|
-
if (
|
|
2409
|
-
|
|
2500
|
+
B(a, (e) => {
|
|
2501
|
+
if (l?.(), l = void 0, !e) {
|
|
2502
|
+
s.value = !1;
|
|
2410
2503
|
return;
|
|
2411
2504
|
}
|
|
2412
|
-
|
|
2413
|
-
|
|
2505
|
+
l = G(u(e.uid), (e) => {
|
|
2506
|
+
s.value = e.exists();
|
|
2414
2507
|
}, (e) => {
|
|
2415
2508
|
console.error("[memi-board:likes] onSnapshot failed", e);
|
|
2416
2509
|
});
|
|
2417
|
-
}, { immediate: !0 }), L(() =>
|
|
2418
|
-
async function
|
|
2419
|
-
let
|
|
2420
|
-
if (!
|
|
2421
|
-
if (
|
|
2422
|
-
|
|
2510
|
+
}, { immediate: !0 }), L(() => l?.());
|
|
2511
|
+
async function d() {
|
|
2512
|
+
let t = a.value?.uid;
|
|
2513
|
+
if (!t) throw Error(o("likes.signInRequired"));
|
|
2514
|
+
if (c.value) return s.value;
|
|
2515
|
+
c.value = !0;
|
|
2423
2516
|
try {
|
|
2424
|
-
let
|
|
2425
|
-
return await Ee(
|
|
2426
|
-
uid:
|
|
2427
|
-
postId:
|
|
2517
|
+
let a = u(t), o = S(i, r(), n);
|
|
2518
|
+
return await Ee(i, async (r) => (await r.get(a)).exists() ? (r.delete(a), r.update(o, { likeCount: we(-1) }), !1) : (r.set(a, {
|
|
2519
|
+
uid: t,
|
|
2520
|
+
postId: n,
|
|
2428
2521
|
boardId: e,
|
|
2429
|
-
createdAt:
|
|
2430
|
-
}),
|
|
2522
|
+
createdAt: J()
|
|
2523
|
+
}), r.update(o, { likeCount: we(1) }), !0));
|
|
2431
2524
|
} finally {
|
|
2432
|
-
|
|
2525
|
+
c.value = !1;
|
|
2433
2526
|
}
|
|
2434
2527
|
}
|
|
2435
2528
|
return {
|
|
2436
|
-
isLiked:
|
|
2437
|
-
likePending:
|
|
2438
|
-
toggleLike:
|
|
2529
|
+
isLiked: s,
|
|
2530
|
+
likePending: c,
|
|
2531
|
+
toggleLike: d
|
|
2439
2532
|
};
|
|
2440
2533
|
}
|
|
2441
|
-
var
|
|
2442
|
-
function
|
|
2443
|
-
let
|
|
2444
|
-
B([
|
|
2445
|
-
|
|
2534
|
+
var Ur = Symbol.for("memi-board:comment-likes");
|
|
2535
|
+
function Wr(e, n) {
|
|
2536
|
+
let r = () => y(), i = Q(), a = Ae(), { t: o } = O(), c = I(() => z(e)), l = I(() => z(n)), u = R(/* @__PURE__ */ new Set()), d = R(null), f;
|
|
2537
|
+
B([a, l], ([e, t]) => {
|
|
2538
|
+
f?.(), f = void 0, u.value = /* @__PURE__ */ new Set(), e && t && (f = G(q(s(i, r()), Z("uid", "==", e.uid), Z("postId", "==", t), Z("target", "==", "comment")), (e) => {
|
|
2446
2539
|
let t = /* @__PURE__ */ new Set();
|
|
2447
2540
|
for (let n of e.docs) {
|
|
2448
2541
|
let e = n.data().commentId;
|
|
2449
2542
|
typeof e == "string" && e && t.add(e);
|
|
2450
2543
|
}
|
|
2451
|
-
|
|
2544
|
+
u.value = t;
|
|
2452
2545
|
}, (e) => {
|
|
2453
2546
|
console.error("[memi-board:comment-likes] onSnapshot failed", e);
|
|
2454
2547
|
}));
|
|
2455
|
-
}, { immediate: !0 }), L(() =>
|
|
2456
|
-
function f(e) {
|
|
2457
|
-
return !!e && c.value.has(e);
|
|
2458
|
-
}
|
|
2548
|
+
}, { immediate: !0 }), L(() => f?.());
|
|
2459
2549
|
function p(e) {
|
|
2460
|
-
return !!e &&
|
|
2550
|
+
return !!e && u.value.has(e);
|
|
2461
2551
|
}
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2552
|
+
function m(e) {
|
|
2553
|
+
return !!e && d.value === e;
|
|
2554
|
+
}
|
|
2555
|
+
async function h(e) {
|
|
2556
|
+
let n = a.value?.uid;
|
|
2557
|
+
if (!n) throw Error(o("likes.signInRequired"));
|
|
2465
2558
|
if (!e) return !1;
|
|
2466
|
-
if (
|
|
2467
|
-
|
|
2559
|
+
if (d.value) return p(e);
|
|
2560
|
+
d.value = e;
|
|
2468
2561
|
try {
|
|
2469
|
-
let
|
|
2470
|
-
let r = await
|
|
2471
|
-
if (!
|
|
2472
|
-
let u = Number(
|
|
2473
|
-
return r.exists() ? (
|
|
2474
|
-
uid:
|
|
2475
|
-
postId:
|
|
2476
|
-
boardId:
|
|
2562
|
+
let a = t(i, r(), e, n), s = _(i, r(), e), d = await Ee(i, async (t) => {
|
|
2563
|
+
let r = await t.get(a), i = await t.get(s);
|
|
2564
|
+
if (!i.exists()) throw Error(o("likes.commentNotFound"));
|
|
2565
|
+
let u = Number(i.data()?.likeCount ?? 0);
|
|
2566
|
+
return r.exists() ? (t.delete(a), t.update(s, { likeCount: Math.max(0, u - 1) }), !1) : (t.set(a, {
|
|
2567
|
+
uid: n,
|
|
2568
|
+
postId: l.value,
|
|
2569
|
+
boardId: c.value,
|
|
2477
2570
|
commentId: e,
|
|
2478
2571
|
target: "comment",
|
|
2479
|
-
createdAt:
|
|
2480
|
-
}),
|
|
2481
|
-
}), f = new Set(
|
|
2482
|
-
return
|
|
2572
|
+
createdAt: J()
|
|
2573
|
+
}), t.update(s, { likeCount: u + 1 }), !0);
|
|
2574
|
+
}), f = new Set(u.value);
|
|
2575
|
+
return d ? f.add(e) : f.delete(e), u.value = f, d;
|
|
2483
2576
|
} finally {
|
|
2484
|
-
|
|
2577
|
+
d.value = null;
|
|
2485
2578
|
}
|
|
2486
2579
|
}
|
|
2487
2580
|
return {
|
|
2488
|
-
isLiked:
|
|
2489
|
-
isPending:
|
|
2490
|
-
toggleLike:
|
|
2581
|
+
isLiked: p,
|
|
2582
|
+
isPending: m,
|
|
2583
|
+
toggleLike: h
|
|
2491
2584
|
};
|
|
2492
2585
|
}
|
|
2493
2586
|
//#endregion
|
|
2494
2587
|
//#region src/composables/useMemiBoardReports.ts
|
|
2495
|
-
var
|
|
2588
|
+
var Gr = 200, Kr = [
|
|
2496
2589
|
{
|
|
2497
2590
|
value: "spam",
|
|
2498
2591
|
label: "스팸·광고"
|
|
@@ -2514,17 +2607,17 @@ var jr = 200, Mr = [
|
|
|
2514
2607
|
label: "기타"
|
|
2515
2608
|
}
|
|
2516
2609
|
];
|
|
2517
|
-
function
|
|
2518
|
-
return
|
|
2610
|
+
function qr(e, t) {
|
|
2611
|
+
return Kr.some((t) => t.value === e) ? j(t, `reports.reason.${e}`) : e || j(t, "reports.fallbackLabel");
|
|
2519
2612
|
}
|
|
2520
|
-
function
|
|
2521
|
-
let n = () =>
|
|
2613
|
+
function Jr(e, t) {
|
|
2614
|
+
let n = () => y(), r = Q(), i = Ae(), { t: a } = O(), o = R(!1), s = R(!1), c;
|
|
2522
2615
|
B(i, (e) => {
|
|
2523
2616
|
if (c?.(), c = void 0, !e) {
|
|
2524
2617
|
o.value = !1;
|
|
2525
2618
|
return;
|
|
2526
2619
|
}
|
|
2527
|
-
c =
|
|
2620
|
+
c = G(oe(r, n(), t, e.uid), (e) => {
|
|
2528
2621
|
o.value = e.exists();
|
|
2529
2622
|
}, (e) => {
|
|
2530
2623
|
console.error("[memi-board:reports] onSnapshot failed", e);
|
|
@@ -2535,24 +2628,24 @@ function Pr(e, t) {
|
|
|
2535
2628
|
if (!l) throw Error(a("reports.signInRequired"));
|
|
2536
2629
|
if (s.value) return;
|
|
2537
2630
|
if (c.authorUid && c.authorUid === l) throw Error(a("reports.cannotReportOwn"));
|
|
2538
|
-
let
|
|
2539
|
-
if (!
|
|
2540
|
-
let
|
|
2541
|
-
if (
|
|
2631
|
+
let u = Kr.some((e) => e.value === c.reason) ? c.reason : null;
|
|
2632
|
+
if (!u) throw Error(a("reports.reasonRequired"));
|
|
2633
|
+
let d = (c.detail || "").trim();
|
|
2634
|
+
if (d.length > 200) throw Error(a("reports.detailTooLong", { max: 200 }));
|
|
2542
2635
|
s.value = !0;
|
|
2543
2636
|
try {
|
|
2544
|
-
await De(
|
|
2637
|
+
await De(oe(r, n(), t, l), {
|
|
2545
2638
|
uid: l,
|
|
2546
2639
|
target: "post",
|
|
2547
2640
|
postId: t,
|
|
2548
2641
|
boardId: e,
|
|
2549
|
-
reason:
|
|
2550
|
-
detail:
|
|
2642
|
+
reason: u,
|
|
2643
|
+
detail: d,
|
|
2551
2644
|
status: "open",
|
|
2552
2645
|
postTitle: (c.postTitle || "").trim().slice(0, 200),
|
|
2553
2646
|
authorUid: c.authorUid || "",
|
|
2554
2647
|
authorName: c.authorName ?? null,
|
|
2555
|
-
createdAt:
|
|
2648
|
+
createdAt: J()
|
|
2556
2649
|
}), o.value = !0;
|
|
2557
2650
|
} finally {
|
|
2558
2651
|
s.value = !1;
|
|
@@ -2564,64 +2657,64 @@ function Pr(e, t) {
|
|
|
2564
2657
|
submitReport: l
|
|
2565
2658
|
};
|
|
2566
2659
|
}
|
|
2567
|
-
var
|
|
2568
|
-
function
|
|
2569
|
-
let t = () =>
|
|
2570
|
-
function
|
|
2660
|
+
var Yr = 20;
|
|
2661
|
+
function Xr(e = {}) {
|
|
2662
|
+
let t = () => y(), n = Q(), { isAdmin: r, canManageContent: i, canManageBoard: a } = Wt(), o = e.pageSize ?? Yr, s = I(() => z(e.boardId)?.trim() || ""), c = R([]), l = R(!0), u = R(!1), d = R(!1), f = R(""), p = null, m;
|
|
2663
|
+
function h(e) {
|
|
2571
2664
|
return {
|
|
2572
2665
|
id: e.id,
|
|
2573
2666
|
...e.data()
|
|
2574
2667
|
};
|
|
2575
2668
|
}
|
|
2576
|
-
function
|
|
2577
|
-
if (
|
|
2578
|
-
c.value = [],
|
|
2669
|
+
function g() {
|
|
2670
|
+
if (m?.(), !i.value || !r.value && !s.value) {
|
|
2671
|
+
c.value = [], l.value = !1;
|
|
2579
2672
|
return;
|
|
2580
2673
|
}
|
|
2581
|
-
|
|
2582
|
-
let e = s.value ? [
|
|
2583
|
-
|
|
2584
|
-
c.value = e.docs.map(
|
|
2674
|
+
l.value = !0;
|
|
2675
|
+
let e = s.value ? [Z("status", "==", "open"), Z("boardId", "==", s.value)] : [Z("status", "==", "open"), Z("target", "==", "post")];
|
|
2676
|
+
m = G(q(w(n, t()), ...e, K("createdAt", "desc"), K(H(), "desc"), W(o)), (e) => {
|
|
2677
|
+
c.value = e.docs.map(h).filter((e) => a(e.boardId)), p = e.docs.at(-1) ?? null, d.value = e.docs.length >= o, l.value = !1;
|
|
2585
2678
|
}, (e) => {
|
|
2586
|
-
console.error("[memi-board:report-queue] onSnapshot failed", e),
|
|
2679
|
+
console.error("[memi-board:report-queue] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
2587
2680
|
});
|
|
2588
2681
|
}
|
|
2589
|
-
B([i, s],
|
|
2590
|
-
async function
|
|
2591
|
-
if (!
|
|
2592
|
-
|
|
2682
|
+
B([i, s], g, { immediate: !0 }), L(() => m?.());
|
|
2683
|
+
async function _() {
|
|
2684
|
+
if (!u.value && d.value && p && i.value) {
|
|
2685
|
+
u.value = !0, f.value = "";
|
|
2593
2686
|
try {
|
|
2594
|
-
let e = s.value ? [
|
|
2595
|
-
c.value.push(...i.map(
|
|
2687
|
+
let e = s.value ? [Z("status", "==", "open"), Z("boardId", "==", s.value)] : [Z("status", "==", "open"), Z("target", "==", "post")], r = await U(q(w(n, t()), ...e, K("createdAt", "desc"), K(H(), "desc"), Y(p), W(o + 1))), i = r.docs.slice(0, o), l = new Set(c.value.map((e) => e.id));
|
|
2688
|
+
c.value.push(...i.map(h).filter((e) => !l.has(e.id) && a(e.boardId))), p = i.at(-1) ?? p, d.value = r.docs.length > o;
|
|
2596
2689
|
} catch (e) {
|
|
2597
|
-
|
|
2690
|
+
f.value = e.message || String(e);
|
|
2598
2691
|
} finally {
|
|
2599
|
-
|
|
2692
|
+
u.value = !1;
|
|
2600
2693
|
}
|
|
2601
2694
|
}
|
|
2602
2695
|
}
|
|
2603
|
-
async function
|
|
2604
|
-
e.id && a(e.boardId) && await
|
|
2696
|
+
async function v(e, r) {
|
|
2697
|
+
e.id && a(e.boardId) && await X(oe(n, t(), e.postId, e.uid), {
|
|
2605
2698
|
status: r,
|
|
2606
|
-
reviewedAt:
|
|
2699
|
+
reviewedAt: J(),
|
|
2607
2700
|
reviewedBy: Ae().value?.uid || ""
|
|
2608
2701
|
});
|
|
2609
2702
|
}
|
|
2610
2703
|
return {
|
|
2611
2704
|
reports: c,
|
|
2612
|
-
pending:
|
|
2613
|
-
loadingMore:
|
|
2614
|
-
hasMore:
|
|
2615
|
-
loadError:
|
|
2616
|
-
loadMore:
|
|
2617
|
-
dismissReport: (e) =>
|
|
2618
|
-
actionReport: (e) =>
|
|
2705
|
+
pending: l,
|
|
2706
|
+
loadingMore: u,
|
|
2707
|
+
hasMore: d,
|
|
2708
|
+
loadError: f,
|
|
2709
|
+
loadMore: _,
|
|
2710
|
+
dismissReport: (e) => v(e, "dismissed"),
|
|
2711
|
+
actionReport: (e) => v(e, "actioned")
|
|
2619
2712
|
};
|
|
2620
2713
|
}
|
|
2621
2714
|
//#endregion
|
|
2622
2715
|
//#region src/composables/useMemiBoardViews.ts
|
|
2623
|
-
function
|
|
2624
|
-
let e = () =>
|
|
2716
|
+
function Zr() {
|
|
2717
|
+
let e = () => y(), t = Q();
|
|
2625
2718
|
function n(t, n) {
|
|
2626
2719
|
let { postsCollection: r } = e();
|
|
2627
2720
|
return `memi-board:viewed:${r}:${t}:${n}`;
|
|
@@ -2644,7 +2737,7 @@ function Lr() {
|
|
|
2644
2737
|
if (s && c && !r(s, c)) {
|
|
2645
2738
|
i(s, c);
|
|
2646
2739
|
try {
|
|
2647
|
-
await
|
|
2740
|
+
await X(S(t, e(), c), { viewCount: we(1) });
|
|
2648
2741
|
} catch (e) {
|
|
2649
2742
|
try {
|
|
2650
2743
|
sessionStorage.removeItem(n(s, c));
|
|
@@ -2660,20 +2753,20 @@ function Lr() {
|
|
|
2660
2753
|
}
|
|
2661
2754
|
//#endregion
|
|
2662
2755
|
//#region src/composables/useMemiBoardModeration.ts
|
|
2663
|
-
var
|
|
2756
|
+
var Qr = {
|
|
2664
2757
|
flagged: !1,
|
|
2665
2758
|
category: "none",
|
|
2666
2759
|
reason: "",
|
|
2667
2760
|
via: "empty"
|
|
2668
2761
|
};
|
|
2669
|
-
function
|
|
2670
|
-
let t =
|
|
2671
|
-
function
|
|
2672
|
-
let t = e.match(
|
|
2762
|
+
function $r(e = {}) {
|
|
2763
|
+
let t = O(), n = I(() => D(z(e.locale)) ?? t.locale.value), r = i().moderation ?? {}, a = Me(), o = (e) => j(n.value, e), { isWriteRestricted: s, restrictedMessage: c, recordContentModerationBlock: l } = Wt(), u = Kn([...Gn, ...r.localBlocklist ?? []]);
|
|
2764
|
+
function d(e) {
|
|
2765
|
+
let t = e.match(u);
|
|
2673
2766
|
return t ? {
|
|
2674
2767
|
flagged: !0,
|
|
2675
2768
|
category: "abuse",
|
|
2676
|
-
reason:
|
|
2769
|
+
reason: Wn({
|
|
2677
2770
|
via: "local",
|
|
2678
2771
|
localHit: t[0] || "",
|
|
2679
2772
|
category: "abuse"
|
|
@@ -2681,14 +2774,14 @@ function zr(e = {}) {
|
|
|
2681
2774
|
via: "local"
|
|
2682
2775
|
} : null;
|
|
2683
2776
|
}
|
|
2684
|
-
function
|
|
2685
|
-
let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1,
|
|
2777
|
+
function f() {
|
|
2778
|
+
let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, i = Xe(a, {
|
|
2686
2779
|
backend: new Je(),
|
|
2687
2780
|
useLimitedUseAppCheckTokens: t
|
|
2688
2781
|
});
|
|
2689
|
-
return Ze(
|
|
2782
|
+
return Ze(i, {
|
|
2690
2783
|
model: e,
|
|
2691
|
-
systemInstruction:
|
|
2784
|
+
systemInstruction: zn(n.value),
|
|
2692
2785
|
generationConfig: {
|
|
2693
2786
|
temperature: 0,
|
|
2694
2787
|
maxOutputTokens: 256,
|
|
@@ -2701,11 +2794,11 @@ function zr(e = {}) {
|
|
|
2701
2794
|
}
|
|
2702
2795
|
});
|
|
2703
2796
|
}
|
|
2704
|
-
function
|
|
2797
|
+
function p() {
|
|
2705
2798
|
return r.onError === "block" ? {
|
|
2706
2799
|
flagged: !0,
|
|
2707
2800
|
category: "other",
|
|
2708
|
-
reason:
|
|
2801
|
+
reason: o("moderation.reviewFailed"),
|
|
2709
2802
|
error: !0,
|
|
2710
2803
|
via: "ai-error-block"
|
|
2711
2804
|
} : {
|
|
@@ -2716,8 +2809,8 @@ function zr(e = {}) {
|
|
|
2716
2809
|
via: "ai-error-allow"
|
|
2717
2810
|
};
|
|
2718
2811
|
}
|
|
2719
|
-
function
|
|
2720
|
-
let n =
|
|
2812
|
+
function m(e, t = "") {
|
|
2813
|
+
let n = Wn({
|
|
2721
2814
|
reason: e.reason,
|
|
2722
2815
|
category: e.category,
|
|
2723
2816
|
via: e.via
|
|
@@ -2727,98 +2820,94 @@ function zr(e = {}) {
|
|
|
2727
2820
|
reason: r
|
|
2728
2821
|
};
|
|
2729
2822
|
}
|
|
2730
|
-
async function
|
|
2823
|
+
async function h(e) {
|
|
2731
2824
|
if (!e.flagged || e.error || e.via !== "local" && e.via !== "ai") return e;
|
|
2732
2825
|
try {
|
|
2733
|
-
let { messageSuffix: t } = await
|
|
2734
|
-
return
|
|
2826
|
+
let { messageSuffix: t } = await l();
|
|
2827
|
+
return m(e, t);
|
|
2735
2828
|
} catch (t) {
|
|
2736
|
-
return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t),
|
|
2829
|
+
return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t), m(e);
|
|
2737
2830
|
}
|
|
2738
2831
|
}
|
|
2739
|
-
async function
|
|
2740
|
-
if (
|
|
2832
|
+
async function g(e) {
|
|
2833
|
+
if (s.value) return {
|
|
2741
2834
|
flagged: !0,
|
|
2742
2835
|
category: "other",
|
|
2743
|
-
reason:
|
|
2836
|
+
reason: c.value || o("moderation.writeRestricted"),
|
|
2744
2837
|
via: "restricted"
|
|
2745
2838
|
};
|
|
2746
|
-
let
|
|
2747
|
-
if (!
|
|
2748
|
-
...
|
|
2839
|
+
let t = e.trim();
|
|
2840
|
+
if (!t) return {
|
|
2841
|
+
...Qr,
|
|
2749
2842
|
via: "empty"
|
|
2750
2843
|
};
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
via: "admin-override"
|
|
2754
|
-
};
|
|
2755
|
-
let c = u(i);
|
|
2756
|
-
if (c) return m(c);
|
|
2844
|
+
let i = d(t);
|
|
2845
|
+
if (i) return h(i);
|
|
2757
2846
|
if (r.enabled === !1) return {
|
|
2758
|
-
...
|
|
2847
|
+
...Qr,
|
|
2759
2848
|
via: "disabled"
|
|
2760
2849
|
};
|
|
2761
2850
|
try {
|
|
2762
|
-
let e =
|
|
2763
|
-
if (!e) return
|
|
2764
|
-
let
|
|
2851
|
+
let e = Jn((await f().generateContent(Bn(t, n.value))).response.text());
|
|
2852
|
+
if (!e) return p();
|
|
2853
|
+
let r = {
|
|
2765
2854
|
flagged: e.flagged,
|
|
2766
2855
|
category: e.category,
|
|
2767
|
-
reason:
|
|
2856
|
+
reason: Wn({
|
|
2768
2857
|
reason: e.reason,
|
|
2769
2858
|
category: e.category,
|
|
2770
2859
|
via: "ai"
|
|
2771
2860
|
}),
|
|
2772
2861
|
via: "ai"
|
|
2773
2862
|
};
|
|
2774
|
-
return
|
|
2863
|
+
return r.flagged ? h(r) : r;
|
|
2775
2864
|
} catch (e) {
|
|
2776
|
-
return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e),
|
|
2865
|
+
return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e), p();
|
|
2777
2866
|
}
|
|
2778
2867
|
}
|
|
2779
|
-
async function
|
|
2780
|
-
if (
|
|
2868
|
+
async function _(e) {
|
|
2869
|
+
if (s.value) return {
|
|
2781
2870
|
flagged: !0,
|
|
2782
2871
|
category: "other",
|
|
2783
|
-
reason:
|
|
2872
|
+
reason: c.value || o("moderation.writeRestricted"),
|
|
2784
2873
|
via: "restricted"
|
|
2785
2874
|
};
|
|
2786
2875
|
if (r.enabled === !1 || !r.moderateImages) return {
|
|
2787
|
-
...
|
|
2876
|
+
...Qr,
|
|
2788
2877
|
via: "disabled"
|
|
2789
2878
|
};
|
|
2790
2879
|
try {
|
|
2791
2880
|
let t = await new Promise((t, n) => {
|
|
2792
2881
|
let r = new FileReader();
|
|
2793
2882
|
r.onload = () => t(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(e);
|
|
2794
|
-
}), r =
|
|
2883
|
+
}), r = Jn((await f().generateContent([{ inlineData: {
|
|
2795
2884
|
mimeType: e.type || "image/jpeg",
|
|
2796
2885
|
data: t
|
|
2797
|
-
} },
|
|
2798
|
-
if (!r) return
|
|
2886
|
+
} }, Vn(n.value)])).response.text());
|
|
2887
|
+
if (!r) return p();
|
|
2799
2888
|
let i = {
|
|
2800
2889
|
flagged: r.flagged,
|
|
2801
2890
|
category: r.category,
|
|
2802
|
-
reason:
|
|
2891
|
+
reason: Wn({
|
|
2803
2892
|
reason: r.reason,
|
|
2804
2893
|
category: r.category,
|
|
2805
2894
|
via: "ai"
|
|
2806
2895
|
}),
|
|
2807
2896
|
via: "ai"
|
|
2808
2897
|
};
|
|
2809
|
-
return i.flagged ?
|
|
2898
|
+
return i.flagged ? h(i) : i;
|
|
2810
2899
|
} catch (e) {
|
|
2811
|
-
return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e),
|
|
2900
|
+
return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e), p();
|
|
2812
2901
|
}
|
|
2813
2902
|
}
|
|
2814
2903
|
return {
|
|
2815
|
-
checkText:
|
|
2816
|
-
checkImage:
|
|
2904
|
+
checkText: g,
|
|
2905
|
+
checkImage: _
|
|
2817
2906
|
};
|
|
2818
2907
|
}
|
|
2819
2908
|
//#endregion
|
|
2820
2909
|
//#region src/composables/useMemiBoardUsers.ts
|
|
2821
|
-
var
|
|
2910
|
+
var ei = [
|
|
2822
2911
|
"owner",
|
|
2823
2912
|
"admin",
|
|
2824
2913
|
"manager",
|
|
@@ -2826,39 +2915,39 @@ var Br = [
|
|
|
2826
2915
|
"user"
|
|
2827
2916
|
].map((e) => ({
|
|
2828
2917
|
value: e,
|
|
2829
|
-
label:
|
|
2830
|
-
description:
|
|
2918
|
+
label: j("ko", `common.role.${e}`),
|
|
2919
|
+
description: j("ko", `boardUsers.roleDescription.${e}`)
|
|
2831
2920
|
}));
|
|
2832
|
-
function
|
|
2833
|
-
let t = () =>
|
|
2834
|
-
async function
|
|
2835
|
-
if (!
|
|
2836
|
-
await
|
|
2921
|
+
function ti(e = {}) {
|
|
2922
|
+
let t = () => y(), n = Q(), { t: r } = O(), i = I(() => z(e.enabled) ?? !0 ? d(n, t()) : null), o = ke(i, { ssrKey: h(t(), "users-management") });
|
|
2923
|
+
async function s(e, i) {
|
|
2924
|
+
if (!ei.some((e) => e.value === i)) throw Error(r("boardUsers.unsupportedRole"));
|
|
2925
|
+
await X(a(n, t(), e), {
|
|
2837
2926
|
role: i,
|
|
2838
|
-
updatedAt:
|
|
2927
|
+
updatedAt: J()
|
|
2839
2928
|
});
|
|
2840
2929
|
}
|
|
2841
2930
|
return {
|
|
2842
|
-
users:
|
|
2843
|
-
usersPending:
|
|
2844
|
-
updateUserRole:
|
|
2931
|
+
users: o,
|
|
2932
|
+
usersPending: o.pending,
|
|
2933
|
+
updateUserRole: s
|
|
2845
2934
|
};
|
|
2846
2935
|
}
|
|
2847
2936
|
//#endregion
|
|
2848
2937
|
//#region src/composables/useMemiBoardUserProfile.ts
|
|
2849
|
-
function
|
|
2850
|
-
let t =
|
|
2938
|
+
function ni(e) {
|
|
2939
|
+
let t = Q(), n = () => y(), r = I(() => z(e)), i = I(() => {
|
|
2851
2940
|
let e = r.value;
|
|
2852
|
-
return e ?
|
|
2853
|
-
}), { data:
|
|
2941
|
+
return e ? a(t, n(), e) : null;
|
|
2942
|
+
}), { data: o, pending: s } = je(i);
|
|
2854
2943
|
return {
|
|
2855
|
-
profile:
|
|
2856
|
-
profilePending:
|
|
2944
|
+
profile: o,
|
|
2945
|
+
profilePending: s
|
|
2857
2946
|
};
|
|
2858
2947
|
}
|
|
2859
2948
|
//#endregion
|
|
2860
2949
|
//#region src/utils/section.ts
|
|
2861
|
-
var
|
|
2950
|
+
var ri = [
|
|
2862
2951
|
3,
|
|
2863
2952
|
4,
|
|
2864
2953
|
5,
|
|
@@ -2868,43 +2957,43 @@ var Ur = [
|
|
|
2868
2957
|
9,
|
|
2869
2958
|
12
|
|
2870
2959
|
];
|
|
2871
|
-
function
|
|
2960
|
+
function ii(e) {
|
|
2872
2961
|
return [
|
|
2873
2962
|
{
|
|
2874
2963
|
value: "list",
|
|
2875
|
-
label:
|
|
2964
|
+
label: j(e, "sectionUtil.kind.list")
|
|
2876
2965
|
},
|
|
2877
2966
|
{
|
|
2878
2967
|
value: "post",
|
|
2879
|
-
label:
|
|
2968
|
+
label: j(e, "sectionUtil.kind.post")
|
|
2880
2969
|
},
|
|
2881
2970
|
{
|
|
2882
2971
|
value: "comments",
|
|
2883
|
-
label:
|
|
2972
|
+
label: j(e, "sectionUtil.kind.comments")
|
|
2884
2973
|
}
|
|
2885
2974
|
];
|
|
2886
2975
|
}
|
|
2887
|
-
function
|
|
2976
|
+
function ai(e) {
|
|
2888
2977
|
return [{
|
|
2889
2978
|
value: "latest",
|
|
2890
|
-
label:
|
|
2979
|
+
label: j(e, "sectionUtil.sort.latest")
|
|
2891
2980
|
}, {
|
|
2892
2981
|
value: "likes",
|
|
2893
|
-
label:
|
|
2982
|
+
label: j(e, "sectionUtil.sort.likes")
|
|
2894
2983
|
}];
|
|
2895
2984
|
}
|
|
2896
|
-
var
|
|
2897
|
-
function
|
|
2985
|
+
var oi = ii("ko"), si = ai("ko");
|
|
2986
|
+
function ci(e) {
|
|
2898
2987
|
return e === "list" ? 5 : 4;
|
|
2899
2988
|
}
|
|
2900
|
-
function
|
|
2989
|
+
function li(e, t) {
|
|
2901
2990
|
let n = Math.floor(Number(t));
|
|
2902
|
-
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) :
|
|
2991
|
+
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : ci(e);
|
|
2903
2992
|
}
|
|
2904
|
-
function
|
|
2993
|
+
function ui(e) {
|
|
2905
2994
|
return e === 12 ? null : 12 - e;
|
|
2906
2995
|
}
|
|
2907
|
-
function
|
|
2996
|
+
function di(e) {
|
|
2908
2997
|
return {
|
|
2909
2998
|
3: "col-span-12 md:col-span-3",
|
|
2910
2999
|
4: "col-span-12 md:col-span-4",
|
|
@@ -2916,36 +3005,36 @@ function Zr(e) {
|
|
|
2916
3005
|
12: "col-span-12"
|
|
2917
3006
|
}[e];
|
|
2918
3007
|
}
|
|
2919
|
-
function
|
|
3008
|
+
function fi(e) {
|
|
2920
3009
|
return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
|
|
2921
3010
|
}
|
|
2922
|
-
function
|
|
3011
|
+
function pi(e) {
|
|
2923
3012
|
let t = e.boardId || e.category || "free";
|
|
2924
3013
|
return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
|
|
2925
3014
|
}
|
|
2926
|
-
function
|
|
3015
|
+
function mi(e) {
|
|
2927
3016
|
return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
|
|
2928
3017
|
}
|
|
2929
|
-
function
|
|
3018
|
+
function hi(e) {
|
|
2930
3019
|
if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
|
|
2931
3020
|
}
|
|
2932
|
-
function
|
|
3021
|
+
function gi(e) {
|
|
2933
3022
|
return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
2934
3023
|
}
|
|
2935
|
-
function
|
|
2936
|
-
return vt(e, t).trim() || yt(e, t).trim() ||
|
|
3024
|
+
function _i(e, t) {
|
|
3025
|
+
return vt(e, t).trim() || yt(e, t).trim() || j(t, "sectionUtil.untitledPost");
|
|
2937
3026
|
}
|
|
2938
|
-
function
|
|
3027
|
+
function vi(e) {
|
|
2939
3028
|
return e === "image" || e === "video" ? "media" : "list";
|
|
2940
3029
|
}
|
|
2941
|
-
function
|
|
2942
|
-
return
|
|
3030
|
+
function yi(e, t) {
|
|
3031
|
+
return j(t, vi(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
|
|
2943
3032
|
}
|
|
2944
|
-
function
|
|
3033
|
+
function bi(e, t) {
|
|
2945
3034
|
return e ? t(e)?.listView ?? "default" : "default";
|
|
2946
3035
|
}
|
|
2947
|
-
function
|
|
2948
|
-
let n = e.map((e) =>
|
|
3036
|
+
function xi(e, t) {
|
|
3037
|
+
let n = e.map((e) => bi(e.boardId, t));
|
|
2949
3038
|
if (!n.length) return "default";
|
|
2950
3039
|
if (n.every((e) => e === n[0])) return n[0];
|
|
2951
3040
|
let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
|
|
@@ -2953,27 +3042,27 @@ function si(e, t) {
|
|
|
2953
3042
|
}
|
|
2954
3043
|
//#endregion
|
|
2955
3044
|
//#region src/composables/useMemiBoardSections.ts
|
|
2956
|
-
var
|
|
2957
|
-
function
|
|
3045
|
+
var Si = [];
|
|
3046
|
+
function Ci(e) {
|
|
2958
3047
|
let t = Number(e.cols);
|
|
2959
|
-
if (
|
|
3048
|
+
if (ri.includes(t)) return t;
|
|
2960
3049
|
let n = e.width;
|
|
2961
3050
|
return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
|
|
2962
3051
|
}
|
|
2963
|
-
function
|
|
3052
|
+
function wi(e) {
|
|
2964
3053
|
let t = e.height ?? e.size;
|
|
2965
3054
|
return t === "sm" || t === "lg" ? t : "md";
|
|
2966
3055
|
}
|
|
2967
|
-
function
|
|
3056
|
+
function Ti(e) {
|
|
2968
3057
|
return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
|
|
2969
3058
|
}
|
|
2970
|
-
function
|
|
3059
|
+
function Ei(e) {
|
|
2971
3060
|
return e.sort === "likes" ? "likes" : "latest";
|
|
2972
3061
|
}
|
|
2973
|
-
function
|
|
3062
|
+
function Di(e) {
|
|
2974
3063
|
return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
|
|
2975
3064
|
}
|
|
2976
|
-
function
|
|
3065
|
+
function Oi(e, t) {
|
|
2977
3066
|
let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
|
|
2978
3067
|
for (let e of n) {
|
|
2979
3068
|
let n = String(e || "").trim();
|
|
@@ -2981,131 +3070,155 @@ function mi(e, t) {
|
|
|
2981
3070
|
}
|
|
2982
3071
|
return r;
|
|
2983
3072
|
}
|
|
2984
|
-
function
|
|
2985
|
-
return
|
|
3073
|
+
function ki(e, t) {
|
|
3074
|
+
return j(t, "sections.defaultTitle", { n: e + 1 });
|
|
2986
3075
|
}
|
|
2987
|
-
function
|
|
2988
|
-
let r =
|
|
3076
|
+
function Ai(e, t, n) {
|
|
3077
|
+
let r = Ti(e), i = li(r, e.count), a = $(e.i18n), o = ut(e.i18nSource);
|
|
2989
3078
|
return {
|
|
2990
3079
|
id: String(e.id || `box-${t + 1}`),
|
|
2991
|
-
title: String(e.title ||
|
|
3080
|
+
title: String(e.title || ki(t, n)),
|
|
2992
3081
|
showTitle: e.showTitle !== !1,
|
|
2993
3082
|
kind: r,
|
|
2994
|
-
boardId:
|
|
3083
|
+
boardId: Di(e),
|
|
2995
3084
|
count: i,
|
|
2996
|
-
postIds:
|
|
2997
|
-
sort:
|
|
2998
|
-
cols:
|
|
2999
|
-
height:
|
|
3085
|
+
postIds: Oi(e, i),
|
|
3086
|
+
sort: Ei(e),
|
|
3087
|
+
cols: Ci(e),
|
|
3088
|
+
height: wi(e),
|
|
3000
3089
|
order: t,
|
|
3001
3090
|
...a ? { i18n: a } : {},
|
|
3002
3091
|
...o ? { i18nSource: o } : {}
|
|
3003
3092
|
};
|
|
3004
3093
|
}
|
|
3005
|
-
function
|
|
3006
|
-
let { locale: e } =
|
|
3007
|
-
async function
|
|
3008
|
-
if (!
|
|
3009
|
-
let
|
|
3094
|
+
function ji() {
|
|
3095
|
+
let { locale: e } = O(), { translateEntries: t } = nr(), n = Q(), r = ve(n, "settings", "homeLayout"), { data: i, pending: a } = je(r), o = I(() => (Array.isArray(i.value?.blocks) ? i.value.blocks : Si).map((t, n) => Ai(t, n, e.value)));
|
|
3096
|
+
async function s(n) {
|
|
3097
|
+
if (!de()) return n;
|
|
3098
|
+
let r = e.value, i = n.filter((e) => {
|
|
3010
3099
|
let t = e.title.trim();
|
|
3011
3100
|
return t ? !(e.i18nSource?.title === t && ht(e.i18n, ["title"])) : !1;
|
|
3012
3101
|
});
|
|
3013
|
-
if (!
|
|
3014
|
-
let
|
|
3102
|
+
if (!i.length) return n;
|
|
3103
|
+
let a = await t(i.map((e) => ({
|
|
3015
3104
|
id: e.id,
|
|
3016
3105
|
fields: { title: e.title.trim() },
|
|
3017
3106
|
context: e.kind
|
|
3018
3107
|
})), {
|
|
3019
|
-
source:
|
|
3108
|
+
source: r,
|
|
3020
3109
|
purpose: "section heading on a website home page"
|
|
3021
3110
|
});
|
|
3022
|
-
return
|
|
3023
|
-
let t =
|
|
3111
|
+
return n.map((e) => {
|
|
3112
|
+
let t = a[e.id];
|
|
3024
3113
|
if (!t) return e;
|
|
3025
|
-
let n = e.title.trim(),
|
|
3026
|
-
return ht(
|
|
3114
|
+
let n = e.title.trim(), i = ft(r, { title: n }, t);
|
|
3115
|
+
return ht(i, ["title"]) ? {
|
|
3027
3116
|
...e,
|
|
3028
3117
|
title: n,
|
|
3029
|
-
i18n:
|
|
3118
|
+
i18n: i,
|
|
3030
3119
|
i18nSource: {
|
|
3031
|
-
locale:
|
|
3120
|
+
locale: r,
|
|
3032
3121
|
title: n
|
|
3033
3122
|
}
|
|
3034
3123
|
} : e;
|
|
3035
3124
|
});
|
|
3036
3125
|
}
|
|
3037
|
-
function
|
|
3038
|
-
let r = t, i =
|
|
3126
|
+
function c(t, n) {
|
|
3127
|
+
let r = t, i = Ti(r), a = li(i, t.count), o = t.title.trim() || ki(n, e.value);
|
|
3039
3128
|
return {
|
|
3040
3129
|
id: t.id,
|
|
3041
3130
|
title: o,
|
|
3042
3131
|
showTitle: t.showTitle !== !1,
|
|
3043
3132
|
kind: i,
|
|
3044
|
-
boardId:
|
|
3133
|
+
boardId: Di(r),
|
|
3045
3134
|
count: a,
|
|
3046
|
-
postIds:
|
|
3047
|
-
sort:
|
|
3048
|
-
cols:
|
|
3049
|
-
height:
|
|
3135
|
+
postIds: Oi(r, a),
|
|
3136
|
+
sort: Ei(r),
|
|
3137
|
+
cols: Ci(r),
|
|
3138
|
+
height: wi(r),
|
|
3050
3139
|
order: n,
|
|
3051
3140
|
...t.i18n ? { i18n: t.i18n } : {},
|
|
3052
3141
|
...t.i18nSource?.title === o ? { i18nSource: t.i18nSource } : {}
|
|
3053
3142
|
};
|
|
3054
3143
|
}
|
|
3055
|
-
async function
|
|
3144
|
+
async function l(e) {
|
|
3056
3145
|
let t = e;
|
|
3057
3146
|
try {
|
|
3058
|
-
t = await
|
|
3147
|
+
t = await s(e);
|
|
3059
3148
|
} catch (e) {
|
|
3060
3149
|
console.warn("[memi-board] section translation skipped", e);
|
|
3061
3150
|
}
|
|
3062
|
-
await De(
|
|
3151
|
+
await De(r, {
|
|
3063
3152
|
columns: 12,
|
|
3064
|
-
blocks: t.map((e, t) =>
|
|
3065
|
-
updatedAt:
|
|
3153
|
+
blocks: t.map((e, t) => c(e, t)),
|
|
3154
|
+
updatedAt: J()
|
|
3066
3155
|
});
|
|
3067
3156
|
}
|
|
3068
3157
|
return {
|
|
3069
|
-
settings:
|
|
3070
|
-
pending:
|
|
3071
|
-
sections:
|
|
3072
|
-
blocks:
|
|
3073
|
-
hasSavedLayout: I(() => Array.isArray(
|
|
3074
|
-
saveSections:
|
|
3075
|
-
saveBlocks:
|
|
3158
|
+
settings: i,
|
|
3159
|
+
pending: a,
|
|
3160
|
+
sections: o,
|
|
3161
|
+
blocks: o,
|
|
3162
|
+
hasSavedLayout: I(() => Array.isArray(i.value?.blocks)),
|
|
3163
|
+
saveSections: l,
|
|
3164
|
+
saveBlocks: l
|
|
3076
3165
|
};
|
|
3077
3166
|
}
|
|
3078
3167
|
//#endregion
|
|
3079
3168
|
//#region src/composables/useMemiBoardMiniPosts.ts
|
|
3080
|
-
function
|
|
3081
|
-
let n =
|
|
3082
|
-
let i = Math.max(1, Math.floor(Number(z(t)) || 5)), a = z(e)?.trim() || "",
|
|
3083
|
-
return a &&
|
|
3084
|
-
}), { data:
|
|
3169
|
+
function Mi(e, t) {
|
|
3170
|
+
let n = Q(), r = () => y(), i = z(e)?.trim() || "all", a = I(() => {
|
|
3171
|
+
let i = Math.max(1, Math.floor(Number(z(t)) || 5)), a = z(e)?.trim() || "", o = [Z("isPublished", "==", !0), Z("listed", "==", !0)];
|
|
3172
|
+
return a && o.unshift(Z("boardId", "==", a)), q(u(n, r()), ...o, K("createdAt", "desc"), W(i));
|
|
3173
|
+
}), { data: o, pending: s, error: c } = ke(a, { ssrKey: h(r(), `mini-list/${i}`) });
|
|
3085
3174
|
return {
|
|
3086
|
-
posts: I(() =>
|
|
3087
|
-
pending:
|
|
3088
|
-
error:
|
|
3175
|
+
posts: I(() => o.value ?? []),
|
|
3176
|
+
pending: s,
|
|
3177
|
+
error: c
|
|
3089
3178
|
};
|
|
3090
3179
|
}
|
|
3091
|
-
function
|
|
3092
|
-
let t =
|
|
3180
|
+
function Ni(e) {
|
|
3181
|
+
let t = Q(), n = () => y(), r = I(() => [...new Set(z(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = I(() => r.value.length ? q(u(t, n()), Z(H(), "in", r.value)) : null), { data: o, pending: s, error: c } = ke(a, { ssrKey: h(n(), `mini-picked/${i}`) });
|
|
3093
3182
|
return {
|
|
3094
3183
|
posts: I(() => {
|
|
3095
|
-
let e = new Map((
|
|
3184
|
+
let e = new Map((o.value ?? []).map((e) => [e.id, e])), t = [];
|
|
3096
3185
|
for (let n of r.value) {
|
|
3097
3186
|
let r = e.get(n);
|
|
3098
3187
|
r && r.isPublished !== !1 && t.push(r);
|
|
3099
3188
|
}
|
|
3100
3189
|
return t;
|
|
3101
3190
|
}),
|
|
3102
|
-
pending:
|
|
3103
|
-
error:
|
|
3191
|
+
pending: s,
|
|
3192
|
+
error: c
|
|
3104
3193
|
};
|
|
3105
3194
|
}
|
|
3106
3195
|
//#endregion
|
|
3107
3196
|
//#region src/data/versionHistory.ts
|
|
3108
|
-
var
|
|
3197
|
+
var Pi = [
|
|
3198
|
+
{
|
|
3199
|
+
version: "0.53.0",
|
|
3200
|
+
date: "2026-11-04",
|
|
3201
|
+
highlights: [
|
|
3202
|
+
"게시판마다 커스텀 필드를 정해 글에 추가 값을 넣을 수 있어요",
|
|
3203
|
+
"파일은 끌어다 놓거나 클릭해서 첨부할 수 있어요",
|
|
3204
|
+
"게시판 설정은 카드 목록에서 고르고, 이름·설명·주소로 정렬할 수 있어요"
|
|
3205
|
+
],
|
|
3206
|
+
highlightsEn: [
|
|
3207
|
+
"Each board can define custom fields and store extra values on posts",
|
|
3208
|
+
"Files can be attached by dropping them or clicking the drop zone",
|
|
3209
|
+
"Board settings open from a card list that can be sorted by name, description, or address"
|
|
3210
|
+
],
|
|
3211
|
+
note: "규칙이나 인덱스 배포는 필요 없어요. 새 게시판 이름은 40자까지이고 주소가 돼요.",
|
|
3212
|
+
noteEn: "No rules or index deploy is required. A new board name is limited to 40 characters and becomes its address."
|
|
3213
|
+
},
|
|
3214
|
+
{
|
|
3215
|
+
version: "0.52.5",
|
|
3216
|
+
date: "2026-10-30",
|
|
3217
|
+
highlights: ["Safari에서 글·댓글 로딩이 늦을 때 long polling을 적용하는 호스트 설정 안내를 추가했어요"],
|
|
3218
|
+
highlightsEn: ["Added host setup guidance for using long polling when posts and comments load slowly in Safari"],
|
|
3219
|
+
note: "문서 안내 추가이며, 통신 설정은 호스트 앱에서 적용해야 해요.",
|
|
3220
|
+
noteEn: "This is a documentation update; the host app must apply the transport setting."
|
|
3221
|
+
},
|
|
3109
3222
|
{
|
|
3110
3223
|
version: "0.52.4",
|
|
3111
3224
|
date: "2026-10-30",
|
|
@@ -3671,14 +3784,14 @@ var bi = [
|
|
|
3671
3784
|
];
|
|
3672
3785
|
//#endregion
|
|
3673
3786
|
//#region src/utils/renderMarkdown.ts
|
|
3674
|
-
function
|
|
3787
|
+
function Fi(e) {
|
|
3675
3788
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3676
3789
|
}
|
|
3677
|
-
function
|
|
3790
|
+
function Ii(e) {
|
|
3678
3791
|
let t = e;
|
|
3679
3792
|
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;
|
|
3680
3793
|
}
|
|
3681
|
-
function
|
|
3794
|
+
function Li(e) {
|
|
3682
3795
|
if (!e?.trim()) return "";
|
|
3683
3796
|
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
|
|
3684
3797
|
function c() {
|
|
@@ -3687,7 +3800,7 @@ function Ci(e) {
|
|
|
3687
3800
|
return;
|
|
3688
3801
|
}
|
|
3689
3802
|
let e = o;
|
|
3690
|
-
n.push(`<${e}>${s.map((e) => `<li>${
|
|
3803
|
+
n.push(`<${e}>${s.map((e) => `<li>${Ii(e)}</li>`).join("")}</${e}>`), o = null, s = [];
|
|
3691
3804
|
}
|
|
3692
3805
|
for (; r < t.length;) {
|
|
3693
3806
|
let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
|
|
@@ -3696,7 +3809,7 @@ function Ci(e) {
|
|
|
3696
3809
|
continue;
|
|
3697
3810
|
}
|
|
3698
3811
|
if (i) {
|
|
3699
|
-
a.push(
|
|
3812
|
+
a.push(Fi(e)), r++;
|
|
3700
3813
|
continue;
|
|
3701
3814
|
}
|
|
3702
3815
|
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
|
|
@@ -3707,24 +3820,24 @@ function Ci(e) {
|
|
|
3707
3820
|
if (u) {
|
|
3708
3821
|
c();
|
|
3709
3822
|
let e = u[1].length;
|
|
3710
|
-
n.push(`<h${e} class="font-semibold mt-4 mb-2">${
|
|
3823
|
+
n.push(`<h${e} class="font-semibold mt-4 mb-2">${Ii(Fi(u[2]))}</h${e}>`), r++;
|
|
3711
3824
|
continue;
|
|
3712
3825
|
}
|
|
3713
3826
|
if (e.startsWith("> ")) {
|
|
3714
3827
|
c();
|
|
3715
3828
|
let e = [];
|
|
3716
|
-
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(
|
|
3717
|
-
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${
|
|
3829
|
+
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(Fi((t[r] ?? "").slice(2))), r++;
|
|
3830
|
+
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Ii(e.join("<br />"))}</blockquote>`);
|
|
3718
3831
|
continue;
|
|
3719
3832
|
}
|
|
3720
3833
|
let d = e.match(/^[-*+]\s+(.+)$/);
|
|
3721
3834
|
if (d) {
|
|
3722
|
-
o && o !== "ul" && c(), o = "ul", s.push(
|
|
3835
|
+
o && o !== "ul" && c(), o = "ul", s.push(Fi(d[1])), r++;
|
|
3723
3836
|
continue;
|
|
3724
3837
|
}
|
|
3725
3838
|
let f = e.match(/^\d+\.\s+(.+)$/);
|
|
3726
3839
|
if (f) {
|
|
3727
|
-
o && o !== "ol" && c(), o = "ol", s.push(
|
|
3840
|
+
o && o !== "ol" && c(), o = "ol", s.push(Fi(f[1])), r++;
|
|
3728
3841
|
continue;
|
|
3729
3842
|
}
|
|
3730
3843
|
if (!e.trim()) {
|
|
@@ -3736,22 +3849,22 @@ function Ci(e) {
|
|
|
3736
3849
|
for (; r < t.length;) {
|
|
3737
3850
|
let e = t[r] ?? "";
|
|
3738
3851
|
if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
|
|
3739
|
-
p.push(
|
|
3852
|
+
p.push(Fi(e)), r++;
|
|
3740
3853
|
}
|
|
3741
|
-
n.push(`<p class="my-2 leading-relaxed">${
|
|
3854
|
+
n.push(`<p class="my-2 leading-relaxed">${Ii(p.join("<br />"))}</p>`);
|
|
3742
3855
|
}
|
|
3743
3856
|
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");
|
|
3744
3857
|
}
|
|
3745
3858
|
//#endregion
|
|
3746
3859
|
//#region src/utils/orphanCleanup.ts
|
|
3747
|
-
function
|
|
3860
|
+
function Ri(e, t, n, r) {
|
|
3748
3861
|
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);
|
|
3749
3862
|
}
|
|
3750
|
-
function
|
|
3863
|
+
function zi(e, t) {
|
|
3751
3864
|
let n = Date.parse(e);
|
|
3752
3865
|
return Number.isFinite(n) && t - n >= 864e5;
|
|
3753
3866
|
}
|
|
3754
|
-
function
|
|
3867
|
+
function Bi(e, t) {
|
|
3755
3868
|
if (!e.startsWith(`${t}/`)) return null;
|
|
3756
3869
|
let n = e.slice(t.length + 1).split("/");
|
|
3757
3870
|
if (n.some((e) => !e || e === "." || e === "..")) return null;
|
|
@@ -3761,18 +3874,18 @@ function Ei(e, t) {
|
|
|
3761
3874
|
commentId: a
|
|
3762
3875
|
} : null;
|
|
3763
3876
|
}
|
|
3764
|
-
function
|
|
3877
|
+
function Vi(e, t, n) {
|
|
3765
3878
|
let r = `${t === "comment" ? n.commentsCollection : n.likesCollection}/`, i = e.startsWith(r) ? e.slice(r.length) : "";
|
|
3766
3879
|
return !!i && !i.includes("/") && i !== "." && i !== "..";
|
|
3767
3880
|
}
|
|
3768
3881
|
//#endregion
|
|
3769
3882
|
//#region src/composables/useMemiBoardCleanup.ts
|
|
3770
|
-
function
|
|
3771
|
-
let e =
|
|
3883
|
+
function Hi() {
|
|
3884
|
+
let e = Q(), t = Me(), { isAdmin: n, rolePending: r } = Wt(), { t: i } = O(), a = R([]), o = R(!1), s = R(!1), c = R(""), l = R(""), u = [], d = "", f = /* @__PURE__ */ new Map();
|
|
3772
3885
|
function p() {
|
|
3773
3886
|
let e = Le(t).currentUser?.uid;
|
|
3774
3887
|
if (!e) throw Error(i("settings.noAccess"));
|
|
3775
|
-
return JSON.stringify([e,
|
|
3888
|
+
return JSON.stringify([e, y()]);
|
|
3776
3889
|
}
|
|
3777
3890
|
function m(e) {
|
|
3778
3891
|
if (h(), p() !== e) throw Error(i("settings.cleanup.contextChanged"));
|
|
@@ -3781,10 +3894,10 @@ function Oi() {
|
|
|
3781
3894
|
if (!n.value || r.value || !Le(t).currentUser) throw Error(i("settings.noAccess"));
|
|
3782
3895
|
}
|
|
3783
3896
|
async function g() {
|
|
3784
|
-
let t =
|
|
3785
|
-
Ce(
|
|
3786
|
-
Ce(
|
|
3787
|
-
Ce(
|
|
3897
|
+
let t = y(), [n, r, i] = await Promise.all([
|
|
3898
|
+
Ce(ge(e, t.postsCollection)),
|
|
3899
|
+
Ce(ge(e, t.commentsCollection)),
|
|
3900
|
+
Ce(ge(e, t.likesCollection))
|
|
3788
3901
|
]), a = /* @__PURE__ */ new Set();
|
|
3789
3902
|
function o(e) {
|
|
3790
3903
|
if (typeof e == "string") {
|
|
@@ -3798,7 +3911,7 @@ function Oi() {
|
|
|
3798
3911
|
} else Array.isArray(e) ? e.forEach(o) : e && typeof e == "object" && Object.getPrototypeOf(e) === Object.prototype && Object.values(e).forEach(o);
|
|
3799
3912
|
}
|
|
3800
3913
|
n.docs.forEach((e) => o(e.data())), r.docs.forEach((e) => o(e.data()));
|
|
3801
|
-
for (let e of n.docs) (await Ce(
|
|
3914
|
+
for (let e of n.docs) (await Ce(ge(e.ref, "body"))).docs.forEach((e) => o(e.data()));
|
|
3802
3915
|
for (let e of [...a]) {
|
|
3803
3916
|
let t = e.match(/^(.*\/images\/)([^/]+)\.[^/.]+$/);
|
|
3804
3917
|
t && a.add(`${t[1]}thumbnails/${t[2]}.jpg`);
|
|
@@ -3822,7 +3935,7 @@ function Oi() {
|
|
|
3822
3935
|
let r = [];
|
|
3823
3936
|
for (let [e, t] of [["comment", n.commentDocs], ["like", n.likes]]) for (let i of t) {
|
|
3824
3937
|
let t = i.data();
|
|
3825
|
-
|
|
3938
|
+
Ri(e, t, n.posts, n.comments) && r.push({
|
|
3826
3939
|
kind: e,
|
|
3827
3940
|
path: i.ref.path,
|
|
3828
3941
|
postId: t.postId,
|
|
@@ -3840,12 +3953,12 @@ function Oi() {
|
|
|
3840
3953
|
});
|
|
3841
3954
|
o.push(...e.prefixes);
|
|
3842
3955
|
for (let t of e.items) {
|
|
3843
|
-
let e =
|
|
3956
|
+
let e = Bi(t.fullPath, n.cfg.postsCollection);
|
|
3844
3957
|
if (!e) continue;
|
|
3845
3958
|
let { postId: i, commentId: a } = e;
|
|
3846
3959
|
if (n.referenced.has(t.fullPath) || n.posts.has(i) && (!a || n.comments.has(a))) continue;
|
|
3847
3960
|
let o = await Ue(t);
|
|
3848
|
-
|
|
3961
|
+
zi(o.updated, Date.now()) && (f.set(t.fullPath, o.generation), r.push({
|
|
3849
3962
|
kind: "file",
|
|
3850
3963
|
path: t.fullPath,
|
|
3851
3964
|
postId: i,
|
|
@@ -3878,23 +3991,23 @@ function Oi() {
|
|
|
3878
3991
|
try {
|
|
3879
3992
|
let i = !1;
|
|
3880
3993
|
if (n.kind === "file") {
|
|
3881
|
-
if (!
|
|
3994
|
+
if (!Bi(n.path, o.cfg.postsCollection)) throw Error("Invalid cleanup path");
|
|
3882
3995
|
let r = We(t), a = qe(r, n.path), [s, c, l] = await Promise.all([
|
|
3883
3996
|
Se(ve(e, o.cfg.postsCollection, n.postId)),
|
|
3884
3997
|
n.commentId ? Se(ve(e, o.cfg.commentsCollection, n.commentId)) : null,
|
|
3885
3998
|
Ue(a)
|
|
3886
3999
|
]);
|
|
3887
|
-
m(d), l.generation === f.get(n.path) && !o.referenced.has(n.path) &&
|
|
4000
|
+
m(d), l.generation === f.get(n.path) && !o.referenced.has(n.path) && zi(l.updated, Date.now()) && (!s.exists() || n.commentId && !c?.exists()) && (await He(a), i = !0);
|
|
3888
4001
|
} else {
|
|
3889
4002
|
let t = n.kind;
|
|
3890
|
-
if (!
|
|
4003
|
+
if (!Vi(n.path, t, o.cfg)) throw Error("Invalid cleanup path");
|
|
3891
4004
|
i = await Ee(e, async (r) => {
|
|
3892
4005
|
let i = await r.get(ve(e, n.path));
|
|
3893
4006
|
if (!i.exists()) return !0;
|
|
3894
4007
|
let a = i.data();
|
|
3895
4008
|
if (typeof a.postId != "string" || !a.postId || a.postId.includes("/")) return !1;
|
|
3896
4009
|
let s = await r.get(ve(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(ve(e, o.cfg.commentsCollection, a.commentId)) : null;
|
|
3897
|
-
return
|
|
4010
|
+
return Ri(t, a, new Set(s.exists() ? [a.postId] : []), new Set(c?.exists() ? [a.commentId] : [])) ? (m(d), r.delete(i.ref), !0) : !1;
|
|
3898
4011
|
});
|
|
3899
4012
|
}
|
|
3900
4013
|
i ? r++ : p++, a.value = a.value.filter((e) => e.path !== n.path);
|
|
@@ -3914,16 +4027,16 @@ function Oi() {
|
|
|
3914
4027
|
}
|
|
3915
4028
|
}
|
|
3916
4029
|
return {
|
|
3917
|
-
items:
|
|
3918
|
-
busy:
|
|
3919
|
-
scanned:
|
|
3920
|
-
error:
|
|
3921
|
-
result:
|
|
4030
|
+
items: he(a),
|
|
4031
|
+
busy: he(o),
|
|
4032
|
+
scanned: he(s),
|
|
4033
|
+
error: he(c),
|
|
4034
|
+
result: he(l),
|
|
3922
4035
|
scan: _,
|
|
3923
4036
|
remove: v
|
|
3924
4037
|
};
|
|
3925
4038
|
}
|
|
3926
4039
|
//#endregion
|
|
3927
|
-
export {
|
|
4040
|
+
export { Sr as AUTHOR_MEMO_MAX_LENGTH, M as BOARD_NAME_MAX, ri as BOARD_SECTION_COLS, oi as BOARD_SECTION_KINDS, si as BOARD_SECTION_SORTS, ei as BOARD_USER_ROLES, Rr as COMMENT_BODY_MAX_LENGTH, yn as CUSTOM_FIELD_LABEL_MAX, vn as CUSTOM_FIELD_MAX, bn as CUSTOM_FIELD_PLACEHOLDER_MAX, xn as CUSTOM_FIELD_VALUE_MAX, It as DEFAULT_BLOCK_BAN_DECAY_MS, Ft as DEFAULT_BLOCK_BAN_THRESHOLD, rr as DEFAULT_BOARDS, ir as DEFAULT_CATEGORIES, r as DEFAULT_COMMENTS_COLLECTION, m as DEFAULT_LIKES_COLLECTION, ee as DEFAULT_MEMI_BOARD_LOCALE, ne as DEFAULT_POSTS_COLLECTION, e as DEFAULT_REPORTS_COLLECTION, te as DEFAULT_SETTINGS_COLLECTION, f as DEFAULT_USERS_COLLECTION, E as FALLBACK_MEMI_BOARD_LOCALE, Zn as HTML_MAX_CHARS, P as MEMI_BOARD_LOCALES, Gr as REPORT_DETAIL_MAX_LENGTH, Kr as REPORT_REASONS, Er as WRITING_ASSISTANT_DAILY_LIMIT, $e as asHttpUrl, xt as boardCopyIsTranslated, at as boardListOgDescription, it as boardListOgTitle, rt as boardPostOgDescription, nt as boardPostOgTitle, ii as boardSectionKinds, ai as boardSectionSorts, h as boardSsrKey, pt as boardTranslationLocales, a as boardUserDoc, d as boardUsersCol, _n as buildPostPreview, At as canManageBoardByRole, jt as canWriteCommentByRole, li as clampSectionCount, _ as commentDoc, pe as commentsCol, v as configureMemiBoard, ht as coversLocales, ci as defaultSectionCount, St as displayCommentBody, bt as displayPostContent, yt as displayPostSummary, vt as displayPostTitle, _t as displayStoredField, Lt as effectiveModerationBlockCount, An as extendForFields, Xt as extractEditorImageUrls, Dt as fetchPublicListForSeo, Et as fetchPublicPostForSeo, re as formatDate, ue as formatFullDate, k as formatRelativeDate, Bt as formatRestrictedUntilLabel, A as formatTimestampDetails, fn as hasBodyImage, dn as hasBodyText, ct as hashText, Jt as imeSafeSubmitClick, qt as imeSafeSubmitPointerDown, kt as isAssignedStaff, pn as isContentEmpty, lr as isFirestorePermissionDenied, n as isMemiBoardI18nEnabled, N as isMemiBoardLocaleLoaded, de as isMemiBoardTranslationEnabled, zt as isModerationWriteRestricted, t as likeDoc, x as likeDocId, s as likesCol, ie as loadMemiBoardLocale, gt as localizedText, Ur as memiBoardCommentLikesKey, ce as memiBoardHostLocaleKey, fe as memiBoardLocaleInfo, ft as mergeSourceFields, bi as miniBoardView, hi as miniCommentLink, mi as miniMoreLink, gi as miniPostImage, pi as miniPostLink, _i as miniPostTitle, xi as miniPostsView, vi as miniViewGroup, yi as miniViewLabel, Rt as moderationWriteRestrictedUntilMs, ot as normalizeBasePath, Ai as normalizeBoardSection, D as normalizeMemiBoardLocale, ui as pairSectionCols, ln as plainTextFromHtml, b as postBodyDoc, S as postDoc, Qt as postNamespaceFromStoragePath, o as postStorageFolder, u as postsCol, On as prepareCustomFields, Dn as readCustomFields, kn as readExtend, ut as readI18nSource, $ as readLocalizedFields, Li as renderMarkdownToHtml, oe as reportDoc, l as reportDocId, qr as reportReasonLabel, w as reportsCol, C as resolveBoardPathConfig, Ct as resolvePublicSeoDb, di as sectionColClass, fi as sectionMinHeight, T as settingsCol, g as settingsDoc, ae as slugify, Zt as storagePathFromDownloadUrl, un as titleFromBody, tt as toAbsoluteUrl, et as toBoardOgImageUrl, j as translate, y as useBoardPathConfig, Wt as useMemiBoardAuth, Tr as useMemiBoardAuthorMemo, nr as useMemiBoardAutoTranslate, Hi as useMemiBoardCleanup, xr as useMemiBoardCommentFeed, Wr as useMemiBoardCommentLikes, Br as useMemiBoardComments, i as useMemiBoardConfig, O as useMemiBoardI18n, Hr as useMemiBoardLikes, Mi as useMemiBoardMiniLatest, Ni as useMemiBoardMiniPicked, $r as useMemiBoardModeration, hr as useMemiBoardPost, mr as useMemiBoardPostList, dr as useMemiBoardPosts, Vr as useMemiBoardReplies, Xr as useMemiBoardReportQueue, Jr as useMemiBoardReports, ji as useMemiBoardSections, sr as useMemiBoardSettings, yr as useMemiBoardUserComments, _r as useMemiBoardUserPosts, ni as useMemiBoardUserProfile, ti as useMemiBoardUsers, Zr as useMemiBoardViews, Pr as useMemiBoardWritingAssistant, Pi as versionHistory, gn as videoListCoverUrl, hn as youtubeId };
|
|
3928
4041
|
|
|
3929
4042
|
//# sourceMappingURL=index.js.map
|