memi-board 0.45.0 → 0.45.1
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 +10 -0
- package/dist/composables/useMemiBoardComments.d.ts +2 -3
- package/dist/{en-BVUBLkxc.js → en-DxkqyZq2.js} +2 -1
- package/dist/{en-BVUBLkxc.js.map → en-DxkqyZq2.js.map} +1 -1
- package/dist/index.js +776 -741
- package/dist/index.js.map +1 -1
- package/dist/runtime/components/CategorySettings.vue +3 -1
- package/dist/runtime/components/CommentThread.vue +1 -1
- package/dist/runtime/components/Editor.vue +1 -0
- package/dist/{slugify-6bG6GSO_.js → slugify-BuOMFLxN.js} +3 -2
- package/dist/{slugify-6bG6GSO_.js.map → slugify-BuOMFLxN.js.map} +1 -1
- package/dist/storage.js +62 -49
- package/dist/storage.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/utils/deletePostCascade.d.ts +0 -2
- package/dist/utils/findReadablePost.d.ts +4 -0
- package/dist/utils/saveBoardVisibility.d.ts +3 -0
- package/dist/utils/subscribeCommentRange.d.ts +9 -0
- package/docs/firebase-setup.md +20 -1
- package/docs/firestore.rules.example +36 -7
- package/docs/storage.rules.example +25 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, L as l, M as u, N as d, O as f, P as p, R as m, S as h, T as g, U as _, V as v, W as y, _ as b, a as x, b as S, c as C, d as w, f as T, g as E, h as D, i as O, j as k, k as ee, l as te, m as
|
|
2
|
-
import { computed as
|
|
3
|
-
import { deleteDoc as
|
|
4
|
-
import { useCollection as
|
|
5
|
-
import { GoogleAuthProvider as
|
|
6
|
-
import { deleteObject as
|
|
7
|
-
import { GoogleAIBackend 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, L as l, M as u, N as d, O as f, P as p, R as m, S as h, T as g, U as _, V as v, W as y, _ as b, a as x, b as S, c as C, d as w, f as T, g as E, h as D, i as O, j as k, k as ee, l as te, m as A, n as ne, o as re, p as ie, r as ae, s as oe, u as se, v as j, w as ce, x as le, y as ue, z as M } from "./slugify-BuOMFLxN.js";
|
|
2
|
+
import { computed as N, onScopeDispose as P, reactive as de, ref as F, toValue as I, watch as L } from "vue";
|
|
3
|
+
import { deleteDoc as fe, deleteField as pe, doc as me, documentId as R, endAt as he, endBefore as ge, getDoc as z, getDocs as B, increment as V, limit as H, limitToLast as _e, onSnapshot as U, orderBy as W, query as G, runTransaction as ve, serverTimestamp as K, setDoc as q, startAfter as J, updateDoc as Y, where as X, writeBatch as ye } from "firebase/firestore";
|
|
4
|
+
import { useCollection as be, useCurrentUser as xe, useDocument as Se, useFirebaseApp as Ce, useFirebaseAuth as we, useFirestore as Z } from "vuefire";
|
|
5
|
+
import { GoogleAuthProvider as Te, OAuthProvider as Ee, createUserWithEmailAndPassword as De, signInWithEmailAndPassword as Oe, signInWithPopup as ke, signOut as Ae, updateProfile as je } from "firebase/auth";
|
|
6
|
+
import { deleteObject as Me, getStorage as Ne, listAll as Pe, ref as Fe } from "firebase/storage";
|
|
7
|
+
import { GoogleAIBackend as Ie, Schema as Q, getAI as Le, getGenerativeModel as Re } from "firebase/ai";
|
|
8
8
|
//#region src/utils/boardSeo.ts
|
|
9
|
-
function
|
|
9
|
+
function ze(e, t) {
|
|
10
10
|
return !e || e === "전체" || e === w(t, "seo.allCategory");
|
|
11
11
|
}
|
|
12
|
-
function
|
|
12
|
+
function Be(e) {
|
|
13
13
|
if (typeof e != "string") return null;
|
|
14
14
|
let t = e.trim();
|
|
15
15
|
return /^https?:\/\//i.test(t) ? t : null;
|
|
16
16
|
}
|
|
17
|
-
function
|
|
18
|
-
let t =
|
|
17
|
+
function Ve(e) {
|
|
18
|
+
let t = Be(e);
|
|
19
19
|
if (!t) return null;
|
|
20
20
|
if (!/firebasestorage\.googleapis\.com/i.test(t)) return t;
|
|
21
21
|
try {
|
|
@@ -32,45 +32,45 @@ function Be(e) {
|
|
|
32
32
|
return t;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
function
|
|
35
|
+
function He(e, t, n = "") {
|
|
36
36
|
let r = t.replace(/\/$/, ""), i = e.trim();
|
|
37
|
-
return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ?
|
|
37
|
+
return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? He(n, t) : r;
|
|
38
38
|
}
|
|
39
|
-
function
|
|
39
|
+
function Ue(e, t, n, r, i) {
|
|
40
40
|
let a = r?.trim().slice(0, 40), o = e.trim() || a || w(i, "seo.photo"), s = t?.trim(), c = n.trim() || "Board";
|
|
41
41
|
return s ? `${o} · ${s} | ${c}` : `${o} | ${c}`;
|
|
42
42
|
}
|
|
43
|
-
function
|
|
43
|
+
function We(e, t) {
|
|
44
44
|
let n = [];
|
|
45
45
|
return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(w(t, "seo.postDescriptionFallback")), e.categoryLabel?.trim() && n.push(e.categoryLabel.trim()), e.authorName?.trim() && n.push(e.authorName.trim()), n.join(" · ").slice(0, 200);
|
|
46
46
|
}
|
|
47
|
-
function
|
|
47
|
+
function Ge(e, t, n) {
|
|
48
48
|
let r = t.trim() || "Board", i = e?.trim();
|
|
49
|
-
return
|
|
49
|
+
return ze(i, n) ? w(n, "seo.listTitleAll", { site: r }) : w(n, "seo.listTitle", {
|
|
50
50
|
name: i,
|
|
51
51
|
site: r
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function Ke(e, t) {
|
|
55
55
|
if (e.description?.trim()) return e.description.trim().slice(0, 200);
|
|
56
|
-
let n = e.categoryLabel?.trim(), r =
|
|
56
|
+
let n = e.categoryLabel?.trim(), r = ze(n, t) ? w(t, "seo.listDescriptionAll") : w(t, "seo.listDescription", { name: n }), i = (e.recentTitles || []).filter(Boolean).slice(0, 3);
|
|
57
57
|
return i.length ? `${r} ${i.map((e) => `「${e}」`).join(" ")}`.slice(0, 200) : r.slice(0, 200);
|
|
58
58
|
}
|
|
59
|
-
function
|
|
59
|
+
function qe(e) {
|
|
60
60
|
let t = (e || "/board").trim() || "/board";
|
|
61
61
|
return (t.startsWith("/") ? t : `/${t}`).replace(/\/$/, "") || "/board";
|
|
62
62
|
}
|
|
63
63
|
//#endregion
|
|
64
64
|
//#region src/composables/fetchPublicSeo.ts
|
|
65
|
-
function
|
|
65
|
+
function Je() {
|
|
66
66
|
return {
|
|
67
67
|
db: Z(),
|
|
68
|
-
paths:
|
|
68
|
+
paths: j()
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
async function
|
|
71
|
+
async function Ye(e, t) {
|
|
72
72
|
try {
|
|
73
|
-
let n = await
|
|
73
|
+
let n = await z(o(e.db, e.paths, t));
|
|
74
74
|
if (!n.exists()) return {
|
|
75
75
|
label: t,
|
|
76
76
|
description: "",
|
|
@@ -90,7 +90,7 @@ async function Je(e, t) {
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
function
|
|
93
|
+
function Xe(e) {
|
|
94
94
|
if (e && typeof e == "object" && "toDate" in e) try {
|
|
95
95
|
let t = e.toDate();
|
|
96
96
|
return t instanceof Date ? t.toISOString() : null;
|
|
@@ -99,15 +99,15 @@ function Ye(e) {
|
|
|
99
99
|
}
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
|
-
async function
|
|
102
|
+
async function Ze(e, t, n) {
|
|
103
103
|
let r = e.trim(), i = t.trim();
|
|
104
104
|
if (!r || !i) return null;
|
|
105
|
-
let a = n ??
|
|
105
|
+
let a = n ?? Je();
|
|
106
106
|
a.paths = _(a.paths);
|
|
107
|
-
let o = await
|
|
107
|
+
let o = await Ye(a, r);
|
|
108
108
|
if (o.hidden) return null;
|
|
109
109
|
try {
|
|
110
|
-
let e = (await
|
|
110
|
+
let e = (await B(G(M(a.db, a.paths), X("boardId", "==", r), X("slug", "==", i), X("listed", "==", !0), X("isPublished", "==", !0), H(1)))).docs[0];
|
|
111
111
|
if (!e) return null;
|
|
112
112
|
let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title.trim() : "";
|
|
113
113
|
return n ? {
|
|
@@ -117,19 +117,19 @@ async function Xe(e, t, n) {
|
|
|
117
117
|
categoryLabel: o.label,
|
|
118
118
|
title: n,
|
|
119
119
|
summary: typeof t.summary == "string" ? t.summary.trim().slice(0, 200) : "",
|
|
120
|
-
previewImage:
|
|
120
|
+
previewImage: Ve(t.previewImage),
|
|
121
121
|
authorName: typeof t.authorName == "string" && t.authorName.trim() ? t.authorName.trim() : null,
|
|
122
|
-
createdAt:
|
|
122
|
+
createdAt: Xe(t.createdAt)
|
|
123
123
|
} : null;
|
|
124
124
|
} catch (e) {
|
|
125
125
|
return import.meta.dev && console.warn("[memi-board] fetchPublicPostForSeo failed", e), null;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
async function
|
|
129
|
-
n && await
|
|
130
|
-
let r = e?.trim() || null, i = t ??
|
|
128
|
+
async function Qe(e, t, n) {
|
|
129
|
+
n && await se(n);
|
|
130
|
+
let r = e?.trim() || null, i = t ?? Je();
|
|
131
131
|
if (i.paths = _(i.paths), r) {
|
|
132
|
-
let e = await
|
|
132
|
+
let e = await Ye(i, r);
|
|
133
133
|
if (e.hidden) return {
|
|
134
134
|
kind: "category",
|
|
135
135
|
category: r,
|
|
@@ -138,7 +138,7 @@ async function Ze(e, t, n) {
|
|
|
138
138
|
ogImage: null,
|
|
139
139
|
recentTitles: []
|
|
140
140
|
};
|
|
141
|
-
let { recentTitles: t, ogImage: a } = await
|
|
141
|
+
let { recentTitles: t, ogImage: a } = await $e(i, r);
|
|
142
142
|
return {
|
|
143
143
|
kind: "category",
|
|
144
144
|
category: r,
|
|
@@ -157,13 +157,13 @@ async function Ze(e, t, n) {
|
|
|
157
157
|
recentTitles: []
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
|
-
async function
|
|
160
|
+
async function $e(e, t) {
|
|
161
161
|
let n = [], r = null;
|
|
162
162
|
try {
|
|
163
|
-
let i = await
|
|
163
|
+
let i = await B(G(M(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), W("createdAt", "desc"), H(12)));
|
|
164
164
|
for (let e of i.docs) {
|
|
165
165
|
let t = e.data() ?? {}, i = typeof t.title == "string" ? t.title.trim() : "";
|
|
166
|
-
i && n.length < 5 && n.push(i), r ||=
|
|
166
|
+
i && n.length < 5 && n.push(i), r ||= Ve(t.previewImage);
|
|
167
167
|
}
|
|
168
168
|
} catch (e) {
|
|
169
169
|
import.meta.dev && console.warn("[memi-board] loadRecentListed failed", e);
|
|
@@ -175,31 +175,31 @@ async function Qe(e, t) {
|
|
|
175
175
|
}
|
|
176
176
|
//#endregion
|
|
177
177
|
//#region src/utils/boardAccess.ts
|
|
178
|
-
function
|
|
178
|
+
function et(e, t) {
|
|
179
179
|
return !e || !t ? !1 : (t.allowedStaffUids ?? []).includes(e);
|
|
180
180
|
}
|
|
181
|
-
function et(e, t, n, r) {
|
|
182
|
-
return e ? t ? !0 : n ? $e(e, r) : !1 : !1;
|
|
183
|
-
}
|
|
184
181
|
function tt(e, t, n, r) {
|
|
182
|
+
return e ? t ? !0 : n ? et(e, r) : !1 : !1;
|
|
183
|
+
}
|
|
184
|
+
function nt(e, t, n, r) {
|
|
185
185
|
if (!e) return !1;
|
|
186
|
-
if (r?.visibility === "hidden") return
|
|
186
|
+
if (r?.visibility === "hidden") return tt(e, t, n, r);
|
|
187
187
|
let i = r?.commentWriteRole ?? "user";
|
|
188
|
-
return i === "admin" ? t : i !== "staff" ||
|
|
188
|
+
return i === "admin" ? t : i !== "staff" || tt(e, t, n, r);
|
|
189
189
|
}
|
|
190
190
|
//#endregion
|
|
191
191
|
//#region src/composables/boardLookup.ts
|
|
192
|
-
var
|
|
193
|
-
function rt(e) {
|
|
194
|
-
nt = e;
|
|
195
|
-
}
|
|
192
|
+
var rt;
|
|
196
193
|
function it(e) {
|
|
197
|
-
|
|
194
|
+
rt = e;
|
|
195
|
+
}
|
|
196
|
+
function at(e) {
|
|
197
|
+
return rt?.(e);
|
|
198
198
|
}
|
|
199
199
|
//#endregion
|
|
200
200
|
//#region src/utils/moderation-strike.ts
|
|
201
|
-
var
|
|
202
|
-
function
|
|
201
|
+
var ot = 10, st = 864e5;
|
|
202
|
+
function ct(e, t, n = Date.now(), r = st) {
|
|
203
203
|
let i = Math.max(0, Math.floor(Number(e) || 0));
|
|
204
204
|
if (i <= 0) return 0;
|
|
205
205
|
let a = typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
@@ -207,7 +207,7 @@ function st(e, t, n = Date.now(), r = ot) {
|
|
|
207
207
|
let o = Math.floor((n - a) / r);
|
|
208
208
|
return Math.max(0, i - o);
|
|
209
209
|
}
|
|
210
|
-
function
|
|
210
|
+
function lt(e, t, n = Date.now(), r = 10, i = st) {
|
|
211
211
|
let a = Math.max(0, Math.floor(Number(e) || 0));
|
|
212
212
|
if (a < r) return null;
|
|
213
213
|
let o = typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
@@ -215,10 +215,10 @@ function ct(e, t, n = Date.now(), r = 10, i = ot) {
|
|
|
215
215
|
let s = o + (a - (r - 1)) * i;
|
|
216
216
|
return s > n ? s : null;
|
|
217
217
|
}
|
|
218
|
-
function
|
|
219
|
-
return
|
|
218
|
+
function ut(e, t, n = Date.now(), r = 10, i = st) {
|
|
219
|
+
return lt(e, t, n, r, i) != null;
|
|
220
220
|
}
|
|
221
|
-
function
|
|
221
|
+
function dt(e, t = Date.now(), n) {
|
|
222
222
|
let r = Math.max(0, e - t), i = Math.ceil(r / 36e5);
|
|
223
223
|
if (i <= 0) return w(n, "moderationStrike.liftSoon");
|
|
224
224
|
if (i < 24) return w(n, "moderationStrike.liftInHours", { hours: i });
|
|
@@ -228,7 +228,7 @@ function ut(e, t = Date.now(), n) {
|
|
|
228
228
|
hours: o
|
|
229
229
|
});
|
|
230
230
|
}
|
|
231
|
-
function
|
|
231
|
+
function ft(e) {
|
|
232
232
|
if (e == null) return null;
|
|
233
233
|
if (typeof e == "number" && Number.isFinite(e)) return e;
|
|
234
234
|
if (typeof e == "object" && e && "toMillis" in e && typeof e.toMillis == "function") return e.toMillis();
|
|
@@ -240,54 +240,54 @@ function dt(e) {
|
|
|
240
240
|
}
|
|
241
241
|
//#endregion
|
|
242
242
|
//#region src/composables/useMemiBoardAuth.ts
|
|
243
|
-
var
|
|
244
|
-
function
|
|
243
|
+
var pt = "__MEMI_BOARD_AUTH_STATE__";
|
|
244
|
+
function mt() {
|
|
245
245
|
let e = globalThis;
|
|
246
|
-
return e[
|
|
247
|
-
role:
|
|
248
|
-
rolePending:
|
|
249
|
-
rawBlockCount:
|
|
250
|
-
blockAtMs:
|
|
246
|
+
return e[pt] || (e[pt] = {
|
|
247
|
+
role: F("user"),
|
|
248
|
+
rolePending: F(!0),
|
|
249
|
+
rawBlockCount: F(0),
|
|
250
|
+
blockAtMs: F(null),
|
|
251
251
|
watchStarted: !1
|
|
252
|
-
}), e[
|
|
252
|
+
}), e[pt];
|
|
253
253
|
}
|
|
254
|
-
function
|
|
255
|
-
let e =
|
|
254
|
+
function ht() {
|
|
255
|
+
let e = ue(), { t, locale: n } = O(), r = mt(), i = Z(), a = we(), o = xe(), { role: s, rolePending: c, rawBlockCount: l, blockAtMs: u } = r;
|
|
256
256
|
function d() {
|
|
257
257
|
let t = e.moderation?.blockBanThreshold;
|
|
258
258
|
return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
|
|
259
259
|
}
|
|
260
260
|
function p() {
|
|
261
261
|
let t = e.moderation?.blockBanDecayMs;
|
|
262
|
-
return typeof t == "number" && t > 0 ? t :
|
|
262
|
+
return typeof t == "number" && t > 0 ? t : st;
|
|
263
263
|
}
|
|
264
264
|
function m(e) {
|
|
265
|
-
return f(i,
|
|
265
|
+
return f(i, j(), e);
|
|
266
266
|
}
|
|
267
267
|
function h(e) {
|
|
268
268
|
if (!e) {
|
|
269
269
|
l.value = 0, u.value = null;
|
|
270
270
|
return;
|
|
271
271
|
}
|
|
272
|
-
l.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), u.value =
|
|
272
|
+
l.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), u.value = ft(e.moderationBlockAt);
|
|
273
273
|
}
|
|
274
274
|
async function g(e) {
|
|
275
|
-
let t = m(e.uid), n = ee(i,
|
|
276
|
-
if (!r.exists()) return await Promise.all([
|
|
275
|
+
let t = m(e.uid), n = ee(i, j(), e.uid), r = await z(t);
|
|
276
|
+
if (!r.exists()) return await Promise.all([q(t, {
|
|
277
277
|
role: "user",
|
|
278
278
|
displayName: e.displayName,
|
|
279
279
|
photoURL: e.photoURL,
|
|
280
|
-
joinedAt:
|
|
281
|
-
lastVisitAt:
|
|
282
|
-
updatedAt:
|
|
283
|
-
}),
|
|
280
|
+
joinedAt: K(),
|
|
281
|
+
lastVisitAt: K(),
|
|
282
|
+
updatedAt: K()
|
|
283
|
+
}), q(n, { email: e.email })]), h({ moderationBlockCount: 0 }), "user";
|
|
284
284
|
let a = r.data();
|
|
285
285
|
h(a);
|
|
286
286
|
let o = typeof a.displayName == "string" && a.displayName.trim(), s = typeof a.photoURL == "string" && a.photoURL.trim(), c = {
|
|
287
|
-
lastVisitAt:
|
|
288
|
-
updatedAt:
|
|
287
|
+
lastVisitAt: K(),
|
|
288
|
+
updatedAt: K()
|
|
289
289
|
};
|
|
290
|
-
return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([
|
|
290
|
+
return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([Y(t, c), q(n, { email: e.email }, { merge: !0 })]), [
|
|
291
291
|
"admin",
|
|
292
292
|
"staff",
|
|
293
293
|
"user"
|
|
@@ -299,10 +299,10 @@ function mt() {
|
|
|
299
299
|
h(void 0);
|
|
300
300
|
return;
|
|
301
301
|
}
|
|
302
|
-
let t = await
|
|
302
|
+
let t = await z(m(e));
|
|
303
303
|
h(t.exists() ? t.data() : void 0);
|
|
304
304
|
}
|
|
305
|
-
r.watchStarted || (r.watchStarted = !0,
|
|
305
|
+
r.watchStarted || (r.watchStarted = !0, L(o, async (e) => {
|
|
306
306
|
if (c.value = !0, !e) {
|
|
307
307
|
s.value = "user", h(void 0), c.value = !1;
|
|
308
308
|
return;
|
|
@@ -315,15 +315,15 @@ function mt() {
|
|
|
315
315
|
c.value = !1;
|
|
316
316
|
}
|
|
317
317
|
}, { immediate: !0 }));
|
|
318
|
-
let v =
|
|
318
|
+
let v = N(() => !!o.value), y = N(() => s.value === "admin"), b = N(() => s.value === "staff"), x = N(() => y.value || b.value), S = N(() => ct(l.value, u.value, Date.now(), p())), C = N(() => {
|
|
319
319
|
let e = d();
|
|
320
|
-
return e <= 0 ? !1 :
|
|
321
|
-
}), w =
|
|
320
|
+
return e <= 0 ? !1 : ut(l.value, u.value, Date.now(), e, p());
|
|
321
|
+
}), w = N(() => {
|
|
322
322
|
let e = d();
|
|
323
323
|
if (e <= 0) return null;
|
|
324
|
-
let t =
|
|
325
|
-
return t == null ? null :
|
|
326
|
-
}), T =
|
|
324
|
+
let t = lt(l.value, u.value, Date.now(), e, p());
|
|
325
|
+
return t == null ? null : dt(t, Date.now(), n.value);
|
|
326
|
+
}), T = N(() => {
|
|
327
327
|
if (!C.value) return null;
|
|
328
328
|
let e = w.value;
|
|
329
329
|
return e ? t("auth.writeRestrictedUntil", { until: e }) : t("auth.writeRestricted");
|
|
@@ -335,26 +335,26 @@ function mt() {
|
|
|
335
335
|
restricted: !1,
|
|
336
336
|
messageSuffix: ""
|
|
337
337
|
};
|
|
338
|
-
let i = m(e), a = await
|
|
339
|
-
a.exists() ? await
|
|
340
|
-
moderationBlockCount:
|
|
341
|
-
moderationBlockAt:
|
|
342
|
-
updatedAt:
|
|
343
|
-
}) : await
|
|
338
|
+
let i = m(e), a = await z(i);
|
|
339
|
+
a.exists() ? await Y(i, {
|
|
340
|
+
moderationBlockCount: V(1),
|
|
341
|
+
moderationBlockAt: K(),
|
|
342
|
+
updatedAt: K()
|
|
343
|
+
}) : await q(i, {
|
|
344
344
|
role: "user",
|
|
345
345
|
displayName: o.value?.displayName ?? null,
|
|
346
346
|
moderationBlockCount: 1,
|
|
347
|
-
moderationBlockAt:
|
|
348
|
-
updatedAt:
|
|
347
|
+
moderationBlockAt: K(),
|
|
348
|
+
updatedAt: K()
|
|
349
349
|
});
|
|
350
350
|
let s = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, c = Date.now();
|
|
351
351
|
l.value = s, u.value = c;
|
|
352
|
-
let f =
|
|
352
|
+
let f = ct(s, c, c, p()), h = ut(s, c, c, r, p()), g = t("auth.strikeSuffix", {
|
|
353
353
|
count: f,
|
|
354
354
|
threshold: r
|
|
355
355
|
});
|
|
356
356
|
if (h) {
|
|
357
|
-
let e =
|
|
357
|
+
let e = lt(s, c, c, r, p()), i = e == null ? null : dt(e, c, n.value);
|
|
358
358
|
g = i ? t("auth.strikeRestrictedUntil", {
|
|
359
359
|
count: f,
|
|
360
360
|
until: i
|
|
@@ -371,33 +371,33 @@ function mt() {
|
|
|
371
371
|
return a;
|
|
372
372
|
}
|
|
373
373
|
async function k() {
|
|
374
|
-
return
|
|
374
|
+
return ke(D(), new Te());
|
|
375
375
|
}
|
|
376
376
|
async function te() {
|
|
377
|
-
let e = new
|
|
378
|
-
return e.addScope("email"), e.addScope("name"),
|
|
377
|
+
let e = new Ee("apple.com");
|
|
378
|
+
return e.addScope("email"), e.addScope("name"), ke(D(), e);
|
|
379
379
|
}
|
|
380
|
-
async function
|
|
381
|
-
return
|
|
380
|
+
async function A(e, t) {
|
|
381
|
+
return Oe(D(), e, t);
|
|
382
382
|
}
|
|
383
|
-
async function
|
|
384
|
-
let r = await
|
|
385
|
-
return n && await
|
|
383
|
+
async function ne(e, t, n) {
|
|
384
|
+
let r = await De(D(), e, t);
|
|
385
|
+
return n && await je(r.user, { displayName: n }), r;
|
|
386
|
+
}
|
|
387
|
+
async function re() {
|
|
388
|
+
await Ae(D());
|
|
386
389
|
}
|
|
387
|
-
|
|
388
|
-
|
|
390
|
+
function ie(e) {
|
|
391
|
+
return tt(o.value?.uid, y.value, b.value, e ? at(e) : void 0);
|
|
389
392
|
}
|
|
390
393
|
function ae(e) {
|
|
391
|
-
return
|
|
394
|
+
return v.value && (o.value?.uid === e.authorUid || ie(e.boardId));
|
|
392
395
|
}
|
|
393
396
|
function oe(e) {
|
|
394
|
-
return v.value && (o.value?.uid === e.authorUid || ae(e.boardId));
|
|
395
|
-
}
|
|
396
|
-
function se(e) {
|
|
397
397
|
return v.value && o.value?.uid === e.authorUid;
|
|
398
398
|
}
|
|
399
|
-
function
|
|
400
|
-
return v.value && (o.value?.uid === e.authorUid ||
|
|
399
|
+
function se(e) {
|
|
400
|
+
return v.value && (o.value?.uid === e.authorUid || ie(e.boardId));
|
|
401
401
|
}
|
|
402
402
|
return {
|
|
403
403
|
user: o,
|
|
@@ -405,7 +405,7 @@ function mt() {
|
|
|
405
405
|
isAdmin: y,
|
|
406
406
|
isStaff: b,
|
|
407
407
|
canManageContent: x,
|
|
408
|
-
canManageBoard:
|
|
408
|
+
canManageBoard: ie,
|
|
409
409
|
rolePending: c,
|
|
410
410
|
moderationBlockCount: S,
|
|
411
411
|
isWriteRestricted: C,
|
|
@@ -413,41 +413,47 @@ function mt() {
|
|
|
413
413
|
restrictedMessage: T,
|
|
414
414
|
signInWithGoogle: k,
|
|
415
415
|
signInWithApple: te,
|
|
416
|
-
signInWithEmail:
|
|
417
|
-
signUpWithEmail:
|
|
418
|
-
signOut:
|
|
419
|
-
canEdit:
|
|
420
|
-
canDelete:
|
|
421
|
-
canEditComment:
|
|
422
|
-
canDeleteComment:
|
|
416
|
+
signInWithEmail: A,
|
|
417
|
+
signUpWithEmail: ne,
|
|
418
|
+
signOut: re,
|
|
419
|
+
canEdit: ae,
|
|
420
|
+
canDelete: ae,
|
|
421
|
+
canEditComment: oe,
|
|
422
|
+
canDeleteComment: se,
|
|
423
423
|
recordContentModerationBlock: E,
|
|
424
424
|
refreshBoardUser: _
|
|
425
425
|
};
|
|
426
426
|
}
|
|
427
427
|
//#endregion
|
|
428
428
|
//#region src/utils/imeSafeSubmit.ts
|
|
429
|
-
var
|
|
430
|
-
function
|
|
429
|
+
var gt = /* @__PURE__ */ new WeakMap();
|
|
430
|
+
function _t(e) {
|
|
431
431
|
let t = e.currentTarget;
|
|
432
432
|
return t instanceof HTMLButtonElement ? t : t instanceof Element ? t.closest("button") : null;
|
|
433
433
|
}
|
|
434
|
-
function
|
|
434
|
+
function vt(e) {
|
|
435
435
|
if (e.pointerType !== "mouse" || e.button !== 0) return;
|
|
436
|
-
let t =
|
|
436
|
+
let t = _t(e), n = t?.form;
|
|
437
437
|
if (!t || !n || t.disabled) return;
|
|
438
|
-
|
|
438
|
+
gt.set(t, Date.now() + 1e3);
|
|
439
439
|
let r = document.activeElement;
|
|
440
440
|
r instanceof HTMLElement && r.blur(), setTimeout(() => n.requestSubmit(t), 0);
|
|
441
441
|
}
|
|
442
|
-
function
|
|
443
|
-
let t =
|
|
442
|
+
function yt(e) {
|
|
443
|
+
let t = _t(e);
|
|
444
444
|
if (!t) return;
|
|
445
|
-
let n =
|
|
446
|
-
n && Date.now() < n && (e.preventDefault(),
|
|
445
|
+
let n = gt.get(t);
|
|
446
|
+
n && Date.now() < n && (e.preventDefault(), gt.delete(t));
|
|
447
|
+
}
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/utils/findReadablePost.ts
|
|
450
|
+
async function bt(e, t, n, r, i, a) {
|
|
451
|
+
let o = [X("boardId", "==", n), X("slug", "==", r)];
|
|
452
|
+
return a ? (await B(G(M(e, t), ...o, H(1)))).docs[0] : (await Promise.all([B(G(M(e, t), ...o, X("listed", "==", !0), X("isPublished", "==", !0), H(1))), ...i ? [B(G(M(e, t), ...o, X("authorUid", "==", i), H(1)))] : []])).flatMap((e) => e.docs)[0];
|
|
447
453
|
}
|
|
448
454
|
//#endregion
|
|
449
455
|
//#region src/utils/extractEditorImageUrls.ts
|
|
450
|
-
function
|
|
456
|
+
function xt(e) {
|
|
451
457
|
if (!e) return [];
|
|
452
458
|
let t = /* @__PURE__ */ new Set();
|
|
453
459
|
for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&", "&"));
|
|
@@ -456,7 +462,7 @@ function yt(e) {
|
|
|
456
462
|
}
|
|
457
463
|
//#endregion
|
|
458
464
|
//#region src/utils/storagePath.ts
|
|
459
|
-
function
|
|
465
|
+
function St(e) {
|
|
460
466
|
try {
|
|
461
467
|
let t = new URL(e), n = t.hostname.toLowerCase();
|
|
462
468
|
if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
|
|
@@ -466,109 +472,106 @@ function bt(e) {
|
|
|
466
472
|
return null;
|
|
467
473
|
}
|
|
468
474
|
}
|
|
469
|
-
function
|
|
475
|
+
function Ct(e) {
|
|
470
476
|
return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
|
|
471
477
|
}
|
|
472
478
|
//#endregion
|
|
473
479
|
//#region src/utils/deletePostCascade.ts
|
|
474
|
-
async function
|
|
480
|
+
async function wt(e) {
|
|
475
481
|
try {
|
|
476
|
-
let t = await
|
|
477
|
-
await Promise.all([...t.items.map((e) =>
|
|
482
|
+
let t = await Pe(e);
|
|
483
|
+
await Promise.all([...t.items.map((e) => Me(e).catch(() => {})), ...t.prefixes.map((e) => wt(e))]);
|
|
478
484
|
} catch {}
|
|
479
485
|
}
|
|
480
|
-
async function
|
|
481
|
-
await
|
|
486
|
+
async function Tt(e, t) {
|
|
487
|
+
await wt(Fe(e, `${t}/images`)), await wt(Fe(e, `${t}/attachments`));
|
|
482
488
|
}
|
|
483
|
-
async function
|
|
489
|
+
async function Et(e, t) {
|
|
484
490
|
let n = [...new Set([...t].filter(Boolean))];
|
|
485
|
-
await Promise.all(n.map((t) =>
|
|
491
|
+
await Promise.all(n.map((t) => Me(Fe(e, t)).catch(() => {})));
|
|
486
492
|
}
|
|
487
|
-
var
|
|
488
|
-
async function
|
|
489
|
-
let n = await
|
|
490
|
-
for (let t = 0; t < n.docs.length; t +=
|
|
491
|
-
let r =
|
|
492
|
-
n.docs.slice(t, t +
|
|
493
|
+
var Dt = 450;
|
|
494
|
+
async function Ot(e, t) {
|
|
495
|
+
let n = await B(t);
|
|
496
|
+
for (let t = 0; t < n.docs.length; t += Dt) {
|
|
497
|
+
let r = ye(e);
|
|
498
|
+
n.docs.slice(t, t + Dt).forEach((e) => r.delete(e.ref)), await r.commit();
|
|
493
499
|
}
|
|
494
500
|
}
|
|
495
|
-
async function Dt(e, t, n) {
|
|
496
|
-
await Et(e, W(a(e, t), Y("postId", "==", n)));
|
|
497
|
-
}
|
|
498
|
-
async function Ot(e, t, n) {
|
|
499
|
-
await Et(e, W(s(e, t), Y("postId", "==", n)));
|
|
500
|
-
}
|
|
501
501
|
async function kt(e, t, n) {
|
|
502
|
-
await
|
|
502
|
+
await Ot(e, G(a(e, t), X("postId", "==", n)));
|
|
503
|
+
}
|
|
504
|
+
async function At(e, t, n) {
|
|
505
|
+
await Ot(e, G(a(e, t), X("commentId", "==", n), X("target", "==", "comment")));
|
|
503
506
|
}
|
|
504
|
-
async function
|
|
505
|
-
let i = l(e, n, r), a = c(e, n, r), [o, s] = await Promise.all([
|
|
507
|
+
async function jt(e, t, n, r) {
|
|
508
|
+
let i = l(e, n, r), a = c(e, n, r), [o, s] = await Promise.all([z(i), z(a)]);
|
|
506
509
|
if (!o.exists()) return;
|
|
507
510
|
let d = o.data(), f = s.exists() ? String(s.data().content ?? "") : "";
|
|
508
|
-
await
|
|
511
|
+
await Ot(e, G(u(e, n), X("postId", "==", r))), await kt(e, n, r);
|
|
509
512
|
let p = /* @__PURE__ */ new Set(), h = /* @__PURE__ */ new Set();
|
|
510
513
|
for (let e of d.attachments ?? []) {
|
|
511
514
|
if (!e?.path) continue;
|
|
512
515
|
p.add(e.path);
|
|
513
|
-
let t =
|
|
516
|
+
let t = Ct(e.path);
|
|
514
517
|
t && t !== r && h.add(t);
|
|
515
518
|
}
|
|
516
|
-
for (let e of
|
|
517
|
-
let t =
|
|
519
|
+
for (let e of xt(f)) {
|
|
520
|
+
let t = St(e);
|
|
518
521
|
if (!t) continue;
|
|
519
522
|
p.add(t);
|
|
520
523
|
let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
|
|
521
524
|
n !== t && n.includes("/images/thumbnails/") && p.add(n);
|
|
522
525
|
let i = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
|
|
523
526
|
i && !t.includes("/thumbnails/") && p.add(`${i[1]}thumbnails/${i[2]}.jpg`);
|
|
524
|
-
let a =
|
|
527
|
+
let a = Ct(t);
|
|
525
528
|
a && a !== r && h.add(a);
|
|
526
529
|
}
|
|
527
|
-
await
|
|
528
|
-
for (let e of h) await
|
|
529
|
-
await
|
|
530
|
+
await fe(a), await Tt(t, m(n, r));
|
|
531
|
+
for (let e of h) await Tt(t, m(n, e));
|
|
532
|
+
await Et(t, p), await fe(i);
|
|
530
533
|
}
|
|
531
534
|
//#endregion
|
|
532
535
|
//#region src/utils/postBody.ts
|
|
533
|
-
function
|
|
536
|
+
function Mt(e) {
|
|
534
537
|
return String(e || "").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<img\b[^>]*>/gi, " ").replace(/<iframe\b[^>]*>[\s\S]*?<\/iframe>/gi, " ").replace(/<video\b[\s\S]*?<\/video>/gi, " ").replace(/<audio\b[\s\S]*?<\/audio>/gi, " ").replace(/<[^>]+>/g, " ").replace(/ /gi, " ").replace(/ /g, " ").replace(/&[a-z]+;/gi, " ").replace(/&#\d+;/g, " ").replace(/[\u200B-\u200D\uFEFF\u00AD]/g, "").replace(/\s+/g, " ").trim();
|
|
535
538
|
}
|
|
536
|
-
function
|
|
537
|
-
let n =
|
|
539
|
+
function Nt(e, t = 40) {
|
|
540
|
+
let n = Mt(e);
|
|
538
541
|
if (!n) return "";
|
|
539
542
|
if (n.length <= t) return n;
|
|
540
543
|
let r = n.slice(0, t), i = r.lastIndexOf(" ");
|
|
541
544
|
return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
|
|
542
545
|
}
|
|
543
|
-
function
|
|
544
|
-
return
|
|
546
|
+
function Pt(e) {
|
|
547
|
+
return Mt(e).length > 0;
|
|
545
548
|
}
|
|
546
|
-
function
|
|
549
|
+
function Ft(e, t) {
|
|
547
550
|
return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
|
|
548
551
|
}
|
|
549
|
-
function
|
|
550
|
-
return !
|
|
552
|
+
function It(e) {
|
|
553
|
+
return !Pt(e);
|
|
551
554
|
}
|
|
552
555
|
//#endregion
|
|
553
556
|
//#region src/utils/postPreview.ts
|
|
554
|
-
function
|
|
557
|
+
function Lt(e) {
|
|
555
558
|
return e.replace(/&/g, "&").replace(/"/g, "\"").replace(/'/g, "'");
|
|
556
559
|
}
|
|
557
|
-
function
|
|
560
|
+
function Rt(e) {
|
|
558
561
|
if (e) try {
|
|
559
|
-
let t = new URL(
|
|
562
|
+
let t = new URL(Lt(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
|
|
560
563
|
if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
|
|
561
564
|
if (n.endsWith("youtube.com") || n === "youtube-nocookie.com") return t.pathname.startsWith("/embed/") || t.pathname.startsWith("/shorts/") ? t.pathname.split("/")[2] : t.searchParams.get("v") || void 0;
|
|
562
565
|
} catch {
|
|
563
566
|
return;
|
|
564
567
|
}
|
|
565
568
|
}
|
|
566
|
-
function
|
|
567
|
-
let t =
|
|
569
|
+
function zt(e) {
|
|
570
|
+
let t = Rt(e.videoUrl);
|
|
568
571
|
return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
569
572
|
}
|
|
570
|
-
function
|
|
571
|
-
let n = e.match(/<img\b[^>]*\bsrc=["']([^"']+)["']/i), r = e.match(/<iframe\b[^>]*\bsrc=["']([^"']+)["']/i), i = t.find((e) => e.type.startsWith("image/"))?.url, a = t.find((e) => e.type.startsWith("video/"))?.url, o = r ?
|
|
573
|
+
function Bt(e, t = []) {
|
|
574
|
+
let n = e.match(/<img\b[^>]*\bsrc=["']([^"']+)["']/i), r = e.match(/<iframe\b[^>]*\bsrc=["']([^"']+)["']/i), i = t.find((e) => e.type.startsWith("image/"))?.url, a = t.find((e) => e.type.startsWith("video/"))?.url, o = r ? Lt(r[1]) : a, s = o ? Rt(o) : void 0, c = n ? Lt(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
|
|
572
575
|
return {
|
|
573
576
|
summary: e.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|li|h[1-6]|blockquote)>/gi, "\n").replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/&/g, "&").replace(/[^\S\n]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{2,}/g, "\n").trim().slice(0, 160),
|
|
574
577
|
...c ? { previewImage: c } : {},
|
|
@@ -576,8 +579,45 @@ function zt(e, t = []) {
|
|
|
576
579
|
};
|
|
577
580
|
}
|
|
578
581
|
//#endregion
|
|
582
|
+
//#region src/utils/saveBoardVisibility.ts
|
|
583
|
+
function Vt(e) {
|
|
584
|
+
return e === "hidden" ? "hidden" : "public";
|
|
585
|
+
}
|
|
586
|
+
async function Ht(e, t, n, r) {
|
|
587
|
+
let i;
|
|
588
|
+
for (;;) {
|
|
589
|
+
let a = await B(G(t, X("boardId", "==", n), W("__name__"), ...i ? [J(i)] : [], H(400)));
|
|
590
|
+
if (a.empty) break;
|
|
591
|
+
let o = ye(e), s = 0;
|
|
592
|
+
for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
|
|
593
|
+
if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async function Ut(e, t, n, r) {
|
|
597
|
+
await Ht(e, M(e, t), n, r), await Ht(e, u(e, t), n, r);
|
|
598
|
+
}
|
|
599
|
+
async function Wt(e, t, n, r) {
|
|
600
|
+
let i = o(e, t, n), a = Vt(r.visibility);
|
|
601
|
+
await ve(e, async (e) => {
|
|
602
|
+
let t = await e.get(i), n = t.data(), o = n?.visibilityTransition || "";
|
|
603
|
+
if (o && o !== a) throw Error("Finish the pending visibility change before changing it again.");
|
|
604
|
+
return !t.exists() || !o && Vt(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
|
|
605
|
+
...r,
|
|
606
|
+
visibility: a === "public" ? "public" : Vt(n?.visibility),
|
|
607
|
+
visibilityTransition: a
|
|
608
|
+
}, { merge: !0 }), !0);
|
|
609
|
+
}) && (await Ut(e, t, n, a !== "hidden"), await ve(e, async (e) => {
|
|
610
|
+
if ((await e.get(i)).data()?.visibilityTransition !== a) throw Error("The visibility transition changed. Reload and retry.");
|
|
611
|
+
e.update(i, {
|
|
612
|
+
visibility: a,
|
|
613
|
+
visibilityTransition: "",
|
|
614
|
+
updatedAt: K()
|
|
615
|
+
});
|
|
616
|
+
}));
|
|
617
|
+
}
|
|
618
|
+
//#endregion
|
|
579
619
|
//#region src/composables/useMemiBoardSettings.ts
|
|
580
|
-
var
|
|
620
|
+
var Gt = [
|
|
581
621
|
{
|
|
582
622
|
id: "free",
|
|
583
623
|
label: "자유",
|
|
@@ -605,17 +645,18 @@ var Bt = [
|
|
|
605
645
|
visibility: "public",
|
|
606
646
|
order: 2
|
|
607
647
|
}
|
|
608
|
-
],
|
|
609
|
-
function
|
|
648
|
+
], Kt = Gt;
|
|
649
|
+
function qt(e) {
|
|
610
650
|
return e === "hidden" ? "hidden" : "public";
|
|
611
651
|
}
|
|
612
|
-
function
|
|
652
|
+
function Jt(e, t, n) {
|
|
613
653
|
return {
|
|
614
654
|
id: e,
|
|
615
655
|
label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
|
|
616
656
|
order: typeof t.order == "number" ? t.order : n,
|
|
617
657
|
description: (typeof t.description == "string" ? t.description : "") || "",
|
|
618
|
-
visibility:
|
|
658
|
+
visibility: qt(t.visibility),
|
|
659
|
+
visibilityTransition: t.visibilityTransition === "hidden" || t.visibilityTransition === "public" ? t.visibilityTransition : void 0,
|
|
619
660
|
listView: t.listView ?? "default",
|
|
620
661
|
editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
|
|
621
662
|
writeRole: t.writeRole ?? "user",
|
|
@@ -624,50 +665,37 @@ function Ut(e, t, n) {
|
|
|
624
665
|
locale: E(t.locale) ?? ""
|
|
625
666
|
};
|
|
626
667
|
}
|
|
627
|
-
function
|
|
628
|
-
let e = () =>
|
|
629
|
-
function
|
|
630
|
-
if (e) return
|
|
631
|
-
}
|
|
632
|
-
let b = v;
|
|
633
|
-
function x(e) {
|
|
634
|
-
if (e) return m.value.find((t) => t.id === e)?.description?.trim() || void 0;
|
|
635
|
-
}
|
|
636
|
-
let S = x;
|
|
637
|
-
function C(e) {
|
|
638
|
-
return e ? m.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
|
|
668
|
+
function Yt() {
|
|
669
|
+
let e = () => j(), t = Z(), n = Ce(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = ht(), { t: l } = O(), u = N(() => G(y(t, e()), W("order", "asc"))), { data: d, pending: f } = be(u, { ssrKey: r(e(), "boards") }), p = N(() => d.value.map((e, t) => Jt(e.id, e, t))), m = p, h = N(() => p.value.filter((e) => e.visibility !== "hidden")), g = h;
|
|
670
|
+
function _(e) {
|
|
671
|
+
if (e) return p.value.find((t) => t.id === e)?.label ?? e;
|
|
639
672
|
}
|
|
640
|
-
let
|
|
641
|
-
function
|
|
642
|
-
|
|
673
|
+
let v = _;
|
|
674
|
+
function b(e) {
|
|
675
|
+
if (e) return p.value.find((t) => t.id === e)?.description?.trim() || void 0;
|
|
643
676
|
}
|
|
644
|
-
let
|
|
645
|
-
function
|
|
646
|
-
|
|
677
|
+
let x = b;
|
|
678
|
+
function S(e) {
|
|
679
|
+
return e ? p.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
|
|
647
680
|
}
|
|
648
|
-
|
|
649
|
-
function
|
|
650
|
-
return
|
|
681
|
+
let C = S;
|
|
682
|
+
function w(e) {
|
|
683
|
+
return S(e) === "hidden";
|
|
651
684
|
}
|
|
652
|
-
let
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
for (;;) {
|
|
656
|
-
let a = await z(W(e, Y("boardId", "==", n), U("__name__"), ...i ? [q(i)] : [], V(400)));
|
|
657
|
-
if (a.empty) break;
|
|
658
|
-
let o = X(t), s = 0;
|
|
659
|
-
for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
|
|
660
|
-
if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
|
|
661
|
-
}
|
|
685
|
+
let T = w;
|
|
686
|
+
function D(e) {
|
|
687
|
+
if (e) return p.value.find((t) => t.id === e);
|
|
662
688
|
}
|
|
663
|
-
|
|
664
|
-
|
|
689
|
+
it((e) => D(e));
|
|
690
|
+
function k(e) {
|
|
691
|
+
return tt(c.value?.uid, a.value, s.value, e ? D(e) : void 0);
|
|
665
692
|
}
|
|
666
|
-
|
|
693
|
+
let ee = N(() => p.value.filter((e) => k(e.id)));
|
|
694
|
+
function te(e, t) {
|
|
667
695
|
return {
|
|
668
696
|
label: e.label.trim(),
|
|
669
697
|
description: (e.description ?? "").trim(),
|
|
670
|
-
visibility:
|
|
698
|
+
visibility: qt(e.visibility),
|
|
671
699
|
listView: e.listView ?? "default",
|
|
672
700
|
editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
|
|
673
701
|
writeRole: e.writeRole ?? "user",
|
|
@@ -675,64 +703,51 @@ function Wt() {
|
|
|
675
703
|
allowedStaffUids: e.allowedStaffUids ?? [],
|
|
676
704
|
locale: E(e.locale) ?? "",
|
|
677
705
|
order: t,
|
|
678
|
-
updatedAt:
|
|
706
|
+
updatedAt: K()
|
|
679
707
|
};
|
|
680
708
|
}
|
|
681
|
-
async function
|
|
709
|
+
async function A(n, r = n.order ?? 0) {
|
|
682
710
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
683
|
-
let a = n.id.trim(),
|
|
684
|
-
if (!a || !
|
|
685
|
-
let
|
|
711
|
+
let a = n.id.trim(), o = n.label.trim();
|
|
712
|
+
if (!a || !o) throw Error(l("boardSettings.idAndNameRequired"));
|
|
713
|
+
let s = qt(n.visibility), c = te({
|
|
686
714
|
...n,
|
|
687
|
-
label:
|
|
688
|
-
visibility:
|
|
715
|
+
label: o,
|
|
716
|
+
visibility: s
|
|
689
717
|
}, r);
|
|
690
|
-
await
|
|
718
|
+
await Wt(t, e(), a, c);
|
|
691
719
|
}
|
|
692
|
-
let
|
|
693
|
-
async function
|
|
720
|
+
let re = A;
|
|
721
|
+
async function ie(e) {
|
|
694
722
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
695
|
-
let
|
|
696
|
-
n.
|
|
697
|
-
let c = n.id.trim(), u = n.label.trim();
|
|
698
|
-
if (!c || !u) throw Error(l("boardSettings.idAndNameRequired"));
|
|
699
|
-
let d = Ht(n.visibility), f = ae({
|
|
700
|
-
...n,
|
|
701
|
-
label: u,
|
|
702
|
-
visibility: d
|
|
703
|
-
}, i);
|
|
704
|
-
a.set(o(t, e(), c), f, { merge: !0 }), ((r.get(c) ?? "public") !== d || d === "hidden") && s.push({
|
|
705
|
-
id: c,
|
|
706
|
-
listed: d !== "hidden"
|
|
707
|
-
});
|
|
708
|
-
}), await a.commit();
|
|
709
|
-
for (let e of s) await ie(e.id, e.listed);
|
|
723
|
+
for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(l("boardSettings.idAndNameRequired"));
|
|
724
|
+
for (let [t, n] of e.entries()) await A(n, t);
|
|
710
725
|
}
|
|
711
|
-
let
|
|
712
|
-
async function
|
|
726
|
+
let ae = ie;
|
|
727
|
+
async function oe(r) {
|
|
713
728
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
714
729
|
let a = r.trim();
|
|
715
730
|
if (!a) throw Error(l("boardSettings.deleteIdRequired"));
|
|
716
731
|
for (;;) {
|
|
717
|
-
let r = await
|
|
732
|
+
let r = await B(G(M(t, e()), X("boardId", "==", a), H(25)));
|
|
718
733
|
if (r.empty) break;
|
|
719
|
-
for (let i of r.docs) await
|
|
734
|
+
for (let i of r.docs) await jt(t, Ne(n), e(), i.id);
|
|
720
735
|
}
|
|
721
|
-
await
|
|
736
|
+
await fe(o(t, e(), r));
|
|
722
737
|
}
|
|
723
|
-
let
|
|
724
|
-
async function
|
|
738
|
+
let se = oe;
|
|
739
|
+
async function ce() {
|
|
725
740
|
return Promise.resolve();
|
|
726
741
|
}
|
|
727
|
-
async function
|
|
742
|
+
async function le(e) {
|
|
728
743
|
let t = e.trim();
|
|
729
744
|
if (!t) throw Error(l("boardSettings.nameRequired"));
|
|
730
745
|
if (!i.value) throw Error(l("boardSettings.signInRequired"));
|
|
731
|
-
let n =
|
|
746
|
+
let n = p.value.find((e) => e.label === t);
|
|
732
747
|
if (n) return n.id;
|
|
733
|
-
let r =
|
|
748
|
+
let r = ne(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(p.value.map((e) => e.id));
|
|
734
749
|
for (; s.has(a);) a = `${r}-${o++}`;
|
|
735
|
-
return await
|
|
750
|
+
return await A({
|
|
736
751
|
id: a,
|
|
737
752
|
label: t,
|
|
738
753
|
visibility: "public",
|
|
@@ -740,76 +755,79 @@ function Wt() {
|
|
|
740
755
|
editorType: "default",
|
|
741
756
|
writeRole: "user",
|
|
742
757
|
commentWriteRole: "user",
|
|
743
|
-
order:
|
|
758
|
+
order: p.value.length
|
|
744
759
|
}), a;
|
|
745
760
|
}
|
|
746
761
|
return {
|
|
747
|
-
boards:
|
|
748
|
-
publicBoards:
|
|
749
|
-
boardLabel:
|
|
750
|
-
boardDescription:
|
|
751
|
-
boardVisibility:
|
|
752
|
-
isBoardHidden:
|
|
753
|
-
getBoard:
|
|
754
|
-
canManageBoard:
|
|
755
|
-
managedBoards:
|
|
756
|
-
categories:
|
|
757
|
-
publicCategories:
|
|
758
|
-
categoryLabel:
|
|
759
|
-
categoryDescription:
|
|
760
|
-
categoryVisibility:
|
|
761
|
-
isCategoryHidden:
|
|
762
|
-
settingsPending:
|
|
763
|
-
ensureSettings:
|
|
764
|
-
addBoard:
|
|
765
|
-
addCategory:
|
|
766
|
-
saveBoard:
|
|
767
|
-
saveCategory:
|
|
768
|
-
saveBoards:
|
|
769
|
-
saveCategories:
|
|
770
|
-
deleteBoard:
|
|
771
|
-
deleteCategory:
|
|
772
|
-
DEFAULT_BOARDS:
|
|
773
|
-
DEFAULT_CATEGORIES:
|
|
762
|
+
boards: p,
|
|
763
|
+
publicBoards: h,
|
|
764
|
+
boardLabel: _,
|
|
765
|
+
boardDescription: b,
|
|
766
|
+
boardVisibility: S,
|
|
767
|
+
isBoardHidden: w,
|
|
768
|
+
getBoard: D,
|
|
769
|
+
canManageBoard: k,
|
|
770
|
+
managedBoards: ee,
|
|
771
|
+
categories: m,
|
|
772
|
+
publicCategories: g,
|
|
773
|
+
categoryLabel: v,
|
|
774
|
+
categoryDescription: x,
|
|
775
|
+
categoryVisibility: C,
|
|
776
|
+
isCategoryHidden: T,
|
|
777
|
+
settingsPending: f,
|
|
778
|
+
ensureSettings: ce,
|
|
779
|
+
addBoard: le,
|
|
780
|
+
addCategory: le,
|
|
781
|
+
saveBoard: A,
|
|
782
|
+
saveCategory: re,
|
|
783
|
+
saveBoards: ie,
|
|
784
|
+
saveCategories: ae,
|
|
785
|
+
deleteBoard: oe,
|
|
786
|
+
deleteCategory: se,
|
|
787
|
+
DEFAULT_BOARDS: Gt,
|
|
788
|
+
DEFAULT_CATEGORIES: Kt
|
|
774
789
|
};
|
|
775
790
|
}
|
|
776
791
|
//#endregion
|
|
777
792
|
//#region src/composables/useMemiBoardPosts.ts
|
|
778
|
-
var
|
|
779
|
-
function
|
|
793
|
+
var Xt = /* @__PURE__ */ new Map();
|
|
794
|
+
function Zt(e) {
|
|
780
795
|
if (!e || typeof e != "object") return !1;
|
|
781
796
|
let t = "code" in e ? String(e.code) : "";
|
|
782
797
|
return t === "permission-denied" || t === "firestore/permission-denied";
|
|
783
798
|
}
|
|
784
|
-
function
|
|
785
|
-
let n =
|
|
799
|
+
function Qt(e, t) {
|
|
800
|
+
let n = I(e)?.trim();
|
|
786
801
|
if (!n) throw Error(w(t, "posts.boardIdRequired"));
|
|
787
802
|
return n;
|
|
788
803
|
}
|
|
789
|
-
function
|
|
790
|
-
let t = Z(), n =
|
|
791
|
-
function
|
|
792
|
-
return !r(
|
|
804
|
+
function $t(e) {
|
|
805
|
+
let t = Z(), n = Ce(), { isBoardHidden: r, getBoard: i } = Yt(), { user: a, canManageBoard: o } = ht(), { t: s, locale: u } = O(), d = () => j(), f = () => Qt(e, u.value), p = () => M(t, d()), m = (e) => l(t, d(), e), h = (e) => c(t, d(), e);
|
|
806
|
+
function g() {
|
|
807
|
+
return !r(f());
|
|
793
808
|
}
|
|
794
|
-
function
|
|
795
|
-
return i(
|
|
809
|
+
function _() {
|
|
810
|
+
return i(f())?.editorType === "image";
|
|
796
811
|
}
|
|
797
|
-
function
|
|
798
|
-
let t =
|
|
812
|
+
function v(e) {
|
|
813
|
+
let t = _(), n = Pt(e.content), r = Ft(e.content, e.attachments);
|
|
799
814
|
if (t) {
|
|
800
|
-
if (!r) throw Error(
|
|
815
|
+
if (!r) throw Error(s("posts.photoRequired"));
|
|
801
816
|
return;
|
|
802
817
|
}
|
|
803
|
-
if (!n && !r) throw Error(
|
|
804
|
-
if (!e.title?.trim()) throw Error(
|
|
818
|
+
if (!n && !r) throw Error(s("posts.bodyRequired"));
|
|
819
|
+
if (!e.title?.trim()) throw Error(s("posts.titleRequired"));
|
|
805
820
|
}
|
|
806
|
-
function
|
|
807
|
-
return
|
|
821
|
+
function y() {
|
|
822
|
+
return me(p()).id;
|
|
823
|
+
}
|
|
824
|
+
function b(e) {
|
|
825
|
+
return bt(t, d(), f(), e, a.value?.uid, o(f()));
|
|
808
826
|
}
|
|
809
|
-
async function
|
|
810
|
-
let t = e.pageSize ?? 20, n = [
|
|
811
|
-
e.publicOnly !== !1 && n.push(
|
|
812
|
-
let r = await
|
|
827
|
+
async function x(e = {}) {
|
|
828
|
+
let t = e.pageSize ?? 20, n = [X("boardId", "==", f()), X("isPublished", "==", !0)];
|
|
829
|
+
e.publicOnly !== !1 && n.push(X("listed", "==", !0)), n.push(W("createdAt", "desc")), e.cursor && n.push(J(e.cursor)), n.push(H(t + 1));
|
|
830
|
+
let r = await B(G(p(), ...n)), i = r.docs.slice(0, t);
|
|
813
831
|
return {
|
|
814
832
|
posts: i.map((e) => ({
|
|
815
833
|
id: e.id,
|
|
@@ -819,73 +837,71 @@ function Jt(e) {
|
|
|
819
837
|
hasMore: r.docs.length > t
|
|
820
838
|
};
|
|
821
839
|
}
|
|
822
|
-
async function
|
|
823
|
-
let [t, n] = await Promise.all([
|
|
840
|
+
async function S(e) {
|
|
841
|
+
let [t, n] = await Promise.all([z(m(e)), z(h(e))]);
|
|
824
842
|
return t.exists() ? {
|
|
825
843
|
id: t.id,
|
|
826
844
|
...t.data(),
|
|
827
845
|
content: n.exists() ? n.data().content ?? "" : ""
|
|
828
846
|
} : null;
|
|
829
847
|
}
|
|
830
|
-
async function
|
|
848
|
+
async function C(e) {
|
|
831
849
|
try {
|
|
832
|
-
let t =
|
|
850
|
+
let t = await b(e.trim());
|
|
833
851
|
if (!t) return { status: "not-found" };
|
|
834
852
|
try {
|
|
835
|
-
let e = await
|
|
853
|
+
let e = await S(t.id);
|
|
836
854
|
return e ? {
|
|
837
855
|
status: "ok",
|
|
838
856
|
post: e
|
|
839
857
|
} : { status: "not-found" };
|
|
840
858
|
} catch (e) {
|
|
841
|
-
return
|
|
859
|
+
return Zt(e) ? { status: "permission-denied" } : {
|
|
842
860
|
status: "error",
|
|
843
861
|
message: e instanceof Error ? e.message : String(e)
|
|
844
862
|
};
|
|
845
863
|
}
|
|
846
864
|
} catch (e) {
|
|
847
|
-
return
|
|
865
|
+
return Zt(e) ? { status: "permission-denied" } : {
|
|
848
866
|
status: "error",
|
|
849
867
|
message: e instanceof Error ? e.message : String(e)
|
|
850
868
|
};
|
|
851
869
|
}
|
|
852
870
|
}
|
|
853
|
-
async function
|
|
854
|
-
let t = e.trim(), n =
|
|
871
|
+
async function w(e) {
|
|
872
|
+
let t = e.trim(), n = Xt.get(`${f()}/${t}`);
|
|
855
873
|
if (n) return {
|
|
856
874
|
status: "ok",
|
|
857
875
|
id: n
|
|
858
876
|
};
|
|
859
877
|
try {
|
|
860
|
-
let e =
|
|
878
|
+
let e = await b(t);
|
|
861
879
|
return e ? {
|
|
862
880
|
status: "ok",
|
|
863
881
|
id: e.id
|
|
864
|
-
} : { status: "not-found" };
|
|
882
|
+
} : { status: r(f()) ? "permission-denied" : "not-found" };
|
|
865
883
|
} catch (e) {
|
|
866
|
-
return
|
|
884
|
+
return Zt(e) ? { status: "permission-denied" } : {
|
|
867
885
|
status: "error",
|
|
868
886
|
message: e instanceof Error ? e.message : String(e)
|
|
869
887
|
};
|
|
870
888
|
}
|
|
871
889
|
}
|
|
872
|
-
async function
|
|
873
|
-
|
|
874
|
-
for (; !(await z(W(d(), Y("boardId", "==", u()), Y("slug", "==", n), V(1)))).empty;) r++, n = `${t}-${r}`;
|
|
875
|
-
return n;
|
|
890
|
+
async function T(e) {
|
|
891
|
+
return `${ne(e.trim()) || "post"}-${y()}`;
|
|
876
892
|
}
|
|
877
|
-
async function
|
|
893
|
+
async function E(e) {
|
|
878
894
|
if (!e.createdAt) return {
|
|
879
895
|
previous: null,
|
|
880
896
|
next: null
|
|
881
897
|
};
|
|
882
898
|
try {
|
|
883
899
|
let t = [
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
...e.listed === !1 ? [] : [
|
|
887
|
-
|
|
888
|
-
], [n, r] = await Promise.all([
|
|
900
|
+
X("boardId", "==", f()),
|
|
901
|
+
X("isPublished", "==", !0),
|
|
902
|
+
...e.listed === !1 ? [] : [X("listed", "==", !0)],
|
|
903
|
+
W("createdAt", "desc")
|
|
904
|
+
], [n, r] = await Promise.all([B(G(p(), ...t, J(e.createdAt), H(1))), B(G(p(), ...t, ge(e.createdAt), _e(1)))]), i = (e) => {
|
|
889
905
|
let t = e.docs[0];
|
|
890
906
|
return t ? {
|
|
891
907
|
id: t.id,
|
|
@@ -903,13 +919,13 @@ function Jt(e) {
|
|
|
903
919
|
};
|
|
904
920
|
}
|
|
905
921
|
}
|
|
906
|
-
async function
|
|
907
|
-
|
|
908
|
-
let n = e.postId ||
|
|
909
|
-
r ? (i = n, a =
|
|
910
|
-
let o =
|
|
911
|
-
return c.set(
|
|
912
|
-
boardId:
|
|
922
|
+
async function D(e) {
|
|
923
|
+
v(e);
|
|
924
|
+
let n = e.postId || y(), r = _(), i, a;
|
|
925
|
+
r ? (i = n, a = Nt(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await T(a));
|
|
926
|
+
let o = Bt(e.content, e.attachments), s = g(), c = ye(t);
|
|
927
|
+
return c.set(m(n), {
|
|
928
|
+
boardId: f(),
|
|
913
929
|
slug: i,
|
|
914
930
|
title: a,
|
|
915
931
|
...o,
|
|
@@ -925,56 +941,56 @@ function Jt(e) {
|
|
|
925
941
|
authorPhoto: e.authorPhoto,
|
|
926
942
|
moderationStatus: "approved",
|
|
927
943
|
moderationModel: e.moderationModel ?? null,
|
|
928
|
-
createdAt:
|
|
929
|
-
updatedAt:
|
|
930
|
-
}), c.set(
|
|
931
|
-
}
|
|
932
|
-
async function
|
|
933
|
-
|
|
934
|
-
let n =
|
|
935
|
-
await Promise.all([
|
|
944
|
+
createdAt: K(),
|
|
945
|
+
updatedAt: K()
|
|
946
|
+
}), c.set(h(n), { content: e.content }), await c.commit(), Xt.set(`${f()}/${i}`, n), i;
|
|
947
|
+
}
|
|
948
|
+
async function k(e, t) {
|
|
949
|
+
v(t);
|
|
950
|
+
let n = _() ? Nt(t.content) : t.title.trim(), r = Bt(t.content, t.attachments), i = g();
|
|
951
|
+
await Promise.all([Y(m(e), {
|
|
936
952
|
title: n,
|
|
937
953
|
...r,
|
|
938
|
-
previewImage: r.previewImage ? r.previewImage :
|
|
939
|
-
videoUrl: r.videoUrl ? r.videoUrl :
|
|
954
|
+
previewImage: r.previewImage ? r.previewImage : pe(),
|
|
955
|
+
videoUrl: r.videoUrl ? r.videoUrl : pe(),
|
|
940
956
|
tags: t.tags ?? [],
|
|
941
957
|
listed: i,
|
|
942
958
|
attachments: t.attachments ?? [],
|
|
943
|
-
updatedAt:
|
|
944
|
-
}),
|
|
959
|
+
updatedAt: K()
|
|
960
|
+
}), q(h(e), { content: t.content }, { merge: !0 })]);
|
|
945
961
|
}
|
|
946
|
-
async function
|
|
947
|
-
await
|
|
962
|
+
async function ee(e) {
|
|
963
|
+
await Y(m(e), {
|
|
948
964
|
isPublished: !0,
|
|
949
|
-
publishedAt:
|
|
950
|
-
updatedAt:
|
|
965
|
+
publishedAt: K(),
|
|
966
|
+
updatedAt: K()
|
|
951
967
|
});
|
|
952
968
|
}
|
|
953
|
-
async function
|
|
954
|
-
await
|
|
955
|
-
for (let [t, n] of
|
|
969
|
+
async function te(e) {
|
|
970
|
+
await jt(t, Ne(n), d(), e);
|
|
971
|
+
for (let [t, n] of Xt) n === e && Xt.delete(t);
|
|
956
972
|
}
|
|
957
973
|
return {
|
|
958
|
-
createPostId:
|
|
959
|
-
getPosts:
|
|
960
|
-
getPost:
|
|
961
|
-
getPostBySlug:
|
|
962
|
-
resolvePostIdBySlug:
|
|
963
|
-
resolveUniqueSlug:
|
|
964
|
-
getAdjacentPosts:
|
|
965
|
-
createPost:
|
|
966
|
-
updatePost:
|
|
967
|
-
publishPost:
|
|
968
|
-
deletePost:
|
|
974
|
+
createPostId: y,
|
|
975
|
+
getPosts: x,
|
|
976
|
+
getPost: S,
|
|
977
|
+
getPostBySlug: C,
|
|
978
|
+
resolvePostIdBySlug: w,
|
|
979
|
+
resolveUniqueSlug: T,
|
|
980
|
+
getAdjacentPosts: E,
|
|
981
|
+
createPost: D,
|
|
982
|
+
updatePost: k,
|
|
983
|
+
publishPost: ee,
|
|
984
|
+
deletePost: te
|
|
969
985
|
};
|
|
970
986
|
}
|
|
971
|
-
var
|
|
972
|
-
function
|
|
973
|
-
let n = Z(), { isAdmin: r, user: i, canManageBoard: a } =
|
|
987
|
+
var en = 10;
|
|
988
|
+
function tn(e, t = {}) {
|
|
989
|
+
let n = Z(), { isAdmin: r, user: i, canManageBoard: a } = ht(), o = () => j(), s = t.pageSize ?? en, c = N(() => i.value?.uid ?? ""), l = N(() => Qt(e)), u = () => M(n, o()), d = N(() => t.publicOnly === void 0 ? !(r.value || a(l.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), f = F([]), p = F([]), m = F([]), h = F(!0), g = F(!0), _ = F(!1), v = F(""), y = null, b = null, x, S;
|
|
974
990
|
function C(e) {
|
|
975
991
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
976
992
|
}
|
|
977
|
-
let w =
|
|
993
|
+
let w = N(() => {
|
|
978
994
|
let e = /* @__PURE__ */ new Map();
|
|
979
995
|
for (let t of [
|
|
980
996
|
...p.value,
|
|
@@ -984,11 +1000,11 @@ function Xt(e, t = {}) {
|
|
|
984
1000
|
return [...e.values()].sort((e, t) => C(t) - C(e) || String(t.id).localeCompare(String(e.id)));
|
|
985
1001
|
});
|
|
986
1002
|
function T() {
|
|
987
|
-
let e = [
|
|
988
|
-
return d.value && e.push(
|
|
1003
|
+
let e = [X("boardId", "==", l.value), X("isPublished", "==", !0)];
|
|
1004
|
+
return d.value && e.push(X("listed", "==", !0)), e;
|
|
989
1005
|
}
|
|
990
1006
|
function E() {
|
|
991
|
-
x?.(), x =
|
|
1007
|
+
x?.(), x = U(G(u(), ...T(), W("createdAt", "desc"), W(R(), "desc"), H(s)), (e) => {
|
|
992
1008
|
f.value = e.docs.map((e) => ({
|
|
993
1009
|
id: e.id,
|
|
994
1010
|
...e.data()
|
|
@@ -1004,7 +1020,7 @@ function Xt(e, t = {}) {
|
|
|
1004
1020
|
m.value = [];
|
|
1005
1021
|
return;
|
|
1006
1022
|
}
|
|
1007
|
-
S =
|
|
1023
|
+
S = U(G(u(), X("boardId", "==", l.value), X("authorUid", "==", e), X("isPublished", "==", !1), W("createdAt", "desc"), H(20)), (e) => {
|
|
1008
1024
|
m.value = e.docs.map((e) => ({
|
|
1009
1025
|
id: e.id,
|
|
1010
1026
|
...e.data()
|
|
@@ -1019,11 +1035,11 @@ function Xt(e, t = {}) {
|
|
|
1019
1035
|
try {
|
|
1020
1036
|
let e = b ?? y, t = [
|
|
1021
1037
|
...T(),
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
...e ? [
|
|
1025
|
-
|
|
1026
|
-
], n = await
|
|
1038
|
+
W("createdAt", "desc"),
|
|
1039
|
+
W(R(), "desc"),
|
|
1040
|
+
...e ? [J(e)] : [],
|
|
1041
|
+
H(s + 1)
|
|
1042
|
+
], n = await B(G(u(), ...t)), r = n.docs.slice(0, s), i = r.map((e) => ({
|
|
1027
1043
|
id: e.id,
|
|
1028
1044
|
...e.data()
|
|
1029
1045
|
})), a = new Set([...p.value, ...f.value].map((e) => e.id));
|
|
@@ -1038,11 +1054,11 @@ function Xt(e, t = {}) {
|
|
|
1038
1054
|
function k() {
|
|
1039
1055
|
x?.(), f.value = [], p.value = [], y = null, b = null, g.value = !0, v.value = "", h.value = !0, E(), D();
|
|
1040
1056
|
}
|
|
1041
|
-
return
|
|
1057
|
+
return L([
|
|
1042
1058
|
l,
|
|
1043
1059
|
d,
|
|
1044
1060
|
c
|
|
1045
|
-
], k, { immediate: !0 }),
|
|
1061
|
+
], k, { immediate: !0 }), P(() => {
|
|
1046
1062
|
x?.(), S?.();
|
|
1047
1063
|
}), {
|
|
1048
1064
|
posts: w,
|
|
@@ -1053,22 +1069,22 @@ function Xt(e, t = {}) {
|
|
|
1053
1069
|
loadMore: O
|
|
1054
1070
|
};
|
|
1055
1071
|
}
|
|
1056
|
-
function
|
|
1057
|
-
let n = Z(), r = () =>
|
|
1072
|
+
function nn(e, t) {
|
|
1073
|
+
let n = Z(), r = () => j(), i = N(() => Qt(e)), a = N(() => typeof t == "string" ? t : t.value), o = N(() => l(n, r(), a.value)), s = N(() => c(n, r(), a.value)), { data: u, pending: d } = Se(o), { data: f, pending: p } = Se(s);
|
|
1058
1074
|
return {
|
|
1059
|
-
post:
|
|
1075
|
+
post: N(() => !u.value || u.value.boardId !== i.value ? null : {
|
|
1060
1076
|
...u.value,
|
|
1061
1077
|
id: a.value,
|
|
1062
1078
|
content: f.value?.content ?? ""
|
|
1063
1079
|
}),
|
|
1064
|
-
pending:
|
|
1080
|
+
pending: N(() => d.value || p.value)
|
|
1065
1081
|
};
|
|
1066
1082
|
}
|
|
1067
1083
|
//#endregion
|
|
1068
1084
|
//#region src/composables/useMemiBoardUserPosts.ts
|
|
1069
|
-
var
|
|
1070
|
-
function
|
|
1071
|
-
let n = Z(), r = () =>
|
|
1085
|
+
var rn = 10;
|
|
1086
|
+
function an(e, t = {}) {
|
|
1087
|
+
let n = Z(), r = () => j(), i = () => M(n, r()), a = t.pageSize ?? rn, o = N(() => I(e)?.trim() || ""), s = F([]), c = F([]), l = F(!0), u = F(!0), d = F(!1), f = F(""), p = null, m = null, h;
|
|
1072
1088
|
function g(e) {
|
|
1073
1089
|
return {
|
|
1074
1090
|
id: e.id,
|
|
@@ -1078,16 +1094,16 @@ function $t(e, t = {}) {
|
|
|
1078
1094
|
function _(e) {
|
|
1079
1095
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1080
1096
|
}
|
|
1081
|
-
let v =
|
|
1097
|
+
let v = N(() => {
|
|
1082
1098
|
let e = /* @__PURE__ */ new Map();
|
|
1083
1099
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1084
1100
|
return [...e.values()].sort((e, t) => _(t) - _(e) || String(t.id).localeCompare(String(e.id)));
|
|
1085
1101
|
});
|
|
1086
1102
|
function y() {
|
|
1087
1103
|
return [
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1104
|
+
X("authorUid", "==", o.value),
|
|
1105
|
+
X("isPublished", "==", !0),
|
|
1106
|
+
X("listed", "==", !0)
|
|
1091
1107
|
];
|
|
1092
1108
|
}
|
|
1093
1109
|
function b() {
|
|
@@ -1095,7 +1111,7 @@ function $t(e, t = {}) {
|
|
|
1095
1111
|
l.value = !1;
|
|
1096
1112
|
return;
|
|
1097
1113
|
}
|
|
1098
|
-
h =
|
|
1114
|
+
h = U(G(i(), ...y(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
|
|
1099
1115
|
s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
|
|
1100
1116
|
}, (e) => {
|
|
1101
1117
|
console.error("[memi-board:userPosts] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
@@ -1107,11 +1123,11 @@ function $t(e, t = {}) {
|
|
|
1107
1123
|
try {
|
|
1108
1124
|
let e = m ?? p, t = [
|
|
1109
1125
|
...y(),
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
...e ? [
|
|
1113
|
-
|
|
1114
|
-
], n = await
|
|
1126
|
+
W("createdAt", "desc"),
|
|
1127
|
+
W(R(), "desc"),
|
|
1128
|
+
...e ? [J(e)] : [],
|
|
1129
|
+
H(a + 1)
|
|
1130
|
+
], n = await B(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(g), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1115
1131
|
c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
|
|
1116
1132
|
} catch (e) {
|
|
1117
1133
|
f.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
|
|
@@ -1123,7 +1139,7 @@ function $t(e, t = {}) {
|
|
|
1123
1139
|
function S() {
|
|
1124
1140
|
h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, b();
|
|
1125
1141
|
}
|
|
1126
|
-
return
|
|
1142
|
+
return L(o, S, { immediate: !0 }), P(() => h?.()), {
|
|
1127
1143
|
posts: v,
|
|
1128
1144
|
postsPending: l,
|
|
1129
1145
|
hasMore: u,
|
|
@@ -1134,9 +1150,9 @@ function $t(e, t = {}) {
|
|
|
1134
1150
|
}
|
|
1135
1151
|
//#endregion
|
|
1136
1152
|
//#region src/composables/useMemiBoardUserComments.ts
|
|
1137
|
-
var
|
|
1138
|
-
function
|
|
1139
|
-
let n = Z(), r = () =>
|
|
1153
|
+
var on = 10;
|
|
1154
|
+
function sn(e, t = {}) {
|
|
1155
|
+
let n = Z(), r = () => j(), i = () => u(n, r()), a = t.pageSize ?? on, o = N(() => I(e)?.trim() || ""), s = F([]), c = F([]), l = F(!0), d = F(!0), f = F(!1), p = F(""), m = null, h = null, g;
|
|
1140
1156
|
function _(e) {
|
|
1141
1157
|
return {
|
|
1142
1158
|
id: e.id,
|
|
@@ -1146,20 +1162,20 @@ function tn(e, t = {}) {
|
|
|
1146
1162
|
function v(e) {
|
|
1147
1163
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1148
1164
|
}
|
|
1149
|
-
let y =
|
|
1165
|
+
let y = N(() => {
|
|
1150
1166
|
let e = /* @__PURE__ */ new Map();
|
|
1151
1167
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1152
1168
|
return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
|
|
1153
1169
|
});
|
|
1154
1170
|
function b() {
|
|
1155
|
-
return [
|
|
1171
|
+
return [X("authorUid", "==", o.value), X("listed", "==", !0)];
|
|
1156
1172
|
}
|
|
1157
1173
|
function x() {
|
|
1158
1174
|
if (g?.(), !o.value) {
|
|
1159
1175
|
l.value = !1;
|
|
1160
1176
|
return;
|
|
1161
1177
|
}
|
|
1162
|
-
g =
|
|
1178
|
+
g = U(G(i(), ...b(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
|
|
1163
1179
|
s.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a), l.value = !1;
|
|
1164
1180
|
}, (e) => {
|
|
1165
1181
|
console.error("[memi-board:userComments] onSnapshot failed", e), p.value = e.message || String(e), l.value = !1;
|
|
@@ -1171,11 +1187,11 @@ function tn(e, t = {}) {
|
|
|
1171
1187
|
try {
|
|
1172
1188
|
let e = h ?? m, t = [
|
|
1173
1189
|
...b(),
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
...e ? [
|
|
1177
|
-
|
|
1178
|
-
], n = await
|
|
1190
|
+
W("createdAt", "desc"),
|
|
1191
|
+
W(R(), "desc"),
|
|
1192
|
+
...e ? [J(e)] : [],
|
|
1193
|
+
H(a + 1)
|
|
1194
|
+
], n = await B(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1179
1195
|
c.value.push(...o.filter((e) => !l.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > a;
|
|
1180
1196
|
} catch (e) {
|
|
1181
1197
|
p.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
|
|
@@ -1187,7 +1203,7 @@ function tn(e, t = {}) {
|
|
|
1187
1203
|
function C() {
|
|
1188
1204
|
g?.(), s.value = [], c.value = [], m = null, h = null, d.value = !0, p.value = "", l.value = !0, x();
|
|
1189
1205
|
}
|
|
1190
|
-
return
|
|
1206
|
+
return L(o, C, { immediate: !0 }), P(() => g?.()), {
|
|
1191
1207
|
comments: y,
|
|
1192
1208
|
commentsPending: l,
|
|
1193
1209
|
hasMore: d,
|
|
@@ -1198,12 +1214,12 @@ function tn(e, t = {}) {
|
|
|
1198
1214
|
}
|
|
1199
1215
|
//#endregion
|
|
1200
1216
|
//#region src/composables/useMemiBoardCommentFeed.ts
|
|
1201
|
-
var
|
|
1202
|
-
function
|
|
1203
|
-
let n = Z(), r = () =>
|
|
1204
|
-
let e = Math.floor(Number(
|
|
1205
|
-
return Number.isFinite(e) && e > 0 ? e :
|
|
1206
|
-
}), o =
|
|
1217
|
+
var cn = 10;
|
|
1218
|
+
function ln(e = "latest", t = {}) {
|
|
1219
|
+
let n = Z(), r = () => j(), i = () => u(n, r()), a = N(() => {
|
|
1220
|
+
let e = Math.floor(Number(I(t.pageSize)));
|
|
1221
|
+
return Number.isFinite(e) && e > 0 ? e : cn;
|
|
1222
|
+
}), o = N(() => I(e) === "likes" ? "likes" : "latest"), s = F([]), c = F([]), l = F(!0), d = F(!0), f = F(!1), p = F(""), m = null, h = null, g;
|
|
1207
1223
|
function _(e) {
|
|
1208
1224
|
return {
|
|
1209
1225
|
id: e.id,
|
|
@@ -1220,25 +1236,25 @@ function rn(e = "latest", t = {}) {
|
|
|
1220
1236
|
}
|
|
1221
1237
|
return v(t) - v(e) || String(t.id).localeCompare(String(e.id));
|
|
1222
1238
|
}
|
|
1223
|
-
let b =
|
|
1239
|
+
let b = N(() => {
|
|
1224
1240
|
let e = /* @__PURE__ */ new Map();
|
|
1225
1241
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1226
1242
|
return [...e.values()].sort(y);
|
|
1227
1243
|
});
|
|
1228
1244
|
function x() {
|
|
1229
1245
|
return o.value === "likes" ? [
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1246
|
+
X("listed", "==", !0),
|
|
1247
|
+
W("likeCount", "desc"),
|
|
1248
|
+
W("createdAt", "desc"),
|
|
1249
|
+
W(R(), "desc")
|
|
1234
1250
|
] : [
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1251
|
+
X("listed", "==", !0),
|
|
1252
|
+
W("createdAt", "desc"),
|
|
1253
|
+
W(R(), "desc")
|
|
1238
1254
|
];
|
|
1239
1255
|
}
|
|
1240
1256
|
function S() {
|
|
1241
|
-
g?.(), g =
|
|
1257
|
+
g?.(), g = U(G(i(), ...x(), H(a.value)), (e) => {
|
|
1242
1258
|
s.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a.value), l.value = !1;
|
|
1243
1259
|
}, (e) => {
|
|
1244
1260
|
console.error("[memi-board:commentFeed] onSnapshot failed", e), p.value = e.message || String(e), l.value = !1;
|
|
@@ -1248,7 +1264,7 @@ function rn(e = "latest", t = {}) {
|
|
|
1248
1264
|
if (!(f.value || !d.value || l.value)) {
|
|
1249
1265
|
f.value = !0, p.value = "";
|
|
1250
1266
|
try {
|
|
1251
|
-
let e = h ?? m, t = await
|
|
1267
|
+
let e = h ?? m, t = await B(G(i(), ...x(), ...e ? [J(e)] : [], H(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1252
1268
|
c.value.push(...r.filter((e) => !o.has(e.id))), h = n.at(-1) ?? h, d.value = t.docs.length > a.value;
|
|
1253
1269
|
} catch (e) {
|
|
1254
1270
|
p.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
|
|
@@ -1260,7 +1276,7 @@ function rn(e = "latest", t = {}) {
|
|
|
1260
1276
|
function w() {
|
|
1261
1277
|
g?.(), s.value = [], c.value = [], m = null, h = null, d.value = !0, p.value = "", l.value = !0, S();
|
|
1262
1278
|
}
|
|
1263
|
-
return
|
|
1279
|
+
return L([o, a], w, { immediate: !0 }), P(() => g?.()), {
|
|
1264
1280
|
comments: b,
|
|
1265
1281
|
commentsPending: l,
|
|
1266
1282
|
hasMore: d,
|
|
@@ -1272,35 +1288,35 @@ function rn(e = "latest", t = {}) {
|
|
|
1272
1288
|
}
|
|
1273
1289
|
//#endregion
|
|
1274
1290
|
//#region src/composables/useMemiBoardAuthorMemo.ts
|
|
1275
|
-
var
|
|
1291
|
+
var un = 100, dn = /* @__PURE__ */ new Map();
|
|
1276
1292
|
function $(e) {
|
|
1277
|
-
let t =
|
|
1278
|
-
return t || (t =
|
|
1293
|
+
let t = dn.get(e);
|
|
1294
|
+
return t || (t = de({
|
|
1279
1295
|
text: "",
|
|
1280
1296
|
sentiment: null,
|
|
1281
1297
|
loaded: !1,
|
|
1282
1298
|
pending: !1,
|
|
1283
1299
|
saving: !1,
|
|
1284
1300
|
error: ""
|
|
1285
|
-
}),
|
|
1301
|
+
}), dn.set(e, t)), t;
|
|
1286
1302
|
}
|
|
1287
|
-
function
|
|
1288
|
-
let t = Z(), n = () =>
|
|
1303
|
+
function fn(e) {
|
|
1304
|
+
let t = Z(), n = () => j(), { user: r } = ht(), { t: a, formatNumber: o } = O(), s = N(() => I(e)), c = N(() => `${r.value?.uid ?? ""}:${s.value}`), l = N(() => {
|
|
1289
1305
|
let e = r.value?.uid, a = s.value;
|
|
1290
1306
|
return !e || !a ? null : i(t, n(), e, a);
|
|
1291
|
-
}), u =
|
|
1307
|
+
}), u = N({
|
|
1292
1308
|
get: () => $(c.value).text,
|
|
1293
1309
|
set: (e) => {
|
|
1294
1310
|
$(c.value).text = e;
|
|
1295
1311
|
}
|
|
1296
|
-
}), d =
|
|
1312
|
+
}), d = N(() => $(c.value).sentiment), f = N(() => $(c.value).loaded), p = N(() => $(c.value).pending), m = N(() => $(c.value).saving), h = N(() => $(c.value).error);
|
|
1297
1313
|
async function g() {
|
|
1298
1314
|
let e = l.value;
|
|
1299
1315
|
if (!e) return;
|
|
1300
1316
|
let t = $(c.value);
|
|
1301
1317
|
t.pending = !0, t.error = "";
|
|
1302
1318
|
try {
|
|
1303
|
-
let n = (await
|
|
1319
|
+
let n = (await z(e)).data();
|
|
1304
1320
|
t.text = n ? n.text ?? "" : "", t.sentiment = n ? n.sentiment ?? null : null, t.loaded = !0;
|
|
1305
1321
|
} catch (e) {
|
|
1306
1322
|
t.error = e.message || String(e), console.error("[memi-board:authorMemo] load failed", e);
|
|
@@ -1316,10 +1332,10 @@ function sn(e) {
|
|
|
1316
1332
|
let i = $(c.value);
|
|
1317
1333
|
i.saving = !0, i.error = "";
|
|
1318
1334
|
try {
|
|
1319
|
-
await
|
|
1335
|
+
await q(n, {
|
|
1320
1336
|
text: r,
|
|
1321
1337
|
sentiment: t,
|
|
1322
|
-
updatedAt:
|
|
1338
|
+
updatedAt: K()
|
|
1323
1339
|
}), i.text = r, i.sentiment = t, i.loaded = !0;
|
|
1324
1340
|
} catch (e) {
|
|
1325
1341
|
throw i.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
|
|
@@ -1333,7 +1349,7 @@ function sn(e) {
|
|
|
1333
1349
|
let t = $(c.value);
|
|
1334
1350
|
t.saving = !0, t.error = "";
|
|
1335
1351
|
try {
|
|
1336
|
-
await
|
|
1352
|
+
await fe(e), t.text = "", t.sentiment = null, t.loaded = !0;
|
|
1337
1353
|
} catch (e) {
|
|
1338
1354
|
throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
|
|
1339
1355
|
} finally {
|
|
@@ -1353,86 +1369,91 @@ function sn(e) {
|
|
|
1353
1369
|
};
|
|
1354
1370
|
}
|
|
1355
1371
|
//#endregion
|
|
1372
|
+
//#region src/utils/subscribeCommentRange.ts
|
|
1373
|
+
function pn(e, t, n, r, i, a) {
|
|
1374
|
+
return U(G(u(e, t), X("postId", "==", n), ...r.rootId ? [X("rootId", "==", r.rootId), X("isReply", "==", !0)] : [X("parentId", "==", null)], W("createdAt", "asc"), W(R(), "asc"), ...r.hasMore && r.cursor ? [he(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
|
|
1375
|
+
...e.data(),
|
|
1376
|
+
id: e.id
|
|
1377
|
+
}))), a);
|
|
1378
|
+
}
|
|
1379
|
+
//#endregion
|
|
1356
1380
|
//#region src/composables/useMemiBoardComments.ts
|
|
1357
|
-
var
|
|
1358
|
-
function
|
|
1381
|
+
var mn = 10, hn = 5, gn = 1e3;
|
|
1382
|
+
function _n(e, { t, formatNumber: n }) {
|
|
1359
1383
|
let r = e.trim();
|
|
1360
1384
|
if (!r) throw Error(t("comments.bodyRequired"));
|
|
1361
|
-
if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(
|
|
1385
|
+
if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(gn) }));
|
|
1362
1386
|
return r;
|
|
1363
1387
|
}
|
|
1364
|
-
function
|
|
1365
|
-
let r = Z(), i = () =>
|
|
1388
|
+
function vn(e, t, n = {}) {
|
|
1389
|
+
let r = Z(), i = () => j(), { isBoardHidden: a } = Yt(), o = O(), { t: s } = o, c = () => u(r, i()), d = N(() => I(e)), f = N(() => I(t)), p = () => !a(d.value), m = F([]), h = F(n.subscribe !== !1), g = F([]), _ = F(!1), v = F(n.subscribe !== !1), y = F(n.subscribe !== !1), b = null, x = 0, S = 0, C;
|
|
1366
1390
|
function w(e) {
|
|
1367
1391
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1368
1392
|
}
|
|
1369
|
-
let T =
|
|
1393
|
+
let T = N(() => {
|
|
1370
1394
|
let e = /* @__PURE__ */ new Map();
|
|
1371
|
-
for (let t of [
|
|
1372
|
-
...m.value,
|
|
1373
|
-
...h.value,
|
|
1374
|
-
..._.value
|
|
1375
|
-
]) t.id && e.set(t.id, t);
|
|
1395
|
+
for (let t of [...m.value, ...g.value]) t.id && e.set(t.id, t);
|
|
1376
1396
|
return [...e.values()].sort((e, t) => w(e) - w(t) || String(e.id).localeCompare(String(t.id)));
|
|
1377
1397
|
});
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1398
|
+
L([f, d], async ([e]) => {
|
|
1399
|
+
let t = ++x;
|
|
1400
|
+
if (S++, _.value = !1, g.value = [], m.value = [], b = null, C?.(), C = void 0, v.value = n.subscribe !== !1, n.subscribe !== !1) {
|
|
1401
|
+
h.value = !0, y.value = !0;
|
|
1381
1402
|
try {
|
|
1382
|
-
let
|
|
1383
|
-
if (await Promise.all([
|
|
1384
|
-
if (
|
|
1385
|
-
let n =
|
|
1403
|
+
let n = B(G(c(), X("postId", "==", e), W("createdAt", "desc"), W(R(), "desc")));
|
|
1404
|
+
if (await Promise.all([n.then((e) => {
|
|
1405
|
+
if (t !== x) return;
|
|
1406
|
+
let n = e.docs.map((e) => ({
|
|
1386
1407
|
id: e.id,
|
|
1387
1408
|
...e.data()
|
|
1388
1409
|
}));
|
|
1389
|
-
|
|
1390
|
-
}), D()]),
|
|
1410
|
+
m.value = n.filter((e) => e.parentId === void 0);
|
|
1411
|
+
}), D()]), t !== x) return;
|
|
1391
1412
|
} finally {
|
|
1392
|
-
|
|
1413
|
+
t === x && (h.value = !1, y.value = !1);
|
|
1393
1414
|
}
|
|
1394
1415
|
}
|
|
1395
1416
|
}, { immediate: !0 });
|
|
1396
1417
|
function E() {
|
|
1397
|
-
C?.()
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1418
|
+
C?.();
|
|
1419
|
+
let e = ++S;
|
|
1420
|
+
C = pn(r, i(), f.value, {
|
|
1421
|
+
cursor: b,
|
|
1422
|
+
hasMore: v.value
|
|
1423
|
+
}, (t) => {
|
|
1424
|
+
e === S && (g.value = t);
|
|
1404
1425
|
}, (e) => {
|
|
1405
1426
|
console.error("[memi-board:comments] onSnapshot failed", e);
|
|
1406
1427
|
});
|
|
1407
1428
|
}
|
|
1408
1429
|
async function D() {
|
|
1409
|
-
if (
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1430
|
+
if (_.value || !v.value) return;
|
|
1431
|
+
let e = x;
|
|
1432
|
+
_.value = !0;
|
|
1433
|
+
try {
|
|
1434
|
+
let t = [
|
|
1435
|
+
X("postId", "==", f.value),
|
|
1436
|
+
X("parentId", "==", null),
|
|
1437
|
+
W("createdAt", "asc"),
|
|
1438
|
+
W(R(), "asc"),
|
|
1439
|
+
...b ? [J(b)] : [],
|
|
1440
|
+
H(11)
|
|
1441
|
+
], n = await B(G(c(), ...t));
|
|
1442
|
+
if (e !== x) return;
|
|
1443
|
+
let r = n.docs.slice(0, mn), i = r.map((e) => ({
|
|
1444
|
+
id: e.id,
|
|
1445
|
+
...e.data()
|
|
1446
|
+
})), a = new Set(g.value.map((e) => e.id));
|
|
1447
|
+
g.value.push(...i.filter((e) => !a.has(e.id))), b = r.at(-1) ?? b, v.value = n.size > mn, E();
|
|
1448
|
+
} finally {
|
|
1449
|
+
e === x && (_.value = !1);
|
|
1429
1450
|
}
|
|
1430
1451
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1452
|
+
P(() => {
|
|
1453
|
+
x++, S++, C?.();
|
|
1433
1454
|
});
|
|
1434
1455
|
async function ee(e) {
|
|
1435
|
-
let t =
|
|
1456
|
+
let t = _n(e.body, o), n = ye(r), a = me(c());
|
|
1436
1457
|
n.set(a, {
|
|
1437
1458
|
postId: f.value,
|
|
1438
1459
|
boardId: d.value,
|
|
@@ -1450,14 +1471,14 @@ function fn(e, t, n = {}) {
|
|
|
1450
1471
|
replyCount: 0,
|
|
1451
1472
|
likeCount: 0,
|
|
1452
1473
|
isReply: !1,
|
|
1453
|
-
createdAt:
|
|
1454
|
-
updatedAt:
|
|
1455
|
-
}), n.update(l(r, i(), f.value), { commentCount:
|
|
1474
|
+
createdAt: K(),
|
|
1475
|
+
updatedAt: K()
|
|
1476
|
+
}), n.update(l(r, i(), f.value), { commentCount: V(1) }), await n.commit();
|
|
1456
1477
|
}
|
|
1457
1478
|
async function te(e) {
|
|
1458
|
-
let t =
|
|
1479
|
+
let t = _n(e.body, o);
|
|
1459
1480
|
if (!e.parent.id) throw Error(s("comments.replyTargetNotFound"));
|
|
1460
|
-
let n =
|
|
1481
|
+
let n = ye(r), a = me(c()), u = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
|
|
1461
1482
|
if (!u) throw Error(s("comments.threadNotFound"));
|
|
1462
1483
|
let m = Math.min((e.parent.depth ?? 0) + 1, 2);
|
|
1463
1484
|
n.set(a, {
|
|
@@ -1477,116 +1498,121 @@ function fn(e, t, n = {}) {
|
|
|
1477
1498
|
replyCount: 0,
|
|
1478
1499
|
likeCount: 0,
|
|
1479
1500
|
isReply: !0,
|
|
1480
|
-
createdAt:
|
|
1481
|
-
updatedAt:
|
|
1482
|
-
}), n.update(k(r, i(), u), { replyCount:
|
|
1501
|
+
createdAt: K(),
|
|
1502
|
+
updatedAt: K()
|
|
1503
|
+
}), n.update(k(r, i(), u), { replyCount: V(1) }), n.update(l(r, i(), f.value), { commentCount: V(1) }), await n.commit();
|
|
1483
1504
|
}
|
|
1484
|
-
async function
|
|
1505
|
+
async function A(e) {
|
|
1485
1506
|
if (!e.id) return;
|
|
1486
1507
|
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(s("comments.hasRepliesCannotDelete"));
|
|
1487
|
-
await
|
|
1488
|
-
let t =
|
|
1489
|
-
t.delete(k(r, i(), e.id)), e.parentId && e.rootId && t.update(k(r, i(), e.rootId), { replyCount:
|
|
1508
|
+
await At(r, i(), e.id);
|
|
1509
|
+
let t = ye(r);
|
|
1510
|
+
t.delete(k(r, i(), e.id)), e.parentId && e.rootId && t.update(k(r, i(), e.rootId), { replyCount: V(-1) }), t.update(l(r, i(), f.value), { commentCount: V(-1) }), await t.commit(), g.value = g.value.filter((t) => t.id !== e.id), m.value = m.value.filter((t) => t.id !== e.id);
|
|
1490
1511
|
}
|
|
1491
|
-
async function
|
|
1492
|
-
let n =
|
|
1493
|
-
await
|
|
1512
|
+
async function ne(e, t) {
|
|
1513
|
+
let n = _n(t, o);
|
|
1514
|
+
await Y(k(r, i(), e), {
|
|
1494
1515
|
body: n,
|
|
1495
|
-
updatedAt:
|
|
1516
|
+
updatedAt: K()
|
|
1496
1517
|
});
|
|
1497
1518
|
}
|
|
1498
|
-
async function
|
|
1499
|
-
await
|
|
1519
|
+
async function re(e, t, n) {
|
|
1520
|
+
await Y(k(r, i(), e), {
|
|
1500
1521
|
isBlinded: t,
|
|
1501
|
-
moderatedAt:
|
|
1522
|
+
moderatedAt: K(),
|
|
1502
1523
|
moderatedBy: n
|
|
1503
1524
|
});
|
|
1504
1525
|
}
|
|
1505
1526
|
return {
|
|
1506
1527
|
comments: T,
|
|
1507
|
-
commentsPending:
|
|
1508
|
-
hasMore:
|
|
1509
|
-
loadingMore:
|
|
1528
|
+
commentsPending: N(() => y.value || h.value),
|
|
1529
|
+
hasMore: v,
|
|
1530
|
+
loadingMore: _,
|
|
1510
1531
|
loadMore: D,
|
|
1511
1532
|
addComment: ee,
|
|
1512
1533
|
addReply: te,
|
|
1513
|
-
updateComment:
|
|
1514
|
-
setCommentBlinded:
|
|
1515
|
-
deleteComment:
|
|
1534
|
+
updateComment: ne,
|
|
1535
|
+
setCommentBlinded: re,
|
|
1536
|
+
deleteComment: A
|
|
1516
1537
|
};
|
|
1517
1538
|
}
|
|
1518
|
-
function
|
|
1519
|
-
let r = Z(), i = () =>
|
|
1520
|
-
function
|
|
1539
|
+
function yn(e, t, n) {
|
|
1540
|
+
let r = Z(), i = () => j(), a = () => u(r, i()), o = t.trim(), s = F([]), c = F(!1), l = F(!1), d = F(!0), f = null, p, m = 0, h = 0;
|
|
1541
|
+
function g(e) {
|
|
1521
1542
|
return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
|
|
1522
1543
|
}
|
|
1523
|
-
function
|
|
1524
|
-
p
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1544
|
+
function _() {
|
|
1545
|
+
p?.();
|
|
1546
|
+
let e = ++h;
|
|
1547
|
+
p = pn(r, i(), o, {
|
|
1548
|
+
rootId: n,
|
|
1549
|
+
cursor: f,
|
|
1550
|
+
hasMore: d.value
|
|
1551
|
+
}, (t) => {
|
|
1552
|
+
e === h && (s.value = t);
|
|
1531
1553
|
}, (e) => {
|
|
1532
1554
|
console.error("[memi-board:replies] onSnapshot failed", e);
|
|
1533
1555
|
});
|
|
1534
1556
|
}
|
|
1535
|
-
async function
|
|
1536
|
-
if (
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1557
|
+
async function v() {
|
|
1558
|
+
if (c.value || !d.value) return;
|
|
1559
|
+
let e = m;
|
|
1560
|
+
c.value = !0;
|
|
1561
|
+
try {
|
|
1562
|
+
let t = [
|
|
1563
|
+
X("postId", "==", o),
|
|
1564
|
+
X("rootId", "==", n),
|
|
1565
|
+
X("isReply", "==", !0),
|
|
1566
|
+
W("createdAt", "asc"),
|
|
1567
|
+
W(R(), "asc"),
|
|
1568
|
+
...f ? [J(f)] : [],
|
|
1569
|
+
H(6)
|
|
1570
|
+
], r = await B(G(a(), ...t));
|
|
1571
|
+
if (e !== m) return;
|
|
1572
|
+
let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0, hn), u = c.map((e) => ({
|
|
1573
|
+
id: e.id,
|
|
1574
|
+
...e.data()
|
|
1575
|
+
})).filter((e) => !i.has(e.id));
|
|
1576
|
+
s.value = g([...s.value, ...u]), f = c.at(-1) ?? f, l.value = !0, d.value = r.size > hn, _();
|
|
1577
|
+
} finally {
|
|
1578
|
+
e === m && (c.value = !1);
|
|
1555
1579
|
}
|
|
1556
1580
|
}
|
|
1557
|
-
function
|
|
1558
|
-
p?.(), p = void 0, s.value = [], f = null, l.value = !1, d.value = !0;
|
|
1581
|
+
function y() {
|
|
1582
|
+
m++, h++, c.value = !1, p?.(), p = void 0, s.value = [], f = null, l.value = !1, d.value = !0;
|
|
1559
1583
|
}
|
|
1560
|
-
async function
|
|
1561
|
-
|
|
1584
|
+
async function b() {
|
|
1585
|
+
y(), await v();
|
|
1562
1586
|
}
|
|
1563
|
-
return
|
|
1587
|
+
return P(() => {
|
|
1588
|
+
m++, h++, p?.();
|
|
1589
|
+
}), {
|
|
1564
1590
|
replies: s,
|
|
1565
1591
|
loading: c,
|
|
1566
1592
|
loaded: l,
|
|
1567
1593
|
hasMore: d,
|
|
1568
|
-
loadMore:
|
|
1569
|
-
refresh:
|
|
1594
|
+
loadMore: v,
|
|
1595
|
+
refresh: b
|
|
1570
1596
|
};
|
|
1571
1597
|
}
|
|
1572
1598
|
//#endregion
|
|
1573
1599
|
//#region src/composables/useMemiBoardLikes.ts
|
|
1574
|
-
function
|
|
1575
|
-
let n = () =>
|
|
1600
|
+
function bn(e, t) {
|
|
1601
|
+
let n = () => j(), r = Z(), i = xe(), { t: a } = O(), o = F(!1), s = F(!1), c;
|
|
1576
1602
|
function u(e) {
|
|
1577
1603
|
return d(r, n(), t, e);
|
|
1578
1604
|
}
|
|
1579
|
-
|
|
1605
|
+
L(i, (e) => {
|
|
1580
1606
|
if (c?.(), c = void 0, !e) {
|
|
1581
1607
|
o.value = !1;
|
|
1582
1608
|
return;
|
|
1583
1609
|
}
|
|
1584
|
-
c =
|
|
1610
|
+
c = U(u(e.uid), (e) => {
|
|
1585
1611
|
o.value = e.exists();
|
|
1586
1612
|
}, (e) => {
|
|
1587
1613
|
console.error("[memi-board:likes] onSnapshot failed", e);
|
|
1588
1614
|
});
|
|
1589
|
-
}, { immediate: !0 }),
|
|
1615
|
+
}, { immediate: !0 }), P(() => c?.());
|
|
1590
1616
|
async function f() {
|
|
1591
1617
|
let c = i.value?.uid;
|
|
1592
1618
|
if (!c) throw Error(a("likes.signInRequired"));
|
|
@@ -1594,12 +1620,12 @@ function mn(e, t) {
|
|
|
1594
1620
|
s.value = !0;
|
|
1595
1621
|
try {
|
|
1596
1622
|
let i = u(c), a = l(r, n(), t);
|
|
1597
|
-
return await ve(r, async (n) => (await n.get(i)).exists() ? (n.delete(i), n.update(a, { likeCount:
|
|
1623
|
+
return await ve(r, async (n) => (await n.get(i)).exists() ? (n.delete(i), n.update(a, { likeCount: V(-1) }), !1) : (n.set(i, {
|
|
1598
1624
|
uid: c,
|
|
1599
1625
|
postId: t,
|
|
1600
1626
|
boardId: e,
|
|
1601
|
-
createdAt:
|
|
1602
|
-
}), n.update(a, { likeCount:
|
|
1627
|
+
createdAt: K()
|
|
1628
|
+
}), n.update(a, { likeCount: V(1) }), !0));
|
|
1603
1629
|
} finally {
|
|
1604
1630
|
s.value = !1;
|
|
1605
1631
|
}
|
|
@@ -1610,11 +1636,11 @@ function mn(e, t) {
|
|
|
1610
1636
|
toggleLike: f
|
|
1611
1637
|
};
|
|
1612
1638
|
}
|
|
1613
|
-
var
|
|
1614
|
-
function
|
|
1615
|
-
let n = () =>
|
|
1616
|
-
|
|
1617
|
-
f?.(), f = void 0, l.value = /* @__PURE__ */ new Set(), e && t && (f =
|
|
1639
|
+
var xn = Symbol.for("memi-board:comment-likes");
|
|
1640
|
+
function Sn(e, t) {
|
|
1641
|
+
let n = () => j(), r = Z(), i = xe(), { t: o } = O(), s = N(() => I(e)), c = N(() => I(t)), l = F(/* @__PURE__ */ new Set()), u = F(null), f;
|
|
1642
|
+
L([i, c], ([e, t]) => {
|
|
1643
|
+
f?.(), f = void 0, l.value = /* @__PURE__ */ new Set(), e && t && (f = U(G(a(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
|
|
1618
1644
|
let t = /* @__PURE__ */ new Set();
|
|
1619
1645
|
for (let n of e.docs) {
|
|
1620
1646
|
let e = n.data().commentId;
|
|
@@ -1624,7 +1650,7 @@ function gn(e, t) {
|
|
|
1624
1650
|
}, (e) => {
|
|
1625
1651
|
console.error("[memi-board:comment-likes] onSnapshot failed", e);
|
|
1626
1652
|
}));
|
|
1627
|
-
}, { immediate: !0 }),
|
|
1653
|
+
}, { immediate: !0 }), P(() => f?.());
|
|
1628
1654
|
function p(e) {
|
|
1629
1655
|
return !!e && l.value.has(e);
|
|
1630
1656
|
}
|
|
@@ -1648,7 +1674,7 @@ function gn(e, t) {
|
|
|
1648
1674
|
boardId: s.value,
|
|
1649
1675
|
commentId: e,
|
|
1650
1676
|
target: "comment",
|
|
1651
|
-
createdAt:
|
|
1677
|
+
createdAt: K()
|
|
1652
1678
|
}), n.update(a, { likeCount: u + 1 }), !0);
|
|
1653
1679
|
}), f = new Set(l.value);
|
|
1654
1680
|
return u ? f.add(e) : f.delete(e), l.value = f, u;
|
|
@@ -1664,7 +1690,7 @@ function gn(e, t) {
|
|
|
1664
1690
|
}
|
|
1665
1691
|
//#endregion
|
|
1666
1692
|
//#region src/composables/useMemiBoardReports.ts
|
|
1667
|
-
var
|
|
1693
|
+
var Cn = 200, wn = [
|
|
1668
1694
|
{
|
|
1669
1695
|
value: "spam",
|
|
1670
1696
|
label: "스팸·광고"
|
|
@@ -1686,34 +1712,34 @@ var _n = 200, vn = [
|
|
|
1686
1712
|
label: "기타"
|
|
1687
1713
|
}
|
|
1688
1714
|
];
|
|
1689
|
-
function
|
|
1690
|
-
return
|
|
1715
|
+
function Tn(e, t) {
|
|
1716
|
+
return wn.some((t) => t.value === e) ? w(t, `reports.reason.${e}`) : e || w(t, "reports.fallbackLabel");
|
|
1691
1717
|
}
|
|
1692
|
-
function
|
|
1693
|
-
let r = () =>
|
|
1694
|
-
|
|
1718
|
+
function En(e, n) {
|
|
1719
|
+
let r = () => j(), i = Z(), a = xe(), { t: o } = O(), s = F(!1), c = F(!1), l;
|
|
1720
|
+
L(a, (e) => {
|
|
1695
1721
|
if (l?.(), l = void 0, !e) {
|
|
1696
1722
|
s.value = !1;
|
|
1697
1723
|
return;
|
|
1698
1724
|
}
|
|
1699
|
-
l =
|
|
1725
|
+
l = U(t(i, r(), n, e.uid), (e) => {
|
|
1700
1726
|
s.value = e.exists();
|
|
1701
1727
|
}, (e) => {
|
|
1702
1728
|
console.error("[memi-board:reports] onSnapshot failed", e);
|
|
1703
1729
|
});
|
|
1704
|
-
}, { immediate: !0 }),
|
|
1730
|
+
}, { immediate: !0 }), P(() => l?.());
|
|
1705
1731
|
async function u(l) {
|
|
1706
1732
|
let u = a.value?.uid;
|
|
1707
1733
|
if (!u) throw Error(o("reports.signInRequired"));
|
|
1708
1734
|
if (c.value) return;
|
|
1709
1735
|
if (l.authorUid && l.authorUid === u) throw Error(o("reports.cannotReportOwn"));
|
|
1710
|
-
let d =
|
|
1736
|
+
let d = wn.some((e) => e.value === l.reason) ? l.reason : null;
|
|
1711
1737
|
if (!d) throw Error(o("reports.reasonRequired"));
|
|
1712
1738
|
let f = (l.detail || "").trim();
|
|
1713
1739
|
if (f.length > 200) throw Error(o("reports.detailTooLong", { max: 200 }));
|
|
1714
1740
|
c.value = !0;
|
|
1715
1741
|
try {
|
|
1716
|
-
await
|
|
1742
|
+
await q(t(i, r(), n, u), {
|
|
1717
1743
|
uid: u,
|
|
1718
1744
|
target: "post",
|
|
1719
1745
|
postId: n,
|
|
@@ -1724,7 +1750,7 @@ function bn(e, n) {
|
|
|
1724
1750
|
postTitle: (l.postTitle || "").trim().slice(0, 200),
|
|
1725
1751
|
authorUid: l.authorUid || "",
|
|
1726
1752
|
authorName: l.authorName ?? null,
|
|
1727
|
-
createdAt:
|
|
1753
|
+
createdAt: K()
|
|
1728
1754
|
}), s.value = !0;
|
|
1729
1755
|
} finally {
|
|
1730
1756
|
c.value = !1;
|
|
@@ -1736,9 +1762,9 @@ function bn(e, n) {
|
|
|
1736
1762
|
submitReport: u
|
|
1737
1763
|
};
|
|
1738
1764
|
}
|
|
1739
|
-
var
|
|
1740
|
-
function
|
|
1741
|
-
let n = () =>
|
|
1765
|
+
var Dn = 20;
|
|
1766
|
+
function On(e = {}) {
|
|
1767
|
+
let n = () => j(), r = Z(), { canManageContent: i, canManageBoard: a } = ht(), o = e.pageSize ?? Dn, c = N(() => I(e.boardId)?.trim() || ""), l = F([]), u = F(!0), d = F(!1), f = F(!1), p = F(""), m = null, h;
|
|
1742
1768
|
function g(e) {
|
|
1743
1769
|
return {
|
|
1744
1770
|
id: e.id,
|
|
@@ -1751,19 +1777,19 @@ function Sn(e = {}) {
|
|
|
1751
1777
|
return;
|
|
1752
1778
|
}
|
|
1753
1779
|
u.value = !0;
|
|
1754
|
-
let e = c.value ? [
|
|
1755
|
-
h =
|
|
1780
|
+
let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")];
|
|
1781
|
+
h = U(G(s(r, n()), ...e, W("createdAt", "desc"), W(R(), "desc"), H(o)), (e) => {
|
|
1756
1782
|
l.value = e.docs.map(g).filter((e) => a(e.boardId)), m = e.docs.at(-1) ?? null, f.value = e.docs.length >= o, u.value = !1;
|
|
1757
1783
|
}, (e) => {
|
|
1758
1784
|
console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
|
|
1759
1785
|
});
|
|
1760
1786
|
}
|
|
1761
|
-
|
|
1787
|
+
L([i, c], _, { immediate: !0 }), P(() => h?.());
|
|
1762
1788
|
async function v() {
|
|
1763
1789
|
if (!d.value && f.value && m && i.value) {
|
|
1764
1790
|
d.value = !0, p.value = "";
|
|
1765
1791
|
try {
|
|
1766
|
-
let e = c.value ? [
|
|
1792
|
+
let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")], t = await B(G(s(r, n()), ...e, W("createdAt", "desc"), W(R(), "desc"), J(m), H(o + 1))), i = t.docs.slice(0, o), u = new Set(l.value.map((e) => e.id));
|
|
1767
1793
|
l.value.push(...i.map(g).filter((e) => !u.has(e.id) && a(e.boardId))), m = i.at(-1) ?? m, f.value = t.docs.length > o;
|
|
1768
1794
|
} catch (e) {
|
|
1769
1795
|
p.value = e.message || String(e);
|
|
@@ -1773,10 +1799,10 @@ function Sn(e = {}) {
|
|
|
1773
1799
|
}
|
|
1774
1800
|
}
|
|
1775
1801
|
async function y(e, i) {
|
|
1776
|
-
e.id && a(e.boardId) && await
|
|
1802
|
+
e.id && a(e.boardId) && await Y(t(r, n(), e.postId, e.uid), {
|
|
1777
1803
|
status: i,
|
|
1778
|
-
reviewedAt:
|
|
1779
|
-
reviewedBy:
|
|
1804
|
+
reviewedAt: K(),
|
|
1805
|
+
reviewedBy: xe().value?.uid || ""
|
|
1780
1806
|
});
|
|
1781
1807
|
}
|
|
1782
1808
|
return {
|
|
@@ -1792,8 +1818,8 @@ function Sn(e = {}) {
|
|
|
1792
1818
|
}
|
|
1793
1819
|
//#endregion
|
|
1794
1820
|
//#region src/composables/useMemiBoardViews.ts
|
|
1795
|
-
function
|
|
1796
|
-
let e = () =>
|
|
1821
|
+
function kn() {
|
|
1822
|
+
let e = () => j(), t = Z();
|
|
1797
1823
|
function n(t, n) {
|
|
1798
1824
|
let { postsCollection: r } = e();
|
|
1799
1825
|
return `memi-board:viewed:${r}:${t}:${n}`;
|
|
@@ -1816,7 +1842,7 @@ function Cn() {
|
|
|
1816
1842
|
if (s && c && !r(s, c)) {
|
|
1817
1843
|
i(s, c);
|
|
1818
1844
|
try {
|
|
1819
|
-
await
|
|
1845
|
+
await Y(l(t, e(), c), { viewCount: V(1) });
|
|
1820
1846
|
} catch (e) {
|
|
1821
1847
|
try {
|
|
1822
1848
|
sessionStorage.removeItem(n(s, c));
|
|
@@ -1832,7 +1858,7 @@ function Cn() {
|
|
|
1832
1858
|
}
|
|
1833
1859
|
//#endregion
|
|
1834
1860
|
//#region src/utils/moderation-prompt.ts
|
|
1835
|
-
var
|
|
1861
|
+
var An = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", jn = {
|
|
1836
1862
|
ko: "Korean",
|
|
1837
1863
|
en: "English",
|
|
1838
1864
|
ja: "Japanese",
|
|
@@ -1844,12 +1870,12 @@ var wn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
|
|
|
1844
1870
|
ar: "Arabic",
|
|
1845
1871
|
id: "Indonesian"
|
|
1846
1872
|
};
|
|
1847
|
-
function
|
|
1848
|
-
let t =
|
|
1873
|
+
function Mn(e) {
|
|
1874
|
+
let t = jn[e] ?? "English", n = D(e).name;
|
|
1849
1875
|
return t === n ? t : `${t} (${n})`;
|
|
1850
1876
|
}
|
|
1851
|
-
function
|
|
1852
|
-
let t =
|
|
1877
|
+
function Nn(e) {
|
|
1878
|
+
let t = Mn(e);
|
|
1853
1879
|
return `You are a strict moderator reviewing content for a message board.
|
|
1854
1880
|
If the text below contains profanity, vulgar slang, sexual harassment, hate speech, threats, spam, or repetitive/flooding advertisements, you MUST reject it (flagged=true).
|
|
1855
1881
|
|
|
@@ -1876,17 +1902,17 @@ Output JSON only:
|
|
|
1876
1902
|
Do not quote the offensive words at length; clearly state the type (profanity/hate/spam, etc.).
|
|
1877
1903
|
- If flagged=false, category is "none" and reason is ""`;
|
|
1878
1904
|
}
|
|
1879
|
-
function
|
|
1880
|
-
return e === "ko" ?
|
|
1905
|
+
function Pn(e = "ko") {
|
|
1906
|
+
return e === "ko" ? An : Nn(e);
|
|
1881
1907
|
}
|
|
1882
|
-
function
|
|
1908
|
+
function Fn(e, t = "ko") {
|
|
1883
1909
|
let n = `"""${e.slice(0, 4e3)}"""`;
|
|
1884
1910
|
return t === "ko" ? `심사할 텍스트:\n${n}` : `Text to review:\n${n}`;
|
|
1885
1911
|
}
|
|
1886
|
-
function
|
|
1912
|
+
function In(e = "ko") {
|
|
1887
1913
|
return e === "ko" ? "이 이미지를 심사해 주세요." : "Please review this image.";
|
|
1888
1914
|
}
|
|
1889
|
-
var
|
|
1915
|
+
var Ln = {
|
|
1890
1916
|
abuse: "욕설·비속어·모욕",
|
|
1891
1917
|
spam: "스팸·광고",
|
|
1892
1918
|
adult: "선정적·성인 내용",
|
|
@@ -1894,10 +1920,10 @@ var jn = {
|
|
|
1894
1920
|
other: "부적절한 내용",
|
|
1895
1921
|
none: ""
|
|
1896
1922
|
};
|
|
1897
|
-
function
|
|
1898
|
-
return !e || e === "none" ? "" : e in
|
|
1923
|
+
function Rn(e, t = "ko") {
|
|
1924
|
+
return !e || e === "none" ? "" : e in Ln ? w(t, `moderationPrompt.categories.${e}`) : e;
|
|
1899
1925
|
}
|
|
1900
|
-
function
|
|
1926
|
+
function zn(e) {
|
|
1901
1927
|
let t = e.locale ?? "ko";
|
|
1902
1928
|
if (e.via === "local" && e.localHit) {
|
|
1903
1929
|
let n = e.localHit.trim();
|
|
@@ -1905,10 +1931,10 @@ function Nn(e) {
|
|
|
1905
1931
|
}
|
|
1906
1932
|
let n = (e.reason || "").trim();
|
|
1907
1933
|
if (n) return n;
|
|
1908
|
-
let r = e.category ?
|
|
1934
|
+
let r = e.category ? Rn(e.category, t) : "";
|
|
1909
1935
|
return r ? w(t, "moderationPrompt.categoryBlocked", { category: r }) : w(t, "moderationPrompt.genericBlocked");
|
|
1910
1936
|
}
|
|
1911
|
-
var
|
|
1937
|
+
var Bn = [
|
|
1912
1938
|
"씨발",
|
|
1913
1939
|
"시발",
|
|
1914
1940
|
"시이발",
|
|
@@ -1934,10 +1960,10 @@ var Pn = [
|
|
|
1934
1960
|
"bitch",
|
|
1935
1961
|
"asshole"
|
|
1936
1962
|
];
|
|
1937
|
-
function
|
|
1963
|
+
function Vn(e) {
|
|
1938
1964
|
return new RegExp(e.join("|"), "i");
|
|
1939
1965
|
}
|
|
1940
|
-
var
|
|
1966
|
+
var Hn = /* @__PURE__ */ new Set([
|
|
1941
1967
|
"none",
|
|
1942
1968
|
"abuse",
|
|
1943
1969
|
"spam",
|
|
@@ -1945,7 +1971,7 @@ var In = /* @__PURE__ */ new Set([
|
|
|
1945
1971
|
"violence",
|
|
1946
1972
|
"other"
|
|
1947
1973
|
]);
|
|
1948
|
-
function
|
|
1974
|
+
function Un(e) {
|
|
1949
1975
|
let t = e.trim();
|
|
1950
1976
|
if (!t) return null;
|
|
1951
1977
|
let n;
|
|
@@ -1963,7 +1989,7 @@ function Ln(e) {
|
|
|
1963
1989
|
if (typeof n != "object" || !n) return null;
|
|
1964
1990
|
let r = n;
|
|
1965
1991
|
if (typeof r.flagged != "boolean") return null;
|
|
1966
|
-
let i = typeof r.category == "string" &&
|
|
1992
|
+
let i = typeof r.category == "string" && Hn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
|
|
1967
1993
|
return {
|
|
1968
1994
|
flagged: r.flagged,
|
|
1969
1995
|
category: i,
|
|
@@ -1972,20 +1998,20 @@ function Ln(e) {
|
|
|
1972
1998
|
}
|
|
1973
1999
|
//#endregion
|
|
1974
2000
|
//#region src/composables/useMemiBoardModeration.ts
|
|
1975
|
-
var
|
|
2001
|
+
var Wn = {
|
|
1976
2002
|
flagged: !1,
|
|
1977
2003
|
category: "none",
|
|
1978
2004
|
reason: "",
|
|
1979
2005
|
via: "empty"
|
|
1980
2006
|
};
|
|
1981
|
-
function
|
|
1982
|
-
let t = O(), n =
|
|
2007
|
+
function Gn(e = {}) {
|
|
2008
|
+
let t = O(), n = N(() => E(I(e.locale)) ?? t.locale.value), r = ue().moderation ?? {}, i = Ce(), a = (e) => w(n.value, e), { isWriteRestricted: o, restrictedMessage: s, recordContentModerationBlock: c } = ht(), l = Vn([...Bn, ...r.localBlocklist ?? []]);
|
|
1983
2009
|
function u(e) {
|
|
1984
2010
|
let t = e.match(l);
|
|
1985
2011
|
return t ? {
|
|
1986
2012
|
flagged: !0,
|
|
1987
2013
|
category: "abuse",
|
|
1988
|
-
reason:
|
|
2014
|
+
reason: zn({
|
|
1989
2015
|
via: "local",
|
|
1990
2016
|
localHit: t[0] || "",
|
|
1991
2017
|
category: "abuse"
|
|
@@ -1994,13 +2020,13 @@ function zn(e = {}) {
|
|
|
1994
2020
|
} : null;
|
|
1995
2021
|
}
|
|
1996
2022
|
function d() {
|
|
1997
|
-
let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, a =
|
|
1998
|
-
backend: new
|
|
2023
|
+
let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, a = Le(i, {
|
|
2024
|
+
backend: new Ie(),
|
|
1999
2025
|
useLimitedUseAppCheckTokens: t
|
|
2000
2026
|
});
|
|
2001
|
-
return
|
|
2027
|
+
return Re(a, {
|
|
2002
2028
|
model: e,
|
|
2003
|
-
systemInstruction:
|
|
2029
|
+
systemInstruction: Pn(n.value),
|
|
2004
2030
|
generationConfig: {
|
|
2005
2031
|
temperature: 0,
|
|
2006
2032
|
maxOutputTokens: 256,
|
|
@@ -2029,7 +2055,7 @@ function zn(e = {}) {
|
|
|
2029
2055
|
};
|
|
2030
2056
|
}
|
|
2031
2057
|
function p(e, t = "") {
|
|
2032
|
-
let n =
|
|
2058
|
+
let n = zn({
|
|
2033
2059
|
reason: e.reason,
|
|
2034
2060
|
category: e.category,
|
|
2035
2061
|
via: e.via
|
|
@@ -2057,26 +2083,26 @@ function zn(e = {}) {
|
|
|
2057
2083
|
};
|
|
2058
2084
|
let i = e.trim();
|
|
2059
2085
|
if (!i) return {
|
|
2060
|
-
...
|
|
2086
|
+
...Wn,
|
|
2061
2087
|
via: "empty"
|
|
2062
2088
|
};
|
|
2063
2089
|
if (t?.skipFilter) return {
|
|
2064
|
-
...
|
|
2090
|
+
...Wn,
|
|
2065
2091
|
via: "admin-override"
|
|
2066
2092
|
};
|
|
2067
2093
|
let c = u(i);
|
|
2068
2094
|
if (c) return m(c);
|
|
2069
2095
|
if (r.enabled === !1) return {
|
|
2070
|
-
...
|
|
2096
|
+
...Wn,
|
|
2071
2097
|
via: "disabled"
|
|
2072
2098
|
};
|
|
2073
2099
|
try {
|
|
2074
|
-
let e =
|
|
2100
|
+
let e = Un((await d().generateContent(Fn(i, n.value))).response.text());
|
|
2075
2101
|
if (!e) return f();
|
|
2076
2102
|
let t = {
|
|
2077
2103
|
flagged: e.flagged,
|
|
2078
2104
|
category: e.category,
|
|
2079
|
-
reason:
|
|
2105
|
+
reason: zn({
|
|
2080
2106
|
reason: e.reason,
|
|
2081
2107
|
category: e.category,
|
|
2082
2108
|
via: "ai"
|
|
@@ -2096,22 +2122,22 @@ function zn(e = {}) {
|
|
|
2096
2122
|
via: "restricted"
|
|
2097
2123
|
};
|
|
2098
2124
|
if (r.enabled === !1 || !r.moderateImages) return {
|
|
2099
|
-
...
|
|
2125
|
+
...Wn,
|
|
2100
2126
|
via: "disabled"
|
|
2101
2127
|
};
|
|
2102
2128
|
try {
|
|
2103
2129
|
let t = await new Promise((t, n) => {
|
|
2104
2130
|
let r = new FileReader();
|
|
2105
2131
|
r.onload = () => t(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(e);
|
|
2106
|
-
}), r =
|
|
2132
|
+
}), r = Un((await d().generateContent([{ inlineData: {
|
|
2107
2133
|
mimeType: e.type || "image/jpeg",
|
|
2108
2134
|
data: t
|
|
2109
|
-
} },
|
|
2135
|
+
} }, In(n.value)])).response.text());
|
|
2110
2136
|
if (!r) return f();
|
|
2111
2137
|
let i = {
|
|
2112
2138
|
flagged: r.flagged,
|
|
2113
2139
|
category: r.category,
|
|
2114
|
-
reason:
|
|
2140
|
+
reason: zn({
|
|
2115
2141
|
reason: r.reason,
|
|
2116
2142
|
category: r.category,
|
|
2117
2143
|
via: "ai"
|
|
@@ -2130,7 +2156,7 @@ function zn(e = {}) {
|
|
|
2130
2156
|
}
|
|
2131
2157
|
//#endregion
|
|
2132
2158
|
//#region src/composables/useMemiBoardUsers.ts
|
|
2133
|
-
var
|
|
2159
|
+
var Kn = [
|
|
2134
2160
|
"admin",
|
|
2135
2161
|
"staff",
|
|
2136
2162
|
"user"
|
|
@@ -2139,13 +2165,13 @@ var Bn = [
|
|
|
2139
2165
|
label: w("ko", `common.role.${e}`),
|
|
2140
2166
|
description: w("ko", `boardUsers.roleDescription.${e}`)
|
|
2141
2167
|
}));
|
|
2142
|
-
function
|
|
2143
|
-
let n = () =>
|
|
2168
|
+
function qn(t = {}) {
|
|
2169
|
+
let n = () => j(), i = Z(), { t: a } = O(), o = N(() => I(t.enabled) ?? !0 ? e(i, n()) : null), s = be(o, { ssrKey: r(n(), "users-management") });
|
|
2144
2170
|
async function c(e, t) {
|
|
2145
|
-
if (!
|
|
2146
|
-
await
|
|
2171
|
+
if (!Kn.some((e) => e.value === t)) throw Error(a("boardUsers.unsupportedRole"));
|
|
2172
|
+
await Y(f(i, n(), e), {
|
|
2147
2173
|
role: t,
|
|
2148
|
-
updatedAt:
|
|
2174
|
+
updatedAt: K()
|
|
2149
2175
|
});
|
|
2150
2176
|
}
|
|
2151
2177
|
return {
|
|
@@ -2156,11 +2182,11 @@ function Vn(t = {}) {
|
|
|
2156
2182
|
}
|
|
2157
2183
|
//#endregion
|
|
2158
2184
|
//#region src/composables/useMemiBoardUserProfile.ts
|
|
2159
|
-
function
|
|
2160
|
-
let t = Z(), n = () =>
|
|
2185
|
+
function Jn(e) {
|
|
2186
|
+
let t = Z(), n = () => j(), r = N(() => I(e)), i = N(() => {
|
|
2161
2187
|
let e = r.value;
|
|
2162
2188
|
return e ? f(t, n(), e) : null;
|
|
2163
|
-
}), { data: a, pending: o } =
|
|
2189
|
+
}), { data: a, pending: o } = Se(i);
|
|
2164
2190
|
return {
|
|
2165
2191
|
profile: a,
|
|
2166
2192
|
profilePending: o
|
|
@@ -2168,7 +2194,7 @@ function Hn(e) {
|
|
|
2168
2194
|
}
|
|
2169
2195
|
//#endregion
|
|
2170
2196
|
//#region src/utils/section.ts
|
|
2171
|
-
var
|
|
2197
|
+
var Yn = [
|
|
2172
2198
|
3,
|
|
2173
2199
|
4,
|
|
2174
2200
|
5,
|
|
@@ -2178,7 +2204,7 @@ var Un = [
|
|
|
2178
2204
|
9,
|
|
2179
2205
|
12
|
|
2180
2206
|
];
|
|
2181
|
-
function
|
|
2207
|
+
function Xn(e) {
|
|
2182
2208
|
return [
|
|
2183
2209
|
{
|
|
2184
2210
|
value: "list",
|
|
@@ -2194,7 +2220,7 @@ function Wn(e) {
|
|
|
2194
2220
|
}
|
|
2195
2221
|
];
|
|
2196
2222
|
}
|
|
2197
|
-
function
|
|
2223
|
+
function Zn(e) {
|
|
2198
2224
|
return [{
|
|
2199
2225
|
value: "latest",
|
|
2200
2226
|
label: w(e, "sectionUtil.sort.latest")
|
|
@@ -2203,18 +2229,18 @@ function Gn(e) {
|
|
|
2203
2229
|
label: w(e, "sectionUtil.sort.likes")
|
|
2204
2230
|
}];
|
|
2205
2231
|
}
|
|
2206
|
-
var
|
|
2207
|
-
function
|
|
2232
|
+
var Qn = Xn("ko"), $n = Zn("ko");
|
|
2233
|
+
function er(e) {
|
|
2208
2234
|
return e === "list" ? 5 : 4;
|
|
2209
2235
|
}
|
|
2210
|
-
function
|
|
2236
|
+
function tr(e, t) {
|
|
2211
2237
|
let n = Math.floor(Number(t));
|
|
2212
|
-
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) :
|
|
2238
|
+
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : er(e);
|
|
2213
2239
|
}
|
|
2214
|
-
function
|
|
2240
|
+
function nr(e) {
|
|
2215
2241
|
return e === 12 ? null : 12 - e;
|
|
2216
2242
|
}
|
|
2217
|
-
function
|
|
2243
|
+
function rr(e) {
|
|
2218
2244
|
return {
|
|
2219
2245
|
3: "col-span-12 md:col-span-3",
|
|
2220
2246
|
4: "col-span-12 md:col-span-4",
|
|
@@ -2226,36 +2252,36 @@ function Zn(e) {
|
|
|
2226
2252
|
12: "col-span-12"
|
|
2227
2253
|
}[e];
|
|
2228
2254
|
}
|
|
2229
|
-
function
|
|
2255
|
+
function ir(e) {
|
|
2230
2256
|
return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
|
|
2231
2257
|
}
|
|
2232
|
-
function
|
|
2258
|
+
function ar(e) {
|
|
2233
2259
|
let t = e.boardId || e.category || "free";
|
|
2234
2260
|
return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
|
|
2235
2261
|
}
|
|
2236
|
-
function
|
|
2262
|
+
function or(e) {
|
|
2237
2263
|
return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
|
|
2238
2264
|
}
|
|
2239
|
-
function
|
|
2265
|
+
function sr(e) {
|
|
2240
2266
|
if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
|
|
2241
2267
|
}
|
|
2242
|
-
function
|
|
2268
|
+
function cr(e) {
|
|
2243
2269
|
return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
2244
2270
|
}
|
|
2245
|
-
function
|
|
2271
|
+
function lr(e, t) {
|
|
2246
2272
|
return e.title?.trim() || e.summary || w(t, "sectionUtil.untitledPost");
|
|
2247
2273
|
}
|
|
2248
|
-
function
|
|
2274
|
+
function ur(e) {
|
|
2249
2275
|
return e === "image" || e === "video" ? "media" : "list";
|
|
2250
2276
|
}
|
|
2251
|
-
function
|
|
2252
|
-
return w(t,
|
|
2277
|
+
function dr(e, t) {
|
|
2278
|
+
return w(t, ur(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
|
|
2253
2279
|
}
|
|
2254
|
-
function
|
|
2280
|
+
function fr(e, t) {
|
|
2255
2281
|
return e ? t(e)?.listView ?? "default" : "default";
|
|
2256
2282
|
}
|
|
2257
|
-
function
|
|
2258
|
-
let n = e.map((e) =>
|
|
2283
|
+
function pr(e, t) {
|
|
2284
|
+
let n = e.map((e) => fr(e.boardId, t));
|
|
2259
2285
|
if (!n.length) return "default";
|
|
2260
2286
|
if (n.every((e) => e === n[0])) return n[0];
|
|
2261
2287
|
let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
|
|
@@ -2263,27 +2289,27 @@ function sr(e, t) {
|
|
|
2263
2289
|
}
|
|
2264
2290
|
//#endregion
|
|
2265
2291
|
//#region src/composables/useMemiBoardSections.ts
|
|
2266
|
-
var
|
|
2267
|
-
function
|
|
2292
|
+
var mr = [];
|
|
2293
|
+
function hr(e) {
|
|
2268
2294
|
let t = Number(e.cols);
|
|
2269
|
-
if (
|
|
2295
|
+
if (Yn.includes(t)) return t;
|
|
2270
2296
|
let n = e.width;
|
|
2271
2297
|
return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
|
|
2272
2298
|
}
|
|
2273
|
-
function
|
|
2299
|
+
function gr(e) {
|
|
2274
2300
|
let t = e.height ?? e.size;
|
|
2275
2301
|
return t === "sm" || t === "lg" ? t : "md";
|
|
2276
2302
|
}
|
|
2277
|
-
function
|
|
2303
|
+
function _r(e) {
|
|
2278
2304
|
return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
|
|
2279
2305
|
}
|
|
2280
|
-
function
|
|
2306
|
+
function vr(e) {
|
|
2281
2307
|
return e.sort === "likes" ? "likes" : "latest";
|
|
2282
2308
|
}
|
|
2283
|
-
function
|
|
2309
|
+
function yr(e) {
|
|
2284
2310
|
return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
|
|
2285
2311
|
}
|
|
2286
|
-
function
|
|
2312
|
+
function br(e, t) {
|
|
2287
2313
|
let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
|
|
2288
2314
|
for (let e of n) {
|
|
2289
2315
|
let n = String(e || "").trim();
|
|
@@ -2291,47 +2317,47 @@ function mr(e, t) {
|
|
|
2291
2317
|
}
|
|
2292
2318
|
return r;
|
|
2293
2319
|
}
|
|
2294
|
-
function
|
|
2320
|
+
function xr(e, t) {
|
|
2295
2321
|
return w(t, "sections.defaultTitle", { n: e + 1 });
|
|
2296
2322
|
}
|
|
2297
|
-
function
|
|
2298
|
-
let r =
|
|
2323
|
+
function Sr(e, t, n) {
|
|
2324
|
+
let r = _r(e), i = tr(r, e.count);
|
|
2299
2325
|
return {
|
|
2300
2326
|
id: String(e.id || `box-${t + 1}`),
|
|
2301
|
-
title: String(e.title ||
|
|
2327
|
+
title: String(e.title || xr(t, n)),
|
|
2302
2328
|
showTitle: e.showTitle !== !1,
|
|
2303
2329
|
kind: r,
|
|
2304
|
-
boardId:
|
|
2330
|
+
boardId: yr(e),
|
|
2305
2331
|
count: i,
|
|
2306
|
-
postIds:
|
|
2307
|
-
sort:
|
|
2308
|
-
cols:
|
|
2309
|
-
height:
|
|
2332
|
+
postIds: br(e, i),
|
|
2333
|
+
sort: vr(e),
|
|
2334
|
+
cols: hr(e),
|
|
2335
|
+
height: gr(e),
|
|
2310
2336
|
order: t
|
|
2311
2337
|
};
|
|
2312
2338
|
}
|
|
2313
|
-
function
|
|
2314
|
-
let { locale: e } = O(), t = Z(), n =
|
|
2339
|
+
function Cr() {
|
|
2340
|
+
let { locale: e } = O(), t = Z(), n = me(t, "settings", "homeLayout"), { data: r, pending: i } = Se(n), a = N(() => (Array.isArray(r.value?.blocks) ? r.value.blocks : mr).map((t, n) => Sr(t, n, e.value)));
|
|
2315
2341
|
async function o(t) {
|
|
2316
|
-
await
|
|
2342
|
+
await q(n, {
|
|
2317
2343
|
columns: 12,
|
|
2318
2344
|
blocks: t.map((t, n) => {
|
|
2319
|
-
let r = t, i =
|
|
2345
|
+
let r = t, i = _r(r), a = tr(i, t.count);
|
|
2320
2346
|
return {
|
|
2321
2347
|
id: t.id,
|
|
2322
|
-
title: t.title.trim() ||
|
|
2348
|
+
title: t.title.trim() || xr(n, e.value),
|
|
2323
2349
|
showTitle: t.showTitle !== !1,
|
|
2324
2350
|
kind: i,
|
|
2325
|
-
boardId:
|
|
2351
|
+
boardId: yr(r),
|
|
2326
2352
|
count: a,
|
|
2327
|
-
postIds:
|
|
2328
|
-
sort:
|
|
2329
|
-
cols:
|
|
2330
|
-
height:
|
|
2353
|
+
postIds: br(r, a),
|
|
2354
|
+
sort: vr(r),
|
|
2355
|
+
cols: hr(r),
|
|
2356
|
+
height: gr(r),
|
|
2331
2357
|
order: n
|
|
2332
2358
|
};
|
|
2333
2359
|
}),
|
|
2334
|
-
updatedAt:
|
|
2360
|
+
updatedAt: K()
|
|
2335
2361
|
});
|
|
2336
2362
|
}
|
|
2337
2363
|
return {
|
|
@@ -2339,28 +2365,28 @@ function _r() {
|
|
|
2339
2365
|
pending: i,
|
|
2340
2366
|
sections: a,
|
|
2341
2367
|
blocks: a,
|
|
2342
|
-
hasSavedLayout:
|
|
2368
|
+
hasSavedLayout: N(() => Array.isArray(r.value?.blocks)),
|
|
2343
2369
|
saveSections: o,
|
|
2344
2370
|
saveBlocks: o
|
|
2345
2371
|
};
|
|
2346
2372
|
}
|
|
2347
2373
|
//#endregion
|
|
2348
2374
|
//#region src/composables/useMemiBoardMiniPosts.ts
|
|
2349
|
-
function
|
|
2350
|
-
let n = Z(), i = () =>
|
|
2351
|
-
let r = Math.max(1, Math.floor(Number(
|
|
2352
|
-
return a && o.unshift(
|
|
2353
|
-
}), { data: s, pending: c, error: l } =
|
|
2375
|
+
function wr(e, t) {
|
|
2376
|
+
let n = Z(), i = () => j(), a = I(e)?.trim() || "all", o = N(() => {
|
|
2377
|
+
let r = Math.max(1, Math.floor(Number(I(t)) || 5)), a = I(e)?.trim() || "", o = [X("isPublished", "==", !0), X("listed", "==", !0)];
|
|
2378
|
+
return a && o.unshift(X("boardId", "==", a)), G(M(n, i()), ...o, W("createdAt", "desc"), H(r));
|
|
2379
|
+
}), { data: s, pending: c, error: l } = be(o, { ssrKey: r(i(), `mini-list/${a}`) });
|
|
2354
2380
|
return {
|
|
2355
|
-
posts:
|
|
2381
|
+
posts: N(() => s.value ?? []),
|
|
2356
2382
|
pending: c,
|
|
2357
2383
|
error: l
|
|
2358
2384
|
};
|
|
2359
2385
|
}
|
|
2360
|
-
function
|
|
2361
|
-
let t = Z(), n = () =>
|
|
2386
|
+
function Tr(e) {
|
|
2387
|
+
let t = Z(), n = () => j(), i = N(() => [...new Set(I(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), a = i.value.join(",") || "none", o = N(() => i.value.length ? G(M(t, n()), X(R(), "in", i.value)) : null), { data: s, pending: c, error: l } = be(o, { ssrKey: r(n(), `mini-picked/${a}`) });
|
|
2362
2388
|
return {
|
|
2363
|
-
posts:
|
|
2389
|
+
posts: N(() => {
|
|
2364
2390
|
let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
|
|
2365
2391
|
for (let n of i.value) {
|
|
2366
2392
|
let r = e.get(n);
|
|
@@ -2374,7 +2400,16 @@ function yr(e) {
|
|
|
2374
2400
|
}
|
|
2375
2401
|
//#endregion
|
|
2376
2402
|
//#region src/data/versionHistory.ts
|
|
2377
|
-
var
|
|
2403
|
+
var Er = [
|
|
2404
|
+
{
|
|
2405
|
+
version: "0.45.1",
|
|
2406
|
+
date: "2026-10-15",
|
|
2407
|
+
highlights: [
|
|
2408
|
+
"일반 계정 글쓰기·초안 조회와 태그 입력을 고쳤어요",
|
|
2409
|
+
"댓글·답글 수정과 좋아요가 다른 사용자에게 바로 반영돼요",
|
|
2410
|
+
"글 삭제·첨부파일 보호·게시판 공개 범위 변경을 보강했어요"
|
|
2411
|
+
]
|
|
2412
|
+
},
|
|
2378
2413
|
{
|
|
2379
2414
|
version: "0.45.0",
|
|
2380
2415
|
date: "2026-10-01",
|
|
@@ -2659,7 +2694,7 @@ var br = [
|
|
|
2659
2694
|
highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
|
|
2660
2695
|
note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
|
|
2661
2696
|
}
|
|
2662
|
-
],
|
|
2697
|
+
], Dr = 10, Or = 864e5, kr = 200, Ar = {
|
|
2663
2698
|
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
2664
2699
|
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
2665
2700
|
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
@@ -2668,7 +2703,7 @@ var br = [
|
|
|
2668
2703
|
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
2669
2704
|
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
2670
2705
|
};
|
|
2671
|
-
function
|
|
2706
|
+
function jr(e) {
|
|
2672
2707
|
return {
|
|
2673
2708
|
proofread: "Fix only spelling, spacing, and grammar errors. Do not change the meaning or tone.",
|
|
2674
2709
|
polish: "Refine the text into more natural, readable sentences while keeping the meaning and the author's tone.",
|
|
@@ -2679,34 +2714,34 @@ function Tr(e) {
|
|
|
2679
2714
|
title: `Create one concise title in ${e} that represents the body. Output only the title, without quotes or explanation.`
|
|
2680
2715
|
};
|
|
2681
2716
|
}
|
|
2682
|
-
function
|
|
2683
|
-
let r = t === "ko", i =
|
|
2717
|
+
function Mr(e, t, n) {
|
|
2718
|
+
let r = t === "ko", i = Mn(t);
|
|
2684
2719
|
if (e.action !== "custom") {
|
|
2685
|
-
if (r) return
|
|
2686
|
-
let t =
|
|
2720
|
+
if (r) return Ar[e.action];
|
|
2721
|
+
let t = jr(i)[e.action];
|
|
2687
2722
|
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}.`;
|
|
2688
2723
|
}
|
|
2689
|
-
let a = e.customInstruction?.trim().slice(0,
|
|
2724
|
+
let a = e.customInstruction?.trim().slice(0, kr);
|
|
2690
2725
|
if (!a) throw Error(n("writingAssistant.customRequired"));
|
|
2691
2726
|
return r ? `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${a}` : `Rewrite the text applying the following style instruction while keeping the meaning: ${a}`;
|
|
2692
2727
|
}
|
|
2693
|
-
function
|
|
2728
|
+
function Nr(e) {
|
|
2694
2729
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
2695
2730
|
}
|
|
2696
|
-
function
|
|
2731
|
+
function Pr(e) {
|
|
2697
2732
|
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
2698
2733
|
}
|
|
2699
|
-
function
|
|
2700
|
-
let t = O(), n =
|
|
2734
|
+
function Fr(e = {}) {
|
|
2735
|
+
let t = O(), n = N(() => E(I(e.locale)) ?? t.locale.value), r = (e, t) => w(n.value, e, t), i = Ce(), a = Z(), o = xe(), s = ue();
|
|
2701
2736
|
async function c() {
|
|
2702
2737
|
let e = o.value?.uid;
|
|
2703
2738
|
if (!e) throw Error(r("writingAssistant.loginRequired"));
|
|
2704
2739
|
await ve(a, async (t) => {
|
|
2705
|
-
let n = f(a,
|
|
2740
|
+
let n = f(a, j(), e), i = await t.get(n);
|
|
2706
2741
|
if (!i.exists()) throw Error(r("writingAssistant.userMissing"));
|
|
2707
|
-
let o = i.data(), s =
|
|
2742
|
+
let o = i.data(), s = Pr(o.aiWritingWindowAt), c = Math.max(0, Math.floor(Number(o.aiWritingCount) || 0)), l = Date.now(), u = s != null && l - s < Or;
|
|
2708
2743
|
if (u && c >= 10) {
|
|
2709
|
-
let e = s +
|
|
2744
|
+
let e = s + Or, t = Math.max(1, Math.ceil((e - l) / 36e5));
|
|
2710
2745
|
throw Error(r("writingAssistant.dailyLimit", {
|
|
2711
2746
|
limit: 10,
|
|
2712
2747
|
hours: t
|
|
@@ -2714,19 +2749,19 @@ function kr(e = {}) {
|
|
|
2714
2749
|
}
|
|
2715
2750
|
t.update(n, {
|
|
2716
2751
|
aiWritingCount: u ? c + 1 : 1,
|
|
2717
|
-
aiWritingWindowAt: u ? o.aiWritingWindowAt :
|
|
2718
|
-
updatedAt:
|
|
2752
|
+
aiWritingWindowAt: u ? o.aiWritingWindowAt : K(),
|
|
2753
|
+
updatedAt: K()
|
|
2719
2754
|
});
|
|
2720
2755
|
});
|
|
2721
2756
|
}
|
|
2722
2757
|
async function l(e) {
|
|
2723
|
-
let t = n.value, a = t === "ko", o =
|
|
2758
|
+
let t = n.value, a = t === "ko", o = Mr(e, t, r);
|
|
2724
2759
|
if (!e.content.trim()) throw Error(r("writingAssistant.contentRequired"));
|
|
2725
2760
|
await c();
|
|
2726
|
-
let l = s.moderation ?? {}, u =
|
|
2727
|
-
backend: new
|
|
2761
|
+
let l = s.moderation ?? {}, u = Le(i, {
|
|
2762
|
+
backend: new Ie(),
|
|
2728
2763
|
useLimitedUseAppCheckTokens: l.useLimitedUseAppCheckTokens !== !1
|
|
2729
|
-
}), d =
|
|
2764
|
+
}), d = Re(u, {
|
|
2730
2765
|
model: l.model ?? "gemini-3.5-flash-lite",
|
|
2731
2766
|
systemInstruction: (a ? [
|
|
2732
2767
|
"너는 게시판 글쓰기 편집 도우미다.",
|
|
@@ -2749,7 +2784,7 @@ function kr(e = {}) {
|
|
|
2749
2784
|
`Task: ${o}`,
|
|
2750
2785
|
e.title ? `Current title: ${e.title}` : "",
|
|
2751
2786
|
`Body:\n${f.slice(0, 12e3)}`
|
|
2752
|
-
]).filter(Boolean).join("\n\n"), m =
|
|
2787
|
+
]).filter(Boolean).join("\n\n"), m = Nr((await d.generateContent(p)).response.text());
|
|
2753
2788
|
if (!m) throw Error(r("writingAssistant.emptyResult"));
|
|
2754
2789
|
return m;
|
|
2755
2790
|
}
|
|
@@ -2757,8 +2792,8 @@ function kr(e = {}) {
|
|
|
2757
2792
|
}
|
|
2758
2793
|
//#endregion
|
|
2759
2794
|
//#region src/composables/useMemiBoardAutoTranslate.ts
|
|
2760
|
-
var
|
|
2761
|
-
function
|
|
2795
|
+
var Ir = 3e4;
|
|
2796
|
+
function Lr(e, t) {
|
|
2762
2797
|
return new Promise((n, r) => {
|
|
2763
2798
|
let i = setTimeout(() => r(/* @__PURE__ */ Error(`translation timed out after ${t / 1e3}s`)), t);
|
|
2764
2799
|
e.then((e) => {
|
|
@@ -2768,14 +2803,14 @@ function jr(e, t) {
|
|
|
2768
2803
|
});
|
|
2769
2804
|
});
|
|
2770
2805
|
}
|
|
2771
|
-
function
|
|
2772
|
-
let e =
|
|
2806
|
+
function Rr() {
|
|
2807
|
+
let e = Ce(), { moderation: t } = ue();
|
|
2773
2808
|
function n(n, r) {
|
|
2774
|
-
let i =
|
|
2775
|
-
backend: new
|
|
2809
|
+
let i = Le(e, {
|
|
2810
|
+
backend: new Ie(),
|
|
2776
2811
|
useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
|
|
2777
2812
|
}), a = Q.object({ properties: Object.fromEntries(r.map((e) => [e, Q.string()])) });
|
|
2778
|
-
return
|
|
2813
|
+
return Re(i, {
|
|
2779
2814
|
model: t.model ?? "gemini-3.5-flash-lite",
|
|
2780
2815
|
systemInstruction: [
|
|
2781
2816
|
"You translate short user-interface strings for a website.",
|
|
@@ -2794,12 +2829,12 @@ function Mr() {
|
|
|
2794
2829
|
async function r(e, t, r, i) {
|
|
2795
2830
|
let a = Object.keys(e.fields), o = [
|
|
2796
2831
|
`Purpose: ${i}`,
|
|
2797
|
-
`Source language: ${
|
|
2798
|
-
`Translate into: ${r.map((e) => `${e} = ${
|
|
2832
|
+
`Source language: ${Mn(t)} (${t})`,
|
|
2833
|
+
`Translate into: ${r.map((e) => `${e} = ${Mn(e)}`).join(", ")}`,
|
|
2799
2834
|
e.context ? `Context (do not translate): ${e.context}` : "",
|
|
2800
2835
|
"Text (JSON):",
|
|
2801
2836
|
JSON.stringify(e.fields)
|
|
2802
|
-
].filter(Boolean).join("\n"), s = await
|
|
2837
|
+
].filter(Boolean).join("\n"), s = await Lr(n(r, a).generateContent(o), Ir), c = JSON.parse(s.response.text()), l = {};
|
|
2803
2838
|
for (let e of r) {
|
|
2804
2839
|
let t = c?.[e];
|
|
2805
2840
|
if (!t) continue;
|
|
@@ -2813,7 +2848,7 @@ function Mr() {
|
|
|
2813
2848
|
return l;
|
|
2814
2849
|
}
|
|
2815
2850
|
async function i(e, t = {}) {
|
|
2816
|
-
let n = t.source ?? "ko", i = (t.targets ??
|
|
2851
|
+
let n = t.source ?? "ko", i = (t.targets ?? A.map((e) => e.code)).filter((e) => e !== n), a = t.purpose ?? "website UI labels", o = e.map((e) => ({
|
|
2817
2852
|
...e,
|
|
2818
2853
|
fields: Object.fromEntries(Object.entries(e.fields).map(([e, t]) => [e, t.trim()]).filter(([, e]) => e))
|
|
2819
2854
|
})).filter((e) => Object.keys(e.fields).length);
|
|
@@ -2823,20 +2858,20 @@ function Mr() {
|
|
|
2823
2858
|
}
|
|
2824
2859
|
return { translateEntries: i };
|
|
2825
2860
|
}
|
|
2826
|
-
function
|
|
2861
|
+
function zr(e, t, n, r) {
|
|
2827
2862
|
let i = E(t);
|
|
2828
2863
|
return !i || i === "ko" ? r : e?.[i]?.[n] || e?.en?.[n] || r;
|
|
2829
2864
|
}
|
|
2830
2865
|
//#endregion
|
|
2831
2866
|
//#region src/utils/renderMarkdown.ts
|
|
2832
|
-
function
|
|
2867
|
+
function Br(e) {
|
|
2833
2868
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
2834
2869
|
}
|
|
2835
|
-
function
|
|
2870
|
+
function Vr(e) {
|
|
2836
2871
|
let t = e;
|
|
2837
2872
|
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;
|
|
2838
2873
|
}
|
|
2839
|
-
function
|
|
2874
|
+
function Hr(e) {
|
|
2840
2875
|
if (!e?.trim()) return "";
|
|
2841
2876
|
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
|
|
2842
2877
|
function c() {
|
|
@@ -2845,7 +2880,7 @@ function Ir(e) {
|
|
|
2845
2880
|
return;
|
|
2846
2881
|
}
|
|
2847
2882
|
let e = o;
|
|
2848
|
-
n.push(`<${e}>${s.map((e) => `<li>${
|
|
2883
|
+
n.push(`<${e}>${s.map((e) => `<li>${Vr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
|
|
2849
2884
|
}
|
|
2850
2885
|
for (; r < t.length;) {
|
|
2851
2886
|
let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
|
|
@@ -2854,7 +2889,7 @@ function Ir(e) {
|
|
|
2854
2889
|
continue;
|
|
2855
2890
|
}
|
|
2856
2891
|
if (i) {
|
|
2857
|
-
a.push(
|
|
2892
|
+
a.push(Br(e)), r++;
|
|
2858
2893
|
continue;
|
|
2859
2894
|
}
|
|
2860
2895
|
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
|
|
@@ -2865,24 +2900,24 @@ function Ir(e) {
|
|
|
2865
2900
|
if (u) {
|
|
2866
2901
|
c();
|
|
2867
2902
|
let e = u[1].length;
|
|
2868
|
-
n.push(`<h${e} class="font-semibold mt-4 mb-2">${
|
|
2903
|
+
n.push(`<h${e} class="font-semibold mt-4 mb-2">${Vr(Br(u[2]))}</h${e}>`), r++;
|
|
2869
2904
|
continue;
|
|
2870
2905
|
}
|
|
2871
2906
|
if (e.startsWith("> ")) {
|
|
2872
2907
|
c();
|
|
2873
2908
|
let e = [];
|
|
2874
|
-
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(
|
|
2875
|
-
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${
|
|
2909
|
+
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(Br((t[r] ?? "").slice(2))), r++;
|
|
2910
|
+
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Vr(e.join("<br />"))}</blockquote>`);
|
|
2876
2911
|
continue;
|
|
2877
2912
|
}
|
|
2878
2913
|
let d = e.match(/^[-*+]\s+(.+)$/);
|
|
2879
2914
|
if (d) {
|
|
2880
|
-
o && o !== "ul" && c(), o = "ul", s.push(
|
|
2915
|
+
o && o !== "ul" && c(), o = "ul", s.push(Br(d[1])), r++;
|
|
2881
2916
|
continue;
|
|
2882
2917
|
}
|
|
2883
2918
|
let f = e.match(/^\d+\.\s+(.+)$/);
|
|
2884
2919
|
if (f) {
|
|
2885
|
-
o && o !== "ol" && c(), o = "ol", s.push(
|
|
2920
|
+
o && o !== "ol" && c(), o = "ol", s.push(Br(f[1])), r++;
|
|
2886
2921
|
continue;
|
|
2887
2922
|
}
|
|
2888
2923
|
if (!e.trim()) {
|
|
@@ -2894,13 +2929,13 @@ function Ir(e) {
|
|
|
2894
2929
|
for (; r < t.length;) {
|
|
2895
2930
|
let e = t[r] ?? "";
|
|
2896
2931
|
if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
|
|
2897
|
-
p.push(
|
|
2932
|
+
p.push(Br(e)), r++;
|
|
2898
2933
|
}
|
|
2899
|
-
n.push(`<p class="my-2 leading-relaxed">${
|
|
2934
|
+
n.push(`<p class="my-2 leading-relaxed">${Vr(p.join("<br />"))}</p>`);
|
|
2900
2935
|
}
|
|
2901
2936
|
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");
|
|
2902
2937
|
}
|
|
2903
2938
|
//#endregion
|
|
2904
|
-
export {
|
|
2939
|
+
export { un as AUTHOR_MEMO_MAX_LENGTH, Yn as BOARD_SECTION_COLS, Qn as BOARD_SECTION_KINDS, $n as BOARD_SECTION_SORTS, Kn as BOARD_USER_ROLES, gn as COMMENT_BODY_MAX_LENGTH, st as DEFAULT_BLOCK_BAN_DECAY_MS, ot as DEFAULT_BLOCK_BAN_THRESHOLD, Gt as DEFAULT_BOARDS, Kt as DEFAULT_CATEGORIES, S as DEFAULT_COMMENTS_COLLECTION, le as DEFAULT_LIKES_COLLECTION, T as DEFAULT_MEMI_BOARD_LOCALE, h as DEFAULT_POSTS_COLLECTION, n as DEFAULT_REPORTS_COLLECTION, ce as DEFAULT_SETTINGS_COLLECTION, g as DEFAULT_USERS_COLLECTION, ie as FALLBACK_MEMI_BOARD_LOCALE, A as MEMI_BOARD_LOCALES, Cn as REPORT_DETAIL_MAX_LENGTH, wn as REPORT_REASONS, Dr as WRITING_ASSISTANT_DAILY_LIMIT, Be as asHttpUrl, Ke as boardListOgDescription, Ge as boardListOgTitle, We as boardPostOgDescription, Ue as boardPostOgTitle, Xn as boardSectionKinds, Zn as boardSectionSorts, r as boardSsrKey, f as boardUserDoc, e as boardUsersCol, Bt as buildPostPreview, tt as canManageBoardByRole, nt as canWriteCommentByRole, tr as clampSectionCount, k as commentDoc, u as commentsCol, b as configureMemiBoard, er as defaultSectionCount, ct as effectiveModerationBlockCount, xt as extractEditorImageUrls, Qe as fetchPublicListForSeo, Ze as fetchPublicPostForSeo, x as formatDate, re as formatFullDate, oe as formatRelativeDate, dt as formatRestrictedUntilLabel, C as formatTimestampDetails, Ft as hasBodyImage, Pt as hasBodyText, yt as imeSafeSubmitClick, vt as imeSafeSubmitPointerDown, et as isAssignedStaff, It as isContentEmpty, Zt as isFirestorePermissionDenied, te as isMemiBoardLocaleLoaded, ut as isModerationWriteRestricted, d as likeDoc, p as likeDocId, a as likesCol, se as loadMemiBoardLocale, zr as localizedText, xn as memiBoardCommentLikesKey, ae as memiBoardHostLocaleKey, D as memiBoardLocaleInfo, fr as miniBoardView, sr as miniCommentLink, or as miniMoreLink, cr as miniPostImage, ar as miniPostLink, lr as miniPostTitle, pr as miniPostsView, ur as miniViewGroup, dr as miniViewLabel, lt as moderationWriteRestrictedUntilMs, qe as normalizeBasePath, Sr as normalizeBoardSection, E as normalizeMemiBoardLocale, nr as pairSectionCols, Mt as plainTextFromHtml, c as postBodyDoc, l as postDoc, Ct as postNamespaceFromStoragePath, m as postStorageFolder, M as postsCol, Hr as renderMarkdownToHtml, t as reportDoc, v as reportDocId, Tn as reportReasonLabel, s as reportsCol, _ as resolveBoardPathConfig, Je as resolvePublicSeoDb, rr as sectionColClass, ir as sectionMinHeight, y as settingsCol, o as settingsDoc, ne as slugify, St as storagePathFromDownloadUrl, Nt as titleFromBody, He as toAbsoluteUrl, Ve as toBoardOgImageUrl, w as translate, j as useBoardPathConfig, ht as useMemiBoardAuth, fn as useMemiBoardAuthorMemo, Rr as useMemiBoardAutoTranslate, ln as useMemiBoardCommentFeed, Sn as useMemiBoardCommentLikes, vn as useMemiBoardComments, ue as useMemiBoardConfig, O as useMemiBoardI18n, bn as useMemiBoardLikes, wr as useMemiBoardMiniLatest, Tr as useMemiBoardMiniPicked, Gn as useMemiBoardModeration, nn as useMemiBoardPost, tn as useMemiBoardPostList, $t as useMemiBoardPosts, yn as useMemiBoardReplies, On as useMemiBoardReportQueue, En as useMemiBoardReports, Cr as useMemiBoardSections, Yt as useMemiBoardSettings, sn as useMemiBoardUserComments, an as useMemiBoardUserPosts, Jn as useMemiBoardUserProfile, qn as useMemiBoardUsers, kn as useMemiBoardViews, Fr as useMemiBoardWritingAssistant, Er as versionHistory, zt as videoListCoverUrl, Rt as youtubeId };
|
|
2905
2940
|
|
|
2906
2941
|
//# sourceMappingURL=index.js.map
|