memi-board 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composables/useMemiBoardComments.d.ts +6 -0
- package/dist/composables/useMemiBoardMiniPosts.d.ts +7 -0
- package/dist/composables/useMemiBoardReports.d.ts +4 -0
- package/dist/index.js +712 -701
- package/dist/index.js.map +1 -1
- package/dist/module.mjs.map +1 -1
- package/dist/{slugify-Cyq-Gg8X.js → slugify-Cm_pi2al.js} +44 -53
- package/dist/{slugify-Cyq-Gg8X.js.map → slugify-Cm_pi2al.js.map} +1 -1
- package/dist/storage.d.ts +2 -4
- package/dist/storage.js +46 -73
- package/dist/storage.js.map +1 -1
- package/package.json +20 -15
- package/dist/heic2any-D2QKy06h.js +0 -977
- package/dist/heic2any-D2QKy06h.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
import { A as e, C as t, D as n, E as r,
|
|
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, C as t, D as n, E as r, O as i, S as a, T as o, _ as s, a as c, b as l, c as u, d, f, g as p, h as m, i as h, j as g, k as _, l as v, m as y, n as b, o as x, p as S, r as C, s as w, u as T, v as E, w as D, x as O, y as k } from "./slugify-Cm_pi2al.js";
|
|
2
|
+
import { computed as A, onScopeDispose as j, reactive as ee, ref as M, toValue as N, watch as P } from "vue";
|
|
3
|
+
import { deleteDoc as F, deleteField as I, doc as L, documentId as R, endBefore as te, getDoc as z, getDocs as B, increment as V, limit as H, limitToLast as ne, onSnapshot as U, orderBy as W, query as G, runTransaction as re, serverTimestamp as K, setDoc as q, startAfter as J, updateDoc as Y, where as X, writeBatch as Z } from "firebase/firestore";
|
|
4
|
+
import { useCollection as ie, useCurrentUser as ae, useDocument as oe, useFirebaseApp as se, useFirebaseAuth as ce, useFirestore as Q } from "vuefire";
|
|
5
|
+
import { GoogleAuthProvider as le, OAuthProvider as ue, createUserWithEmailAndPassword as de, signInWithEmailAndPassword as fe, signInWithPopup as pe, signOut as me, updateProfile as he } from "firebase/auth";
|
|
6
|
+
import { deleteObject as ge, getStorage as _e, listAll as ve, ref as ye } from "firebase/storage";
|
|
7
|
+
import { GoogleAIBackend as be, Schema as xe, getAI as Se, getGenerativeModel as Ce } from "firebase/ai";
|
|
8
|
+
//#region \0rolldown/runtime.js
|
|
9
|
+
var we = Object.create, Te = Object.defineProperty, Ee = Object.getOwnPropertyDescriptor, De = Object.getOwnPropertyNames, Oe = Object.getPrototypeOf, ke = Object.prototype.hasOwnProperty, Ae = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), je = (e, t, n, r) => {
|
|
10
|
+
if (t && typeof t == "object" || typeof t == "function") for (var i = De(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !ke.call(e, s) && s !== n && Te(e, s, {
|
|
11
|
+
get: ((e) => t[e]).bind(null, s),
|
|
12
|
+
enumerable: !(r = Ee(t, s)) || r.enumerable
|
|
13
|
+
});
|
|
14
|
+
return e;
|
|
15
|
+
}, Me = (e, t, n) => (n = e == null ? {} : we(Oe(e)), je(t || !e || !e.__esModule || !ke.call(e, "default") ? Te(n, "default", {
|
|
16
|
+
value: e,
|
|
17
|
+
enumerable: !0
|
|
18
|
+
}) : n, e));
|
|
19
|
+
//#endregion
|
|
8
20
|
//#region src/utils/boardSeo.ts
|
|
9
|
-
function
|
|
21
|
+
function Ne(e) {
|
|
10
22
|
if (typeof e != "string") return null;
|
|
11
23
|
let t = e.trim();
|
|
12
24
|
return /^https?:\/\//i.test(t) ? t : null;
|
|
13
25
|
}
|
|
14
|
-
function
|
|
15
|
-
let t =
|
|
26
|
+
function Pe(e) {
|
|
27
|
+
let t = Ne(e);
|
|
16
28
|
if (!t) return null;
|
|
17
29
|
if (!/firebasestorage\.googleapis\.com/i.test(t)) return t;
|
|
18
30
|
try {
|
|
@@ -29,42 +41,42 @@ function De(e) {
|
|
|
29
41
|
return t;
|
|
30
42
|
}
|
|
31
43
|
}
|
|
32
|
-
function
|
|
44
|
+
function Fe(e, t, n = "") {
|
|
33
45
|
let r = t.replace(/\/$/, ""), i = e.trim();
|
|
34
|
-
return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ?
|
|
46
|
+
return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? Fe(n, t) : r;
|
|
35
47
|
}
|
|
36
|
-
function
|
|
48
|
+
function Ie(e, t, n, r) {
|
|
37
49
|
let i = r?.trim().slice(0, 40), a = e.trim() || i || "사진", o = t?.trim(), s = n.trim() || "Board";
|
|
38
50
|
return o ? `${a} · ${o} | ${s}` : `${a} | ${s}`;
|
|
39
51
|
}
|
|
40
|
-
function
|
|
52
|
+
function Le(e) {
|
|
41
53
|
let t = [];
|
|
42
54
|
return e.summary?.trim() ? t.push(e.summary.trim().slice(0, 140)) : t.push("게시판 글"), e.categoryLabel?.trim() && t.push(e.categoryLabel.trim()), e.authorName?.trim() && t.push(e.authorName.trim()), t.join(" · ").slice(0, 200);
|
|
43
55
|
}
|
|
44
|
-
function
|
|
56
|
+
function Re(e, t) {
|
|
45
57
|
let n = t.trim() || "Board", r = e?.trim();
|
|
46
58
|
return r && r !== "전체" ? `${r} 게시판 | ${n}` : `게시판 | ${n}`;
|
|
47
59
|
}
|
|
48
|
-
function
|
|
60
|
+
function ze(e) {
|
|
49
61
|
if (e.description?.trim()) return e.description.trim().slice(0, 200);
|
|
50
62
|
let t = e.categoryLabel?.trim(), n = t && t !== "전체" ? `${t} 게시판 — 소식을 확인하세요.` : "게시판 — 공지와 이야기를 확인하세요.", r = (e.recentTitles || []).filter(Boolean).slice(0, 3);
|
|
51
63
|
return r.length ? `${n} ${r.map((e) => `「${e}」`).join(" ")}`.slice(0, 200) : n.slice(0, 200);
|
|
52
64
|
}
|
|
53
|
-
function
|
|
65
|
+
function Be(e) {
|
|
54
66
|
let t = (e || "/board").trim() || "/board";
|
|
55
67
|
return (t.startsWith("/") ? t : `/${t}`).replace(/\/$/, "") || "/board";
|
|
56
68
|
}
|
|
57
69
|
//#endregion
|
|
58
70
|
//#region src/composables/fetchPublicSeo.ts
|
|
59
|
-
function
|
|
71
|
+
function Ve() {
|
|
60
72
|
return {
|
|
61
73
|
db: Q(),
|
|
62
|
-
paths:
|
|
74
|
+
paths: h()
|
|
63
75
|
};
|
|
64
76
|
}
|
|
65
|
-
async function
|
|
77
|
+
async function He(e, t) {
|
|
66
78
|
try {
|
|
67
|
-
let n = await
|
|
79
|
+
let n = await z(g(e.db, e.paths, t));
|
|
68
80
|
if (!n.exists()) return {
|
|
69
81
|
label: t,
|
|
70
82
|
description: "",
|
|
@@ -84,7 +96,7 @@ async function Fe(e, t) {
|
|
|
84
96
|
};
|
|
85
97
|
}
|
|
86
98
|
}
|
|
87
|
-
function
|
|
99
|
+
function Ue(e) {
|
|
88
100
|
if (e && typeof e == "object" && "toDate" in e) try {
|
|
89
101
|
let t = e.toDate();
|
|
90
102
|
return t instanceof Date ? t.toISOString() : null;
|
|
@@ -93,36 +105,36 @@ function Ie(e) {
|
|
|
93
105
|
}
|
|
94
106
|
return null;
|
|
95
107
|
}
|
|
96
|
-
async function
|
|
108
|
+
async function We(e, t, n) {
|
|
97
109
|
let r = e.trim(), i = t.trim();
|
|
98
110
|
if (!r || !i) return null;
|
|
99
|
-
let a = n ??
|
|
100
|
-
a.paths =
|
|
101
|
-
let
|
|
102
|
-
if (
|
|
111
|
+
let a = n ?? Ve();
|
|
112
|
+
a.paths = _(a.paths);
|
|
113
|
+
let s = await He(a, r);
|
|
114
|
+
if (s.hidden) return null;
|
|
103
115
|
try {
|
|
104
|
-
let e = (await
|
|
116
|
+
let e = (await B(G(o(a.db, a.paths), X("boardId", "==", r), X("slug", "==", i), X("listed", "==", !0), X("isPublished", "==", !0), H(1)))).docs[0];
|
|
105
117
|
if (!e) return null;
|
|
106
118
|
let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title.trim() : "";
|
|
107
119
|
return n ? {
|
|
108
120
|
id: e.id,
|
|
109
121
|
slug: typeof t.slug == "string" ? t.slug : i,
|
|
110
122
|
category: r,
|
|
111
|
-
categoryLabel:
|
|
123
|
+
categoryLabel: s.label,
|
|
112
124
|
title: n,
|
|
113
125
|
summary: typeof t.summary == "string" ? t.summary.trim().slice(0, 200) : "",
|
|
114
|
-
previewImage:
|
|
126
|
+
previewImage: Pe(t.previewImage),
|
|
115
127
|
authorName: typeof t.authorName == "string" && t.authorName.trim() ? t.authorName.trim() : null,
|
|
116
|
-
createdAt:
|
|
128
|
+
createdAt: Ue(t.createdAt)
|
|
117
129
|
} : null;
|
|
118
130
|
} catch (e) {
|
|
119
131
|
return import.meta.dev && console.warn("[memi-board] fetchPublicPostForSeo failed", e), null;
|
|
120
132
|
}
|
|
121
133
|
}
|
|
122
|
-
async function
|
|
123
|
-
let n = e?.trim() || null, r = t ??
|
|
124
|
-
if (r.paths =
|
|
125
|
-
let e = await
|
|
134
|
+
async function Ge(e, t) {
|
|
135
|
+
let n = e?.trim() || null, r = t ?? Ve();
|
|
136
|
+
if (r.paths = _(r.paths), n) {
|
|
137
|
+
let e = await He(r, n);
|
|
126
138
|
if (e.hidden) return {
|
|
127
139
|
kind: "category",
|
|
128
140
|
category: n,
|
|
@@ -131,7 +143,7 @@ async function Re(e, t) {
|
|
|
131
143
|
ogImage: null,
|
|
132
144
|
recentTitles: []
|
|
133
145
|
};
|
|
134
|
-
let { recentTitles: t, ogImage: i } = await
|
|
146
|
+
let { recentTitles: t, ogImage: i } = await Ke(r, n);
|
|
135
147
|
return {
|
|
136
148
|
kind: "category",
|
|
137
149
|
category: n,
|
|
@@ -150,13 +162,13 @@ async function Re(e, t) {
|
|
|
150
162
|
recentTitles: []
|
|
151
163
|
};
|
|
152
164
|
}
|
|
153
|
-
async function
|
|
165
|
+
async function Ke(e, t) {
|
|
154
166
|
let n = [], r = null;
|
|
155
167
|
try {
|
|
156
|
-
let i = await
|
|
168
|
+
let i = await B(G(o(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), W("createdAt", "desc"), H(12)));
|
|
157
169
|
for (let e of i.docs) {
|
|
158
170
|
let t = e.data() ?? {}, i = typeof t.title == "string" ? t.title.trim() : "";
|
|
159
|
-
i && n.length < 5 && n.push(i), r ||=
|
|
171
|
+
i && n.length < 5 && n.push(i), r ||= Pe(t.previewImage);
|
|
160
172
|
}
|
|
161
173
|
} catch (e) {
|
|
162
174
|
import.meta.dev && console.warn("[memi-board] loadRecentListed failed", e);
|
|
@@ -168,31 +180,31 @@ async function ze(e, t) {
|
|
|
168
180
|
}
|
|
169
181
|
//#endregion
|
|
170
182
|
//#region src/utils/boardAccess.ts
|
|
171
|
-
function
|
|
183
|
+
function qe(e, t) {
|
|
172
184
|
return !e || !t ? !1 : (t.allowedStaffUids ?? []).includes(e);
|
|
173
185
|
}
|
|
174
|
-
function
|
|
175
|
-
return e ? t ? !0 : n ?
|
|
186
|
+
function Je(e, t, n, r) {
|
|
187
|
+
return e ? t ? !0 : n ? qe(e, r) : !1 : !1;
|
|
176
188
|
}
|
|
177
|
-
function
|
|
189
|
+
function Ye(e, t, n, r) {
|
|
178
190
|
if (!e) return !1;
|
|
179
|
-
if (r?.visibility === "hidden") return
|
|
191
|
+
if (r?.visibility === "hidden") return Je(e, t, n, r);
|
|
180
192
|
let i = r?.commentWriteRole ?? "user";
|
|
181
|
-
return i === "admin" ? t : i !== "staff" ||
|
|
193
|
+
return i === "admin" ? t : i !== "staff" || Je(e, t, n, r);
|
|
182
194
|
}
|
|
183
195
|
//#endregion
|
|
184
196
|
//#region src/composables/boardLookup.ts
|
|
185
|
-
var
|
|
186
|
-
function
|
|
187
|
-
|
|
197
|
+
var Xe;
|
|
198
|
+
function Ze(e) {
|
|
199
|
+
Xe = e;
|
|
188
200
|
}
|
|
189
|
-
function
|
|
190
|
-
return
|
|
201
|
+
function Qe(e) {
|
|
202
|
+
return Xe?.(e);
|
|
191
203
|
}
|
|
192
204
|
//#endregion
|
|
193
205
|
//#region src/utils/moderation-strike.ts
|
|
194
|
-
var
|
|
195
|
-
function
|
|
206
|
+
var $e = 10, et = 864e5;
|
|
207
|
+
function tt(e, t, n = Date.now(), r = et) {
|
|
196
208
|
let i = Math.max(0, Math.floor(Number(e) || 0));
|
|
197
209
|
if (i <= 0) return 0;
|
|
198
210
|
let a = typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
@@ -200,7 +212,7 @@ function Je(e, t, n = Date.now(), r = qe) {
|
|
|
200
212
|
let o = Math.floor((n - a) / r);
|
|
201
213
|
return Math.max(0, i - o);
|
|
202
214
|
}
|
|
203
|
-
function
|
|
215
|
+
function nt(e, t, n = Date.now(), r = 10, i = et) {
|
|
204
216
|
let a = Math.max(0, Math.floor(Number(e) || 0));
|
|
205
217
|
if (a < r) return null;
|
|
206
218
|
let o = typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
@@ -208,17 +220,17 @@ function Ye(e, t, n = Date.now(), r = 10, i = qe) {
|
|
|
208
220
|
let s = o + (a - (r - 1)) * i;
|
|
209
221
|
return s > n ? s : null;
|
|
210
222
|
}
|
|
211
|
-
function
|
|
212
|
-
return
|
|
223
|
+
function rt(e, t, n = Date.now(), r = 10, i = et) {
|
|
224
|
+
return nt(e, t, n, r, i) != null;
|
|
213
225
|
}
|
|
214
|
-
function
|
|
226
|
+
function it(e, t = Date.now()) {
|
|
215
227
|
let n = Math.max(0, e - t), r = Math.ceil(n / 36e5);
|
|
216
228
|
if (r <= 0) return "곧 해제";
|
|
217
229
|
if (r < 24) return `약 ${r}시간 후 해제`;
|
|
218
230
|
let i = Math.floor(r / 24), a = r % 24;
|
|
219
231
|
return a === 0 ? `약 ${i}일 후 해제` : `약 ${i}일 ${a}시간 후 해제`;
|
|
220
232
|
}
|
|
221
|
-
function
|
|
233
|
+
function at(e) {
|
|
222
234
|
if (e == null) return null;
|
|
223
235
|
if (typeof e == "number" && Number.isFinite(e)) return e;
|
|
224
236
|
if (typeof e == "object" && e && "toMillis" in e && typeof e.toMillis == "function") return e.toMillis();
|
|
@@ -230,122 +242,122 @@ function Qe(e) {
|
|
|
230
242
|
}
|
|
231
243
|
//#endregion
|
|
232
244
|
//#region src/composables/useMemiBoardAuth.ts
|
|
233
|
-
var
|
|
234
|
-
function
|
|
245
|
+
var ot = "__MEMI_BOARD_AUTH_STATE__";
|
|
246
|
+
function st() {
|
|
235
247
|
let e = globalThis;
|
|
236
|
-
return e[
|
|
237
|
-
role:
|
|
238
|
-
rolePending:
|
|
239
|
-
rawBlockCount:
|
|
240
|
-
blockAtMs:
|
|
248
|
+
return e[ot] || (e[ot] = {
|
|
249
|
+
role: M("user"),
|
|
250
|
+
rolePending: M(!0),
|
|
251
|
+
rawBlockCount: M(0),
|
|
252
|
+
blockAtMs: M(null),
|
|
241
253
|
watchStarted: !1
|
|
242
|
-
}), e[
|
|
254
|
+
}), e[ot];
|
|
243
255
|
}
|
|
244
|
-
function
|
|
245
|
-
let e =
|
|
246
|
-
function
|
|
256
|
+
function ct() {
|
|
257
|
+
let e = c(), t = st(), n = Q(), r = ce(), i = ae(), { role: a, rolePending: o, rawBlockCount: s, blockAtMs: l } = t;
|
|
258
|
+
function u() {
|
|
247
259
|
let t = e.moderation?.blockBanThreshold;
|
|
248
260
|
return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
|
|
249
261
|
}
|
|
250
262
|
function d() {
|
|
251
263
|
let t = e.moderation?.blockBanDecayMs;
|
|
252
|
-
return typeof t == "number" && t > 0 ? t :
|
|
264
|
+
return typeof t == "number" && t > 0 ? t : et;
|
|
253
265
|
}
|
|
254
266
|
function f(e) {
|
|
255
|
-
return
|
|
267
|
+
return y(n, h(), e);
|
|
256
268
|
}
|
|
257
269
|
function p(e) {
|
|
258
270
|
if (!e) {
|
|
259
|
-
s.value = 0,
|
|
271
|
+
s.value = 0, l.value = null;
|
|
260
272
|
return;
|
|
261
273
|
}
|
|
262
|
-
s.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)),
|
|
274
|
+
s.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), l.value = at(e.moderationBlockAt);
|
|
263
275
|
}
|
|
264
|
-
async function
|
|
265
|
-
let t = f(e.uid), r =
|
|
266
|
-
if (!i.exists()) return await Promise.all([
|
|
276
|
+
async function g(e) {
|
|
277
|
+
let t = f(e.uid), r = m(n, h(), e.uid), i = await z(t);
|
|
278
|
+
if (!i.exists()) return await Promise.all([q(t, {
|
|
267
279
|
role: "user",
|
|
268
280
|
displayName: e.displayName,
|
|
269
281
|
photoURL: e.photoURL,
|
|
270
|
-
joinedAt:
|
|
271
|
-
lastVisitAt:
|
|
272
|
-
updatedAt:
|
|
273
|
-
}),
|
|
282
|
+
joinedAt: K(),
|
|
283
|
+
lastVisitAt: K(),
|
|
284
|
+
updatedAt: K()
|
|
285
|
+
}), q(r, { email: e.email })]), p({ moderationBlockCount: 0 }), "user";
|
|
274
286
|
let a = i.data();
|
|
275
287
|
p(a);
|
|
276
288
|
let o = typeof a.displayName == "string" && a.displayName.trim(), s = typeof a.photoURL == "string" && a.photoURL.trim(), c = {
|
|
277
|
-
lastVisitAt:
|
|
278
|
-
updatedAt:
|
|
289
|
+
lastVisitAt: K(),
|
|
290
|
+
updatedAt: K()
|
|
279
291
|
};
|
|
280
|
-
return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([
|
|
292
|
+
return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([Y(t, c), q(r, { email: e.email }, { merge: !0 })]), [
|
|
281
293
|
"admin",
|
|
282
294
|
"staff",
|
|
283
295
|
"user"
|
|
284
296
|
].includes(String(a.role)) ? a.role : "user";
|
|
285
297
|
}
|
|
286
|
-
async function
|
|
298
|
+
async function _() {
|
|
287
299
|
let e = i.value?.uid;
|
|
288
300
|
if (!e) {
|
|
289
301
|
p(void 0);
|
|
290
302
|
return;
|
|
291
303
|
}
|
|
292
|
-
let t = await
|
|
304
|
+
let t = await z(f(e));
|
|
293
305
|
p(t.exists() ? t.data() : void 0);
|
|
294
306
|
}
|
|
295
|
-
t.watchStarted || (t.watchStarted = !0,
|
|
307
|
+
t.watchStarted || (t.watchStarted = !0, P(i, async (e) => {
|
|
296
308
|
if (o.value = !0, !e) {
|
|
297
309
|
a.value = "user", p(void 0), o.value = !1;
|
|
298
310
|
return;
|
|
299
311
|
}
|
|
300
312
|
try {
|
|
301
|
-
a.value = await
|
|
313
|
+
a.value = await g(e);
|
|
302
314
|
} catch (e) {
|
|
303
315
|
console.error("[memi-board] ensureUserDoc failed", e), a.value = "user", p(void 0);
|
|
304
316
|
} finally {
|
|
305
317
|
o.value = !1;
|
|
306
318
|
}
|
|
307
319
|
}, { immediate: !0 }));
|
|
308
|
-
let v =
|
|
309
|
-
let e =
|
|
310
|
-
return e <= 0 ? !1 :
|
|
311
|
-
}), T =
|
|
312
|
-
let e =
|
|
320
|
+
let v = A(() => !!i.value), b = A(() => a.value === "admin"), x = A(() => a.value === "staff"), S = A(() => b.value || x.value), C = A(() => tt(s.value, l.value, Date.now(), d())), w = A(() => {
|
|
321
|
+
let e = u();
|
|
322
|
+
return e <= 0 ? !1 : rt(s.value, l.value, Date.now(), e, d());
|
|
323
|
+
}), T = A(() => {
|
|
324
|
+
let e = u();
|
|
313
325
|
if (e <= 0) return null;
|
|
314
|
-
let t =
|
|
315
|
-
return t == null ? null :
|
|
316
|
-
}), E =
|
|
326
|
+
let t = nt(s.value, l.value, Date.now(), e, d());
|
|
327
|
+
return t == null ? null : it(t);
|
|
328
|
+
}), E = A(() => {
|
|
317
329
|
if (!w.value) return null;
|
|
318
330
|
let e = T.value;
|
|
319
331
|
return e ? `콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요. (${e})` : "콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요.";
|
|
320
332
|
});
|
|
321
333
|
async function D() {
|
|
322
|
-
let e = i.value?.uid, t =
|
|
334
|
+
let e = i.value?.uid, t = u();
|
|
323
335
|
if (!e || t <= 0) return {
|
|
324
336
|
effectiveCount: 0,
|
|
325
337
|
restricted: !1,
|
|
326
338
|
messageSuffix: ""
|
|
327
339
|
};
|
|
328
|
-
let n = f(e), r = await
|
|
329
|
-
r.exists() ? await
|
|
330
|
-
moderationBlockCount:
|
|
331
|
-
moderationBlockAt:
|
|
332
|
-
updatedAt:
|
|
333
|
-
}) : await
|
|
340
|
+
let n = f(e), r = await z(n);
|
|
341
|
+
r.exists() ? await Y(n, {
|
|
342
|
+
moderationBlockCount: V(1),
|
|
343
|
+
moderationBlockAt: K(),
|
|
344
|
+
updatedAt: K()
|
|
345
|
+
}) : await q(n, {
|
|
334
346
|
role: "user",
|
|
335
347
|
displayName: i.value?.displayName ?? null,
|
|
336
348
|
moderationBlockCount: 1,
|
|
337
|
-
moderationBlockAt:
|
|
338
|
-
updatedAt:
|
|
349
|
+
moderationBlockAt: K(),
|
|
350
|
+
updatedAt: K()
|
|
339
351
|
});
|
|
340
352
|
let a = (r.exists() ? Math.max(0, Math.floor(Number(r.data().moderationBlockCount) || 0)) : 0) + 1, o = Date.now();
|
|
341
|
-
s.value = a,
|
|
342
|
-
let
|
|
353
|
+
s.value = a, l.value = o;
|
|
354
|
+
let c = tt(a, o, o, d()), p = rt(a, o, o, t, d()), m = ` (경고 ${c}/${t})`;
|
|
343
355
|
if (p) {
|
|
344
|
-
let e =
|
|
345
|
-
m = n ? ` 경고 ${
|
|
356
|
+
let e = nt(a, o, o, t, d()), n = e == null ? null : it(e, o);
|
|
357
|
+
m = n ? ` 경고 ${c}회가 되어 글·댓글 작성이 제한됩니다 (${n}).` : ` 경고 ${c}회가 되어 글·댓글 작성이 제한됩니다.`;
|
|
346
358
|
}
|
|
347
359
|
return {
|
|
348
|
-
effectiveCount:
|
|
360
|
+
effectiveCount: c,
|
|
349
361
|
restricted: p,
|
|
350
362
|
messageSuffix: m
|
|
351
363
|
};
|
|
@@ -355,62 +367,62 @@ function tt() {
|
|
|
355
367
|
return r;
|
|
356
368
|
}
|
|
357
369
|
async function k() {
|
|
358
|
-
return
|
|
370
|
+
return pe(O(), new le());
|
|
359
371
|
}
|
|
360
|
-
async function
|
|
361
|
-
let e = new
|
|
362
|
-
return e.addScope("email"), e.addScope("name"),
|
|
372
|
+
async function j() {
|
|
373
|
+
let e = new ue("apple.com");
|
|
374
|
+
return e.addScope("email"), e.addScope("name"), pe(O(), e);
|
|
363
375
|
}
|
|
364
|
-
async function
|
|
365
|
-
return
|
|
376
|
+
async function ee(e, t) {
|
|
377
|
+
return fe(O(), e, t);
|
|
366
378
|
}
|
|
367
|
-
async function
|
|
368
|
-
let r = await
|
|
369
|
-
return n && await
|
|
370
|
-
}
|
|
371
|
-
async function ee() {
|
|
372
|
-
await ge(O());
|
|
379
|
+
async function M(e, t, n) {
|
|
380
|
+
let r = await de(O(), e, t);
|
|
381
|
+
return n && await he(r.user, { displayName: n }), r;
|
|
373
382
|
}
|
|
374
|
-
function
|
|
375
|
-
|
|
383
|
+
async function N() {
|
|
384
|
+
await me(O());
|
|
376
385
|
}
|
|
377
386
|
function F(e) {
|
|
378
|
-
return
|
|
387
|
+
return Je(i.value?.uid, b.value, x.value, e ? Qe(e) : void 0);
|
|
379
388
|
}
|
|
380
|
-
function
|
|
389
|
+
function I(e) {
|
|
390
|
+
return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
|
|
391
|
+
}
|
|
392
|
+
function L(e) {
|
|
381
393
|
return v.value && i.value?.uid === e.authorUid;
|
|
382
394
|
}
|
|
383
|
-
function
|
|
384
|
-
return v.value && (i.value?.uid === e.authorUid ||
|
|
395
|
+
function R(e) {
|
|
396
|
+
return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
|
|
385
397
|
}
|
|
386
398
|
return {
|
|
387
399
|
user: i,
|
|
388
400
|
isSignedIn: v,
|
|
389
|
-
isAdmin:
|
|
390
|
-
isStaff:
|
|
401
|
+
isAdmin: b,
|
|
402
|
+
isStaff: x,
|
|
391
403
|
canManageContent: S,
|
|
392
|
-
canManageBoard:
|
|
404
|
+
canManageBoard: F,
|
|
393
405
|
rolePending: o,
|
|
394
406
|
moderationBlockCount: C,
|
|
395
407
|
isWriteRestricted: w,
|
|
396
408
|
restrictedUntilLabel: T,
|
|
397
409
|
restrictedMessage: E,
|
|
398
410
|
signInWithGoogle: k,
|
|
399
|
-
signInWithApple:
|
|
400
|
-
signInWithEmail:
|
|
401
|
-
signUpWithEmail:
|
|
402
|
-
signOut:
|
|
403
|
-
canEdit:
|
|
404
|
-
canDelete:
|
|
405
|
-
canEditComment:
|
|
406
|
-
canDeleteComment:
|
|
411
|
+
signInWithApple: j,
|
|
412
|
+
signInWithEmail: ee,
|
|
413
|
+
signUpWithEmail: M,
|
|
414
|
+
signOut: N,
|
|
415
|
+
canEdit: I,
|
|
416
|
+
canDelete: I,
|
|
417
|
+
canEditComment: L,
|
|
418
|
+
canDeleteComment: R,
|
|
407
419
|
recordContentModerationBlock: D,
|
|
408
|
-
refreshBoardUser:
|
|
420
|
+
refreshBoardUser: _
|
|
409
421
|
};
|
|
410
422
|
}
|
|
411
423
|
//#endregion
|
|
412
424
|
//#region src/utils/extractEditorImageUrls.ts
|
|
413
|
-
function
|
|
425
|
+
function lt(e) {
|
|
414
426
|
if (!e) return [];
|
|
415
427
|
let t = /* @__PURE__ */ new Set();
|
|
416
428
|
for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&", "&"));
|
|
@@ -419,7 +431,7 @@ function nt(e) {
|
|
|
419
431
|
}
|
|
420
432
|
//#endregion
|
|
421
433
|
//#region src/utils/storagePath.ts
|
|
422
|
-
function
|
|
434
|
+
function ut(e) {
|
|
423
435
|
try {
|
|
424
436
|
let t = new URL(e), n = t.hostname.toLowerCase();
|
|
425
437
|
if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
|
|
@@ -429,109 +441,109 @@ function rt(e) {
|
|
|
429
441
|
return null;
|
|
430
442
|
}
|
|
431
443
|
}
|
|
432
|
-
function
|
|
444
|
+
function dt(e) {
|
|
433
445
|
return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
|
|
434
446
|
}
|
|
435
447
|
//#endregion
|
|
436
448
|
//#region src/utils/deletePostCascade.ts
|
|
437
|
-
async function
|
|
449
|
+
async function ft(e) {
|
|
438
450
|
try {
|
|
439
|
-
let t = await
|
|
440
|
-
await Promise.all([...t.items.map((e) =>
|
|
451
|
+
let t = await ve(e);
|
|
452
|
+
await Promise.all([...t.items.map((e) => ge(e).catch(() => {})), ...t.prefixes.map((e) => ft(e))]);
|
|
441
453
|
} catch {}
|
|
442
454
|
}
|
|
443
|
-
async function
|
|
444
|
-
await
|
|
455
|
+
async function pt(e, t) {
|
|
456
|
+
await ft(ye(e, `${t}/images`)), await ft(ye(e, `${t}/attachments`));
|
|
445
457
|
}
|
|
446
|
-
async function
|
|
458
|
+
async function mt(e, t) {
|
|
447
459
|
let n = [...new Set([...t].filter(Boolean))];
|
|
448
|
-
await Promise.all(n.map((t) =>
|
|
460
|
+
await Promise.all(n.map((t) => ge(ye(e, t)).catch(() => {})));
|
|
449
461
|
}
|
|
450
|
-
var
|
|
451
|
-
async function
|
|
452
|
-
let n = await
|
|
453
|
-
for (let t = 0; t < n.docs.length; t +=
|
|
454
|
-
let r =
|
|
455
|
-
n.docs.slice(t, t +
|
|
462
|
+
var ht = 450;
|
|
463
|
+
async function gt(e, t) {
|
|
464
|
+
let n = await B(t);
|
|
465
|
+
for (let t = 0; t < n.docs.length; t += ht) {
|
|
466
|
+
let r = Z(e);
|
|
467
|
+
n.docs.slice(t, t + ht).forEach((e) => r.delete(e.ref)), await r.commit();
|
|
456
468
|
}
|
|
457
469
|
}
|
|
458
|
-
async function
|
|
459
|
-
await
|
|
470
|
+
async function _t(e, t, n) {
|
|
471
|
+
await gt(e, G(O(e, t), X("postId", "==", n)));
|
|
460
472
|
}
|
|
461
|
-
async function
|
|
462
|
-
await
|
|
473
|
+
async function vt(e, t, n) {
|
|
474
|
+
await gt(e, G(i(e, t), X("postId", "==", n)));
|
|
463
475
|
}
|
|
464
|
-
async function
|
|
465
|
-
await
|
|
476
|
+
async function yt(e, t, n) {
|
|
477
|
+
await gt(e, G(O(e, t), X("commentId", "==", n)));
|
|
466
478
|
}
|
|
467
|
-
async function
|
|
468
|
-
let
|
|
479
|
+
async function bt(e, n, r, i) {
|
|
480
|
+
let o = t(e, r, i), s = a(e, r, i), [c, l] = await Promise.all([z(o), z(s)]);
|
|
469
481
|
if (!c.exists()) return;
|
|
470
482
|
let u = c.data(), d = l.exists() ? String(l.data().content ?? "") : "";
|
|
471
|
-
await
|
|
483
|
+
await gt(e, G(E(e, r), X("postId", "==", i))), await _t(e, r, i), await vt(e, r, i);
|
|
472
484
|
let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
|
|
473
485
|
for (let e of u.attachments ?? []) {
|
|
474
486
|
if (!e?.path) continue;
|
|
475
487
|
f.add(e.path);
|
|
476
|
-
let t =
|
|
488
|
+
let t = dt(e.path);
|
|
477
489
|
t && t !== i && p.add(t);
|
|
478
490
|
}
|
|
479
|
-
for (let e of
|
|
480
|
-
let t =
|
|
491
|
+
for (let e of lt(d)) {
|
|
492
|
+
let t = ut(e);
|
|
481
493
|
if (!t) continue;
|
|
482
494
|
f.add(t);
|
|
483
495
|
let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
|
|
484
496
|
n !== t && n.includes("/images/thumbnails/") && f.add(n);
|
|
485
497
|
let r = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
|
|
486
498
|
r && !t.includes("/thumbnails/") && f.add(`${r[1]}thumbnails/${r[2]}.jpg`);
|
|
487
|
-
let a =
|
|
499
|
+
let a = dt(t);
|
|
488
500
|
a && a !== i && p.add(a);
|
|
489
501
|
}
|
|
490
|
-
await
|
|
491
|
-
for (let e of p) await
|
|
492
|
-
await
|
|
502
|
+
await F(s), await pt(n, D(r, i));
|
|
503
|
+
for (let e of p) await pt(n, D(r, e));
|
|
504
|
+
await mt(n, f), await F(o);
|
|
493
505
|
}
|
|
494
506
|
//#endregion
|
|
495
507
|
//#region src/utils/postBody.ts
|
|
496
|
-
function
|
|
508
|
+
function xt(e) {
|
|
497
509
|
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();
|
|
498
510
|
}
|
|
499
|
-
function
|
|
500
|
-
let n =
|
|
511
|
+
function St(e, t = 40) {
|
|
512
|
+
let n = xt(e);
|
|
501
513
|
if (!n) return "";
|
|
502
514
|
if (n.length <= t) return n;
|
|
503
515
|
let r = n.slice(0, t), i = r.lastIndexOf(" ");
|
|
504
516
|
return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
|
|
505
517
|
}
|
|
506
|
-
function
|
|
507
|
-
return
|
|
518
|
+
function Ct(e) {
|
|
519
|
+
return xt(e).length > 0;
|
|
508
520
|
}
|
|
509
|
-
function
|
|
521
|
+
function wt(e, t) {
|
|
510
522
|
return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
|
|
511
523
|
}
|
|
512
|
-
function
|
|
513
|
-
return !
|
|
524
|
+
function Tt(e) {
|
|
525
|
+
return !Ct(e);
|
|
514
526
|
}
|
|
515
527
|
//#endregion
|
|
516
528
|
//#region src/utils/postPreview.ts
|
|
517
|
-
function
|
|
529
|
+
function Et(e) {
|
|
518
530
|
return e.replace(/&/g, "&").replace(/"/g, "\"").replace(/'/g, "'");
|
|
519
531
|
}
|
|
520
|
-
function
|
|
532
|
+
function Dt(e) {
|
|
521
533
|
if (e) try {
|
|
522
|
-
let t = new URL(
|
|
534
|
+
let t = new URL(Et(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
|
|
523
535
|
if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
|
|
524
536
|
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;
|
|
525
537
|
} catch {
|
|
526
538
|
return;
|
|
527
539
|
}
|
|
528
540
|
}
|
|
529
|
-
function
|
|
530
|
-
let t =
|
|
541
|
+
function Ot(e) {
|
|
542
|
+
let t = Dt(e.videoUrl);
|
|
531
543
|
return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
532
544
|
}
|
|
533
|
-
function
|
|
534
|
-
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 ?
|
|
545
|
+
function kt(e, t = []) {
|
|
546
|
+
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 ? Et(r[1]) : a, s = o ? Dt(o) : void 0, c = n ? Et(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
|
|
535
547
|
return {
|
|
536
548
|
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),
|
|
537
549
|
...c ? { previewImage: c } : {},
|
|
@@ -540,7 +552,7 @@ function St(e, t = []) {
|
|
|
540
552
|
}
|
|
541
553
|
//#endregion
|
|
542
554
|
//#region src/composables/useMemiBoardSettings.ts
|
|
543
|
-
var
|
|
555
|
+
var At = [
|
|
544
556
|
{
|
|
545
557
|
id: "free",
|
|
546
558
|
label: "자유",
|
|
@@ -568,17 +580,17 @@ var Ct = [
|
|
|
568
580
|
visibility: "public",
|
|
569
581
|
order: 2
|
|
570
582
|
}
|
|
571
|
-
],
|
|
572
|
-
function
|
|
583
|
+
], jt = At;
|
|
584
|
+
function Mt(e) {
|
|
573
585
|
return e === "hidden" ? "hidden" : "public";
|
|
574
586
|
}
|
|
575
|
-
function
|
|
587
|
+
function Nt(e, t, n) {
|
|
576
588
|
return {
|
|
577
589
|
id: e,
|
|
578
590
|
label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
|
|
579
591
|
order: typeof t.order == "number" ? t.order : n,
|
|
580
592
|
description: (typeof t.description == "string" ? t.description : "") || "",
|
|
581
|
-
visibility:
|
|
593
|
+
visibility: Mt(t.visibility),
|
|
582
594
|
listView: t.listView ?? "default",
|
|
583
595
|
editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
|
|
584
596
|
writeRole: t.writeRole ?? "user",
|
|
@@ -586,114 +598,114 @@ function Et(e, t, n) {
|
|
|
586
598
|
allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : []
|
|
587
599
|
};
|
|
588
600
|
}
|
|
589
|
-
function
|
|
590
|
-
let t = () =>
|
|
591
|
-
function
|
|
601
|
+
function Pt() {
|
|
602
|
+
let t = () => h(), n = Q(), r = se(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = ct(), l = A(() => G(e(n, t()), W("order", "asc"))), { data: u, pending: d } = ie(l, { ssrKey: S(t(), "boards") }), f = A(() => u.value.map((e, t) => Nt(e.id, e, t))), p = f, m = A(() => f.value.filter((e) => e.visibility !== "hidden")), _ = m;
|
|
603
|
+
function v(e) {
|
|
592
604
|
if (e) return f.value.find((t) => t.id === e)?.label ?? e;
|
|
593
605
|
}
|
|
594
|
-
let y =
|
|
595
|
-
function
|
|
606
|
+
let y = v;
|
|
607
|
+
function x(e) {
|
|
596
608
|
if (e) return f.value.find((t) => t.id === e)?.description?.trim() || void 0;
|
|
597
609
|
}
|
|
598
|
-
let
|
|
599
|
-
function
|
|
610
|
+
let C = x;
|
|
611
|
+
function w(e) {
|
|
600
612
|
return e ? f.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
|
|
601
613
|
}
|
|
602
|
-
let T =
|
|
603
|
-
function
|
|
604
|
-
return
|
|
614
|
+
let T = w;
|
|
615
|
+
function D(e) {
|
|
616
|
+
return w(e) === "hidden";
|
|
605
617
|
}
|
|
606
|
-
let
|
|
618
|
+
let O = D;
|
|
607
619
|
function k(e) {
|
|
608
620
|
if (e) return f.value.find((t) => t.id === e);
|
|
609
621
|
}
|
|
610
|
-
|
|
611
|
-
function
|
|
612
|
-
return
|
|
622
|
+
Ze((e) => k(e));
|
|
623
|
+
function j(e) {
|
|
624
|
+
return Je(c.value?.uid, a.value, s.value, e ? k(e) : void 0);
|
|
613
625
|
}
|
|
614
|
-
let
|
|
615
|
-
async function
|
|
626
|
+
let ee = A(() => f.value.filter((e) => j(e.id)));
|
|
627
|
+
async function M(e, t, r) {
|
|
616
628
|
let i;
|
|
617
629
|
for (;;) {
|
|
618
|
-
let a = await
|
|
630
|
+
let a = await B(G(e, X("boardId", "==", t), W("__name__"), ...i ? [J(i)] : [], H(400)));
|
|
619
631
|
if (a.empty) break;
|
|
620
|
-
let o =
|
|
632
|
+
let o = Z(n), s = 0;
|
|
621
633
|
for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
|
|
622
634
|
if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
|
|
623
635
|
}
|
|
624
636
|
}
|
|
625
|
-
async function
|
|
626
|
-
await
|
|
637
|
+
async function N(e, r) {
|
|
638
|
+
await M(o(n, t()), e, r), await M(E(n, t()), e, r);
|
|
627
639
|
}
|
|
628
640
|
function P(e, t) {
|
|
629
641
|
return {
|
|
630
642
|
label: e.label.trim(),
|
|
631
643
|
description: (e.description ?? "").trim(),
|
|
632
|
-
visibility:
|
|
644
|
+
visibility: Mt(e.visibility),
|
|
633
645
|
listView: e.listView ?? "default",
|
|
634
646
|
editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
|
|
635
647
|
writeRole: e.writeRole ?? "user",
|
|
636
648
|
commentWriteRole: e.commentWriteRole ?? "user",
|
|
637
649
|
allowedStaffUids: e.allowedStaffUids ?? [],
|
|
638
650
|
order: t,
|
|
639
|
-
updatedAt:
|
|
651
|
+
updatedAt: K()
|
|
640
652
|
};
|
|
641
653
|
}
|
|
642
|
-
async function
|
|
654
|
+
async function I(e, r = e.order ?? 0) {
|
|
643
655
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
644
656
|
let a = e.id.trim(), o = e.label.trim();
|
|
645
657
|
if (!a || !o) throw Error("보드 ID와 이름을 입력해 주세요.");
|
|
646
|
-
let s =
|
|
658
|
+
let s = Mt(e.visibility), c = P({
|
|
647
659
|
...e,
|
|
648
660
|
label: o,
|
|
649
661
|
visibility: s
|
|
650
662
|
}, r);
|
|
651
|
-
await
|
|
663
|
+
await q(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
|
|
652
664
|
}
|
|
653
|
-
let
|
|
654
|
-
async function
|
|
665
|
+
let L = I;
|
|
666
|
+
async function R(e) {
|
|
655
667
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
656
|
-
let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a =
|
|
668
|
+
let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = Z(n), o = [];
|
|
657
669
|
e.forEach((e, i) => {
|
|
658
670
|
let s = e.id.trim(), c = e.label.trim();
|
|
659
671
|
if (!s || !c) throw Error("보드 ID와 이름을 입력해 주세요.");
|
|
660
|
-
let l =
|
|
672
|
+
let l = Mt(e.visibility), u = P({
|
|
661
673
|
...e,
|
|
662
674
|
label: c,
|
|
663
675
|
visibility: l
|
|
664
676
|
}, i);
|
|
665
|
-
a.set(
|
|
677
|
+
a.set(g(n, t(), s), u, { merge: !0 }), ((r.get(s) ?? "public") !== l || l === "hidden") && o.push({
|
|
666
678
|
id: s,
|
|
667
679
|
listed: l !== "hidden"
|
|
668
680
|
});
|
|
669
681
|
}), await a.commit();
|
|
670
|
-
for (let e of o) await
|
|
682
|
+
for (let e of o) await N(e.id, e.listed);
|
|
671
683
|
}
|
|
672
|
-
let
|
|
673
|
-
async function
|
|
684
|
+
let te = R;
|
|
685
|
+
async function z(e) {
|
|
674
686
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
675
687
|
let a = e.trim();
|
|
676
688
|
if (!a) throw Error("삭제할 게시판 ID가 필요합니다.");
|
|
677
689
|
for (;;) {
|
|
678
|
-
let e = await
|
|
690
|
+
let e = await B(G(o(n, t()), X("boardId", "==", a), H(25)));
|
|
679
691
|
if (e.empty) break;
|
|
680
|
-
for (let i of e.docs) await
|
|
692
|
+
for (let i of e.docs) await bt(n, _e(r), t(), i.id);
|
|
681
693
|
}
|
|
682
|
-
await
|
|
694
|
+
await F(g(n, t(), e));
|
|
683
695
|
}
|
|
684
|
-
let
|
|
685
|
-
async function
|
|
696
|
+
let V = z;
|
|
697
|
+
async function ne() {
|
|
686
698
|
return Promise.resolve();
|
|
687
699
|
}
|
|
688
|
-
async function
|
|
700
|
+
async function U(e) {
|
|
689
701
|
let t = e.trim();
|
|
690
702
|
if (!t) throw Error("보드 이름을 입력해 주세요.");
|
|
691
703
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
692
704
|
let n = f.value.find((e) => e.label === t);
|
|
693
705
|
if (n) return n.id;
|
|
694
|
-
let r =
|
|
706
|
+
let r = b(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(f.value.map((e) => e.id));
|
|
695
707
|
for (; s.has(a);) a = `${r}-${o++}`;
|
|
696
|
-
return await
|
|
708
|
+
return await I({
|
|
697
709
|
id: a,
|
|
698
710
|
label: t,
|
|
699
711
|
visibility: "public",
|
|
@@ -707,55 +719,55 @@ function Dt() {
|
|
|
707
719
|
return {
|
|
708
720
|
boards: f,
|
|
709
721
|
publicBoards: m,
|
|
710
|
-
boardLabel:
|
|
711
|
-
boardDescription:
|
|
712
|
-
boardVisibility:
|
|
713
|
-
isBoardHidden:
|
|
722
|
+
boardLabel: v,
|
|
723
|
+
boardDescription: x,
|
|
724
|
+
boardVisibility: w,
|
|
725
|
+
isBoardHidden: D,
|
|
714
726
|
getBoard: k,
|
|
715
|
-
canManageBoard:
|
|
716
|
-
managedBoards:
|
|
727
|
+
canManageBoard: j,
|
|
728
|
+
managedBoards: ee,
|
|
717
729
|
categories: p,
|
|
718
|
-
publicCategories:
|
|
730
|
+
publicCategories: _,
|
|
719
731
|
categoryLabel: y,
|
|
720
|
-
categoryDescription:
|
|
732
|
+
categoryDescription: C,
|
|
721
733
|
categoryVisibility: T,
|
|
722
|
-
isCategoryHidden:
|
|
734
|
+
isCategoryHidden: O,
|
|
723
735
|
settingsPending: d,
|
|
724
|
-
ensureSettings:
|
|
725
|
-
addBoard:
|
|
726
|
-
addCategory:
|
|
727
|
-
saveBoard:
|
|
728
|
-
saveCategory:
|
|
729
|
-
saveBoards:
|
|
730
|
-
saveCategories:
|
|
731
|
-
deleteBoard:
|
|
732
|
-
deleteCategory:
|
|
733
|
-
DEFAULT_BOARDS:
|
|
734
|
-
DEFAULT_CATEGORIES:
|
|
736
|
+
ensureSettings: ne,
|
|
737
|
+
addBoard: U,
|
|
738
|
+
addCategory: U,
|
|
739
|
+
saveBoard: I,
|
|
740
|
+
saveCategory: L,
|
|
741
|
+
saveBoards: R,
|
|
742
|
+
saveCategories: te,
|
|
743
|
+
deleteBoard: z,
|
|
744
|
+
deleteCategory: V,
|
|
745
|
+
DEFAULT_BOARDS: At,
|
|
746
|
+
DEFAULT_CATEGORIES: jt
|
|
735
747
|
};
|
|
736
748
|
}
|
|
737
749
|
//#endregion
|
|
738
750
|
//#region src/composables/useMemiBoardPosts.ts
|
|
739
|
-
function
|
|
751
|
+
function Ft(e) {
|
|
740
752
|
if (!e || typeof e != "object") return !1;
|
|
741
753
|
let t = "code" in e ? String(e.code) : "";
|
|
742
754
|
return t === "permission-denied" || t === "firestore/permission-denied";
|
|
743
755
|
}
|
|
744
|
-
function
|
|
745
|
-
let t =
|
|
756
|
+
function It(e) {
|
|
757
|
+
let t = N(e)?.trim();
|
|
746
758
|
if (!t) throw Error("[memi-board] boardId 가 필요합니다.");
|
|
747
759
|
return t;
|
|
748
760
|
}
|
|
749
|
-
function
|
|
750
|
-
let n = Q(), r =
|
|
761
|
+
function Lt(e) {
|
|
762
|
+
let n = Q(), r = se(), { isBoardHidden: i, getBoard: s } = Pt(), c = () => h(), l = () => It(e), u = () => o(n, c()), d = (e) => t(n, c(), e), f = (e) => a(n, c(), e);
|
|
751
763
|
function p() {
|
|
752
764
|
return !i(l());
|
|
753
765
|
}
|
|
754
766
|
function m() {
|
|
755
|
-
return
|
|
767
|
+
return s(l())?.editorType === "image";
|
|
756
768
|
}
|
|
757
|
-
function
|
|
758
|
-
let t = m(), n =
|
|
769
|
+
function g(e) {
|
|
770
|
+
let t = m(), n = Ct(e.content), r = wt(e.content, e.attachments);
|
|
759
771
|
if (t) {
|
|
760
772
|
if (!r) throw Error("사진을 올려 주세요.");
|
|
761
773
|
return;
|
|
@@ -763,13 +775,13 @@ function At(e) {
|
|
|
763
775
|
if (!n && !r) throw Error("본문에 글자를 입력하거나 이미지를 첨부해 주세요.");
|
|
764
776
|
if (!e.title?.trim()) throw Error("제목을 입력해 주세요.");
|
|
765
777
|
}
|
|
766
|
-
function
|
|
767
|
-
return
|
|
778
|
+
function _() {
|
|
779
|
+
return L(u()).id;
|
|
768
780
|
}
|
|
769
781
|
async function v(e = {}) {
|
|
770
|
-
let t = e.pageSize ?? 20, n = [
|
|
771
|
-
e.publicOnly !== !1 && n.push(
|
|
772
|
-
let r = await
|
|
782
|
+
let t = e.pageSize ?? 20, n = [X("boardId", "==", l()), X("isPublished", "==", !0)];
|
|
783
|
+
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));
|
|
784
|
+
let r = await B(G(u(), ...n)), i = r.docs.slice(0, t);
|
|
773
785
|
return {
|
|
774
786
|
posts: i.map((e) => ({
|
|
775
787
|
id: e.id,
|
|
@@ -780,16 +792,16 @@ function At(e) {
|
|
|
780
792
|
};
|
|
781
793
|
}
|
|
782
794
|
async function y(e) {
|
|
783
|
-
let [t, n] = await Promise.all([
|
|
795
|
+
let [t, n] = await Promise.all([z(d(e)), z(f(e))]);
|
|
784
796
|
return t.exists() ? {
|
|
785
797
|
id: t.id,
|
|
786
798
|
...t.data(),
|
|
787
799
|
content: n.exists() ? n.data().content ?? "" : ""
|
|
788
800
|
} : null;
|
|
789
801
|
}
|
|
790
|
-
async function
|
|
802
|
+
async function x(e) {
|
|
791
803
|
try {
|
|
792
|
-
let t = (await
|
|
804
|
+
let t = (await B(G(u(), X("boardId", "==", l()), X("slug", "==", e.trim()), H(1)))).docs[0];
|
|
793
805
|
if (!t) return { status: "not-found" };
|
|
794
806
|
try {
|
|
795
807
|
let e = await y(t.id);
|
|
@@ -798,30 +810,30 @@ function At(e) {
|
|
|
798
810
|
post: e
|
|
799
811
|
} : { status: "not-found" };
|
|
800
812
|
} catch (e) {
|
|
801
|
-
return
|
|
813
|
+
return Ft(e) ? { status: "permission-denied" } : {
|
|
802
814
|
status: "error",
|
|
803
815
|
message: e instanceof Error ? e.message : String(e)
|
|
804
816
|
};
|
|
805
817
|
}
|
|
806
818
|
} catch (e) {
|
|
807
|
-
return
|
|
819
|
+
return Ft(e) ? { status: "permission-denied" } : {
|
|
808
820
|
status: "error",
|
|
809
821
|
message: e instanceof Error ? e.message : String(e)
|
|
810
822
|
};
|
|
811
823
|
}
|
|
812
824
|
}
|
|
813
|
-
async function
|
|
825
|
+
async function S(e) {
|
|
814
826
|
if (!e.createdAt) return {
|
|
815
827
|
previous: null,
|
|
816
828
|
next: null
|
|
817
829
|
};
|
|
818
830
|
try {
|
|
819
831
|
let t = [
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
...e.listed === !1 ? [] : [
|
|
823
|
-
|
|
824
|
-
], [n, r] = await Promise.all([
|
|
832
|
+
X("boardId", "==", l()),
|
|
833
|
+
X("isPublished", "==", !0),
|
|
834
|
+
...e.listed === !1 ? [] : [X("listed", "==", !0)],
|
|
835
|
+
W("createdAt", "desc")
|
|
836
|
+
], [n, r] = await Promise.all([B(G(u(), ...t, J(e.createdAt), H(1))), B(G(u(), ...t, te(e.createdAt), ne(1)))]), i = (e) => {
|
|
825
837
|
let t = e.docs[0];
|
|
826
838
|
return t ? {
|
|
827
839
|
id: t.id,
|
|
@@ -840,18 +852,18 @@ function At(e) {
|
|
|
840
852
|
}
|
|
841
853
|
}
|
|
842
854
|
async function C(e) {
|
|
843
|
-
|
|
844
|
-
let t = e.postId ||
|
|
845
|
-
if (n) r = t, i =
|
|
855
|
+
g(e);
|
|
856
|
+
let t = e.postId || _(), n = m(), r, i;
|
|
857
|
+
if (n) r = t, i = St(e.content);
|
|
846
858
|
else {
|
|
847
859
|
i = e.title.trim();
|
|
848
|
-
let t =
|
|
860
|
+
let t = b(i) || "post";
|
|
849
861
|
r = t;
|
|
850
862
|
let n = 1;
|
|
851
|
-
for (; !(await
|
|
863
|
+
for (; !(await B(G(u(), X("boardId", "==", l()), X("slug", "==", r), H(1)))).empty;) n++, r = `${t}-${n}`;
|
|
852
864
|
}
|
|
853
|
-
let a =
|
|
854
|
-
return await
|
|
865
|
+
let a = kt(e.content, e.attachments), o = p();
|
|
866
|
+
return await q(d(t), {
|
|
855
867
|
boardId: l(),
|
|
856
868
|
slug: r,
|
|
857
869
|
title: i,
|
|
@@ -868,84 +880,84 @@ function At(e) {
|
|
|
868
880
|
authorPhoto: e.authorPhoto,
|
|
869
881
|
moderationStatus: "approved",
|
|
870
882
|
moderationModel: e.moderationModel ?? null,
|
|
871
|
-
createdAt:
|
|
872
|
-
updatedAt:
|
|
873
|
-
}), await
|
|
883
|
+
createdAt: K(),
|
|
884
|
+
updatedAt: K()
|
|
885
|
+
}), await q(f(t), { content: e.content }), r;
|
|
874
886
|
}
|
|
875
887
|
async function w(e, t) {
|
|
876
|
-
|
|
877
|
-
let n = m() ?
|
|
878
|
-
await Promise.all([
|
|
888
|
+
g(t);
|
|
889
|
+
let n = m() ? St(t.content) : t.title.trim(), r = kt(t.content, t.attachments), i = p();
|
|
890
|
+
await Promise.all([Y(d(e), {
|
|
879
891
|
title: n,
|
|
880
892
|
...r,
|
|
881
|
-
previewImage: r.previewImage ? r.previewImage :
|
|
882
|
-
videoUrl: r.videoUrl ? r.videoUrl :
|
|
893
|
+
previewImage: r.previewImage ? r.previewImage : I(),
|
|
894
|
+
videoUrl: r.videoUrl ? r.videoUrl : I(),
|
|
883
895
|
tags: t.tags ?? [],
|
|
884
896
|
listed: i,
|
|
885
897
|
attachments: t.attachments ?? [],
|
|
886
|
-
updatedAt:
|
|
887
|
-
}),
|
|
898
|
+
updatedAt: K()
|
|
899
|
+
}), q(f(e), { content: t.content }, { merge: !0 })]);
|
|
888
900
|
}
|
|
889
901
|
async function T(e) {
|
|
890
|
-
await
|
|
902
|
+
await Y(d(e), {
|
|
891
903
|
isPublished: !0,
|
|
892
|
-
publishedAt:
|
|
893
|
-
updatedAt:
|
|
904
|
+
publishedAt: K(),
|
|
905
|
+
updatedAt: K()
|
|
894
906
|
});
|
|
895
907
|
}
|
|
896
908
|
async function E(e) {
|
|
897
|
-
await
|
|
909
|
+
await bt(n, _e(r), c(), e);
|
|
898
910
|
}
|
|
899
911
|
return {
|
|
900
|
-
createPostId:
|
|
912
|
+
createPostId: _,
|
|
901
913
|
getPosts: v,
|
|
902
914
|
getPost: y,
|
|
903
|
-
getPostBySlug:
|
|
904
|
-
getAdjacentPosts:
|
|
915
|
+
getPostBySlug: x,
|
|
916
|
+
getAdjacentPosts: S,
|
|
905
917
|
createPost: C,
|
|
906
918
|
updatePost: w,
|
|
907
919
|
publishPost: T,
|
|
908
920
|
deletePost: E
|
|
909
921
|
};
|
|
910
922
|
}
|
|
911
|
-
var
|
|
912
|
-
function
|
|
913
|
-
let n = Q(), { isAdmin: r, user: i, canManageBoard: a } =
|
|
923
|
+
var Rt = 10;
|
|
924
|
+
function zt(e, t = {}) {
|
|
925
|
+
let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = ct(), s = () => h(), c = t.pageSize ?? Rt, l = A(() => i.value?.uid ?? ""), u = A(() => It(e)), d = () => o(n, s()), f = A(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = M([]), m = M([]), g = M([]), _ = M(!0), v = M(!0), y = M(!1), b = M(""), x = null, S = null, C, w;
|
|
914
926
|
function T(e) {
|
|
915
927
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
916
928
|
}
|
|
917
|
-
let E =
|
|
929
|
+
let E = A(() => {
|
|
918
930
|
let e = /* @__PURE__ */ new Map();
|
|
919
931
|
for (let t of [
|
|
920
932
|
...m.value,
|
|
921
933
|
...p.value,
|
|
922
|
-
...
|
|
934
|
+
...g.value
|
|
923
935
|
]) t.id && e.set(t.id, t);
|
|
924
936
|
return [...e.values()].sort((e, t) => T(t) - T(e) || String(t.id).localeCompare(String(e.id)));
|
|
925
937
|
});
|
|
926
938
|
function D() {
|
|
927
|
-
let e = [
|
|
928
|
-
return f.value && e.push(
|
|
939
|
+
let e = [X("boardId", "==", u.value), X("isPublished", "==", !0)];
|
|
940
|
+
return f.value && e.push(X("listed", "==", !0)), e;
|
|
929
941
|
}
|
|
930
942
|
function O() {
|
|
931
|
-
C?.(), C =
|
|
943
|
+
C?.(), C = U(G(d(), ...D(), W("createdAt", "desc"), W(R(), "desc"), H(c)), (e) => {
|
|
932
944
|
p.value = e.docs.map((e) => ({
|
|
933
945
|
id: e.id,
|
|
934
946
|
...e.data()
|
|
935
|
-
})), x = e.docs.at(-1) ?? null, S || (v.value = e.docs.length >=
|
|
947
|
+
})), x = e.docs.at(-1) ?? null, S || (v.value = e.docs.length >= c), _.value = !1;
|
|
936
948
|
}, (e) => {
|
|
937
|
-
console.error("[memi-board:postList] onSnapshot failed", e), b.value = e.message || String(e),
|
|
949
|
+
console.error("[memi-board:postList] onSnapshot failed", e), b.value = e.message || String(e), _.value = !1;
|
|
938
950
|
});
|
|
939
951
|
}
|
|
940
952
|
function k() {
|
|
941
953
|
w?.();
|
|
942
954
|
let e = l.value;
|
|
943
955
|
if (!e) {
|
|
944
|
-
|
|
956
|
+
g.value = [];
|
|
945
957
|
return;
|
|
946
958
|
}
|
|
947
|
-
w =
|
|
948
|
-
|
|
959
|
+
w = U(G(d(), X("boardId", "==", u.value), X("authorUid", "==", e), X("isPublished", "==", !1), W("createdAt", "desc"), H(20)), (e) => {
|
|
960
|
+
g.value = e.docs.map((e) => ({
|
|
949
961
|
id: e.id,
|
|
950
962
|
...e.data()
|
|
951
963
|
}));
|
|
@@ -953,21 +965,21 @@ function Mt(e, t = {}) {
|
|
|
953
965
|
console.error("[memi-board:postList] own draft onSnapshot failed", e);
|
|
954
966
|
});
|
|
955
967
|
}
|
|
956
|
-
async function
|
|
957
|
-
if (!(y.value || !v.value ||
|
|
968
|
+
async function ee() {
|
|
969
|
+
if (!(y.value || !v.value || _.value)) {
|
|
958
970
|
y.value = !0, b.value = "";
|
|
959
971
|
try {
|
|
960
972
|
let e = S ?? x, t = [
|
|
961
973
|
...D(),
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
...e ? [
|
|
965
|
-
|
|
966
|
-
], n = await
|
|
974
|
+
W("createdAt", "desc"),
|
|
975
|
+
W(R(), "desc"),
|
|
976
|
+
...e ? [J(e)] : [],
|
|
977
|
+
H(c + 1)
|
|
978
|
+
], n = await B(G(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
|
|
967
979
|
id: e.id,
|
|
968
980
|
...e.data()
|
|
969
981
|
})), a = new Set([...m.value, ...p.value].map((e) => e.id));
|
|
970
|
-
m.value.push(...i.filter((e) => !a.has(e.id))), S = r.at(-1) ?? S, v.value = n.docs.length >
|
|
982
|
+
m.value.push(...i.filter((e) => !a.has(e.id))), S = r.at(-1) ?? S, v.value = n.docs.length > c;
|
|
971
983
|
} catch (e) {
|
|
972
984
|
b.value = e.message || String(e), console.error("[memi-board:postList] loadMore failed", e);
|
|
973
985
|
} finally {
|
|
@@ -975,40 +987,40 @@ function Mt(e, t = {}) {
|
|
|
975
987
|
}
|
|
976
988
|
}
|
|
977
989
|
}
|
|
978
|
-
function
|
|
979
|
-
C?.(), p.value = [], m.value = [], x = null, S = null, v.value = !0, b.value = "",
|
|
990
|
+
function N() {
|
|
991
|
+
C?.(), p.value = [], m.value = [], x = null, S = null, v.value = !0, b.value = "", _.value = !0, O(), k();
|
|
980
992
|
}
|
|
981
|
-
return
|
|
993
|
+
return P([
|
|
982
994
|
u,
|
|
983
995
|
f,
|
|
984
996
|
l
|
|
985
|
-
],
|
|
997
|
+
], N, { immediate: !0 }), j(() => {
|
|
986
998
|
C?.(), w?.();
|
|
987
999
|
}), {
|
|
988
1000
|
posts: E,
|
|
989
|
-
postsPending:
|
|
1001
|
+
postsPending: _,
|
|
990
1002
|
hasMore: v,
|
|
991
1003
|
loadingMore: y,
|
|
992
1004
|
loadError: b,
|
|
993
|
-
loadMore:
|
|
1005
|
+
loadMore: ee
|
|
994
1006
|
};
|
|
995
1007
|
}
|
|
996
|
-
function
|
|
997
|
-
let r = Q(), i = () =>
|
|
1008
|
+
function Bt(e, n) {
|
|
1009
|
+
let r = Q(), i = () => h(), o = A(() => It(e)), s = A(() => typeof n == "string" ? n : n.value), c = A(() => t(r, i(), s.value)), l = A(() => a(r, i(), s.value)), { data: u, pending: d } = oe(c), { data: f, pending: p } = oe(l);
|
|
998
1010
|
return {
|
|
999
|
-
post:
|
|
1011
|
+
post: A(() => !u.value || u.value.boardId !== o.value ? null : {
|
|
1000
1012
|
...u.value,
|
|
1001
|
-
id:
|
|
1013
|
+
id: s.value,
|
|
1002
1014
|
content: f.value?.content ?? ""
|
|
1003
1015
|
}),
|
|
1004
|
-
pending:
|
|
1016
|
+
pending: A(() => d.value || p.value)
|
|
1005
1017
|
};
|
|
1006
1018
|
}
|
|
1007
1019
|
//#endregion
|
|
1008
1020
|
//#region src/composables/useMemiBoardUserPosts.ts
|
|
1009
|
-
var
|
|
1010
|
-
function
|
|
1011
|
-
let n = Q(), r = () =>
|
|
1021
|
+
var Vt = 10;
|
|
1022
|
+
function Ht(e, t = {}) {
|
|
1023
|
+
let n = Q(), r = () => h(), i = () => o(n, r()), a = t.pageSize ?? Vt, s = A(() => N(e)?.trim() || ""), c = M([]), l = M([]), u = M(!0), d = M(!0), f = M(!1), p = M(""), m = null, g = null, _;
|
|
1012
1024
|
function v(e) {
|
|
1013
1025
|
return {
|
|
1014
1026
|
id: e.id,
|
|
@@ -1018,41 +1030,41 @@ function Ft(e, t = {}) {
|
|
|
1018
1030
|
function y(e) {
|
|
1019
1031
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1020
1032
|
}
|
|
1021
|
-
let b =
|
|
1033
|
+
let b = A(() => {
|
|
1022
1034
|
let e = /* @__PURE__ */ new Map();
|
|
1023
|
-
for (let t of [...l.value, ...
|
|
1035
|
+
for (let t of [...l.value, ...c.value]) t.id && e.set(t.id, t);
|
|
1024
1036
|
return [...e.values()].sort((e, t) => y(t) - y(e) || String(t.id).localeCompare(String(e.id)));
|
|
1025
1037
|
});
|
|
1026
1038
|
function x() {
|
|
1027
1039
|
return [
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1040
|
+
X("authorUid", "==", s.value),
|
|
1041
|
+
X("isPublished", "==", !0),
|
|
1042
|
+
X("listed", "==", !0)
|
|
1031
1043
|
];
|
|
1032
1044
|
}
|
|
1033
1045
|
function S() {
|
|
1034
|
-
if (
|
|
1046
|
+
if (_?.(), !s.value) {
|
|
1035
1047
|
u.value = !1;
|
|
1036
1048
|
return;
|
|
1037
1049
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1050
|
+
_ = U(G(i(), ...x(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
|
|
1051
|
+
c.value = e.docs.map(v), m = e.docs.at(-1) ?? null, g || (d.value = e.docs.length >= a), u.value = !1;
|
|
1040
1052
|
}, (e) => {
|
|
1041
1053
|
console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
|
|
1042
1054
|
});
|
|
1043
1055
|
}
|
|
1044
1056
|
async function C() {
|
|
1045
|
-
if (!
|
|
1057
|
+
if (!f.value && d.value && !u.value && s.value) {
|
|
1046
1058
|
f.value = !0, p.value = "";
|
|
1047
1059
|
try {
|
|
1048
|
-
let e =
|
|
1060
|
+
let e = g ?? m, t = [
|
|
1049
1061
|
...x(),
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
...e ? [
|
|
1053
|
-
|
|
1054
|
-
], n = await
|
|
1055
|
-
l.value.push(...o.filter((e) => !
|
|
1062
|
+
W("createdAt", "desc"),
|
|
1063
|
+
W(R(), "desc"),
|
|
1064
|
+
...e ? [J(e)] : [],
|
|
1065
|
+
H(a + 1)
|
|
1066
|
+
], n = await B(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(v), s = new Set([...l.value, ...c.value].map((e) => e.id));
|
|
1067
|
+
l.value.push(...o.filter((e) => !s.has(e.id))), g = r.at(-1) ?? g, d.value = n.docs.length > a;
|
|
1056
1068
|
} catch (e) {
|
|
1057
1069
|
p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
|
|
1058
1070
|
} finally {
|
|
@@ -1061,9 +1073,9 @@ function Ft(e, t = {}) {
|
|
|
1061
1073
|
}
|
|
1062
1074
|
}
|
|
1063
1075
|
function w() {
|
|
1064
|
-
|
|
1076
|
+
_?.(), c.value = [], l.value = [], m = null, g = null, d.value = !0, p.value = "", u.value = !0, S();
|
|
1065
1077
|
}
|
|
1066
|
-
return
|
|
1078
|
+
return P(s, w, { immediate: !0 }), j(() => _?.()), {
|
|
1067
1079
|
posts: b,
|
|
1068
1080
|
postsPending: u,
|
|
1069
1081
|
hasMore: d,
|
|
@@ -1074,10 +1086,10 @@ function Ft(e, t = {}) {
|
|
|
1074
1086
|
}
|
|
1075
1087
|
//#endregion
|
|
1076
1088
|
//#region src/composables/useMemiBoardUserComments.ts
|
|
1077
|
-
var
|
|
1078
|
-
function
|
|
1079
|
-
let n = Q(), r = () =>
|
|
1080
|
-
function
|
|
1089
|
+
var Ut = 10;
|
|
1090
|
+
function Wt(e, t = {}) {
|
|
1091
|
+
let n = Q(), r = () => h(), i = () => E(n, r()), a = t.pageSize ?? Ut, o = A(() => N(e)?.trim() || ""), s = M([]), c = M([]), l = M(!0), u = M(!0), d = M(!1), f = M(""), p = null, m = null, g;
|
|
1092
|
+
function _(e) {
|
|
1081
1093
|
return {
|
|
1082
1094
|
id: e.id,
|
|
1083
1095
|
...e.data()
|
|
@@ -1086,36 +1098,36 @@ function Lt(e, t = {}) {
|
|
|
1086
1098
|
function v(e) {
|
|
1087
1099
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1088
1100
|
}
|
|
1089
|
-
let y =
|
|
1101
|
+
let y = A(() => {
|
|
1090
1102
|
let e = /* @__PURE__ */ new Map();
|
|
1091
1103
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1092
1104
|
return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
|
|
1093
1105
|
});
|
|
1094
1106
|
function b() {
|
|
1095
|
-
return [
|
|
1107
|
+
return [X("authorUid", "==", o.value), X("listed", "==", !0)];
|
|
1096
1108
|
}
|
|
1097
1109
|
function x() {
|
|
1098
|
-
if (
|
|
1110
|
+
if (g?.(), !o.value) {
|
|
1099
1111
|
l.value = !1;
|
|
1100
1112
|
return;
|
|
1101
1113
|
}
|
|
1102
|
-
|
|
1103
|
-
s.value = e.docs.map(
|
|
1114
|
+
g = U(G(i(), ...b(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
|
|
1115
|
+
s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
|
|
1104
1116
|
}, (e) => {
|
|
1105
1117
|
console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
1106
1118
|
});
|
|
1107
1119
|
}
|
|
1108
1120
|
async function S() {
|
|
1109
|
-
if (!
|
|
1121
|
+
if (!d.value && u.value && !l.value && o.value) {
|
|
1110
1122
|
d.value = !0, f.value = "";
|
|
1111
1123
|
try {
|
|
1112
1124
|
let e = m ?? p, t = [
|
|
1113
1125
|
...b(),
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
...e ? [
|
|
1117
|
-
|
|
1118
|
-
], 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(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1119
1131
|
c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
|
|
1120
1132
|
} catch (e) {
|
|
1121
1133
|
f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
|
|
@@ -1125,9 +1137,9 @@ function Lt(e, t = {}) {
|
|
|
1125
1137
|
}
|
|
1126
1138
|
}
|
|
1127
1139
|
function C() {
|
|
1128
|
-
|
|
1140
|
+
g?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
|
|
1129
1141
|
}
|
|
1130
|
-
return
|
|
1142
|
+
return P(o, C, { immediate: !0 }), j(() => g?.()), {
|
|
1131
1143
|
comments: y,
|
|
1132
1144
|
commentsPending: l,
|
|
1133
1145
|
hasMore: u,
|
|
@@ -1138,13 +1150,13 @@ function Lt(e, t = {}) {
|
|
|
1138
1150
|
}
|
|
1139
1151
|
//#endregion
|
|
1140
1152
|
//#region src/composables/useMemiBoardCommentFeed.ts
|
|
1141
|
-
var
|
|
1142
|
-
function
|
|
1143
|
-
let n = Q(), r = () =>
|
|
1144
|
-
let e = Math.floor(Number(
|
|
1145
|
-
return Number.isFinite(e) && e > 0 ? e :
|
|
1146
|
-
}), o =
|
|
1147
|
-
function
|
|
1153
|
+
var Gt = 10;
|
|
1154
|
+
function Kt(e = "latest", t = {}) {
|
|
1155
|
+
let n = Q(), r = () => h(), i = () => E(n, r()), a = A(() => {
|
|
1156
|
+
let e = Math.floor(Number(N(t.pageSize)));
|
|
1157
|
+
return Number.isFinite(e) && e > 0 ? e : Gt;
|
|
1158
|
+
}), o = A(() => N(e) === "likes" ? "likes" : "latest"), s = M([]), c = M([]), l = M(!0), u = M(!0), d = M(!1), f = M(""), p = null, m = null, g;
|
|
1159
|
+
function _(e) {
|
|
1148
1160
|
return {
|
|
1149
1161
|
id: e.id,
|
|
1150
1162
|
...e.data()
|
|
@@ -1160,26 +1172,26 @@ function zt(e = "latest", t = {}) {
|
|
|
1160
1172
|
}
|
|
1161
1173
|
return v(t) - v(e) || String(t.id).localeCompare(String(e.id));
|
|
1162
1174
|
}
|
|
1163
|
-
let b =
|
|
1175
|
+
let b = A(() => {
|
|
1164
1176
|
let e = /* @__PURE__ */ new Map();
|
|
1165
1177
|
for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
|
|
1166
1178
|
return [...e.values()].sort(y);
|
|
1167
1179
|
});
|
|
1168
1180
|
function x() {
|
|
1169
1181
|
return o.value === "likes" ? [
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1182
|
+
X("listed", "==", !0),
|
|
1183
|
+
W("likeCount", "desc"),
|
|
1184
|
+
W("createdAt", "desc"),
|
|
1185
|
+
W(R(), "desc")
|
|
1174
1186
|
] : [
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1187
|
+
X("listed", "==", !0),
|
|
1188
|
+
W("createdAt", "desc"),
|
|
1189
|
+
W(R(), "desc")
|
|
1178
1190
|
];
|
|
1179
1191
|
}
|
|
1180
1192
|
function S() {
|
|
1181
|
-
|
|
1182
|
-
s.value = e.docs.map(
|
|
1193
|
+
g?.(), g = U(G(i(), ...x(), H(a.value)), (e) => {
|
|
1194
|
+
s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
|
|
1183
1195
|
}, (e) => {
|
|
1184
1196
|
console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
1185
1197
|
});
|
|
@@ -1188,7 +1200,7 @@ function zt(e = "latest", t = {}) {
|
|
|
1188
1200
|
if (!(d.value || !u.value || l.value)) {
|
|
1189
1201
|
d.value = !0, f.value = "";
|
|
1190
1202
|
try {
|
|
1191
|
-
let e = m ?? p, t = await
|
|
1203
|
+
let e = m ?? p, t = await B(G(i(), ...x(), ...e ? [J(e)] : [], H(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1192
1204
|
c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
|
|
1193
1205
|
} catch (e) {
|
|
1194
1206
|
f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
|
|
@@ -1198,9 +1210,9 @@ function zt(e = "latest", t = {}) {
|
|
|
1198
1210
|
}
|
|
1199
1211
|
}
|
|
1200
1212
|
function w() {
|
|
1201
|
-
|
|
1213
|
+
g?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, S();
|
|
1202
1214
|
}
|
|
1203
|
-
return
|
|
1215
|
+
return P([o, a], w, { immediate: !0 }), j(() => g?.()), {
|
|
1204
1216
|
comments: b,
|
|
1205
1217
|
commentsPending: l,
|
|
1206
1218
|
hasMore: u,
|
|
@@ -1212,9 +1224,9 @@ function zt(e = "latest", t = {}) {
|
|
|
1212
1224
|
}
|
|
1213
1225
|
//#endregion
|
|
1214
1226
|
//#region src/composables/useMemiBoardAuthorMemo.ts
|
|
1215
|
-
var
|
|
1227
|
+
var qt = 100, Jt = /* @__PURE__ */ new Map();
|
|
1216
1228
|
function $(e) {
|
|
1217
|
-
let t =
|
|
1229
|
+
let t = Jt.get(e);
|
|
1218
1230
|
return t || (t = ee({
|
|
1219
1231
|
text: "",
|
|
1220
1232
|
sentiment: null,
|
|
@@ -1222,25 +1234,25 @@ function $(e) {
|
|
|
1222
1234
|
pending: !1,
|
|
1223
1235
|
saving: !1,
|
|
1224
1236
|
error: ""
|
|
1225
|
-
}),
|
|
1237
|
+
}), Jt.set(e, t)), t;
|
|
1226
1238
|
}
|
|
1227
|
-
function
|
|
1228
|
-
let t = Q(), n = () =>
|
|
1239
|
+
function Yt(e) {
|
|
1240
|
+
let t = Q(), n = () => h(), { user: r } = ct(), i = A(() => N(e)), a = A(() => `${r.value?.uid ?? ""}:${i.value}`), o = A(() => {
|
|
1229
1241
|
let e = r.value?.uid, a = i.value;
|
|
1230
|
-
return !e || !a ? null :
|
|
1231
|
-
}), s =
|
|
1242
|
+
return !e || !a ? null : f(t, n(), e, a);
|
|
1243
|
+
}), s = A({
|
|
1232
1244
|
get: () => $(a.value).text,
|
|
1233
1245
|
set: (e) => {
|
|
1234
1246
|
$(a.value).text = e;
|
|
1235
1247
|
}
|
|
1236
|
-
}), c =
|
|
1237
|
-
async function
|
|
1248
|
+
}), c = A(() => $(a.value).sentiment), l = A(() => $(a.value).loaded), u = A(() => $(a.value).pending), d = A(() => $(a.value).saving), p = A(() => $(a.value).error);
|
|
1249
|
+
async function m() {
|
|
1238
1250
|
let e = o.value;
|
|
1239
1251
|
if (!e) return;
|
|
1240
1252
|
let t = $(a.value);
|
|
1241
1253
|
t.pending = !0, t.error = "";
|
|
1242
1254
|
try {
|
|
1243
|
-
let n = (await
|
|
1255
|
+
let n = (await z(e)).data();
|
|
1244
1256
|
t.text = n ? n.text ?? "" : "", t.sentiment = n ? n.sentiment ?? null : null, t.loaded = !0;
|
|
1245
1257
|
} catch (e) {
|
|
1246
1258
|
t.error = e.message || String(e), console.error("[memi-board:authorMemo] load failed", e);
|
|
@@ -1248,7 +1260,7 @@ function Ht(e) {
|
|
|
1248
1260
|
t.pending = !1;
|
|
1249
1261
|
}
|
|
1250
1262
|
}
|
|
1251
|
-
async function
|
|
1263
|
+
async function g(e, t) {
|
|
1252
1264
|
let n = o.value;
|
|
1253
1265
|
if (!n) return;
|
|
1254
1266
|
let r = e.trim();
|
|
@@ -1256,10 +1268,10 @@ function Ht(e) {
|
|
|
1256
1268
|
let i = $(a.value);
|
|
1257
1269
|
i.saving = !0, i.error = "";
|
|
1258
1270
|
try {
|
|
1259
|
-
await
|
|
1271
|
+
await q(n, {
|
|
1260
1272
|
text: r,
|
|
1261
1273
|
sentiment: t,
|
|
1262
|
-
updatedAt:
|
|
1274
|
+
updatedAt: K()
|
|
1263
1275
|
}), i.text = r, i.sentiment = t, i.loaded = !0;
|
|
1264
1276
|
} catch (e) {
|
|
1265
1277
|
throw i.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
|
|
@@ -1267,13 +1279,13 @@ function Ht(e) {
|
|
|
1267
1279
|
i.saving = !1;
|
|
1268
1280
|
}
|
|
1269
1281
|
}
|
|
1270
|
-
async function
|
|
1282
|
+
async function _() {
|
|
1271
1283
|
let e = o.value;
|
|
1272
1284
|
if (!e) return;
|
|
1273
1285
|
let t = $(a.value);
|
|
1274
1286
|
t.saving = !0, t.error = "";
|
|
1275
1287
|
try {
|
|
1276
|
-
await
|
|
1288
|
+
await F(e), t.text = "", t.sentiment = null, t.loaded = !0;
|
|
1277
1289
|
} catch (e) {
|
|
1278
1290
|
throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
|
|
1279
1291
|
} finally {
|
|
@@ -1286,40 +1298,40 @@ function Ht(e) {
|
|
|
1286
1298
|
loaded: l,
|
|
1287
1299
|
pending: u,
|
|
1288
1300
|
saving: d,
|
|
1289
|
-
error:
|
|
1290
|
-
load:
|
|
1291
|
-
save:
|
|
1292
|
-
remove:
|
|
1301
|
+
error: p,
|
|
1302
|
+
load: m,
|
|
1303
|
+
save: g,
|
|
1304
|
+
remove: _
|
|
1293
1305
|
};
|
|
1294
1306
|
}
|
|
1295
1307
|
//#endregion
|
|
1296
1308
|
//#region src/composables/useMemiBoardComments.ts
|
|
1297
|
-
var
|
|
1298
|
-
function
|
|
1309
|
+
var Xt = 10, Zt = 5, Qt = 1e3;
|
|
1310
|
+
function $t(e) {
|
|
1299
1311
|
let t = e.trim();
|
|
1300
1312
|
if (!t) throw Error("댓글 내용을 입력해 주세요.");
|
|
1301
|
-
if (t.length > 1e3) throw Error(`댓글은 ${
|
|
1313
|
+
if (t.length > 1e3) throw Error(`댓글은 ${Qt.toLocaleString()}자까지 작성할 수 있습니다.`);
|
|
1302
1314
|
return t;
|
|
1303
1315
|
}
|
|
1304
|
-
function
|
|
1305
|
-
let i = Q(), a = () =>
|
|
1316
|
+
function en(e, n, r = {}) {
|
|
1317
|
+
let i = Q(), a = () => h(), { isBoardHidden: o } = Pt(), c = () => E(i, a()), l = A(() => N(e)), u = A(() => N(n)), d = () => !o(l.value), f = M([]), p = M([]), m = M(r.subscribe !== !1), g = M([]), _ = M(!1), v = M(r.subscribe !== !1), y = M(r.subscribe !== !1), b = null, x, S;
|
|
1306
1318
|
function C(e) {
|
|
1307
1319
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1308
1320
|
}
|
|
1309
|
-
let w =
|
|
1321
|
+
let w = A(() => {
|
|
1310
1322
|
let e = /* @__PURE__ */ new Map();
|
|
1311
1323
|
for (let t of [
|
|
1312
1324
|
...f.value,
|
|
1313
1325
|
...p.value,
|
|
1314
|
-
...
|
|
1326
|
+
...g.value
|
|
1315
1327
|
]) t.id && e.set(t.id, t);
|
|
1316
1328
|
return [...e.values()].sort((e, t) => C(e) - C(t) || String(e.id).localeCompare(String(t.id)));
|
|
1317
1329
|
});
|
|
1318
|
-
|
|
1319
|
-
if (
|
|
1330
|
+
P([u, l], async ([e]) => {
|
|
1331
|
+
if (g.value = [], f.value = [], p.value = [], b = null, clearTimeout(x), x = void 0, S?.(), S = void 0, v.value = r.subscribe !== !1, r.subscribe !== !1) {
|
|
1320
1332
|
m.value = !0, y.value = !0;
|
|
1321
1333
|
try {
|
|
1322
|
-
let t =
|
|
1334
|
+
let t = B(G(c(), X("postId", "==", e), W("createdAt", "desc"), W(R(), "desc")));
|
|
1323
1335
|
if (await Promise.all([t.then((t) => {
|
|
1324
1336
|
if (u.value !== e) return;
|
|
1325
1337
|
let n = t.docs.map((e) => ({
|
|
@@ -1327,14 +1339,14 @@ function qt(e, n, r = {}) {
|
|
|
1327
1339
|
...e.data()
|
|
1328
1340
|
}));
|
|
1329
1341
|
p.value = n.filter((e) => e.parentId === void 0);
|
|
1330
|
-
}),
|
|
1342
|
+
}), D()]), u.value !== e) return;
|
|
1331
1343
|
} finally {
|
|
1332
1344
|
u.value === e && (m.value = !1, y.value = !1);
|
|
1333
1345
|
}
|
|
1334
1346
|
}
|
|
1335
1347
|
}, { immediate: !0 });
|
|
1336
1348
|
function T() {
|
|
1337
|
-
S?.(), S =
|
|
1349
|
+
S?.(), S = U(G(c(), X("postId", "==", u.value), X("parentId", "==", null), W("createdAt", "desc"), W(R(), "desc"), H(1)), (e) => {
|
|
1338
1350
|
let t = new Map(f.value.map((e) => [e.id, e]));
|
|
1339
1351
|
for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
|
|
1340
1352
|
id: n.doc.id,
|
|
@@ -1345,37 +1357,37 @@ function qt(e, n, r = {}) {
|
|
|
1345
1357
|
console.error("[memi-board:comments] onSnapshot failed", e);
|
|
1346
1358
|
});
|
|
1347
1359
|
}
|
|
1348
|
-
async function
|
|
1349
|
-
if (!
|
|
1350
|
-
|
|
1360
|
+
async function D() {
|
|
1361
|
+
if (!_.value && v.value) {
|
|
1362
|
+
_.value = !0;
|
|
1351
1363
|
try {
|
|
1352
1364
|
let e = [
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
...b ? [
|
|
1358
|
-
|
|
1359
|
-
], t = await
|
|
1365
|
+
X("postId", "==", u.value),
|
|
1366
|
+
X("parentId", "==", null),
|
|
1367
|
+
W("createdAt", "asc"),
|
|
1368
|
+
W(R(), "asc"),
|
|
1369
|
+
...b ? [J(b)] : [],
|
|
1370
|
+
H(11)
|
|
1371
|
+
], t = await B(G(c(), ...e)), n = t.docs.slice(0, Xt), r = n.map((e) => ({
|
|
1360
1372
|
id: e.id,
|
|
1361
1373
|
...e.data()
|
|
1362
|
-
})), i = new Set(
|
|
1363
|
-
|
|
1374
|
+
})), i = new Set(g.value.map((e) => e.id));
|
|
1375
|
+
g.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= Xt && (v.value = !1, x = setTimeout(() => {
|
|
1364
1376
|
x = void 0, T();
|
|
1365
1377
|
}, 1e3));
|
|
1366
1378
|
} finally {
|
|
1367
|
-
|
|
1379
|
+
_.value = !1;
|
|
1368
1380
|
}
|
|
1369
1381
|
}
|
|
1370
1382
|
}
|
|
1371
|
-
|
|
1383
|
+
j(() => {
|
|
1372
1384
|
clearTimeout(x), S?.();
|
|
1373
1385
|
});
|
|
1374
|
-
async function
|
|
1375
|
-
let n =
|
|
1386
|
+
async function O(e) {
|
|
1387
|
+
let n = $t(e.body), r = Z(i), o = L(c());
|
|
1376
1388
|
r.set(o, {
|
|
1377
1389
|
postId: u.value,
|
|
1378
|
-
boardId:
|
|
1390
|
+
boardId: l.value,
|
|
1379
1391
|
listed: d(),
|
|
1380
1392
|
body: n,
|
|
1381
1393
|
authorUid: e.authorUid,
|
|
@@ -1390,19 +1402,19 @@ function qt(e, n, r = {}) {
|
|
|
1390
1402
|
replyCount: 0,
|
|
1391
1403
|
likeCount: 0,
|
|
1392
1404
|
isReply: !1,
|
|
1393
|
-
createdAt:
|
|
1394
|
-
updatedAt:
|
|
1395
|
-
}), r.update(t(i, a(), u.value), { commentCount:
|
|
1405
|
+
createdAt: K(),
|
|
1406
|
+
updatedAt: K()
|
|
1407
|
+
}), r.update(t(i, a(), u.value), { commentCount: V(1) }), await r.commit();
|
|
1396
1408
|
}
|
|
1397
1409
|
async function k(e) {
|
|
1398
|
-
let n =
|
|
1410
|
+
let n = $t(e.body);
|
|
1399
1411
|
if (!e.parent.id) throw Error("답글 대상 댓글을 찾을 수 없습니다.");
|
|
1400
|
-
let r =
|
|
1412
|
+
let r = Z(i), o = L(c()), f = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
|
|
1401
1413
|
if (!f) throw Error("댓글 스레드를 찾을 수 없습니다.");
|
|
1402
1414
|
let p = Math.min((e.parent.depth ?? 0) + 1, 2);
|
|
1403
1415
|
r.set(o, {
|
|
1404
1416
|
postId: u.value,
|
|
1405
|
-
boardId:
|
|
1417
|
+
boardId: l.value,
|
|
1406
1418
|
listed: d(),
|
|
1407
1419
|
body: n,
|
|
1408
1420
|
authorUid: e.authorUid,
|
|
@@ -1417,51 +1429,51 @@ function qt(e, n, r = {}) {
|
|
|
1417
1429
|
replyCount: 0,
|
|
1418
1430
|
likeCount: 0,
|
|
1419
1431
|
isReply: !0,
|
|
1420
|
-
createdAt:
|
|
1421
|
-
updatedAt:
|
|
1422
|
-
}), r.update(
|
|
1432
|
+
createdAt: K(),
|
|
1433
|
+
updatedAt: K()
|
|
1434
|
+
}), r.update(s(i, a(), f), { replyCount: V(1) }), r.update(t(i, a(), u.value), { commentCount: V(1) }), await r.commit();
|
|
1423
1435
|
}
|
|
1424
|
-
async function
|
|
1436
|
+
async function ee(e) {
|
|
1425
1437
|
if (!e.id) return;
|
|
1426
1438
|
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error("답글이 있는 댓글은 현재 삭제할 수 없습니다.");
|
|
1427
|
-
await
|
|
1428
|
-
let n =
|
|
1429
|
-
n.delete(
|
|
1439
|
+
await yt(i, a(), e.id);
|
|
1440
|
+
let n = Z(i);
|
|
1441
|
+
n.delete(s(i, a(), e.id)), e.parentId && e.rootId && n.update(s(i, a(), e.rootId), { replyCount: V(-1) }), n.update(t(i, a(), u.value), { commentCount: V(-1) }), await n.commit(), g.value = g.value.filter((t) => t.id !== e.id), p.value = p.value.filter((t) => t.id !== e.id), f.value = f.value.filter((t) => t.id !== e.id);
|
|
1430
1442
|
}
|
|
1431
|
-
async function
|
|
1432
|
-
let n =
|
|
1433
|
-
await
|
|
1443
|
+
async function F(e, t) {
|
|
1444
|
+
let n = $t(t);
|
|
1445
|
+
await Y(s(i, a(), e), {
|
|
1434
1446
|
body: n,
|
|
1435
|
-
updatedAt:
|
|
1447
|
+
updatedAt: K()
|
|
1436
1448
|
});
|
|
1437
1449
|
}
|
|
1438
|
-
async function
|
|
1439
|
-
await
|
|
1450
|
+
async function I(e, t, n) {
|
|
1451
|
+
await Y(s(i, a(), e), {
|
|
1440
1452
|
isBlinded: t,
|
|
1441
|
-
moderatedAt:
|
|
1453
|
+
moderatedAt: K(),
|
|
1442
1454
|
moderatedBy: n
|
|
1443
1455
|
});
|
|
1444
1456
|
}
|
|
1445
1457
|
return {
|
|
1446
1458
|
comments: w,
|
|
1447
|
-
commentsPending:
|
|
1459
|
+
commentsPending: A(() => y.value || m.value),
|
|
1448
1460
|
hasMore: v,
|
|
1449
|
-
loadingMore:
|
|
1450
|
-
loadMore:
|
|
1451
|
-
addComment:
|
|
1461
|
+
loadingMore: _,
|
|
1462
|
+
loadMore: D,
|
|
1463
|
+
addComment: O,
|
|
1452
1464
|
addReply: k,
|
|
1453
|
-
updateComment:
|
|
1454
|
-
setCommentBlinded:
|
|
1455
|
-
deleteComment:
|
|
1465
|
+
updateComment: F,
|
|
1466
|
+
setCommentBlinded: I,
|
|
1467
|
+
deleteComment: ee
|
|
1456
1468
|
};
|
|
1457
1469
|
}
|
|
1458
|
-
function
|
|
1459
|
-
let r = Q(), i = () =>
|
|
1470
|
+
function tn(e, t, n) {
|
|
1471
|
+
let r = Q(), i = () => h(), a = () => E(r, i()), o = t.trim(), s = M([]), c = M(!1), l = M(!1), u = M(!0), d = null, f;
|
|
1460
1472
|
function p(e) {
|
|
1461
1473
|
return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
|
|
1462
1474
|
}
|
|
1463
1475
|
function m() {
|
|
1464
|
-
f ||=
|
|
1476
|
+
f ||= U(G(a(), X("postId", "==", o), X("rootId", "==", n), X("isReply", "==", !0), W("createdAt", "desc"), W(R(), "desc"), H(1)), (e) => {
|
|
1465
1477
|
let t = new Map(s.value.map((e) => [e.id, e]));
|
|
1466
1478
|
for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
|
|
1467
1479
|
id: n.doc.id,
|
|
@@ -1472,61 +1484,61 @@ function Jt(e, t, n) {
|
|
|
1472
1484
|
console.error("[memi-board:replies] onSnapshot failed", e);
|
|
1473
1485
|
});
|
|
1474
1486
|
}
|
|
1475
|
-
async function
|
|
1476
|
-
if (!
|
|
1487
|
+
async function g() {
|
|
1488
|
+
if (!c.value && u.value) {
|
|
1477
1489
|
c.value = !0;
|
|
1478
1490
|
try {
|
|
1479
1491
|
let e = [
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
...d ? [
|
|
1486
|
-
|
|
1487
|
-
], t = await
|
|
1492
|
+
X("postId", "==", o),
|
|
1493
|
+
X("rootId", "==", n),
|
|
1494
|
+
X("isReply", "==", !0),
|
|
1495
|
+
W("createdAt", "asc"),
|
|
1496
|
+
W(R(), "asc"),
|
|
1497
|
+
...d ? [J(d)] : [],
|
|
1498
|
+
H(6)
|
|
1499
|
+
], t = await B(G(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0, Zt), c = i.map((e) => ({
|
|
1488
1500
|
id: e.id,
|
|
1489
1501
|
...e.data()
|
|
1490
1502
|
})).filter((e) => !r.has(e.id));
|
|
1491
|
-
s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <=
|
|
1503
|
+
s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <= Zt && (u.value = !1, m());
|
|
1492
1504
|
} finally {
|
|
1493
1505
|
c.value = !1;
|
|
1494
1506
|
}
|
|
1495
1507
|
}
|
|
1496
1508
|
}
|
|
1497
|
-
function
|
|
1509
|
+
function _() {
|
|
1498
1510
|
f?.(), f = void 0, s.value = [], d = null, l.value = !1, u.value = !0;
|
|
1499
1511
|
}
|
|
1500
1512
|
async function v() {
|
|
1501
|
-
|
|
1513
|
+
_(), await g();
|
|
1502
1514
|
}
|
|
1503
|
-
return
|
|
1515
|
+
return j(() => f?.()), {
|
|
1504
1516
|
replies: s,
|
|
1505
1517
|
loading: c,
|
|
1506
1518
|
loaded: l,
|
|
1507
1519
|
hasMore: u,
|
|
1508
|
-
loadMore:
|
|
1520
|
+
loadMore: g,
|
|
1509
1521
|
refresh: v
|
|
1510
1522
|
};
|
|
1511
1523
|
}
|
|
1512
1524
|
//#endregion
|
|
1513
1525
|
//#region src/composables/useMemiBoardLikes.ts
|
|
1514
|
-
function
|
|
1515
|
-
let r = () =>
|
|
1526
|
+
function nn(e, n) {
|
|
1527
|
+
let r = () => h(), i = Q(), a = ae(), o = M(!1), s = M(!1), c;
|
|
1516
1528
|
function l(e) {
|
|
1517
|
-
return
|
|
1529
|
+
return k(i, r(), n, e);
|
|
1518
1530
|
}
|
|
1519
|
-
|
|
1531
|
+
P(a, (e) => {
|
|
1520
1532
|
if (c?.(), c = void 0, !e) {
|
|
1521
1533
|
o.value = !1;
|
|
1522
1534
|
return;
|
|
1523
1535
|
}
|
|
1524
|
-
c =
|
|
1536
|
+
c = U(l(e.uid), (e) => {
|
|
1525
1537
|
o.value = e.exists();
|
|
1526
1538
|
}, (e) => {
|
|
1527
1539
|
console.error("[memi-board:likes] onSnapshot failed", e);
|
|
1528
1540
|
});
|
|
1529
|
-
}, { immediate: !0 }),
|
|
1541
|
+
}, { immediate: !0 }), j(() => c?.());
|
|
1530
1542
|
async function u() {
|
|
1531
1543
|
let c = a.value?.uid;
|
|
1532
1544
|
if (!c) throw Error("로그인이 필요합니다.");
|
|
@@ -1534,12 +1546,12 @@ function Yt(e, n) {
|
|
|
1534
1546
|
s.value = !0;
|
|
1535
1547
|
try {
|
|
1536
1548
|
let a = l(c), o = t(i, r(), n);
|
|
1537
|
-
return await
|
|
1549
|
+
return await re(i, async (t) => (await t.get(a)).exists() ? (t.delete(a), t.update(o, { likeCount: V(-1) }), !1) : (t.set(a, {
|
|
1538
1550
|
uid: c,
|
|
1539
1551
|
postId: n,
|
|
1540
1552
|
boardId: e,
|
|
1541
|
-
createdAt:
|
|
1542
|
-
}), t.update(o, { likeCount:
|
|
1553
|
+
createdAt: K()
|
|
1554
|
+
}), t.update(o, { likeCount: V(1) }), !0));
|
|
1543
1555
|
} finally {
|
|
1544
1556
|
s.value = !1;
|
|
1545
1557
|
}
|
|
@@ -1550,50 +1562,50 @@ function Yt(e, n) {
|
|
|
1550
1562
|
toggleLike: u
|
|
1551
1563
|
};
|
|
1552
1564
|
}
|
|
1553
|
-
var
|
|
1554
|
-
function
|
|
1555
|
-
let n = () =>
|
|
1556
|
-
|
|
1557
|
-
u?.(), u = void 0,
|
|
1565
|
+
var rn = Symbol.for("memi-board:comment-likes");
|
|
1566
|
+
function an(e, t) {
|
|
1567
|
+
let n = () => h(), r = Q(), i = ae(), a = A(() => N(e)), o = A(() => N(t)), c = M(/* @__PURE__ */ new Set()), l = M(null), u;
|
|
1568
|
+
P([i, o], ([e, t]) => {
|
|
1569
|
+
u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = U(G(O(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
|
|
1558
1570
|
let t = /* @__PURE__ */ new Set();
|
|
1559
1571
|
for (let n of e.docs) {
|
|
1560
1572
|
let e = n.data().commentId;
|
|
1561
1573
|
typeof e == "string" && e && t.add(e);
|
|
1562
1574
|
}
|
|
1563
|
-
|
|
1575
|
+
c.value = t;
|
|
1564
1576
|
}, (e) => {
|
|
1565
1577
|
console.error("[memi-board:comment-likes] onSnapshot failed", e);
|
|
1566
1578
|
}));
|
|
1567
|
-
}, { immediate: !0 }),
|
|
1579
|
+
}, { immediate: !0 }), j(() => u?.());
|
|
1568
1580
|
function d(e) {
|
|
1569
|
-
return !!e &&
|
|
1581
|
+
return !!e && c.value.has(e);
|
|
1570
1582
|
}
|
|
1571
1583
|
function f(e) {
|
|
1572
|
-
return !!e &&
|
|
1584
|
+
return !!e && l.value === e;
|
|
1573
1585
|
}
|
|
1574
1586
|
async function p(e) {
|
|
1575
1587
|
let t = i.value?.uid;
|
|
1576
1588
|
if (!t) throw Error("로그인이 필요합니다.");
|
|
1577
1589
|
if (!e) return !1;
|
|
1578
|
-
if (
|
|
1579
|
-
|
|
1590
|
+
if (l.value) return d(e);
|
|
1591
|
+
l.value = e;
|
|
1580
1592
|
try {
|
|
1581
|
-
let i =
|
|
1582
|
-
let r = await n.get(i), s = await n.get(
|
|
1593
|
+
let i = k(r, n(), e, t), l = s(r, n(), e), u = await re(r, async (n) => {
|
|
1594
|
+
let r = await n.get(i), s = await n.get(l);
|
|
1583
1595
|
if (!s.exists()) throw Error("댓글을 찾을 수 없습니다.");
|
|
1584
|
-
let
|
|
1585
|
-
return r.exists() ? (n.delete(i), n.update(
|
|
1596
|
+
let c = Number(s.data()?.likeCount ?? 0);
|
|
1597
|
+
return r.exists() ? (n.delete(i), n.update(l, { likeCount: Math.max(0, c - 1) }), !1) : (n.set(i, {
|
|
1586
1598
|
uid: t,
|
|
1587
1599
|
postId: o.value,
|
|
1588
1600
|
boardId: a.value,
|
|
1589
1601
|
commentId: e,
|
|
1590
1602
|
target: "comment",
|
|
1591
|
-
createdAt:
|
|
1592
|
-
}), n.update(
|
|
1593
|
-
}), d = new Set(
|
|
1594
|
-
return u ? d.add(e) : d.delete(e),
|
|
1603
|
+
createdAt: K()
|
|
1604
|
+
}), n.update(l, { likeCount: c + 1 }), !0);
|
|
1605
|
+
}), d = new Set(c.value);
|
|
1606
|
+
return u ? d.add(e) : d.delete(e), c.value = d, u;
|
|
1595
1607
|
} finally {
|
|
1596
|
-
|
|
1608
|
+
l.value = null;
|
|
1597
1609
|
}
|
|
1598
1610
|
}
|
|
1599
1611
|
return {
|
|
@@ -1604,7 +1616,7 @@ function Zt(e, t) {
|
|
|
1604
1616
|
}
|
|
1605
1617
|
//#endregion
|
|
1606
1618
|
//#region src/composables/useMemiBoardReports.ts
|
|
1607
|
-
var
|
|
1619
|
+
var on = 200, sn = [
|
|
1608
1620
|
{
|
|
1609
1621
|
value: "spam",
|
|
1610
1622
|
label: "스팸·광고"
|
|
@@ -1626,34 +1638,34 @@ var Qt = 200, $t = [
|
|
|
1626
1638
|
label: "기타"
|
|
1627
1639
|
}
|
|
1628
1640
|
];
|
|
1629
|
-
function
|
|
1630
|
-
return
|
|
1641
|
+
function cn(e) {
|
|
1642
|
+
return sn.find((t) => t.value === e)?.label || e || "신고";
|
|
1631
1643
|
}
|
|
1632
|
-
function
|
|
1633
|
-
let n = () =>
|
|
1634
|
-
|
|
1644
|
+
function ln(e, t) {
|
|
1645
|
+
let n = () => h(), i = Q(), a = ae(), o = M(!1), s = M(!1), c;
|
|
1646
|
+
P(a, (e) => {
|
|
1635
1647
|
if (c?.(), c = void 0, !e) {
|
|
1636
1648
|
o.value = !1;
|
|
1637
1649
|
return;
|
|
1638
1650
|
}
|
|
1639
|
-
c =
|
|
1651
|
+
c = U(r(i, n(), t, e.uid), (e) => {
|
|
1640
1652
|
o.value = e.exists();
|
|
1641
1653
|
}, (e) => {
|
|
1642
1654
|
console.error("[memi-board:reports] onSnapshot failed", e);
|
|
1643
1655
|
});
|
|
1644
|
-
}, { immediate: !0 }),
|
|
1656
|
+
}, { immediate: !0 }), j(() => c?.());
|
|
1645
1657
|
async function l(c) {
|
|
1646
1658
|
let l = a.value?.uid;
|
|
1647
1659
|
if (!l) throw Error("로그인이 필요합니다.");
|
|
1648
1660
|
if (s.value) return;
|
|
1649
1661
|
if (c.authorUid && c.authorUid === l) throw Error("자신의 글은 신고할 수 없습니다.");
|
|
1650
|
-
let u =
|
|
1662
|
+
let u = sn.some((e) => e.value === c.reason) ? c.reason : null;
|
|
1651
1663
|
if (!u) throw Error("신고 사유를 선택해 주세요.");
|
|
1652
1664
|
let d = (c.detail || "").trim();
|
|
1653
1665
|
if (d.length > 200) throw Error("자세한 내용은 200자까지입니다.");
|
|
1654
1666
|
s.value = !0;
|
|
1655
1667
|
try {
|
|
1656
|
-
await
|
|
1668
|
+
await q(r(i, n(), t, l), {
|
|
1657
1669
|
uid: l,
|
|
1658
1670
|
target: "post",
|
|
1659
1671
|
postId: t,
|
|
@@ -1664,7 +1676,7 @@ function tn(e, t) {
|
|
|
1664
1676
|
postTitle: (c.postTitle || "").trim().slice(0, 200),
|
|
1665
1677
|
authorUid: c.authorUid || "",
|
|
1666
1678
|
authorName: c.authorName ?? null,
|
|
1667
|
-
createdAt:
|
|
1679
|
+
createdAt: K()
|
|
1668
1680
|
}), o.value = !0;
|
|
1669
1681
|
} finally {
|
|
1670
1682
|
s.value = !1;
|
|
@@ -1676,35 +1688,35 @@ function tn(e, t) {
|
|
|
1676
1688
|
submitReport: l
|
|
1677
1689
|
};
|
|
1678
1690
|
}
|
|
1679
|
-
var
|
|
1680
|
-
function
|
|
1681
|
-
let t = () =>
|
|
1682
|
-
function
|
|
1691
|
+
var un = 20;
|
|
1692
|
+
function dn(e = {}) {
|
|
1693
|
+
let t = () => h(), n = Q(), { canManageContent: a, canManageBoard: o } = ct(), s = e.pageSize ?? un, c = A(() => N(e.boardId)?.trim() || ""), l = M([]), u = M(!0), d = M(!1), f = M(!1), p = M(""), m = null, g;
|
|
1694
|
+
function _(e) {
|
|
1683
1695
|
return {
|
|
1684
1696
|
id: e.id,
|
|
1685
1697
|
...e.data()
|
|
1686
1698
|
};
|
|
1687
1699
|
}
|
|
1688
1700
|
function v() {
|
|
1689
|
-
if (
|
|
1701
|
+
if (g?.(), !a.value) {
|
|
1690
1702
|
l.value = [], u.value = !1;
|
|
1691
1703
|
return;
|
|
1692
1704
|
}
|
|
1693
1705
|
u.value = !0;
|
|
1694
|
-
let e = c.value ? [
|
|
1695
|
-
|
|
1696
|
-
l.value = e.docs.map(
|
|
1706
|
+
let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")];
|
|
1707
|
+
g = U(G(i(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), H(s)), (e) => {
|
|
1708
|
+
l.value = e.docs.map(_).filter((e) => o(e.boardId)), m = e.docs.at(-1) ?? null, f.value = e.docs.length >= s, u.value = !1;
|
|
1697
1709
|
}, (e) => {
|
|
1698
1710
|
console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
|
|
1699
1711
|
});
|
|
1700
1712
|
}
|
|
1701
|
-
|
|
1713
|
+
P([a, c], v, { immediate: !0 }), j(() => g?.());
|
|
1702
1714
|
async function y() {
|
|
1703
|
-
if (!
|
|
1715
|
+
if (!d.value && f.value && m && a.value) {
|
|
1704
1716
|
d.value = !0, p.value = "";
|
|
1705
1717
|
try {
|
|
1706
|
-
let e = c.value ? [
|
|
1707
|
-
l.value.push(...
|
|
1718
|
+
let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await B(G(i(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), J(m), H(s + 1))), a = r.docs.slice(0, s), u = new Set(l.value.map((e) => e.id));
|
|
1719
|
+
l.value.push(...a.map(_).filter((e) => !u.has(e.id) && o(e.boardId))), m = a.at(-1) ?? m, f.value = r.docs.length > s;
|
|
1708
1720
|
} catch (e) {
|
|
1709
1721
|
p.value = e.message || String(e);
|
|
1710
1722
|
} finally {
|
|
@@ -1713,10 +1725,10 @@ function rn(e = {}) {
|
|
|
1713
1725
|
}
|
|
1714
1726
|
}
|
|
1715
1727
|
async function b(e, i) {
|
|
1716
|
-
|
|
1728
|
+
e.id && o(e.boardId) && await Y(r(n, t(), e.postId, e.uid), {
|
|
1717
1729
|
status: i,
|
|
1718
|
-
reviewedAt:
|
|
1719
|
-
reviewedBy:
|
|
1730
|
+
reviewedAt: K(),
|
|
1731
|
+
reviewedBy: ae().value?.uid || ""
|
|
1720
1732
|
});
|
|
1721
1733
|
}
|
|
1722
1734
|
return {
|
|
@@ -1732,8 +1744,8 @@ function rn(e = {}) {
|
|
|
1732
1744
|
}
|
|
1733
1745
|
//#endregion
|
|
1734
1746
|
//#region src/composables/useMemiBoardViews.ts
|
|
1735
|
-
function
|
|
1736
|
-
let e = () =>
|
|
1747
|
+
function fn() {
|
|
1748
|
+
let e = () => h(), n = Q();
|
|
1737
1749
|
function r(t, n) {
|
|
1738
1750
|
let { postsCollection: r } = e();
|
|
1739
1751
|
return `memi-board:viewed:${r}:${t}:${n}`;
|
|
@@ -1747,16 +1759,16 @@ function an() {
|
|
|
1747
1759
|
}
|
|
1748
1760
|
}
|
|
1749
1761
|
function a(e, t) {
|
|
1750
|
-
if (
|
|
1762
|
+
if (typeof sessionStorage < "u") try {
|
|
1751
1763
|
sessionStorage.setItem(r(e, t), "1");
|
|
1752
1764
|
} catch {}
|
|
1753
1765
|
}
|
|
1754
1766
|
async function o(o, s) {
|
|
1755
1767
|
let c = o?.trim(), l = s?.trim();
|
|
1756
|
-
if (
|
|
1768
|
+
if (c && l && !i(c, l)) {
|
|
1757
1769
|
a(c, l);
|
|
1758
1770
|
try {
|
|
1759
|
-
await
|
|
1771
|
+
await Y(t(n, e(), l), { viewCount: V(1) });
|
|
1760
1772
|
} catch (e) {
|
|
1761
1773
|
try {
|
|
1762
1774
|
sessionStorage.removeItem(r(c, l));
|
|
@@ -1772,7 +1784,7 @@ function an() {
|
|
|
1772
1784
|
}
|
|
1773
1785
|
//#endregion
|
|
1774
1786
|
//#region src/utils/moderation-prompt.ts
|
|
1775
|
-
var
|
|
1787
|
+
var pn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", mn = {
|
|
1776
1788
|
abuse: "욕설·비속어·모욕",
|
|
1777
1789
|
spam: "스팸·광고",
|
|
1778
1790
|
adult: "선정적·성인 내용",
|
|
@@ -1780,17 +1792,17 @@ var on = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
|
|
|
1780
1792
|
other: "부적절한 내용",
|
|
1781
1793
|
none: ""
|
|
1782
1794
|
};
|
|
1783
|
-
function
|
|
1795
|
+
function hn(e) {
|
|
1784
1796
|
if (e.via === "local" && e.localHit) {
|
|
1785
1797
|
let t = e.localHit.trim();
|
|
1786
1798
|
return t.length > 0 && t.length <= 12 ? `「${t}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.` : "욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.";
|
|
1787
1799
|
}
|
|
1788
1800
|
let t = (e.reason || "").trim();
|
|
1789
1801
|
if (t) return t;
|
|
1790
|
-
let n = e.category && e.category !== "none" ?
|
|
1802
|
+
let n = e.category && e.category !== "none" ? mn[e.category] || e.category : "";
|
|
1791
1803
|
return n ? `${n}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.` : "게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.";
|
|
1792
1804
|
}
|
|
1793
|
-
var
|
|
1805
|
+
var gn = [
|
|
1794
1806
|
"씨발",
|
|
1795
1807
|
"시발",
|
|
1796
1808
|
"시이발",
|
|
@@ -1816,10 +1828,10 @@ var ln = [
|
|
|
1816
1828
|
"bitch",
|
|
1817
1829
|
"asshole"
|
|
1818
1830
|
];
|
|
1819
|
-
function
|
|
1831
|
+
function _n(e) {
|
|
1820
1832
|
return new RegExp(e.join("|"), "i");
|
|
1821
1833
|
}
|
|
1822
|
-
var
|
|
1834
|
+
var vn = /* @__PURE__ */ new Set([
|
|
1823
1835
|
"none",
|
|
1824
1836
|
"abuse",
|
|
1825
1837
|
"spam",
|
|
@@ -1827,7 +1839,7 @@ var dn = /* @__PURE__ */ new Set([
|
|
|
1827
1839
|
"violence",
|
|
1828
1840
|
"other"
|
|
1829
1841
|
]);
|
|
1830
|
-
function
|
|
1842
|
+
function yn(e) {
|
|
1831
1843
|
let t = e.trim();
|
|
1832
1844
|
if (!t) return null;
|
|
1833
1845
|
let n;
|
|
@@ -1845,7 +1857,7 @@ function fn(e) {
|
|
|
1845
1857
|
if (typeof n != "object" || !n) return null;
|
|
1846
1858
|
let r = n;
|
|
1847
1859
|
if (typeof r.flagged != "boolean") return null;
|
|
1848
|
-
let i = typeof r.category == "string" &&
|
|
1860
|
+
let i = typeof r.category == "string" && vn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
|
|
1849
1861
|
return {
|
|
1850
1862
|
flagged: r.flagged,
|
|
1851
1863
|
category: i,
|
|
@@ -1854,20 +1866,20 @@ function fn(e) {
|
|
|
1854
1866
|
}
|
|
1855
1867
|
//#endregion
|
|
1856
1868
|
//#region src/composables/useMemiBoardModeration.ts
|
|
1857
|
-
var
|
|
1869
|
+
var bn = {
|
|
1858
1870
|
flagged: !1,
|
|
1859
1871
|
category: "none",
|
|
1860
1872
|
reason: "",
|
|
1861
1873
|
via: "empty"
|
|
1862
1874
|
};
|
|
1863
|
-
function
|
|
1864
|
-
let e =
|
|
1875
|
+
function xn() {
|
|
1876
|
+
let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = _n([...gn, ...e.localBlocklist ?? []]);
|
|
1865
1877
|
function o(e) {
|
|
1866
1878
|
let t = e.match(a);
|
|
1867
1879
|
return t ? {
|
|
1868
1880
|
flagged: !0,
|
|
1869
1881
|
category: "abuse",
|
|
1870
|
-
reason:
|
|
1882
|
+
reason: hn({
|
|
1871
1883
|
via: "local",
|
|
1872
1884
|
localHit: t[0] || "",
|
|
1873
1885
|
category: "abuse"
|
|
@@ -1876,26 +1888,26 @@ function mn() {
|
|
|
1876
1888
|
} : null;
|
|
1877
1889
|
}
|
|
1878
1890
|
function s() {
|
|
1879
|
-
let n = e.model ?? "gemini-3.5-flash-lite", r = e.useLimitedUseAppCheckTokens !== !1, i =
|
|
1880
|
-
backend: new
|
|
1891
|
+
let n = e.model ?? "gemini-3.5-flash-lite", r = e.useLimitedUseAppCheckTokens !== !1, i = Se(t, {
|
|
1892
|
+
backend: new be(),
|
|
1881
1893
|
useLimitedUseAppCheckTokens: r
|
|
1882
1894
|
});
|
|
1883
|
-
return
|
|
1895
|
+
return Ce(i, {
|
|
1884
1896
|
model: n,
|
|
1885
|
-
systemInstruction:
|
|
1897
|
+
systemInstruction: pn,
|
|
1886
1898
|
generationConfig: {
|
|
1887
1899
|
temperature: 0,
|
|
1888
1900
|
maxOutputTokens: 256,
|
|
1889
1901
|
responseMimeType: "application/json",
|
|
1890
|
-
responseSchema:
|
|
1891
|
-
flagged:
|
|
1892
|
-
category:
|
|
1893
|
-
reason:
|
|
1902
|
+
responseSchema: xe.object({ properties: {
|
|
1903
|
+
flagged: xe.boolean(),
|
|
1904
|
+
category: xe.string(),
|
|
1905
|
+
reason: xe.string()
|
|
1894
1906
|
} })
|
|
1895
1907
|
}
|
|
1896
1908
|
});
|
|
1897
1909
|
}
|
|
1898
|
-
function
|
|
1910
|
+
function l() {
|
|
1899
1911
|
return e.onError === "block" ? {
|
|
1900
1912
|
flagged: !0,
|
|
1901
1913
|
category: "other",
|
|
@@ -1910,8 +1922,8 @@ function mn() {
|
|
|
1910
1922
|
via: "ai-error-allow"
|
|
1911
1923
|
};
|
|
1912
1924
|
}
|
|
1913
|
-
function
|
|
1914
|
-
let n =
|
|
1925
|
+
function u(e, t = "") {
|
|
1926
|
+
let n = hn({
|
|
1915
1927
|
reason: e.reason,
|
|
1916
1928
|
category: e.category,
|
|
1917
1929
|
via: e.via
|
|
@@ -1925,9 +1937,9 @@ function mn() {
|
|
|
1925
1937
|
if (!e.flagged || e.error || e.via !== "local" && e.via !== "ai") return e;
|
|
1926
1938
|
try {
|
|
1927
1939
|
let { messageSuffix: t } = await i();
|
|
1928
|
-
return
|
|
1940
|
+
return u(e, t);
|
|
1929
1941
|
} catch (t) {
|
|
1930
|
-
return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t),
|
|
1942
|
+
return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t), u(e);
|
|
1931
1943
|
}
|
|
1932
1944
|
}
|
|
1933
1945
|
async function f(t, i) {
|
|
@@ -1939,26 +1951,26 @@ function mn() {
|
|
|
1939
1951
|
};
|
|
1940
1952
|
let a = t.trim();
|
|
1941
1953
|
if (!a) return {
|
|
1942
|
-
...
|
|
1954
|
+
...bn,
|
|
1943
1955
|
via: "empty"
|
|
1944
1956
|
};
|
|
1945
1957
|
if (i?.skipFilter) return {
|
|
1946
|
-
...
|
|
1958
|
+
...bn,
|
|
1947
1959
|
via: "admin-override"
|
|
1948
1960
|
};
|
|
1949
|
-
let
|
|
1950
|
-
if (
|
|
1961
|
+
let c = o(a);
|
|
1962
|
+
if (c) return d(c);
|
|
1951
1963
|
if (e.enabled === !1) return {
|
|
1952
|
-
...
|
|
1964
|
+
...bn,
|
|
1953
1965
|
via: "disabled"
|
|
1954
1966
|
};
|
|
1955
1967
|
try {
|
|
1956
|
-
let e =
|
|
1957
|
-
if (!e) return
|
|
1968
|
+
let e = yn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
|
|
1969
|
+
if (!e) return l();
|
|
1958
1970
|
let t = {
|
|
1959
1971
|
flagged: e.flagged,
|
|
1960
1972
|
category: e.category,
|
|
1961
|
-
reason:
|
|
1973
|
+
reason: hn({
|
|
1962
1974
|
reason: e.reason,
|
|
1963
1975
|
category: e.category,
|
|
1964
1976
|
via: "ai"
|
|
@@ -1967,7 +1979,7 @@ function mn() {
|
|
|
1967
1979
|
};
|
|
1968
1980
|
return t.flagged ? d(t) : t;
|
|
1969
1981
|
} catch (e) {
|
|
1970
|
-
return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e),
|
|
1982
|
+
return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e), l();
|
|
1971
1983
|
}
|
|
1972
1984
|
}
|
|
1973
1985
|
async function p(t) {
|
|
@@ -1978,22 +1990,22 @@ function mn() {
|
|
|
1978
1990
|
via: "restricted"
|
|
1979
1991
|
};
|
|
1980
1992
|
if (e.enabled === !1 || !e.moderateImages) return {
|
|
1981
|
-
...
|
|
1993
|
+
...bn,
|
|
1982
1994
|
via: "disabled"
|
|
1983
1995
|
};
|
|
1984
1996
|
try {
|
|
1985
1997
|
let e = await new Promise((e, n) => {
|
|
1986
1998
|
let r = new FileReader();
|
|
1987
1999
|
r.onload = () => e(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(t);
|
|
1988
|
-
}), n =
|
|
2000
|
+
}), n = yn((await s().generateContent([{ inlineData: {
|
|
1989
2001
|
mimeType: t.type || "image/jpeg",
|
|
1990
2002
|
data: e
|
|
1991
2003
|
} }, "이 이미지를 심사해 주세요."])).response.text());
|
|
1992
|
-
if (!n) return
|
|
2004
|
+
if (!n) return l();
|
|
1993
2005
|
let r = {
|
|
1994
2006
|
flagged: n.flagged,
|
|
1995
2007
|
category: n.category,
|
|
1996
|
-
reason:
|
|
2008
|
+
reason: hn({
|
|
1997
2009
|
reason: n.reason,
|
|
1998
2010
|
category: n.category,
|
|
1999
2011
|
via: "ai"
|
|
@@ -2002,7 +2014,7 @@ function mn() {
|
|
|
2002
2014
|
};
|
|
2003
2015
|
return r.flagged ? d(r) : r;
|
|
2004
2016
|
} catch (e) {
|
|
2005
|
-
return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e),
|
|
2017
|
+
return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e), l();
|
|
2006
2018
|
}
|
|
2007
2019
|
}
|
|
2008
2020
|
return {
|
|
@@ -2012,7 +2024,7 @@ function mn() {
|
|
|
2012
2024
|
}
|
|
2013
2025
|
//#endregion
|
|
2014
2026
|
//#region src/composables/useMemiBoardUsers.ts
|
|
2015
|
-
var
|
|
2027
|
+
var Sn = [
|
|
2016
2028
|
{
|
|
2017
2029
|
value: "admin",
|
|
2018
2030
|
label: "관리자",
|
|
@@ -2029,13 +2041,13 @@ var hn = [
|
|
|
2029
2041
|
description: "글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다."
|
|
2030
2042
|
}
|
|
2031
2043
|
];
|
|
2032
|
-
function
|
|
2033
|
-
let t = () =>
|
|
2044
|
+
function Cn(e = {}) {
|
|
2045
|
+
let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i = ie(r, { ssrKey: S(t(), "users-management") });
|
|
2034
2046
|
async function a(e, r) {
|
|
2035
|
-
if (!
|
|
2036
|
-
await
|
|
2047
|
+
if (!Sn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
|
|
2048
|
+
await Y(y(n, t(), e), {
|
|
2037
2049
|
role: r,
|
|
2038
|
-
updatedAt:
|
|
2050
|
+
updatedAt: K()
|
|
2039
2051
|
});
|
|
2040
2052
|
}
|
|
2041
2053
|
return {
|
|
@@ -2046,11 +2058,11 @@ function gn(e = {}) {
|
|
|
2046
2058
|
}
|
|
2047
2059
|
//#endregion
|
|
2048
2060
|
//#region src/composables/useMemiBoardUserProfile.ts
|
|
2049
|
-
function
|
|
2050
|
-
let t = Q(), n = () =>
|
|
2061
|
+
function wn(e) {
|
|
2062
|
+
let t = Q(), n = () => h(), r = A(() => N(e)), i = A(() => {
|
|
2051
2063
|
let e = r.value;
|
|
2052
|
-
return e ?
|
|
2053
|
-
}), { data: a, pending: o } =
|
|
2064
|
+
return e ? y(t, n(), e) : null;
|
|
2065
|
+
}), { data: a, pending: o } = oe(i);
|
|
2054
2066
|
return {
|
|
2055
2067
|
profile: a,
|
|
2056
2068
|
profilePending: o
|
|
@@ -2058,7 +2070,7 @@ function _n(e) {
|
|
|
2058
2070
|
}
|
|
2059
2071
|
//#endregion
|
|
2060
2072
|
//#region src/utils/section.ts
|
|
2061
|
-
var
|
|
2073
|
+
var Tn = [
|
|
2062
2074
|
3,
|
|
2063
2075
|
4,
|
|
2064
2076
|
5,
|
|
@@ -2067,7 +2079,7 @@ var vn = [
|
|
|
2067
2079
|
8,
|
|
2068
2080
|
9,
|
|
2069
2081
|
12
|
|
2070
|
-
],
|
|
2082
|
+
], En = [
|
|
2071
2083
|
{
|
|
2072
2084
|
value: "list",
|
|
2073
2085
|
label: "게시목록"
|
|
@@ -2080,24 +2092,24 @@ var vn = [
|
|
|
2080
2092
|
value: "comments",
|
|
2081
2093
|
label: "댓글모음"
|
|
2082
2094
|
}
|
|
2083
|
-
],
|
|
2095
|
+
], Dn = [{
|
|
2084
2096
|
value: "latest",
|
|
2085
2097
|
label: "최신순"
|
|
2086
2098
|
}, {
|
|
2087
2099
|
value: "likes",
|
|
2088
2100
|
label: "좋아요순"
|
|
2089
2101
|
}];
|
|
2090
|
-
function
|
|
2102
|
+
function On(e) {
|
|
2091
2103
|
return e === "list" ? 5 : 4;
|
|
2092
2104
|
}
|
|
2093
|
-
function
|
|
2105
|
+
function kn(e, t) {
|
|
2094
2106
|
let n = Math.floor(Number(t));
|
|
2095
|
-
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) :
|
|
2107
|
+
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : On(e);
|
|
2096
2108
|
}
|
|
2097
|
-
function
|
|
2109
|
+
function An(e) {
|
|
2098
2110
|
return e === 12 ? null : 12 - e;
|
|
2099
2111
|
}
|
|
2100
|
-
function
|
|
2112
|
+
function jn(e) {
|
|
2101
2113
|
return {
|
|
2102
2114
|
3: "col-span-12 md:col-span-3",
|
|
2103
2115
|
4: "col-span-12 md:col-span-4",
|
|
@@ -2109,36 +2121,36 @@ function wn(e) {
|
|
|
2109
2121
|
12: "col-span-12"
|
|
2110
2122
|
}[e];
|
|
2111
2123
|
}
|
|
2112
|
-
function
|
|
2124
|
+
function Mn(e) {
|
|
2113
2125
|
return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
|
|
2114
2126
|
}
|
|
2115
|
-
function
|
|
2127
|
+
function Nn(e) {
|
|
2116
2128
|
let t = e.boardId || e.category || "free";
|
|
2117
2129
|
return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
|
|
2118
2130
|
}
|
|
2119
|
-
function
|
|
2131
|
+
function Pn(e) {
|
|
2120
2132
|
return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
|
|
2121
2133
|
}
|
|
2122
|
-
function
|
|
2123
|
-
if (
|
|
2134
|
+
function Fn(e) {
|
|
2135
|
+
if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
|
|
2124
2136
|
}
|
|
2125
|
-
function
|
|
2137
|
+
function In(e) {
|
|
2126
2138
|
return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
2127
2139
|
}
|
|
2128
|
-
function
|
|
2140
|
+
function Ln(e) {
|
|
2129
2141
|
return e.title?.trim() || e.summary || "게시물";
|
|
2130
2142
|
}
|
|
2131
|
-
function
|
|
2143
|
+
function Rn(e) {
|
|
2132
2144
|
return e === "image" || e === "video" ? "media" : "list";
|
|
2133
2145
|
}
|
|
2134
|
-
function
|
|
2135
|
-
return
|
|
2146
|
+
function zn(e) {
|
|
2147
|
+
return Rn(e) === "media" ? "미디어" : "목록";
|
|
2136
2148
|
}
|
|
2137
|
-
function
|
|
2149
|
+
function Bn(e, t) {
|
|
2138
2150
|
return e ? t(e)?.listView ?? "default" : "default";
|
|
2139
2151
|
}
|
|
2140
|
-
function
|
|
2141
|
-
let n = e.map((e) =>
|
|
2152
|
+
function Vn(e, t) {
|
|
2153
|
+
let n = e.map((e) => Bn(e.boardId, t));
|
|
2142
2154
|
if (!n.length) return "default";
|
|
2143
2155
|
if (n.every((e) => e === n[0])) return n[0];
|
|
2144
2156
|
let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
|
|
@@ -2146,72 +2158,72 @@ function Pn(e, t) {
|
|
|
2146
2158
|
}
|
|
2147
2159
|
//#endregion
|
|
2148
2160
|
//#region src/composables/useMemiBoardSections.ts
|
|
2149
|
-
var
|
|
2150
|
-
function
|
|
2161
|
+
var Hn = [];
|
|
2162
|
+
function Un(e) {
|
|
2151
2163
|
let t = Number(e.cols);
|
|
2152
|
-
if (
|
|
2164
|
+
if (Tn.includes(t)) return t;
|
|
2153
2165
|
let n = e.width;
|
|
2154
2166
|
return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
|
|
2155
2167
|
}
|
|
2156
|
-
function
|
|
2168
|
+
function Wn(e) {
|
|
2157
2169
|
let t = e.height ?? e.size;
|
|
2158
2170
|
return t === "sm" || t === "lg" ? t : "md";
|
|
2159
2171
|
}
|
|
2160
|
-
function
|
|
2172
|
+
function Gn(e) {
|
|
2161
2173
|
return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
|
|
2162
2174
|
}
|
|
2163
|
-
function
|
|
2175
|
+
function Kn(e) {
|
|
2164
2176
|
return e.sort === "likes" ? "likes" : "latest";
|
|
2165
2177
|
}
|
|
2166
|
-
function
|
|
2178
|
+
function qn(e) {
|
|
2167
2179
|
return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
|
|
2168
2180
|
}
|
|
2169
|
-
function
|
|
2181
|
+
function Jn(e, t) {
|
|
2170
2182
|
let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
|
|
2171
2183
|
for (let e of n) {
|
|
2172
2184
|
let n = String(e || "").trim();
|
|
2173
|
-
if (
|
|
2185
|
+
if (n && !r.includes(n) && (r.push(n), r.length >= t)) break;
|
|
2174
2186
|
}
|
|
2175
2187
|
return r;
|
|
2176
2188
|
}
|
|
2177
|
-
function
|
|
2178
|
-
let n =
|
|
2189
|
+
function Yn(e, t) {
|
|
2190
|
+
let n = Gn(e), r = kn(n, e.count);
|
|
2179
2191
|
return {
|
|
2180
2192
|
id: String(e.id || `box-${t + 1}`),
|
|
2181
2193
|
title: String(e.title || `섹션 ${t + 1}`),
|
|
2182
2194
|
showTitle: e.showTitle !== !1,
|
|
2183
2195
|
kind: n,
|
|
2184
|
-
boardId:
|
|
2196
|
+
boardId: qn(e),
|
|
2185
2197
|
count: r,
|
|
2186
|
-
postIds:
|
|
2187
|
-
sort:
|
|
2188
|
-
cols:
|
|
2189
|
-
height:
|
|
2198
|
+
postIds: Jn(e, r),
|
|
2199
|
+
sort: Kn(e),
|
|
2200
|
+
cols: Un(e),
|
|
2201
|
+
height: Wn(e),
|
|
2190
2202
|
order: t
|
|
2191
2203
|
};
|
|
2192
2204
|
}
|
|
2193
|
-
function
|
|
2194
|
-
let e = Q(), t =
|
|
2205
|
+
function Xn() {
|
|
2206
|
+
let e = Q(), t = L(e, "settings", "homeLayout"), { data: n, pending: r } = oe(t), i = A(() => (Array.isArray(n.value?.blocks) ? n.value.blocks : Hn).map((e, t) => Yn(e, t)));
|
|
2195
2207
|
async function a(e) {
|
|
2196
|
-
await
|
|
2208
|
+
await q(t, {
|
|
2197
2209
|
columns: 12,
|
|
2198
2210
|
blocks: e.map((e, t) => {
|
|
2199
|
-
let n = e, r =
|
|
2211
|
+
let n = e, r = Gn(n), i = kn(r, e.count);
|
|
2200
2212
|
return {
|
|
2201
2213
|
id: e.id,
|
|
2202
2214
|
title: e.title.trim() || `섹션 ${t + 1}`,
|
|
2203
2215
|
showTitle: e.showTitle !== !1,
|
|
2204
2216
|
kind: r,
|
|
2205
|
-
boardId:
|
|
2217
|
+
boardId: qn(n),
|
|
2206
2218
|
count: i,
|
|
2207
|
-
postIds:
|
|
2208
|
-
sort:
|
|
2209
|
-
cols:
|
|
2210
|
-
height:
|
|
2219
|
+
postIds: Jn(n, i),
|
|
2220
|
+
sort: Kn(n),
|
|
2221
|
+
cols: Un(n),
|
|
2222
|
+
height: Wn(n),
|
|
2211
2223
|
order: t
|
|
2212
2224
|
};
|
|
2213
2225
|
}),
|
|
2214
|
-
updatedAt:
|
|
2226
|
+
updatedAt: K()
|
|
2215
2227
|
});
|
|
2216
2228
|
}
|
|
2217
2229
|
return {
|
|
@@ -2219,43 +2231,42 @@ function Un() {
|
|
|
2219
2231
|
pending: r,
|
|
2220
2232
|
sections: i,
|
|
2221
2233
|
blocks: i,
|
|
2222
|
-
hasSavedLayout:
|
|
2234
|
+
hasSavedLayout: A(() => Array.isArray(n.value?.blocks)),
|
|
2223
2235
|
saveSections: a,
|
|
2224
2236
|
saveBlocks: a
|
|
2225
2237
|
};
|
|
2226
2238
|
}
|
|
2227
2239
|
//#endregion
|
|
2228
2240
|
//#region src/composables/useMemiBoardMiniPosts.ts
|
|
2229
|
-
function
|
|
2230
|
-
let n = Q(), r = () =>
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
}), { data: a, pending: o, error: s } = se(i);
|
|
2241
|
+
function Zn(e, t) {
|
|
2242
|
+
let n = Q(), r = () => h(), i = N(e)?.trim() || "all", a = A(() => {
|
|
2243
|
+
let i = Math.max(1, Math.floor(Number(N(t)) || 5)), a = N(e)?.trim() || "", s = [X("isPublished", "==", !0), X("listed", "==", !0)];
|
|
2244
|
+
return a && s.unshift(X("boardId", "==", a)), G(o(n, r()), ...s, W("createdAt", "desc"), H(i));
|
|
2245
|
+
}), { data: s, pending: c, error: l } = ie(a, { ssrKey: S(r(), `mini-list/${i}`) });
|
|
2235
2246
|
return {
|
|
2236
|
-
posts:
|
|
2237
|
-
pending:
|
|
2238
|
-
error:
|
|
2247
|
+
posts: A(() => s.value ?? []),
|
|
2248
|
+
pending: c,
|
|
2249
|
+
error: l
|
|
2239
2250
|
};
|
|
2240
2251
|
}
|
|
2241
|
-
function
|
|
2242
|
-
let t = Q(), n = () =>
|
|
2252
|
+
function Qn(e) {
|
|
2253
|
+
let t = Q(), n = () => h(), r = A(() => [...new Set(N(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = A(() => r.value.length ? G(o(t, n()), X(R(), "in", r.value)) : null), { data: s, pending: c, error: l } = ie(a, { ssrKey: S(n(), `mini-picked/${i}`) });
|
|
2243
2254
|
return {
|
|
2244
|
-
posts:
|
|
2245
|
-
let e = new Map((
|
|
2255
|
+
posts: A(() => {
|
|
2256
|
+
let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
|
|
2246
2257
|
for (let n of r.value) {
|
|
2247
2258
|
let r = e.get(n);
|
|
2248
2259
|
r && r.isPublished !== !1 && t.push(r);
|
|
2249
2260
|
}
|
|
2250
2261
|
return t;
|
|
2251
2262
|
}),
|
|
2252
|
-
pending:
|
|
2253
|
-
error:
|
|
2263
|
+
pending: c,
|
|
2264
|
+
error: l
|
|
2254
2265
|
};
|
|
2255
2266
|
}
|
|
2256
2267
|
//#endregion
|
|
2257
2268
|
//#region src/data/versionHistory.ts
|
|
2258
|
-
var
|
|
2269
|
+
var $n = [
|
|
2259
2270
|
{
|
|
2260
2271
|
version: "0.42.0",
|
|
2261
2272
|
date: "2026-08-27",
|
|
@@ -2525,7 +2536,7 @@ var Kn = [
|
|
|
2525
2536
|
highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
|
|
2526
2537
|
note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
|
|
2527
2538
|
}
|
|
2528
|
-
],
|
|
2539
|
+
], er = /* @__PURE__ */ Ae(((e, t) => {
|
|
2529
2540
|
(function(n, r) {
|
|
2530
2541
|
typeof e == "object" && t !== void 0 ? t.exports = r() : typeof define == "function" && define.amd ? define(r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs = r();
|
|
2531
2542
|
})(e, (function() {
|
|
@@ -2819,7 +2830,7 @@ var Kn = [
|
|
|
2819
2830
|
return w(1e3 * e);
|
|
2820
2831
|
}, w.en = b[y], w.Ls = b, w.p = {}, w;
|
|
2821
2832
|
}));
|
|
2822
|
-
})),
|
|
2833
|
+
})), tr = /* @__PURE__ */ Ae(((e, t) => {
|
|
2823
2834
|
(function(n, r) {
|
|
2824
2835
|
typeof e == "object" && t !== void 0 ? t.exports = r() : typeof define == "function" && define.amd ? define(r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_plugin_relativeTime = r();
|
|
2825
2836
|
})(e, (function() {
|
|
@@ -2923,9 +2934,9 @@ var Kn = [
|
|
|
2923
2934
|
};
|
|
2924
2935
|
};
|
|
2925
2936
|
}));
|
|
2926
|
-
})),
|
|
2937
|
+
})), nr = /* @__PURE__ */ Ae(((e, t) => {
|
|
2927
2938
|
(function(n, r) {
|
|
2928
|
-
typeof e == "object" && t !== void 0 ? t.exports = r(
|
|
2939
|
+
typeof e == "object" && t !== void 0 ? t.exports = r(er()) : typeof define == "function" && define.amd ? define(["dayjs"], r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_locale_ko = r(n.dayjs);
|
|
2929
2940
|
})(e, (function(e) {
|
|
2930
2941
|
function t(e) {
|
|
2931
2942
|
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
@@ -2973,24 +2984,24 @@ var Kn = [
|
|
|
2973
2984
|
};
|
|
2974
2985
|
return n.default.locale(r, null, !0), r;
|
|
2975
2986
|
}));
|
|
2976
|
-
})),
|
|
2977
|
-
|
|
2978
|
-
function
|
|
2987
|
+
})), rr = /* @__PURE__ */ Me(er(), 1), ir = /* @__PURE__ */ Me(tr(), 1);
|
|
2988
|
+
nr(), rr.default.extend(ir.default), rr.default.locale("ko");
|
|
2989
|
+
function ar(e) {
|
|
2979
2990
|
return e?.toDate ? e.toDate().toLocaleDateString("ko-KR") : "";
|
|
2980
2991
|
}
|
|
2981
|
-
function
|
|
2982
|
-
return e?.toDate ? (0,
|
|
2992
|
+
function or(e, t = Date.now()) {
|
|
2993
|
+
return e?.toDate ? (0, rr.default)(e.toDate()).from((0, rr.default)(t)) : "방금 전";
|
|
2983
2994
|
}
|
|
2984
|
-
function
|
|
2985
|
-
return e?.toDate ? (0,
|
|
2995
|
+
function sr(e) {
|
|
2996
|
+
return e?.toDate ? (0, rr.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
|
|
2986
2997
|
}
|
|
2987
|
-
function
|
|
2988
|
-
let n =
|
|
2989
|
-
return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${
|
|
2998
|
+
function cr(e, t) {
|
|
2999
|
+
let n = sr(e), r = e?.toMillis?.(), i = t?.toMillis?.();
|
|
3000
|
+
return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${sr(t)}`];
|
|
2990
3001
|
}
|
|
2991
3002
|
//#endregion
|
|
2992
3003
|
//#region src/composables/useMemiBoardWritingAssistant.ts
|
|
2993
|
-
var
|
|
3004
|
+
var lr = 10, ur = 864e5, dr = 200, fr = {
|
|
2994
3005
|
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
2995
3006
|
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
2996
3007
|
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
@@ -2999,46 +3010,46 @@ var nr = 10, rr = 864e5, ir = 200, ar = {
|
|
|
2999
3010
|
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
3000
3011
|
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
3001
3012
|
};
|
|
3002
|
-
function
|
|
3003
|
-
if (e.action !== "custom") return
|
|
3004
|
-
let t = e.customInstruction?.trim().slice(0,
|
|
3013
|
+
function pr(e) {
|
|
3014
|
+
if (e.action !== "custom") return fr[e.action];
|
|
3015
|
+
let t = e.customInstruction?.trim().slice(0, dr);
|
|
3005
3016
|
if (!t) throw Error("어떻게 바꿀지 지시문을 입력해 주세요.");
|
|
3006
3017
|
return `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${t}`;
|
|
3007
3018
|
}
|
|
3008
|
-
function
|
|
3019
|
+
function mr(e) {
|
|
3009
3020
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
3010
3021
|
}
|
|
3011
|
-
function
|
|
3022
|
+
function hr(e) {
|
|
3012
3023
|
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
3013
3024
|
}
|
|
3014
|
-
function
|
|
3015
|
-
let e =
|
|
3025
|
+
function gr() {
|
|
3026
|
+
let e = se(), t = Q(), n = ae(), r = c();
|
|
3016
3027
|
async function i() {
|
|
3017
3028
|
let e = n.value?.uid;
|
|
3018
3029
|
if (!e) throw Error("AI 글쓰기 도우미는 로그인 후 사용할 수 있습니다.");
|
|
3019
|
-
await
|
|
3020
|
-
let r =
|
|
3030
|
+
await re(t, async (n) => {
|
|
3031
|
+
let r = y(t, h(), e), i = await n.get(r);
|
|
3021
3032
|
if (!i.exists()) throw Error("사용자 정보를 확인한 뒤 다시 시도해 주세요.");
|
|
3022
|
-
let a = i.data(), o =
|
|
3033
|
+
let a = i.data(), o = hr(a.aiWritingWindowAt), s = Math.max(0, Math.floor(Number(a.aiWritingCount) || 0)), c = Date.now(), l = o != null && c - o < ur;
|
|
3023
3034
|
if (l && s >= 10) {
|
|
3024
|
-
let e = o +
|
|
3035
|
+
let e = o + ur, t = Math.max(1, Math.ceil((e - c) / 36e5));
|
|
3025
3036
|
throw Error(`AI 글쓰기 도우미는 하루 10회까지 사용할 수 있습니다. 약 ${t}시간 후 다시 이용해 주세요.`);
|
|
3026
3037
|
}
|
|
3027
3038
|
n.update(r, {
|
|
3028
3039
|
aiWritingCount: l ? s + 1 : 1,
|
|
3029
|
-
aiWritingWindowAt: l ? a.aiWritingWindowAt :
|
|
3030
|
-
updatedAt:
|
|
3040
|
+
aiWritingWindowAt: l ? a.aiWritingWindowAt : K(),
|
|
3041
|
+
updatedAt: K()
|
|
3031
3042
|
});
|
|
3032
3043
|
});
|
|
3033
3044
|
}
|
|
3034
3045
|
async function a(t) {
|
|
3035
|
-
let n =
|
|
3046
|
+
let n = pr(t);
|
|
3036
3047
|
if (!t.content.trim()) throw Error("AI로 다듬을 내용을 먼저 입력해 주세요.");
|
|
3037
3048
|
await i();
|
|
3038
|
-
let a = r.moderation ?? {}, o =
|
|
3039
|
-
backend: new
|
|
3049
|
+
let a = r.moderation ?? {}, o = Se(e, {
|
|
3050
|
+
backend: new be(),
|
|
3040
3051
|
useLimitedUseAppCheckTokens: a.useLimitedUseAppCheckTokens !== !1
|
|
3041
|
-
}), s =
|
|
3052
|
+
}), s = Ce(o, {
|
|
3042
3053
|
model: a.model ?? "gemini-3.5-flash-lite",
|
|
3043
3054
|
systemInstruction: [
|
|
3044
3055
|
"너는 게시판 글쓰기 편집 도우미다.",
|
|
@@ -3053,7 +3064,7 @@ function lr() {
|
|
|
3053
3064
|
`작업: ${n}`,
|
|
3054
3065
|
t.title ? `현재 제목: ${t.title}` : "",
|
|
3055
3066
|
`본문:\n${c.slice(0, 12e3)}`
|
|
3056
|
-
].filter(Boolean).join("\n\n"), u =
|
|
3067
|
+
].filter(Boolean).join("\n\n"), u = mr((await s.generateContent(l)).response.text());
|
|
3057
3068
|
if (!u) throw Error("AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.");
|
|
3058
3069
|
return u;
|
|
3059
3070
|
}
|
|
@@ -3061,14 +3072,14 @@ function lr() {
|
|
|
3061
3072
|
}
|
|
3062
3073
|
//#endregion
|
|
3063
3074
|
//#region src/utils/renderMarkdown.ts
|
|
3064
|
-
function
|
|
3075
|
+
function _r(e) {
|
|
3065
3076
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3066
3077
|
}
|
|
3067
|
-
function
|
|
3078
|
+
function vr(e) {
|
|
3068
3079
|
let t = e;
|
|
3069
3080
|
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;
|
|
3070
3081
|
}
|
|
3071
|
-
function
|
|
3082
|
+
function yr(e) {
|
|
3072
3083
|
if (!e?.trim()) return "";
|
|
3073
3084
|
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
|
|
3074
3085
|
function c() {
|
|
@@ -3077,7 +3088,7 @@ function fr(e) {
|
|
|
3077
3088
|
return;
|
|
3078
3089
|
}
|
|
3079
3090
|
let e = o;
|
|
3080
|
-
n.push(`<${e}>${s.map((e) => `<li>${
|
|
3091
|
+
n.push(`<${e}>${s.map((e) => `<li>${vr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
|
|
3081
3092
|
}
|
|
3082
3093
|
for (; r < t.length;) {
|
|
3083
3094
|
let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
|
|
@@ -3086,7 +3097,7 @@ function fr(e) {
|
|
|
3086
3097
|
continue;
|
|
3087
3098
|
}
|
|
3088
3099
|
if (i) {
|
|
3089
|
-
a.push(
|
|
3100
|
+
a.push(_r(e)), r++;
|
|
3090
3101
|
continue;
|
|
3091
3102
|
}
|
|
3092
3103
|
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
|
|
@@ -3097,24 +3108,24 @@ function fr(e) {
|
|
|
3097
3108
|
if (u) {
|
|
3098
3109
|
c();
|
|
3099
3110
|
let e = u[1].length;
|
|
3100
|
-
n.push(`<h${e} class="font-semibold mt-4 mb-2">${
|
|
3111
|
+
n.push(`<h${e} class="font-semibold mt-4 mb-2">${vr(_r(u[2]))}</h${e}>`), r++;
|
|
3101
3112
|
continue;
|
|
3102
3113
|
}
|
|
3103
3114
|
if (e.startsWith("> ")) {
|
|
3104
3115
|
c();
|
|
3105
3116
|
let e = [];
|
|
3106
|
-
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(
|
|
3107
|
-
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${
|
|
3117
|
+
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(_r((t[r] ?? "").slice(2))), r++;
|
|
3118
|
+
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${vr(e.join("<br />"))}</blockquote>`);
|
|
3108
3119
|
continue;
|
|
3109
3120
|
}
|
|
3110
3121
|
let d = e.match(/^[-*+]\s+(.+)$/);
|
|
3111
3122
|
if (d) {
|
|
3112
|
-
o && o !== "ul" && c(), o = "ul", s.push(
|
|
3123
|
+
o && o !== "ul" && c(), o = "ul", s.push(_r(d[1])), r++;
|
|
3113
3124
|
continue;
|
|
3114
3125
|
}
|
|
3115
3126
|
let f = e.match(/^\d+\.\s+(.+)$/);
|
|
3116
3127
|
if (f) {
|
|
3117
|
-
o && o !== "ol" && c(), o = "ol", s.push(
|
|
3128
|
+
o && o !== "ol" && c(), o = "ol", s.push(_r(f[1])), r++;
|
|
3118
3129
|
continue;
|
|
3119
3130
|
}
|
|
3120
3131
|
if (!e.trim()) {
|
|
@@ -3126,13 +3137,13 @@ function fr(e) {
|
|
|
3126
3137
|
for (; r < t.length;) {
|
|
3127
3138
|
let e = t[r] ?? "";
|
|
3128
3139
|
if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
|
|
3129
|
-
p.push(
|
|
3140
|
+
p.push(_r(e)), r++;
|
|
3130
3141
|
}
|
|
3131
|
-
n.push(`<p class="my-2 leading-relaxed">${
|
|
3142
|
+
n.push(`<p class="my-2 leading-relaxed">${vr(p.join("<br />"))}</p>`);
|
|
3132
3143
|
}
|
|
3133
3144
|
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");
|
|
3134
3145
|
}
|
|
3135
3146
|
//#endregion
|
|
3136
|
-
export {
|
|
3147
|
+
export { qt as AUTHOR_MEMO_MAX_LENGTH, Tn as BOARD_SECTION_COLS, En as BOARD_SECTION_KINDS, Dn as BOARD_SECTION_SORTS, Sn as BOARD_USER_ROLES, Qt as COMMENT_BODY_MAX_LENGTH, et as DEFAULT_BLOCK_BAN_DECAY_MS, $e as DEFAULT_BLOCK_BAN_THRESHOLD, At as DEFAULT_BOARDS, jt as DEFAULT_CATEGORIES, x as DEFAULT_COMMENTS_COLLECTION, w as DEFAULT_LIKES_COLLECTION, u as DEFAULT_POSTS_COLLECTION, v as DEFAULT_REPORTS_COLLECTION, T as DEFAULT_SETTINGS_COLLECTION, d as DEFAULT_USERS_COLLECTION, on as REPORT_DETAIL_MAX_LENGTH, sn as REPORT_REASONS, lr as WRITING_ASSISTANT_DAILY_LIMIT, Ne as asHttpUrl, ze as boardListOgDescription, Re as boardListOgTitle, Le as boardPostOgDescription, Ie as boardPostOgTitle, S as boardSsrKey, y as boardUserDoc, p as boardUsersCol, kt as buildPostPreview, Je as canManageBoardByRole, Ye as canWriteCommentByRole, kn as clampSectionCount, s as commentDoc, E as commentsCol, C as configureMemiBoard, On as defaultSectionCount, tt as effectiveModerationBlockCount, lt as extractEditorImageUrls, Ge as fetchPublicListForSeo, We as fetchPublicPostForSeo, ar as formatDate, sr as formatFullDate, or as formatRelativeDate, it as formatRestrictedUntilLabel, cr as formatTimestampDetails, wt as hasBodyImage, Ct as hasBodyText, qe as isAssignedStaff, Tt as isContentEmpty, Ft as isFirestorePermissionDenied, rt as isModerationWriteRestricted, k as likeDoc, l as likeDocId, O as likesCol, rn as memiBoardCommentLikesKey, Bn as miniBoardView, Fn as miniCommentLink, Pn as miniMoreLink, In as miniPostImage, Nn as miniPostLink, Ln as miniPostTitle, Vn as miniPostsView, Rn as miniViewGroup, zn as miniViewLabel, nt as moderationWriteRestrictedUntilMs, Be as normalizeBasePath, Yn as normalizeBoardSection, An as pairSectionCols, xt as plainTextFromHtml, a as postBodyDoc, t as postDoc, dt as postNamespaceFromStoragePath, D as postStorageFolder, o as postsCol, yr as renderMarkdownToHtml, r as reportDoc, n as reportDocId, cn as reportReasonLabel, i as reportsCol, _ as resolveBoardPathConfig, Ve as resolvePublicSeoDb, jn as sectionColClass, Mn as sectionMinHeight, e as settingsCol, g as settingsDoc, b as slugify, ut as storagePathFromDownloadUrl, St as titleFromBody, Fe as toAbsoluteUrl, Pe as toBoardOgImageUrl, h as useBoardPathConfig, ct as useMemiBoardAuth, Yt as useMemiBoardAuthorMemo, Kt as useMemiBoardCommentFeed, an as useMemiBoardCommentLikes, en as useMemiBoardComments, c as useMemiBoardConfig, nn as useMemiBoardLikes, Zn as useMemiBoardMiniLatest, Qn as useMemiBoardMiniPicked, xn as useMemiBoardModeration, Bt as useMemiBoardPost, zt as useMemiBoardPostList, Lt as useMemiBoardPosts, tn as useMemiBoardReplies, dn as useMemiBoardReportQueue, ln as useMemiBoardReports, Xn as useMemiBoardSections, Pt as useMemiBoardSettings, Wt as useMemiBoardUserComments, Ht as useMemiBoardUserPosts, wn as useMemiBoardUserProfile, Cn as useMemiBoardUsers, fn as useMemiBoardViews, gr as useMemiBoardWritingAssistant, $n as versionHistory, Ot as videoListCoverUrl, Dt as youtubeId };
|
|
3137
3148
|
|
|
3138
3149
|
//# sourceMappingURL=index.js.map
|