memi-board 0.43.0 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/dist/composables/useMemiBoardPosts.d.ts +15 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +465 -413
- package/dist/index.js.map +1 -1
- package/dist/runtime/components/CommentForm.vue +4 -0
- package/dist/runtime/components/CommentItem.vue +4 -0
- package/dist/runtime/components/Editor.vue +9 -1
- package/dist/runtime/components/ReportButton.vue +4 -0
- package/dist/runtime/components/SignIn.vue +4 -0
- package/dist/runtime/composables/useMemiBoardSeo.ts +9 -3
- package/dist/utils/imeSafeSubmit.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
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
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
|
|
4
|
-
import { useCollection as
|
|
3
|
+
import { deleteDoc as F, deleteField as I, doc as te, documentId as L, endBefore as ne, getDoc as R, getDocs as z, increment as B, limit as V, limitToLast as re, onSnapshot as H, orderBy as U, query as W, runTransaction as ie, serverTimestamp as G, setDoc as K, startAfter as q, updateDoc as J, where as Y, writeBatch as X } from "firebase/firestore";
|
|
4
|
+
import { useCollection as ae, useCurrentUser as Z, useDocument as oe, useFirebaseApp as se, useFirebaseAuth as ce, useFirestore as Q } from "vuefire";
|
|
5
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
6
|
import { deleteObject as ge, getStorage as _e, listAll as ve, ref as ye } from "firebase/storage";
|
|
7
7
|
import { GoogleAIBackend as be, Schema as xe, getAI as Se, getGenerativeModel as Ce } from "firebase/ai";
|
|
@@ -76,7 +76,7 @@ function Ve() {
|
|
|
76
76
|
}
|
|
77
77
|
async function He(e, t) {
|
|
78
78
|
try {
|
|
79
|
-
let n = await
|
|
79
|
+
let n = await R(g(e.db, e.paths, t));
|
|
80
80
|
if (!n.exists()) return {
|
|
81
81
|
label: t,
|
|
82
82
|
description: "",
|
|
@@ -113,7 +113,7 @@ async function We(e, t, n) {
|
|
|
113
113
|
let s = await He(a, r);
|
|
114
114
|
if (s.hidden) return null;
|
|
115
115
|
try {
|
|
116
|
-
let e = (await
|
|
116
|
+
let e = (await z(W(o(a.db, a.paths), Y("boardId", "==", r), Y("slug", "==", i), Y("listed", "==", !0), Y("isPublished", "==", !0), V(1)))).docs[0];
|
|
117
117
|
if (!e) return null;
|
|
118
118
|
let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title.trim() : "";
|
|
119
119
|
return n ? {
|
|
@@ -165,7 +165,7 @@ async function Ge(e, t) {
|
|
|
165
165
|
async function Ke(e, t) {
|
|
166
166
|
let n = [], r = null;
|
|
167
167
|
try {
|
|
168
|
-
let i = await
|
|
168
|
+
let i = await z(W(o(e.db, e.paths), Y("boardId", "==", t), Y("listed", "==", !0), Y("isPublished", "==", !0), U("createdAt", "desc"), V(12)));
|
|
169
169
|
for (let e of i.docs) {
|
|
170
170
|
let t = e.data() ?? {}, i = typeof t.title == "string" ? t.title.trim() : "";
|
|
171
171
|
i && n.length < 5 && n.push(i), r ||= Pe(t.previewImage);
|
|
@@ -254,7 +254,7 @@ function st() {
|
|
|
254
254
|
}), e[ot];
|
|
255
255
|
}
|
|
256
256
|
function ct() {
|
|
257
|
-
let e = c(), t = st(), n = Q(), r = ce(), i =
|
|
257
|
+
let e = c(), t = st(), n = Q(), r = ce(), i = Z(), { role: a, rolePending: o, rawBlockCount: s, blockAtMs: l } = t;
|
|
258
258
|
function u() {
|
|
259
259
|
let t = e.moderation?.blockBanThreshold;
|
|
260
260
|
return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
|
|
@@ -274,22 +274,22 @@ function ct() {
|
|
|
274
274
|
s.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), l.value = at(e.moderationBlockAt);
|
|
275
275
|
}
|
|
276
276
|
async function g(e) {
|
|
277
|
-
let t = f(e.uid), r = m(n, h(), e.uid), i = await
|
|
278
|
-
if (!i.exists()) return await Promise.all([
|
|
277
|
+
let t = f(e.uid), r = m(n, h(), e.uid), i = await R(t);
|
|
278
|
+
if (!i.exists()) return await Promise.all([K(t, {
|
|
279
279
|
role: "user",
|
|
280
280
|
displayName: e.displayName,
|
|
281
281
|
photoURL: e.photoURL,
|
|
282
|
-
joinedAt:
|
|
283
|
-
lastVisitAt:
|
|
284
|
-
updatedAt:
|
|
285
|
-
}),
|
|
282
|
+
joinedAt: G(),
|
|
283
|
+
lastVisitAt: G(),
|
|
284
|
+
updatedAt: G()
|
|
285
|
+
}), K(r, { email: e.email })]), p({ moderationBlockCount: 0 }), "user";
|
|
286
286
|
let a = i.data();
|
|
287
287
|
p(a);
|
|
288
288
|
let o = typeof a.displayName == "string" && a.displayName.trim(), s = typeof a.photoURL == "string" && a.photoURL.trim(), c = {
|
|
289
|
-
lastVisitAt:
|
|
290
|
-
updatedAt:
|
|
289
|
+
lastVisitAt: G(),
|
|
290
|
+
updatedAt: G()
|
|
291
291
|
};
|
|
292
|
-
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([J(t, c), K(r, { email: e.email }, { merge: !0 })]), [
|
|
293
293
|
"admin",
|
|
294
294
|
"staff",
|
|
295
295
|
"user"
|
|
@@ -301,7 +301,7 @@ function ct() {
|
|
|
301
301
|
p(void 0);
|
|
302
302
|
return;
|
|
303
303
|
}
|
|
304
|
-
let t = await
|
|
304
|
+
let t = await R(f(e));
|
|
305
305
|
p(t.exists() ? t.data() : void 0);
|
|
306
306
|
}
|
|
307
307
|
t.watchStarted || (t.watchStarted = !0, P(i, async (e) => {
|
|
@@ -337,17 +337,17 @@ function ct() {
|
|
|
337
337
|
restricted: !1,
|
|
338
338
|
messageSuffix: ""
|
|
339
339
|
};
|
|
340
|
-
let n = f(e), r = await
|
|
341
|
-
r.exists() ? await
|
|
342
|
-
moderationBlockCount:
|
|
343
|
-
moderationBlockAt:
|
|
344
|
-
updatedAt:
|
|
345
|
-
}) : await
|
|
340
|
+
let n = f(e), r = await R(n);
|
|
341
|
+
r.exists() ? await J(n, {
|
|
342
|
+
moderationBlockCount: B(1),
|
|
343
|
+
moderationBlockAt: G(),
|
|
344
|
+
updatedAt: G()
|
|
345
|
+
}) : await K(n, {
|
|
346
346
|
role: "user",
|
|
347
347
|
displayName: i.value?.displayName ?? null,
|
|
348
348
|
moderationBlockCount: 1,
|
|
349
|
-
moderationBlockAt:
|
|
350
|
-
updatedAt:
|
|
349
|
+
moderationBlockAt: G(),
|
|
350
|
+
updatedAt: G()
|
|
351
351
|
});
|
|
352
352
|
let a = (r.exists() ? Math.max(0, Math.floor(Number(r.data().moderationBlockCount) || 0)) : 0) + 1, o = Date.now();
|
|
353
353
|
s.value = a, l.value = o;
|
|
@@ -389,10 +389,10 @@ function ct() {
|
|
|
389
389
|
function I(e) {
|
|
390
390
|
return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
|
|
391
391
|
}
|
|
392
|
-
function
|
|
392
|
+
function te(e) {
|
|
393
393
|
return v.value && i.value?.uid === e.authorUid;
|
|
394
394
|
}
|
|
395
|
-
function
|
|
395
|
+
function L(e) {
|
|
396
396
|
return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
|
|
397
397
|
}
|
|
398
398
|
return {
|
|
@@ -414,15 +414,36 @@ function ct() {
|
|
|
414
414
|
signOut: N,
|
|
415
415
|
canEdit: I,
|
|
416
416
|
canDelete: I,
|
|
417
|
-
canEditComment:
|
|
418
|
-
canDeleteComment:
|
|
417
|
+
canEditComment: te,
|
|
418
|
+
canDeleteComment: L,
|
|
419
419
|
recordContentModerationBlock: D,
|
|
420
420
|
refreshBoardUser: _
|
|
421
421
|
};
|
|
422
422
|
}
|
|
423
423
|
//#endregion
|
|
424
|
+
//#region src/utils/imeSafeSubmit.ts
|
|
425
|
+
var lt = /* @__PURE__ */ new WeakMap();
|
|
426
|
+
function ut(e) {
|
|
427
|
+
let t = e.currentTarget;
|
|
428
|
+
return t instanceof HTMLButtonElement ? t : t instanceof Element ? t.closest("button") : null;
|
|
429
|
+
}
|
|
430
|
+
function dt(e) {
|
|
431
|
+
if (e.pointerType !== "mouse" || e.button !== 0) return;
|
|
432
|
+
let t = ut(e), n = t?.form;
|
|
433
|
+
if (!t || !n || t.disabled) return;
|
|
434
|
+
lt.set(t, Date.now() + 1e3);
|
|
435
|
+
let r = document.activeElement;
|
|
436
|
+
r instanceof HTMLElement && r.blur(), setTimeout(() => n.requestSubmit(t), 0);
|
|
437
|
+
}
|
|
438
|
+
function ft(e) {
|
|
439
|
+
let t = ut(e);
|
|
440
|
+
if (!t) return;
|
|
441
|
+
let n = lt.get(t);
|
|
442
|
+
n && Date.now() < n && (e.preventDefault(), lt.delete(t));
|
|
443
|
+
}
|
|
444
|
+
//#endregion
|
|
424
445
|
//#region src/utils/extractEditorImageUrls.ts
|
|
425
|
-
function
|
|
446
|
+
function pt(e) {
|
|
426
447
|
if (!e) return [];
|
|
427
448
|
let t = /* @__PURE__ */ new Set();
|
|
428
449
|
for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&", "&"));
|
|
@@ -431,7 +452,7 @@ function lt(e) {
|
|
|
431
452
|
}
|
|
432
453
|
//#endregion
|
|
433
454
|
//#region src/utils/storagePath.ts
|
|
434
|
-
function
|
|
455
|
+
function mt(e) {
|
|
435
456
|
try {
|
|
436
457
|
let t = new URL(e), n = t.hostname.toLowerCase();
|
|
437
458
|
if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
|
|
@@ -441,109 +462,109 @@ function ut(e) {
|
|
|
441
462
|
return null;
|
|
442
463
|
}
|
|
443
464
|
}
|
|
444
|
-
function
|
|
465
|
+
function ht(e) {
|
|
445
466
|
return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
|
|
446
467
|
}
|
|
447
468
|
//#endregion
|
|
448
469
|
//#region src/utils/deletePostCascade.ts
|
|
449
|
-
async function
|
|
470
|
+
async function gt(e) {
|
|
450
471
|
try {
|
|
451
472
|
let t = await ve(e);
|
|
452
|
-
await Promise.all([...t.items.map((e) => ge(e).catch(() => {})), ...t.prefixes.map((e) =>
|
|
473
|
+
await Promise.all([...t.items.map((e) => ge(e).catch(() => {})), ...t.prefixes.map((e) => gt(e))]);
|
|
453
474
|
} catch {}
|
|
454
475
|
}
|
|
455
|
-
async function
|
|
456
|
-
await
|
|
476
|
+
async function _t(e, t) {
|
|
477
|
+
await gt(ye(e, `${t}/images`)), await gt(ye(e, `${t}/attachments`));
|
|
457
478
|
}
|
|
458
|
-
async function
|
|
479
|
+
async function vt(e, t) {
|
|
459
480
|
let n = [...new Set([...t].filter(Boolean))];
|
|
460
481
|
await Promise.all(n.map((t) => ge(ye(e, t)).catch(() => {})));
|
|
461
482
|
}
|
|
462
|
-
var
|
|
463
|
-
async function
|
|
464
|
-
let n = await
|
|
465
|
-
for (let t = 0; t < n.docs.length; t +=
|
|
466
|
-
let r =
|
|
467
|
-
n.docs.slice(t, t +
|
|
483
|
+
var yt = 450;
|
|
484
|
+
async function bt(e, t) {
|
|
485
|
+
let n = await z(t);
|
|
486
|
+
for (let t = 0; t < n.docs.length; t += yt) {
|
|
487
|
+
let r = X(e);
|
|
488
|
+
n.docs.slice(t, t + yt).forEach((e) => r.delete(e.ref)), await r.commit();
|
|
468
489
|
}
|
|
469
490
|
}
|
|
470
|
-
async function
|
|
471
|
-
await
|
|
491
|
+
async function xt(e, t, n) {
|
|
492
|
+
await bt(e, W(O(e, t), Y("postId", "==", n)));
|
|
472
493
|
}
|
|
473
|
-
async function
|
|
474
|
-
await
|
|
494
|
+
async function St(e, t, n) {
|
|
495
|
+
await bt(e, W(i(e, t), Y("postId", "==", n)));
|
|
475
496
|
}
|
|
476
|
-
async function
|
|
477
|
-
await
|
|
497
|
+
async function Ct(e, t, n) {
|
|
498
|
+
await bt(e, W(O(e, t), Y("commentId", "==", n)));
|
|
478
499
|
}
|
|
479
|
-
async function
|
|
480
|
-
let o = t(e, r, i), s = a(e, r, i), [c, l] = await Promise.all([
|
|
500
|
+
async function wt(e, n, r, i) {
|
|
501
|
+
let o = t(e, r, i), s = a(e, r, i), [c, l] = await Promise.all([R(o), R(s)]);
|
|
481
502
|
if (!c.exists()) return;
|
|
482
503
|
let u = c.data(), d = l.exists() ? String(l.data().content ?? "") : "";
|
|
483
|
-
await
|
|
504
|
+
await bt(e, W(E(e, r), Y("postId", "==", i))), await xt(e, r, i), await St(e, r, i);
|
|
484
505
|
let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
|
|
485
506
|
for (let e of u.attachments ?? []) {
|
|
486
507
|
if (!e?.path) continue;
|
|
487
508
|
f.add(e.path);
|
|
488
|
-
let t =
|
|
509
|
+
let t = ht(e.path);
|
|
489
510
|
t && t !== i && p.add(t);
|
|
490
511
|
}
|
|
491
|
-
for (let e of
|
|
492
|
-
let t =
|
|
512
|
+
for (let e of pt(d)) {
|
|
513
|
+
let t = mt(e);
|
|
493
514
|
if (!t) continue;
|
|
494
515
|
f.add(t);
|
|
495
516
|
let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
|
|
496
517
|
n !== t && n.includes("/images/thumbnails/") && f.add(n);
|
|
497
518
|
let r = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
|
|
498
519
|
r && !t.includes("/thumbnails/") && f.add(`${r[1]}thumbnails/${r[2]}.jpg`);
|
|
499
|
-
let a =
|
|
520
|
+
let a = ht(t);
|
|
500
521
|
a && a !== i && p.add(a);
|
|
501
522
|
}
|
|
502
|
-
await F(s), await
|
|
503
|
-
for (let e of p) await
|
|
504
|
-
await
|
|
523
|
+
await F(s), await _t(n, D(r, i));
|
|
524
|
+
for (let e of p) await _t(n, D(r, e));
|
|
525
|
+
await vt(n, f), await F(o);
|
|
505
526
|
}
|
|
506
527
|
//#endregion
|
|
507
528
|
//#region src/utils/postBody.ts
|
|
508
|
-
function
|
|
529
|
+
function Tt(e) {
|
|
509
530
|
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();
|
|
510
531
|
}
|
|
511
|
-
function
|
|
512
|
-
let n =
|
|
532
|
+
function Et(e, t = 40) {
|
|
533
|
+
let n = Tt(e);
|
|
513
534
|
if (!n) return "";
|
|
514
535
|
if (n.length <= t) return n;
|
|
515
536
|
let r = n.slice(0, t), i = r.lastIndexOf(" ");
|
|
516
537
|
return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
|
|
517
538
|
}
|
|
518
|
-
function
|
|
519
|
-
return
|
|
539
|
+
function Dt(e) {
|
|
540
|
+
return Tt(e).length > 0;
|
|
520
541
|
}
|
|
521
|
-
function
|
|
542
|
+
function Ot(e, t) {
|
|
522
543
|
return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
|
|
523
544
|
}
|
|
524
|
-
function
|
|
525
|
-
return !
|
|
545
|
+
function kt(e) {
|
|
546
|
+
return !Dt(e);
|
|
526
547
|
}
|
|
527
548
|
//#endregion
|
|
528
549
|
//#region src/utils/postPreview.ts
|
|
529
|
-
function
|
|
550
|
+
function At(e) {
|
|
530
551
|
return e.replace(/&/g, "&").replace(/"/g, "\"").replace(/'/g, "'");
|
|
531
552
|
}
|
|
532
|
-
function
|
|
553
|
+
function jt(e) {
|
|
533
554
|
if (e) try {
|
|
534
|
-
let t = new URL(
|
|
555
|
+
let t = new URL(At(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
|
|
535
556
|
if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
|
|
536
557
|
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;
|
|
537
558
|
} catch {
|
|
538
559
|
return;
|
|
539
560
|
}
|
|
540
561
|
}
|
|
541
|
-
function
|
|
542
|
-
let t =
|
|
562
|
+
function Mt(e) {
|
|
563
|
+
let t = jt(e.videoUrl);
|
|
543
564
|
return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
544
565
|
}
|
|
545
|
-
function
|
|
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 ?
|
|
566
|
+
function Nt(e, t = []) {
|
|
567
|
+
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 ? At(r[1]) : a, s = o ? jt(o) : void 0, c = n ? At(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
|
|
547
568
|
return {
|
|
548
569
|
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),
|
|
549
570
|
...c ? { previewImage: c } : {},
|
|
@@ -552,7 +573,7 @@ function kt(e, t = []) {
|
|
|
552
573
|
}
|
|
553
574
|
//#endregion
|
|
554
575
|
//#region src/composables/useMemiBoardSettings.ts
|
|
555
|
-
var
|
|
576
|
+
var Pt = [
|
|
556
577
|
{
|
|
557
578
|
id: "free",
|
|
558
579
|
label: "자유",
|
|
@@ -580,17 +601,17 @@ var At = [
|
|
|
580
601
|
visibility: "public",
|
|
581
602
|
order: 2
|
|
582
603
|
}
|
|
583
|
-
],
|
|
584
|
-
function
|
|
604
|
+
], Ft = Pt;
|
|
605
|
+
function It(e) {
|
|
585
606
|
return e === "hidden" ? "hidden" : "public";
|
|
586
607
|
}
|
|
587
|
-
function
|
|
608
|
+
function Lt(e, t, n) {
|
|
588
609
|
return {
|
|
589
610
|
id: e,
|
|
590
611
|
label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
|
|
591
612
|
order: typeof t.order == "number" ? t.order : n,
|
|
592
613
|
description: (typeof t.description == "string" ? t.description : "") || "",
|
|
593
|
-
visibility:
|
|
614
|
+
visibility: It(t.visibility),
|
|
594
615
|
listView: t.listView ?? "default",
|
|
595
616
|
editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
|
|
596
617
|
writeRole: t.writeRole ?? "user",
|
|
@@ -598,8 +619,8 @@ function Nt(e, t, n) {
|
|
|
598
619
|
allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : []
|
|
599
620
|
};
|
|
600
621
|
}
|
|
601
|
-
function
|
|
602
|
-
let t = () => h(), n = Q(), r = se(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = ct(), l = A(() =>
|
|
622
|
+
function Rt() {
|
|
623
|
+
let t = () => h(), n = Q(), r = se(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = ct(), l = A(() => W(e(n, t()), U("order", "asc"))), { data: u, pending: d } = ae(l, { ssrKey: S(t(), "boards") }), f = A(() => u.value.map((e, t) => Lt(e.id, e, t))), p = f, m = A(() => f.value.filter((e) => e.visibility !== "hidden")), _ = m;
|
|
603
624
|
function v(e) {
|
|
604
625
|
if (e) return f.value.find((t) => t.id === e)?.label ?? e;
|
|
605
626
|
}
|
|
@@ -627,9 +648,9 @@ function Pt() {
|
|
|
627
648
|
async function M(e, t, r) {
|
|
628
649
|
let i;
|
|
629
650
|
for (;;) {
|
|
630
|
-
let a = await
|
|
651
|
+
let a = await z(W(e, Y("boardId", "==", t), U("__name__"), ...i ? [q(i)] : [], V(400)));
|
|
631
652
|
if (a.empty) break;
|
|
632
|
-
let o =
|
|
653
|
+
let o = X(n), s = 0;
|
|
633
654
|
for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
|
|
634
655
|
if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
|
|
635
656
|
}
|
|
@@ -641,35 +662,35 @@ function Pt() {
|
|
|
641
662
|
return {
|
|
642
663
|
label: e.label.trim(),
|
|
643
664
|
description: (e.description ?? "").trim(),
|
|
644
|
-
visibility:
|
|
665
|
+
visibility: It(e.visibility),
|
|
645
666
|
listView: e.listView ?? "default",
|
|
646
667
|
editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
|
|
647
668
|
writeRole: e.writeRole ?? "user",
|
|
648
669
|
commentWriteRole: e.commentWriteRole ?? "user",
|
|
649
670
|
allowedStaffUids: e.allowedStaffUids ?? [],
|
|
650
671
|
order: t,
|
|
651
|
-
updatedAt:
|
|
672
|
+
updatedAt: G()
|
|
652
673
|
};
|
|
653
674
|
}
|
|
654
675
|
async function I(e, r = e.order ?? 0) {
|
|
655
676
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
656
677
|
let a = e.id.trim(), o = e.label.trim();
|
|
657
678
|
if (!a || !o) throw Error("보드 ID와 이름을 입력해 주세요.");
|
|
658
|
-
let s =
|
|
679
|
+
let s = It(e.visibility), c = P({
|
|
659
680
|
...e,
|
|
660
681
|
label: o,
|
|
661
682
|
visibility: s
|
|
662
683
|
}, r);
|
|
663
|
-
await
|
|
684
|
+
await K(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
|
|
664
685
|
}
|
|
665
|
-
let
|
|
666
|
-
async function
|
|
686
|
+
let te = I;
|
|
687
|
+
async function L(e) {
|
|
667
688
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
668
|
-
let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a =
|
|
689
|
+
let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = X(n), o = [];
|
|
669
690
|
e.forEach((e, i) => {
|
|
670
691
|
let s = e.id.trim(), c = e.label.trim();
|
|
671
692
|
if (!s || !c) throw Error("보드 ID와 이름을 입력해 주세요.");
|
|
672
|
-
let l =
|
|
693
|
+
let l = It(e.visibility), u = P({
|
|
673
694
|
...e,
|
|
674
695
|
label: c,
|
|
675
696
|
visibility: l
|
|
@@ -681,23 +702,23 @@ function Pt() {
|
|
|
681
702
|
}), await a.commit();
|
|
682
703
|
for (let e of o) await N(e.id, e.listed);
|
|
683
704
|
}
|
|
684
|
-
let
|
|
685
|
-
async function
|
|
705
|
+
let ne = L;
|
|
706
|
+
async function R(e) {
|
|
686
707
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
687
708
|
let a = e.trim();
|
|
688
709
|
if (!a) throw Error("삭제할 게시판 ID가 필요합니다.");
|
|
689
710
|
for (;;) {
|
|
690
|
-
let e = await
|
|
711
|
+
let e = await z(W(o(n, t()), Y("boardId", "==", a), V(25)));
|
|
691
712
|
if (e.empty) break;
|
|
692
|
-
for (let i of e.docs) await
|
|
713
|
+
for (let i of e.docs) await wt(n, _e(r), t(), i.id);
|
|
693
714
|
}
|
|
694
715
|
await F(g(n, t(), e));
|
|
695
716
|
}
|
|
696
|
-
let
|
|
697
|
-
async function
|
|
717
|
+
let B = R;
|
|
718
|
+
async function re() {
|
|
698
719
|
return Promise.resolve();
|
|
699
720
|
}
|
|
700
|
-
async function
|
|
721
|
+
async function H(e) {
|
|
701
722
|
let t = e.trim();
|
|
702
723
|
if (!t) throw Error("보드 이름을 입력해 주세요.");
|
|
703
724
|
if (!i.value) throw Error("로그인이 필요합니다.");
|
|
@@ -733,33 +754,34 @@ function Pt() {
|
|
|
733
754
|
categoryVisibility: T,
|
|
734
755
|
isCategoryHidden: O,
|
|
735
756
|
settingsPending: d,
|
|
736
|
-
ensureSettings:
|
|
737
|
-
addBoard:
|
|
738
|
-
addCategory:
|
|
757
|
+
ensureSettings: re,
|
|
758
|
+
addBoard: H,
|
|
759
|
+
addCategory: H,
|
|
739
760
|
saveBoard: I,
|
|
740
|
-
saveCategory:
|
|
741
|
-
saveBoards:
|
|
742
|
-
saveCategories:
|
|
743
|
-
deleteBoard:
|
|
744
|
-
deleteCategory:
|
|
745
|
-
DEFAULT_BOARDS:
|
|
746
|
-
DEFAULT_CATEGORIES:
|
|
761
|
+
saveCategory: te,
|
|
762
|
+
saveBoards: L,
|
|
763
|
+
saveCategories: ne,
|
|
764
|
+
deleteBoard: R,
|
|
765
|
+
deleteCategory: B,
|
|
766
|
+
DEFAULT_BOARDS: Pt,
|
|
767
|
+
DEFAULT_CATEGORIES: Ft
|
|
747
768
|
};
|
|
748
769
|
}
|
|
749
770
|
//#endregion
|
|
750
771
|
//#region src/composables/useMemiBoardPosts.ts
|
|
751
|
-
|
|
772
|
+
var zt = /* @__PURE__ */ new Map();
|
|
773
|
+
function Bt(e) {
|
|
752
774
|
if (!e || typeof e != "object") return !1;
|
|
753
775
|
let t = "code" in e ? String(e.code) : "";
|
|
754
776
|
return t === "permission-denied" || t === "firestore/permission-denied";
|
|
755
777
|
}
|
|
756
|
-
function
|
|
778
|
+
function Vt(e) {
|
|
757
779
|
let t = N(e)?.trim();
|
|
758
780
|
if (!t) throw Error("[memi-board] boardId 가 필요합니다.");
|
|
759
781
|
return t;
|
|
760
782
|
}
|
|
761
|
-
function
|
|
762
|
-
let n = Q(), r = se(), { isBoardHidden: i, getBoard: s } =
|
|
783
|
+
function Ht(e) {
|
|
784
|
+
let n = Q(), r = se(), { isBoardHidden: i, getBoard: s } = Rt(), c = () => h(), l = () => Vt(e), u = () => o(n, c()), d = (e) => t(n, c(), e), f = (e) => a(n, c(), e);
|
|
763
785
|
function p() {
|
|
764
786
|
return !i(l());
|
|
765
787
|
}
|
|
@@ -767,7 +789,7 @@ function Lt(e) {
|
|
|
767
789
|
return s(l())?.editorType === "image";
|
|
768
790
|
}
|
|
769
791
|
function g(e) {
|
|
770
|
-
let t = m(), n =
|
|
792
|
+
let t = m(), n = Dt(e.content), r = Ot(e.content, e.attachments);
|
|
771
793
|
if (t) {
|
|
772
794
|
if (!r) throw Error("사진을 올려 주세요.");
|
|
773
795
|
return;
|
|
@@ -776,12 +798,12 @@ function Lt(e) {
|
|
|
776
798
|
if (!e.title?.trim()) throw Error("제목을 입력해 주세요.");
|
|
777
799
|
}
|
|
778
800
|
function _() {
|
|
779
|
-
return
|
|
801
|
+
return te(u()).id;
|
|
780
802
|
}
|
|
781
803
|
async function v(e = {}) {
|
|
782
|
-
let t = e.pageSize ?? 20, n = [
|
|
783
|
-
e.publicOnly !== !1 && n.push(
|
|
784
|
-
let r = await
|
|
804
|
+
let t = e.pageSize ?? 20, n = [Y("boardId", "==", l()), Y("isPublished", "==", !0)];
|
|
805
|
+
e.publicOnly !== !1 && n.push(Y("listed", "==", !0)), n.push(U("createdAt", "desc")), e.cursor && n.push(q(e.cursor)), n.push(V(t + 1));
|
|
806
|
+
let r = await z(W(u(), ...n)), i = r.docs.slice(0, t);
|
|
785
807
|
return {
|
|
786
808
|
posts: i.map((e) => ({
|
|
787
809
|
id: e.id,
|
|
@@ -792,7 +814,7 @@ function Lt(e) {
|
|
|
792
814
|
};
|
|
793
815
|
}
|
|
794
816
|
async function y(e) {
|
|
795
|
-
let [t, n] = await Promise.all([
|
|
817
|
+
let [t, n] = await Promise.all([R(d(e)), R(f(e))]);
|
|
796
818
|
return t.exists() ? {
|
|
797
819
|
id: t.id,
|
|
798
820
|
...t.data(),
|
|
@@ -801,7 +823,7 @@ function Lt(e) {
|
|
|
801
823
|
}
|
|
802
824
|
async function x(e) {
|
|
803
825
|
try {
|
|
804
|
-
let t = (await
|
|
826
|
+
let t = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", e.trim()), V(1)))).docs[0];
|
|
805
827
|
if (!t) return { status: "not-found" };
|
|
806
828
|
try {
|
|
807
829
|
let e = await y(t.id);
|
|
@@ -810,30 +832,54 @@ function Lt(e) {
|
|
|
810
832
|
post: e
|
|
811
833
|
} : { status: "not-found" };
|
|
812
834
|
} catch (e) {
|
|
813
|
-
return
|
|
835
|
+
return Bt(e) ? { status: "permission-denied" } : {
|
|
814
836
|
status: "error",
|
|
815
837
|
message: e instanceof Error ? e.message : String(e)
|
|
816
838
|
};
|
|
817
839
|
}
|
|
818
840
|
} catch (e) {
|
|
819
|
-
return
|
|
841
|
+
return Bt(e) ? { status: "permission-denied" } : {
|
|
820
842
|
status: "error",
|
|
821
843
|
message: e instanceof Error ? e.message : String(e)
|
|
822
844
|
};
|
|
823
845
|
}
|
|
824
846
|
}
|
|
825
847
|
async function S(e) {
|
|
848
|
+
let t = e.trim(), n = zt.get(`${l()}/${t}`);
|
|
849
|
+
if (n) return {
|
|
850
|
+
status: "ok",
|
|
851
|
+
id: n
|
|
852
|
+
};
|
|
853
|
+
try {
|
|
854
|
+
let e = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", t), V(1)))).docs[0];
|
|
855
|
+
return e ? {
|
|
856
|
+
status: "ok",
|
|
857
|
+
id: e.id
|
|
858
|
+
} : { status: "not-found" };
|
|
859
|
+
} catch (e) {
|
|
860
|
+
return Bt(e) ? { status: "permission-denied" } : {
|
|
861
|
+
status: "error",
|
|
862
|
+
message: e instanceof Error ? e.message : String(e)
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
async function C(e) {
|
|
867
|
+
let t = b(e.trim()) || "post", n = t, r = 1;
|
|
868
|
+
for (; !(await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", n), V(1)))).empty;) r++, n = `${t}-${r}`;
|
|
869
|
+
return n;
|
|
870
|
+
}
|
|
871
|
+
async function w(e) {
|
|
826
872
|
if (!e.createdAt) return {
|
|
827
873
|
previous: null,
|
|
828
874
|
next: null
|
|
829
875
|
};
|
|
830
876
|
try {
|
|
831
877
|
let t = [
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
...e.listed === !1 ? [] : [
|
|
835
|
-
|
|
836
|
-
], [n, r] = await Promise.all([
|
|
878
|
+
Y("boardId", "==", l()),
|
|
879
|
+
Y("isPublished", "==", !0),
|
|
880
|
+
...e.listed === !1 ? [] : [Y("listed", "==", !0)],
|
|
881
|
+
U("createdAt", "desc")
|
|
882
|
+
], [n, r] = await Promise.all([z(W(u(), ...t, q(e.createdAt), V(1))), z(W(u(), ...t, ne(e.createdAt), re(1)))]), i = (e) => {
|
|
837
883
|
let t = e.docs[0];
|
|
838
884
|
return t ? {
|
|
839
885
|
id: t.id,
|
|
@@ -851,43 +897,36 @@ function Lt(e) {
|
|
|
851
897
|
};
|
|
852
898
|
}
|
|
853
899
|
}
|
|
854
|
-
async function
|
|
900
|
+
async function T(e) {
|
|
855
901
|
g(e);
|
|
856
|
-
let t = e.postId || _(),
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
let t = b(i) || "post";
|
|
861
|
-
r = t;
|
|
862
|
-
let n = 1;
|
|
863
|
-
for (; !(await B(G(u(), X("boardId", "==", l()), X("slug", "==", r), H(1)))).empty;) n++, r = `${t}-${n}`;
|
|
864
|
-
}
|
|
865
|
-
let a = kt(e.content, e.attachments), o = p();
|
|
866
|
-
return await q(d(t), {
|
|
902
|
+
let t = e.postId || _(), r = m(), i, a;
|
|
903
|
+
r ? (i = t, a = Et(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await C(a));
|
|
904
|
+
let o = Nt(e.content, e.attachments), s = p(), c = X(n);
|
|
905
|
+
return c.set(d(t), {
|
|
867
906
|
boardId: l(),
|
|
868
|
-
slug:
|
|
869
|
-
title:
|
|
870
|
-
...
|
|
907
|
+
slug: i,
|
|
908
|
+
title: a,
|
|
909
|
+
...o,
|
|
871
910
|
tags: e.tags ?? [],
|
|
872
911
|
attachments: e.attachments ?? [],
|
|
873
912
|
commentCount: 0,
|
|
874
913
|
likeCount: 0,
|
|
875
914
|
viewCount: 0,
|
|
876
|
-
listed:
|
|
915
|
+
listed: s,
|
|
877
916
|
isPublished: !1,
|
|
878
917
|
authorUid: e.authorUid,
|
|
879
918
|
authorName: e.authorName,
|
|
880
919
|
authorPhoto: e.authorPhoto,
|
|
881
920
|
moderationStatus: "approved",
|
|
882
921
|
moderationModel: e.moderationModel ?? null,
|
|
883
|
-
createdAt:
|
|
884
|
-
updatedAt:
|
|
885
|
-
}),
|
|
922
|
+
createdAt: G(),
|
|
923
|
+
updatedAt: G()
|
|
924
|
+
}), c.set(f(t), { content: e.content }), await c.commit(), zt.set(`${l()}/${i}`, t), i;
|
|
886
925
|
}
|
|
887
|
-
async function
|
|
926
|
+
async function E(e, t) {
|
|
888
927
|
g(t);
|
|
889
|
-
let n = m() ?
|
|
890
|
-
await Promise.all([
|
|
928
|
+
let n = m() ? Et(t.content) : t.title.trim(), r = Nt(t.content, t.attachments), i = p();
|
|
929
|
+
await Promise.all([J(d(e), {
|
|
891
930
|
title: n,
|
|
892
931
|
...r,
|
|
893
932
|
previewImage: r.previewImage ? r.previewImage : I(),
|
|
@@ -895,34 +934,37 @@ function Lt(e) {
|
|
|
895
934
|
tags: t.tags ?? [],
|
|
896
935
|
listed: i,
|
|
897
936
|
attachments: t.attachments ?? [],
|
|
898
|
-
updatedAt:
|
|
899
|
-
}),
|
|
937
|
+
updatedAt: G()
|
|
938
|
+
}), K(f(e), { content: t.content }, { merge: !0 })]);
|
|
900
939
|
}
|
|
901
|
-
async function
|
|
902
|
-
await
|
|
940
|
+
async function D(e) {
|
|
941
|
+
await J(d(e), {
|
|
903
942
|
isPublished: !0,
|
|
904
|
-
publishedAt:
|
|
905
|
-
updatedAt:
|
|
943
|
+
publishedAt: G(),
|
|
944
|
+
updatedAt: G()
|
|
906
945
|
});
|
|
907
946
|
}
|
|
908
|
-
async function
|
|
909
|
-
await
|
|
947
|
+
async function O(e) {
|
|
948
|
+
await wt(n, _e(r), c(), e);
|
|
949
|
+
for (let [t, n] of zt) n === e && zt.delete(t);
|
|
910
950
|
}
|
|
911
951
|
return {
|
|
912
952
|
createPostId: _,
|
|
913
953
|
getPosts: v,
|
|
914
954
|
getPost: y,
|
|
915
955
|
getPostBySlug: x,
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
956
|
+
resolvePostIdBySlug: S,
|
|
957
|
+
resolveUniqueSlug: C,
|
|
958
|
+
getAdjacentPosts: w,
|
|
959
|
+
createPost: T,
|
|
960
|
+
updatePost: E,
|
|
961
|
+
publishPost: D,
|
|
962
|
+
deletePost: O
|
|
921
963
|
};
|
|
922
964
|
}
|
|
923
|
-
var
|
|
924
|
-
function
|
|
925
|
-
let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = ct(), s = () => h(), c = t.pageSize ??
|
|
965
|
+
var Ut = 10;
|
|
966
|
+
function Wt(e, t = {}) {
|
|
967
|
+
let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = ct(), s = () => h(), c = t.pageSize ?? Ut, l = A(() => i.value?.uid ?? ""), u = A(() => Vt(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;
|
|
926
968
|
function T(e) {
|
|
927
969
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
928
970
|
}
|
|
@@ -936,11 +978,11 @@ function zt(e, t = {}) {
|
|
|
936
978
|
return [...e.values()].sort((e, t) => T(t) - T(e) || String(t.id).localeCompare(String(e.id)));
|
|
937
979
|
});
|
|
938
980
|
function D() {
|
|
939
|
-
let e = [
|
|
940
|
-
return f.value && e.push(
|
|
981
|
+
let e = [Y("boardId", "==", u.value), Y("isPublished", "==", !0)];
|
|
982
|
+
return f.value && e.push(Y("listed", "==", !0)), e;
|
|
941
983
|
}
|
|
942
984
|
function O() {
|
|
943
|
-
C?.(), C =
|
|
985
|
+
C?.(), C = H(W(d(), ...D(), U("createdAt", "desc"), U(L(), "desc"), V(c)), (e) => {
|
|
944
986
|
p.value = e.docs.map((e) => ({
|
|
945
987
|
id: e.id,
|
|
946
988
|
...e.data()
|
|
@@ -956,7 +998,7 @@ function zt(e, t = {}) {
|
|
|
956
998
|
g.value = [];
|
|
957
999
|
return;
|
|
958
1000
|
}
|
|
959
|
-
w =
|
|
1001
|
+
w = H(W(d(), Y("boardId", "==", u.value), Y("authorUid", "==", e), Y("isPublished", "==", !1), U("createdAt", "desc"), V(20)), (e) => {
|
|
960
1002
|
g.value = e.docs.map((e) => ({
|
|
961
1003
|
id: e.id,
|
|
962
1004
|
...e.data()
|
|
@@ -971,11 +1013,11 @@ function zt(e, t = {}) {
|
|
|
971
1013
|
try {
|
|
972
1014
|
let e = S ?? x, t = [
|
|
973
1015
|
...D(),
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
...e ? [
|
|
977
|
-
|
|
978
|
-
], n = await
|
|
1016
|
+
U("createdAt", "desc"),
|
|
1017
|
+
U(L(), "desc"),
|
|
1018
|
+
...e ? [q(e)] : [],
|
|
1019
|
+
V(c + 1)
|
|
1020
|
+
], n = await z(W(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
|
|
979
1021
|
id: e.id,
|
|
980
1022
|
...e.data()
|
|
981
1023
|
})), a = new Set([...m.value, ...p.value].map((e) => e.id));
|
|
@@ -1005,8 +1047,8 @@ function zt(e, t = {}) {
|
|
|
1005
1047
|
loadMore: ee
|
|
1006
1048
|
};
|
|
1007
1049
|
}
|
|
1008
|
-
function
|
|
1009
|
-
let r = Q(), i = () => h(), o = A(() =>
|
|
1050
|
+
function Gt(e, n) {
|
|
1051
|
+
let r = Q(), i = () => h(), o = A(() => Vt(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);
|
|
1010
1052
|
return {
|
|
1011
1053
|
post: A(() => !u.value || u.value.boardId !== o.value ? null : {
|
|
1012
1054
|
...u.value,
|
|
@@ -1018,9 +1060,9 @@ function Bt(e, n) {
|
|
|
1018
1060
|
}
|
|
1019
1061
|
//#endregion
|
|
1020
1062
|
//#region src/composables/useMemiBoardUserPosts.ts
|
|
1021
|
-
var
|
|
1022
|
-
function
|
|
1023
|
-
let n = Q(), r = () => h(), i = () => o(n, r()), a = t.pageSize ??
|
|
1063
|
+
var Kt = 10;
|
|
1064
|
+
function qt(e, t = {}) {
|
|
1065
|
+
let n = Q(), r = () => h(), i = () => o(n, r()), a = t.pageSize ?? Kt, s = A(() => N(e)?.trim() || ""), c = M([]), l = M([]), u = M(!0), d = M(!0), f = M(!1), p = M(""), m = null, g = null, _;
|
|
1024
1066
|
function v(e) {
|
|
1025
1067
|
return {
|
|
1026
1068
|
id: e.id,
|
|
@@ -1037,9 +1079,9 @@ function Ht(e, t = {}) {
|
|
|
1037
1079
|
});
|
|
1038
1080
|
function x() {
|
|
1039
1081
|
return [
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1082
|
+
Y("authorUid", "==", s.value),
|
|
1083
|
+
Y("isPublished", "==", !0),
|
|
1084
|
+
Y("listed", "==", !0)
|
|
1043
1085
|
];
|
|
1044
1086
|
}
|
|
1045
1087
|
function S() {
|
|
@@ -1047,7 +1089,7 @@ function Ht(e, t = {}) {
|
|
|
1047
1089
|
u.value = !1;
|
|
1048
1090
|
return;
|
|
1049
1091
|
}
|
|
1050
|
-
_ =
|
|
1092
|
+
_ = H(W(i(), ...x(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
|
|
1051
1093
|
c.value = e.docs.map(v), m = e.docs.at(-1) ?? null, g || (d.value = e.docs.length >= a), u.value = !1;
|
|
1052
1094
|
}, (e) => {
|
|
1053
1095
|
console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
|
|
@@ -1059,11 +1101,11 @@ function Ht(e, t = {}) {
|
|
|
1059
1101
|
try {
|
|
1060
1102
|
let e = g ?? m, t = [
|
|
1061
1103
|
...x(),
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
...e ? [
|
|
1065
|
-
|
|
1066
|
-
], n = await
|
|
1104
|
+
U("createdAt", "desc"),
|
|
1105
|
+
U(L(), "desc"),
|
|
1106
|
+
...e ? [q(e)] : [],
|
|
1107
|
+
V(a + 1)
|
|
1108
|
+
], n = await z(W(i(), ...t)), r = n.docs.slice(0, a), o = r.map(v), s = new Set([...l.value, ...c.value].map((e) => e.id));
|
|
1067
1109
|
l.value.push(...o.filter((e) => !s.has(e.id))), g = r.at(-1) ?? g, d.value = n.docs.length > a;
|
|
1068
1110
|
} catch (e) {
|
|
1069
1111
|
p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
|
|
@@ -1086,9 +1128,9 @@ function Ht(e, t = {}) {
|
|
|
1086
1128
|
}
|
|
1087
1129
|
//#endregion
|
|
1088
1130
|
//#region src/composables/useMemiBoardUserComments.ts
|
|
1089
|
-
var
|
|
1090
|
-
function
|
|
1091
|
-
let n = Q(), r = () => h(), i = () => E(n, r()), a = t.pageSize ??
|
|
1131
|
+
var Jt = 10;
|
|
1132
|
+
function Yt(e, t = {}) {
|
|
1133
|
+
let n = Q(), r = () => h(), i = () => E(n, r()), a = t.pageSize ?? Jt, 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
1134
|
function _(e) {
|
|
1093
1135
|
return {
|
|
1094
1136
|
id: e.id,
|
|
@@ -1104,14 +1146,14 @@ function Wt(e, t = {}) {
|
|
|
1104
1146
|
return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
|
|
1105
1147
|
});
|
|
1106
1148
|
function b() {
|
|
1107
|
-
return [
|
|
1149
|
+
return [Y("authorUid", "==", o.value), Y("listed", "==", !0)];
|
|
1108
1150
|
}
|
|
1109
1151
|
function x() {
|
|
1110
1152
|
if (g?.(), !o.value) {
|
|
1111
1153
|
l.value = !1;
|
|
1112
1154
|
return;
|
|
1113
1155
|
}
|
|
1114
|
-
g =
|
|
1156
|
+
g = H(W(i(), ...b(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
|
|
1115
1157
|
s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
|
|
1116
1158
|
}, (e) => {
|
|
1117
1159
|
console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
@@ -1123,11 +1165,11 @@ function Wt(e, t = {}) {
|
|
|
1123
1165
|
try {
|
|
1124
1166
|
let e = m ?? p, t = [
|
|
1125
1167
|
...b(),
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
...e ? [
|
|
1129
|
-
|
|
1130
|
-
], n = await
|
|
1168
|
+
U("createdAt", "desc"),
|
|
1169
|
+
U(L(), "desc"),
|
|
1170
|
+
...e ? [q(e)] : [],
|
|
1171
|
+
V(a + 1)
|
|
1172
|
+
], n = await z(W(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1131
1173
|
c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
|
|
1132
1174
|
} catch (e) {
|
|
1133
1175
|
f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
|
|
@@ -1150,11 +1192,11 @@ function Wt(e, t = {}) {
|
|
|
1150
1192
|
}
|
|
1151
1193
|
//#endregion
|
|
1152
1194
|
//#region src/composables/useMemiBoardCommentFeed.ts
|
|
1153
|
-
var
|
|
1154
|
-
function
|
|
1195
|
+
var Xt = 10;
|
|
1196
|
+
function Zt(e = "latest", t = {}) {
|
|
1155
1197
|
let n = Q(), r = () => h(), i = () => E(n, r()), a = A(() => {
|
|
1156
1198
|
let e = Math.floor(Number(N(t.pageSize)));
|
|
1157
|
-
return Number.isFinite(e) && e > 0 ? e :
|
|
1199
|
+
return Number.isFinite(e) && e > 0 ? e : Xt;
|
|
1158
1200
|
}), 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
1201
|
function _(e) {
|
|
1160
1202
|
return {
|
|
@@ -1179,18 +1221,18 @@ function Kt(e = "latest", t = {}) {
|
|
|
1179
1221
|
});
|
|
1180
1222
|
function x() {
|
|
1181
1223
|
return o.value === "likes" ? [
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1224
|
+
Y("listed", "==", !0),
|
|
1225
|
+
U("likeCount", "desc"),
|
|
1226
|
+
U("createdAt", "desc"),
|
|
1227
|
+
U(L(), "desc")
|
|
1186
1228
|
] : [
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1229
|
+
Y("listed", "==", !0),
|
|
1230
|
+
U("createdAt", "desc"),
|
|
1231
|
+
U(L(), "desc")
|
|
1190
1232
|
];
|
|
1191
1233
|
}
|
|
1192
1234
|
function S() {
|
|
1193
|
-
g?.(), g =
|
|
1235
|
+
g?.(), g = H(W(i(), ...x(), V(a.value)), (e) => {
|
|
1194
1236
|
s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
|
|
1195
1237
|
}, (e) => {
|
|
1196
1238
|
console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
|
|
@@ -1200,7 +1242,7 @@ function Kt(e = "latest", t = {}) {
|
|
|
1200
1242
|
if (!(d.value || !u.value || l.value)) {
|
|
1201
1243
|
d.value = !0, f.value = "";
|
|
1202
1244
|
try {
|
|
1203
|
-
let e = m ?? p, t = await
|
|
1245
|
+
let e = m ?? p, t = await z(W(i(), ...x(), ...e ? [q(e)] : [], V(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
|
|
1204
1246
|
c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
|
|
1205
1247
|
} catch (e) {
|
|
1206
1248
|
f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
|
|
@@ -1224,9 +1266,9 @@ function Kt(e = "latest", t = {}) {
|
|
|
1224
1266
|
}
|
|
1225
1267
|
//#endregion
|
|
1226
1268
|
//#region src/composables/useMemiBoardAuthorMemo.ts
|
|
1227
|
-
var
|
|
1269
|
+
var Qt = 100, $t = /* @__PURE__ */ new Map();
|
|
1228
1270
|
function $(e) {
|
|
1229
|
-
let t =
|
|
1271
|
+
let t = $t.get(e);
|
|
1230
1272
|
return t || (t = ee({
|
|
1231
1273
|
text: "",
|
|
1232
1274
|
sentiment: null,
|
|
@@ -1234,9 +1276,9 @@ function $(e) {
|
|
|
1234
1276
|
pending: !1,
|
|
1235
1277
|
saving: !1,
|
|
1236
1278
|
error: ""
|
|
1237
|
-
}),
|
|
1279
|
+
}), $t.set(e, t)), t;
|
|
1238
1280
|
}
|
|
1239
|
-
function
|
|
1281
|
+
function en(e) {
|
|
1240
1282
|
let t = Q(), n = () => h(), { user: r } = ct(), i = A(() => N(e)), a = A(() => `${r.value?.uid ?? ""}:${i.value}`), o = A(() => {
|
|
1241
1283
|
let e = r.value?.uid, a = i.value;
|
|
1242
1284
|
return !e || !a ? null : f(t, n(), e, a);
|
|
@@ -1252,7 +1294,7 @@ function Yt(e) {
|
|
|
1252
1294
|
let t = $(a.value);
|
|
1253
1295
|
t.pending = !0, t.error = "";
|
|
1254
1296
|
try {
|
|
1255
|
-
let n = (await
|
|
1297
|
+
let n = (await R(e)).data();
|
|
1256
1298
|
t.text = n ? n.text ?? "" : "", t.sentiment = n ? n.sentiment ?? null : null, t.loaded = !0;
|
|
1257
1299
|
} catch (e) {
|
|
1258
1300
|
t.error = e.message || String(e), console.error("[memi-board:authorMemo] load failed", e);
|
|
@@ -1268,10 +1310,10 @@ function Yt(e) {
|
|
|
1268
1310
|
let i = $(a.value);
|
|
1269
1311
|
i.saving = !0, i.error = "";
|
|
1270
1312
|
try {
|
|
1271
|
-
await
|
|
1313
|
+
await K(n, {
|
|
1272
1314
|
text: r,
|
|
1273
1315
|
sentiment: t,
|
|
1274
|
-
updatedAt:
|
|
1316
|
+
updatedAt: G()
|
|
1275
1317
|
}), i.text = r, i.sentiment = t, i.loaded = !0;
|
|
1276
1318
|
} catch (e) {
|
|
1277
1319
|
throw i.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
|
|
@@ -1306,15 +1348,15 @@ function Yt(e) {
|
|
|
1306
1348
|
}
|
|
1307
1349
|
//#endregion
|
|
1308
1350
|
//#region src/composables/useMemiBoardComments.ts
|
|
1309
|
-
var
|
|
1310
|
-
function
|
|
1351
|
+
var tn = 10, nn = 5, rn = 1e3;
|
|
1352
|
+
function an(e) {
|
|
1311
1353
|
let t = e.trim();
|
|
1312
1354
|
if (!t) throw Error("댓글 내용을 입력해 주세요.");
|
|
1313
|
-
if (t.length > 1e3) throw Error(`댓글은 ${
|
|
1355
|
+
if (t.length > 1e3) throw Error(`댓글은 ${rn.toLocaleString()}자까지 작성할 수 있습니다.`);
|
|
1314
1356
|
return t;
|
|
1315
1357
|
}
|
|
1316
|
-
function
|
|
1317
|
-
let i = Q(), a = () => h(), { isBoardHidden: o } =
|
|
1358
|
+
function on(e, n, r = {}) {
|
|
1359
|
+
let i = Q(), a = () => h(), { isBoardHidden: o } = Rt(), 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;
|
|
1318
1360
|
function C(e) {
|
|
1319
1361
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1320
1362
|
}
|
|
@@ -1331,7 +1373,7 @@ function en(e, n, r = {}) {
|
|
|
1331
1373
|
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) {
|
|
1332
1374
|
m.value = !0, y.value = !0;
|
|
1333
1375
|
try {
|
|
1334
|
-
let t =
|
|
1376
|
+
let t = z(W(c(), Y("postId", "==", e), U("createdAt", "desc"), U(L(), "desc")));
|
|
1335
1377
|
if (await Promise.all([t.then((t) => {
|
|
1336
1378
|
if (u.value !== e) return;
|
|
1337
1379
|
let n = t.docs.map((e) => ({
|
|
@@ -1346,7 +1388,7 @@ function en(e, n, r = {}) {
|
|
|
1346
1388
|
}
|
|
1347
1389
|
}, { immediate: !0 });
|
|
1348
1390
|
function T() {
|
|
1349
|
-
S?.(), S =
|
|
1391
|
+
S?.(), S = H(W(c(), Y("postId", "==", u.value), Y("parentId", "==", null), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
|
|
1350
1392
|
let t = new Map(f.value.map((e) => [e.id, e]));
|
|
1351
1393
|
for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
|
|
1352
1394
|
id: n.doc.id,
|
|
@@ -1362,17 +1404,17 @@ function en(e, n, r = {}) {
|
|
|
1362
1404
|
_.value = !0;
|
|
1363
1405
|
try {
|
|
1364
1406
|
let e = [
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
...b ? [
|
|
1370
|
-
|
|
1371
|
-
], t = await
|
|
1407
|
+
Y("postId", "==", u.value),
|
|
1408
|
+
Y("parentId", "==", null),
|
|
1409
|
+
U("createdAt", "asc"),
|
|
1410
|
+
U(L(), "asc"),
|
|
1411
|
+
...b ? [q(b)] : [],
|
|
1412
|
+
V(11)
|
|
1413
|
+
], t = await z(W(c(), ...e)), n = t.docs.slice(0, tn), r = n.map((e) => ({
|
|
1372
1414
|
id: e.id,
|
|
1373
1415
|
...e.data()
|
|
1374
1416
|
})), 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 <=
|
|
1417
|
+
g.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= tn && (v.value = !1, x = setTimeout(() => {
|
|
1376
1418
|
x = void 0, T();
|
|
1377
1419
|
}, 1e3));
|
|
1378
1420
|
} finally {
|
|
@@ -1384,7 +1426,7 @@ function en(e, n, r = {}) {
|
|
|
1384
1426
|
clearTimeout(x), S?.();
|
|
1385
1427
|
});
|
|
1386
1428
|
async function O(e) {
|
|
1387
|
-
let n =
|
|
1429
|
+
let n = an(e.body), r = X(i), o = te(c());
|
|
1388
1430
|
r.set(o, {
|
|
1389
1431
|
postId: u.value,
|
|
1390
1432
|
boardId: l.value,
|
|
@@ -1402,14 +1444,14 @@ function en(e, n, r = {}) {
|
|
|
1402
1444
|
replyCount: 0,
|
|
1403
1445
|
likeCount: 0,
|
|
1404
1446
|
isReply: !1,
|
|
1405
|
-
createdAt:
|
|
1406
|
-
updatedAt:
|
|
1407
|
-
}), r.update(t(i, a(), u.value), { commentCount:
|
|
1447
|
+
createdAt: G(),
|
|
1448
|
+
updatedAt: G()
|
|
1449
|
+
}), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
|
|
1408
1450
|
}
|
|
1409
1451
|
async function k(e) {
|
|
1410
|
-
let n =
|
|
1452
|
+
let n = an(e.body);
|
|
1411
1453
|
if (!e.parent.id) throw Error("답글 대상 댓글을 찾을 수 없습니다.");
|
|
1412
|
-
let r =
|
|
1454
|
+
let r = X(i), o = te(c()), f = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
|
|
1413
1455
|
if (!f) throw Error("댓글 스레드를 찾을 수 없습니다.");
|
|
1414
1456
|
let p = Math.min((e.parent.depth ?? 0) + 1, 2);
|
|
1415
1457
|
r.set(o, {
|
|
@@ -1429,28 +1471,28 @@ function en(e, n, r = {}) {
|
|
|
1429
1471
|
replyCount: 0,
|
|
1430
1472
|
likeCount: 0,
|
|
1431
1473
|
isReply: !0,
|
|
1432
|
-
createdAt:
|
|
1433
|
-
updatedAt:
|
|
1434
|
-
}), r.update(s(i, a(), f), { replyCount:
|
|
1474
|
+
createdAt: G(),
|
|
1475
|
+
updatedAt: G()
|
|
1476
|
+
}), r.update(s(i, a(), f), { replyCount: B(1) }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
|
|
1435
1477
|
}
|
|
1436
1478
|
async function ee(e) {
|
|
1437
1479
|
if (!e.id) return;
|
|
1438
1480
|
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error("답글이 있는 댓글은 현재 삭제할 수 없습니다.");
|
|
1439
|
-
await
|
|
1440
|
-
let n =
|
|
1441
|
-
n.delete(s(i, a(), e.id)), e.parentId && e.rootId && n.update(s(i, a(), e.rootId), { replyCount:
|
|
1481
|
+
await Ct(i, a(), e.id);
|
|
1482
|
+
let n = X(i);
|
|
1483
|
+
n.delete(s(i, a(), e.id)), e.parentId && e.rootId && n.update(s(i, a(), e.rootId), { replyCount: B(-1) }), n.update(t(i, a(), u.value), { commentCount: B(-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);
|
|
1442
1484
|
}
|
|
1443
1485
|
async function F(e, t) {
|
|
1444
|
-
let n =
|
|
1445
|
-
await
|
|
1486
|
+
let n = an(t);
|
|
1487
|
+
await J(s(i, a(), e), {
|
|
1446
1488
|
body: n,
|
|
1447
|
-
updatedAt:
|
|
1489
|
+
updatedAt: G()
|
|
1448
1490
|
});
|
|
1449
1491
|
}
|
|
1450
1492
|
async function I(e, t, n) {
|
|
1451
|
-
await
|
|
1493
|
+
await J(s(i, a(), e), {
|
|
1452
1494
|
isBlinded: t,
|
|
1453
|
-
moderatedAt:
|
|
1495
|
+
moderatedAt: G(),
|
|
1454
1496
|
moderatedBy: n
|
|
1455
1497
|
});
|
|
1456
1498
|
}
|
|
@@ -1467,13 +1509,13 @@ function en(e, n, r = {}) {
|
|
|
1467
1509
|
deleteComment: ee
|
|
1468
1510
|
};
|
|
1469
1511
|
}
|
|
1470
|
-
function
|
|
1512
|
+
function sn(e, t, n) {
|
|
1471
1513
|
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;
|
|
1472
1514
|
function p(e) {
|
|
1473
1515
|
return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
|
|
1474
1516
|
}
|
|
1475
1517
|
function m() {
|
|
1476
|
-
f ||=
|
|
1518
|
+
f ||= H(W(a(), Y("postId", "==", o), Y("rootId", "==", n), Y("isReply", "==", !0), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
|
|
1477
1519
|
let t = new Map(s.value.map((e) => [e.id, e]));
|
|
1478
1520
|
for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
|
|
1479
1521
|
id: n.doc.id,
|
|
@@ -1489,18 +1531,18 @@ function tn(e, t, n) {
|
|
|
1489
1531
|
c.value = !0;
|
|
1490
1532
|
try {
|
|
1491
1533
|
let e = [
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
...d ? [
|
|
1498
|
-
|
|
1499
|
-
], t = await
|
|
1534
|
+
Y("postId", "==", o),
|
|
1535
|
+
Y("rootId", "==", n),
|
|
1536
|
+
Y("isReply", "==", !0),
|
|
1537
|
+
U("createdAt", "asc"),
|
|
1538
|
+
U(L(), "asc"),
|
|
1539
|
+
...d ? [q(d)] : [],
|
|
1540
|
+
V(6)
|
|
1541
|
+
], t = await z(W(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0, nn), c = i.map((e) => ({
|
|
1500
1542
|
id: e.id,
|
|
1501
1543
|
...e.data()
|
|
1502
1544
|
})).filter((e) => !r.has(e.id));
|
|
1503
|
-
s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <=
|
|
1545
|
+
s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <= nn && (u.value = !1, m());
|
|
1504
1546
|
} finally {
|
|
1505
1547
|
c.value = !1;
|
|
1506
1548
|
}
|
|
@@ -1523,8 +1565,8 @@ function tn(e, t, n) {
|
|
|
1523
1565
|
}
|
|
1524
1566
|
//#endregion
|
|
1525
1567
|
//#region src/composables/useMemiBoardLikes.ts
|
|
1526
|
-
function
|
|
1527
|
-
let r = () => h(), i = Q(), a =
|
|
1568
|
+
function cn(e, n) {
|
|
1569
|
+
let r = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
|
|
1528
1570
|
function l(e) {
|
|
1529
1571
|
return k(i, r(), n, e);
|
|
1530
1572
|
}
|
|
@@ -1533,7 +1575,7 @@ function nn(e, n) {
|
|
|
1533
1575
|
o.value = !1;
|
|
1534
1576
|
return;
|
|
1535
1577
|
}
|
|
1536
|
-
c =
|
|
1578
|
+
c = H(l(e.uid), (e) => {
|
|
1537
1579
|
o.value = e.exists();
|
|
1538
1580
|
}, (e) => {
|
|
1539
1581
|
console.error("[memi-board:likes] onSnapshot failed", e);
|
|
@@ -1546,12 +1588,12 @@ function nn(e, n) {
|
|
|
1546
1588
|
s.value = !0;
|
|
1547
1589
|
try {
|
|
1548
1590
|
let a = l(c), o = t(i, r(), n);
|
|
1549
|
-
return await
|
|
1591
|
+
return await ie(i, async (t) => (await t.get(a)).exists() ? (t.delete(a), t.update(o, { likeCount: B(-1) }), !1) : (t.set(a, {
|
|
1550
1592
|
uid: c,
|
|
1551
1593
|
postId: n,
|
|
1552
1594
|
boardId: e,
|
|
1553
|
-
createdAt:
|
|
1554
|
-
}), t.update(o, { likeCount:
|
|
1595
|
+
createdAt: G()
|
|
1596
|
+
}), t.update(o, { likeCount: B(1) }), !0));
|
|
1555
1597
|
} finally {
|
|
1556
1598
|
s.value = !1;
|
|
1557
1599
|
}
|
|
@@ -1562,11 +1604,11 @@ function nn(e, n) {
|
|
|
1562
1604
|
toggleLike: u
|
|
1563
1605
|
};
|
|
1564
1606
|
}
|
|
1565
|
-
var
|
|
1566
|
-
function
|
|
1567
|
-
let n = () => h(), r = Q(), i =
|
|
1607
|
+
var ln = Symbol.for("memi-board:comment-likes");
|
|
1608
|
+
function un(e, t) {
|
|
1609
|
+
let n = () => h(), r = Q(), i = Z(), a = A(() => N(e)), o = A(() => N(t)), c = M(/* @__PURE__ */ new Set()), l = M(null), u;
|
|
1568
1610
|
P([i, o], ([e, t]) => {
|
|
1569
|
-
u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u =
|
|
1611
|
+
u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = H(W(O(r, n()), Y("uid", "==", e.uid), Y("postId", "==", t), Y("target", "==", "comment")), (e) => {
|
|
1570
1612
|
let t = /* @__PURE__ */ new Set();
|
|
1571
1613
|
for (let n of e.docs) {
|
|
1572
1614
|
let e = n.data().commentId;
|
|
@@ -1590,7 +1632,7 @@ function an(e, t) {
|
|
|
1590
1632
|
if (l.value) return d(e);
|
|
1591
1633
|
l.value = e;
|
|
1592
1634
|
try {
|
|
1593
|
-
let i = k(r, n(), e, t), l = s(r, n(), e), u = await
|
|
1635
|
+
let i = k(r, n(), e, t), l = s(r, n(), e), u = await ie(r, async (n) => {
|
|
1594
1636
|
let r = await n.get(i), s = await n.get(l);
|
|
1595
1637
|
if (!s.exists()) throw Error("댓글을 찾을 수 없습니다.");
|
|
1596
1638
|
let c = Number(s.data()?.likeCount ?? 0);
|
|
@@ -1600,7 +1642,7 @@ function an(e, t) {
|
|
|
1600
1642
|
boardId: a.value,
|
|
1601
1643
|
commentId: e,
|
|
1602
1644
|
target: "comment",
|
|
1603
|
-
createdAt:
|
|
1645
|
+
createdAt: G()
|
|
1604
1646
|
}), n.update(l, { likeCount: c + 1 }), !0);
|
|
1605
1647
|
}), d = new Set(c.value);
|
|
1606
1648
|
return u ? d.add(e) : d.delete(e), c.value = d, u;
|
|
@@ -1616,7 +1658,7 @@ function an(e, t) {
|
|
|
1616
1658
|
}
|
|
1617
1659
|
//#endregion
|
|
1618
1660
|
//#region src/composables/useMemiBoardReports.ts
|
|
1619
|
-
var
|
|
1661
|
+
var dn = 200, fn = [
|
|
1620
1662
|
{
|
|
1621
1663
|
value: "spam",
|
|
1622
1664
|
label: "스팸·광고"
|
|
@@ -1638,17 +1680,17 @@ var on = 200, sn = [
|
|
|
1638
1680
|
label: "기타"
|
|
1639
1681
|
}
|
|
1640
1682
|
];
|
|
1641
|
-
function
|
|
1642
|
-
return
|
|
1683
|
+
function pn(e) {
|
|
1684
|
+
return fn.find((t) => t.value === e)?.label || e || "신고";
|
|
1643
1685
|
}
|
|
1644
|
-
function
|
|
1645
|
-
let n = () => h(), i = Q(), a =
|
|
1686
|
+
function mn(e, t) {
|
|
1687
|
+
let n = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
|
|
1646
1688
|
P(a, (e) => {
|
|
1647
1689
|
if (c?.(), c = void 0, !e) {
|
|
1648
1690
|
o.value = !1;
|
|
1649
1691
|
return;
|
|
1650
1692
|
}
|
|
1651
|
-
c =
|
|
1693
|
+
c = H(r(i, n(), t, e.uid), (e) => {
|
|
1652
1694
|
o.value = e.exists();
|
|
1653
1695
|
}, (e) => {
|
|
1654
1696
|
console.error("[memi-board:reports] onSnapshot failed", e);
|
|
@@ -1659,13 +1701,13 @@ function ln(e, t) {
|
|
|
1659
1701
|
if (!l) throw Error("로그인이 필요합니다.");
|
|
1660
1702
|
if (s.value) return;
|
|
1661
1703
|
if (c.authorUid && c.authorUid === l) throw Error("자신의 글은 신고할 수 없습니다.");
|
|
1662
|
-
let u =
|
|
1704
|
+
let u = fn.some((e) => e.value === c.reason) ? c.reason : null;
|
|
1663
1705
|
if (!u) throw Error("신고 사유를 선택해 주세요.");
|
|
1664
1706
|
let d = (c.detail || "").trim();
|
|
1665
1707
|
if (d.length > 200) throw Error("자세한 내용은 200자까지입니다.");
|
|
1666
1708
|
s.value = !0;
|
|
1667
1709
|
try {
|
|
1668
|
-
await
|
|
1710
|
+
await K(r(i, n(), t, l), {
|
|
1669
1711
|
uid: l,
|
|
1670
1712
|
target: "post",
|
|
1671
1713
|
postId: t,
|
|
@@ -1676,7 +1718,7 @@ function ln(e, t) {
|
|
|
1676
1718
|
postTitle: (c.postTitle || "").trim().slice(0, 200),
|
|
1677
1719
|
authorUid: c.authorUid || "",
|
|
1678
1720
|
authorName: c.authorName ?? null,
|
|
1679
|
-
createdAt:
|
|
1721
|
+
createdAt: G()
|
|
1680
1722
|
}), o.value = !0;
|
|
1681
1723
|
} finally {
|
|
1682
1724
|
s.value = !1;
|
|
@@ -1688,9 +1730,9 @@ function ln(e, t) {
|
|
|
1688
1730
|
submitReport: l
|
|
1689
1731
|
};
|
|
1690
1732
|
}
|
|
1691
|
-
var
|
|
1692
|
-
function
|
|
1693
|
-
let t = () => h(), n = Q(), { canManageContent: a, canManageBoard: o } = ct(), s = e.pageSize ??
|
|
1733
|
+
var hn = 20;
|
|
1734
|
+
function gn(e = {}) {
|
|
1735
|
+
let t = () => h(), n = Q(), { canManageContent: a, canManageBoard: o } = ct(), s = e.pageSize ?? hn, c = A(() => N(e.boardId)?.trim() || ""), l = M([]), u = M(!0), d = M(!1), f = M(!1), p = M(""), m = null, g;
|
|
1694
1736
|
function _(e) {
|
|
1695
1737
|
return {
|
|
1696
1738
|
id: e.id,
|
|
@@ -1703,8 +1745,8 @@ function dn(e = {}) {
|
|
|
1703
1745
|
return;
|
|
1704
1746
|
}
|
|
1705
1747
|
u.value = !0;
|
|
1706
|
-
let e = c.value ? [
|
|
1707
|
-
g =
|
|
1748
|
+
let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")];
|
|
1749
|
+
g = H(W(i(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), V(s)), (e) => {
|
|
1708
1750
|
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;
|
|
1709
1751
|
}, (e) => {
|
|
1710
1752
|
console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
|
|
@@ -1715,7 +1757,7 @@ function dn(e = {}) {
|
|
|
1715
1757
|
if (!d.value && f.value && m && a.value) {
|
|
1716
1758
|
d.value = !0, p.value = "";
|
|
1717
1759
|
try {
|
|
1718
|
-
let e = c.value ? [
|
|
1760
|
+
let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")], r = await z(W(i(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), q(m), V(s + 1))), a = r.docs.slice(0, s), u = new Set(l.value.map((e) => e.id));
|
|
1719
1761
|
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;
|
|
1720
1762
|
} catch (e) {
|
|
1721
1763
|
p.value = e.message || String(e);
|
|
@@ -1725,10 +1767,10 @@ function dn(e = {}) {
|
|
|
1725
1767
|
}
|
|
1726
1768
|
}
|
|
1727
1769
|
async function b(e, i) {
|
|
1728
|
-
e.id && o(e.boardId) && await
|
|
1770
|
+
e.id && o(e.boardId) && await J(r(n, t(), e.postId, e.uid), {
|
|
1729
1771
|
status: i,
|
|
1730
|
-
reviewedAt:
|
|
1731
|
-
reviewedBy:
|
|
1772
|
+
reviewedAt: G(),
|
|
1773
|
+
reviewedBy: Z().value?.uid || ""
|
|
1732
1774
|
});
|
|
1733
1775
|
}
|
|
1734
1776
|
return {
|
|
@@ -1744,7 +1786,7 @@ function dn(e = {}) {
|
|
|
1744
1786
|
}
|
|
1745
1787
|
//#endregion
|
|
1746
1788
|
//#region src/composables/useMemiBoardViews.ts
|
|
1747
|
-
function
|
|
1789
|
+
function _n() {
|
|
1748
1790
|
let e = () => h(), n = Q();
|
|
1749
1791
|
function r(t, n) {
|
|
1750
1792
|
let { postsCollection: r } = e();
|
|
@@ -1768,7 +1810,7 @@ function fn() {
|
|
|
1768
1810
|
if (c && l && !i(c, l)) {
|
|
1769
1811
|
a(c, l);
|
|
1770
1812
|
try {
|
|
1771
|
-
await
|
|
1813
|
+
await J(t(n, e(), l), { viewCount: B(1) });
|
|
1772
1814
|
} catch (e) {
|
|
1773
1815
|
try {
|
|
1774
1816
|
sessionStorage.removeItem(r(c, l));
|
|
@@ -1784,7 +1826,7 @@ function fn() {
|
|
|
1784
1826
|
}
|
|
1785
1827
|
//#endregion
|
|
1786
1828
|
//#region src/utils/moderation-prompt.ts
|
|
1787
|
-
var
|
|
1829
|
+
var vn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", yn = {
|
|
1788
1830
|
abuse: "욕설·비속어·모욕",
|
|
1789
1831
|
spam: "스팸·광고",
|
|
1790
1832
|
adult: "선정적·성인 내용",
|
|
@@ -1792,17 +1834,17 @@ var pn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
|
|
|
1792
1834
|
other: "부적절한 내용",
|
|
1793
1835
|
none: ""
|
|
1794
1836
|
};
|
|
1795
|
-
function
|
|
1837
|
+
function bn(e) {
|
|
1796
1838
|
if (e.via === "local" && e.localHit) {
|
|
1797
1839
|
let t = e.localHit.trim();
|
|
1798
1840
|
return t.length > 0 && t.length <= 12 ? `「${t}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.` : "욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.";
|
|
1799
1841
|
}
|
|
1800
1842
|
let t = (e.reason || "").trim();
|
|
1801
1843
|
if (t) return t;
|
|
1802
|
-
let n = e.category && e.category !== "none" ?
|
|
1844
|
+
let n = e.category && e.category !== "none" ? yn[e.category] || e.category : "";
|
|
1803
1845
|
return n ? `${n}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.` : "게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.";
|
|
1804
1846
|
}
|
|
1805
|
-
var
|
|
1847
|
+
var xn = [
|
|
1806
1848
|
"씨발",
|
|
1807
1849
|
"시발",
|
|
1808
1850
|
"시이발",
|
|
@@ -1828,10 +1870,10 @@ var gn = [
|
|
|
1828
1870
|
"bitch",
|
|
1829
1871
|
"asshole"
|
|
1830
1872
|
];
|
|
1831
|
-
function
|
|
1873
|
+
function Sn(e) {
|
|
1832
1874
|
return new RegExp(e.join("|"), "i");
|
|
1833
1875
|
}
|
|
1834
|
-
var
|
|
1876
|
+
var Cn = /* @__PURE__ */ new Set([
|
|
1835
1877
|
"none",
|
|
1836
1878
|
"abuse",
|
|
1837
1879
|
"spam",
|
|
@@ -1839,7 +1881,7 @@ var vn = /* @__PURE__ */ new Set([
|
|
|
1839
1881
|
"violence",
|
|
1840
1882
|
"other"
|
|
1841
1883
|
]);
|
|
1842
|
-
function
|
|
1884
|
+
function wn(e) {
|
|
1843
1885
|
let t = e.trim();
|
|
1844
1886
|
if (!t) return null;
|
|
1845
1887
|
let n;
|
|
@@ -1857,7 +1899,7 @@ function yn(e) {
|
|
|
1857
1899
|
if (typeof n != "object" || !n) return null;
|
|
1858
1900
|
let r = n;
|
|
1859
1901
|
if (typeof r.flagged != "boolean") return null;
|
|
1860
|
-
let i = typeof r.category == "string" &&
|
|
1902
|
+
let i = typeof r.category == "string" && Cn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
|
|
1861
1903
|
return {
|
|
1862
1904
|
flagged: r.flagged,
|
|
1863
1905
|
category: i,
|
|
@@ -1866,20 +1908,20 @@ function yn(e) {
|
|
|
1866
1908
|
}
|
|
1867
1909
|
//#endregion
|
|
1868
1910
|
//#region src/composables/useMemiBoardModeration.ts
|
|
1869
|
-
var
|
|
1911
|
+
var Tn = {
|
|
1870
1912
|
flagged: !1,
|
|
1871
1913
|
category: "none",
|
|
1872
1914
|
reason: "",
|
|
1873
1915
|
via: "empty"
|
|
1874
1916
|
};
|
|
1875
|
-
function
|
|
1876
|
-
let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a =
|
|
1917
|
+
function En() {
|
|
1918
|
+
let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = Sn([...xn, ...e.localBlocklist ?? []]);
|
|
1877
1919
|
function o(e) {
|
|
1878
1920
|
let t = e.match(a);
|
|
1879
1921
|
return t ? {
|
|
1880
1922
|
flagged: !0,
|
|
1881
1923
|
category: "abuse",
|
|
1882
|
-
reason:
|
|
1924
|
+
reason: bn({
|
|
1883
1925
|
via: "local",
|
|
1884
1926
|
localHit: t[0] || "",
|
|
1885
1927
|
category: "abuse"
|
|
@@ -1894,7 +1936,7 @@ function xn() {
|
|
|
1894
1936
|
});
|
|
1895
1937
|
return Ce(i, {
|
|
1896
1938
|
model: n,
|
|
1897
|
-
systemInstruction:
|
|
1939
|
+
systemInstruction: vn,
|
|
1898
1940
|
generationConfig: {
|
|
1899
1941
|
temperature: 0,
|
|
1900
1942
|
maxOutputTokens: 256,
|
|
@@ -1923,7 +1965,7 @@ function xn() {
|
|
|
1923
1965
|
};
|
|
1924
1966
|
}
|
|
1925
1967
|
function u(e, t = "") {
|
|
1926
|
-
let n =
|
|
1968
|
+
let n = bn({
|
|
1927
1969
|
reason: e.reason,
|
|
1928
1970
|
category: e.category,
|
|
1929
1971
|
via: e.via
|
|
@@ -1951,26 +1993,26 @@ function xn() {
|
|
|
1951
1993
|
};
|
|
1952
1994
|
let a = t.trim();
|
|
1953
1995
|
if (!a) return {
|
|
1954
|
-
...
|
|
1996
|
+
...Tn,
|
|
1955
1997
|
via: "empty"
|
|
1956
1998
|
};
|
|
1957
1999
|
if (i?.skipFilter) return {
|
|
1958
|
-
...
|
|
2000
|
+
...Tn,
|
|
1959
2001
|
via: "admin-override"
|
|
1960
2002
|
};
|
|
1961
2003
|
let c = o(a);
|
|
1962
2004
|
if (c) return d(c);
|
|
1963
2005
|
if (e.enabled === !1) return {
|
|
1964
|
-
...
|
|
2006
|
+
...Tn,
|
|
1965
2007
|
via: "disabled"
|
|
1966
2008
|
};
|
|
1967
2009
|
try {
|
|
1968
|
-
let e =
|
|
2010
|
+
let e = wn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
|
|
1969
2011
|
if (!e) return l();
|
|
1970
2012
|
let t = {
|
|
1971
2013
|
flagged: e.flagged,
|
|
1972
2014
|
category: e.category,
|
|
1973
|
-
reason:
|
|
2015
|
+
reason: bn({
|
|
1974
2016
|
reason: e.reason,
|
|
1975
2017
|
category: e.category,
|
|
1976
2018
|
via: "ai"
|
|
@@ -1990,14 +2032,14 @@ function xn() {
|
|
|
1990
2032
|
via: "restricted"
|
|
1991
2033
|
};
|
|
1992
2034
|
if (e.enabled === !1 || !e.moderateImages) return {
|
|
1993
|
-
...
|
|
2035
|
+
...Tn,
|
|
1994
2036
|
via: "disabled"
|
|
1995
2037
|
};
|
|
1996
2038
|
try {
|
|
1997
2039
|
let e = await new Promise((e, n) => {
|
|
1998
2040
|
let r = new FileReader();
|
|
1999
2041
|
r.onload = () => e(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(t);
|
|
2000
|
-
}), n =
|
|
2042
|
+
}), n = wn((await s().generateContent([{ inlineData: {
|
|
2001
2043
|
mimeType: t.type || "image/jpeg",
|
|
2002
2044
|
data: e
|
|
2003
2045
|
} }, "이 이미지를 심사해 주세요."])).response.text());
|
|
@@ -2005,7 +2047,7 @@ function xn() {
|
|
|
2005
2047
|
let r = {
|
|
2006
2048
|
flagged: n.flagged,
|
|
2007
2049
|
category: n.category,
|
|
2008
|
-
reason:
|
|
2050
|
+
reason: bn({
|
|
2009
2051
|
reason: n.reason,
|
|
2010
2052
|
category: n.category,
|
|
2011
2053
|
via: "ai"
|
|
@@ -2024,7 +2066,7 @@ function xn() {
|
|
|
2024
2066
|
}
|
|
2025
2067
|
//#endregion
|
|
2026
2068
|
//#region src/composables/useMemiBoardUsers.ts
|
|
2027
|
-
var
|
|
2069
|
+
var Dn = [
|
|
2028
2070
|
{
|
|
2029
2071
|
value: "admin",
|
|
2030
2072
|
label: "관리자",
|
|
@@ -2041,13 +2083,13 @@ var Sn = [
|
|
|
2041
2083
|
description: "글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다."
|
|
2042
2084
|
}
|
|
2043
2085
|
];
|
|
2044
|
-
function
|
|
2045
|
-
let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i =
|
|
2086
|
+
function On(e = {}) {
|
|
2087
|
+
let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i = ae(r, { ssrKey: S(t(), "users-management") });
|
|
2046
2088
|
async function a(e, r) {
|
|
2047
|
-
if (!
|
|
2048
|
-
await
|
|
2089
|
+
if (!Dn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
|
|
2090
|
+
await J(y(n, t(), e), {
|
|
2049
2091
|
role: r,
|
|
2050
|
-
updatedAt:
|
|
2092
|
+
updatedAt: G()
|
|
2051
2093
|
});
|
|
2052
2094
|
}
|
|
2053
2095
|
return {
|
|
@@ -2058,7 +2100,7 @@ function Cn(e = {}) {
|
|
|
2058
2100
|
}
|
|
2059
2101
|
//#endregion
|
|
2060
2102
|
//#region src/composables/useMemiBoardUserProfile.ts
|
|
2061
|
-
function
|
|
2103
|
+
function kn(e) {
|
|
2062
2104
|
let t = Q(), n = () => h(), r = A(() => N(e)), i = A(() => {
|
|
2063
2105
|
let e = r.value;
|
|
2064
2106
|
return e ? y(t, n(), e) : null;
|
|
@@ -2070,7 +2112,7 @@ function wn(e) {
|
|
|
2070
2112
|
}
|
|
2071
2113
|
//#endregion
|
|
2072
2114
|
//#region src/utils/section.ts
|
|
2073
|
-
var
|
|
2115
|
+
var An = [
|
|
2074
2116
|
3,
|
|
2075
2117
|
4,
|
|
2076
2118
|
5,
|
|
@@ -2079,7 +2121,7 @@ var Tn = [
|
|
|
2079
2121
|
8,
|
|
2080
2122
|
9,
|
|
2081
2123
|
12
|
|
2082
|
-
],
|
|
2124
|
+
], jn = [
|
|
2083
2125
|
{
|
|
2084
2126
|
value: "list",
|
|
2085
2127
|
label: "게시목록"
|
|
@@ -2092,24 +2134,24 @@ var Tn = [
|
|
|
2092
2134
|
value: "comments",
|
|
2093
2135
|
label: "댓글모음"
|
|
2094
2136
|
}
|
|
2095
|
-
],
|
|
2137
|
+
], Mn = [{
|
|
2096
2138
|
value: "latest",
|
|
2097
2139
|
label: "최신순"
|
|
2098
2140
|
}, {
|
|
2099
2141
|
value: "likes",
|
|
2100
2142
|
label: "좋아요순"
|
|
2101
2143
|
}];
|
|
2102
|
-
function
|
|
2144
|
+
function Nn(e) {
|
|
2103
2145
|
return e === "list" ? 5 : 4;
|
|
2104
2146
|
}
|
|
2105
|
-
function
|
|
2147
|
+
function Pn(e, t) {
|
|
2106
2148
|
let n = Math.floor(Number(t));
|
|
2107
|
-
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) :
|
|
2149
|
+
return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : Nn(e);
|
|
2108
2150
|
}
|
|
2109
|
-
function
|
|
2151
|
+
function Fn(e) {
|
|
2110
2152
|
return e === 12 ? null : 12 - e;
|
|
2111
2153
|
}
|
|
2112
|
-
function
|
|
2154
|
+
function In(e) {
|
|
2113
2155
|
return {
|
|
2114
2156
|
3: "col-span-12 md:col-span-3",
|
|
2115
2157
|
4: "col-span-12 md:col-span-4",
|
|
@@ -2121,36 +2163,36 @@ function jn(e) {
|
|
|
2121
2163
|
12: "col-span-12"
|
|
2122
2164
|
}[e];
|
|
2123
2165
|
}
|
|
2124
|
-
function
|
|
2166
|
+
function Ln(e) {
|
|
2125
2167
|
return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
|
|
2126
2168
|
}
|
|
2127
|
-
function
|
|
2169
|
+
function Rn(e) {
|
|
2128
2170
|
let t = e.boardId || e.category || "free";
|
|
2129
2171
|
return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
|
|
2130
2172
|
}
|
|
2131
|
-
function
|
|
2173
|
+
function zn(e) {
|
|
2132
2174
|
return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
|
|
2133
2175
|
}
|
|
2134
|
-
function
|
|
2176
|
+
function Bn(e) {
|
|
2135
2177
|
if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
|
|
2136
2178
|
}
|
|
2137
|
-
function
|
|
2179
|
+
function Vn(e) {
|
|
2138
2180
|
return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
2139
2181
|
}
|
|
2140
|
-
function
|
|
2182
|
+
function Hn(e) {
|
|
2141
2183
|
return e.title?.trim() || e.summary || "게시물";
|
|
2142
2184
|
}
|
|
2143
|
-
function
|
|
2185
|
+
function Un(e) {
|
|
2144
2186
|
return e === "image" || e === "video" ? "media" : "list";
|
|
2145
2187
|
}
|
|
2146
|
-
function
|
|
2147
|
-
return
|
|
2188
|
+
function Wn(e) {
|
|
2189
|
+
return Un(e) === "media" ? "미디어" : "목록";
|
|
2148
2190
|
}
|
|
2149
|
-
function
|
|
2191
|
+
function Gn(e, t) {
|
|
2150
2192
|
return e ? t(e)?.listView ?? "default" : "default";
|
|
2151
2193
|
}
|
|
2152
|
-
function
|
|
2153
|
-
let n = e.map((e) =>
|
|
2194
|
+
function Kn(e, t) {
|
|
2195
|
+
let n = e.map((e) => Gn(e.boardId, t));
|
|
2154
2196
|
if (!n.length) return "default";
|
|
2155
2197
|
if (n.every((e) => e === n[0])) return n[0];
|
|
2156
2198
|
let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
|
|
@@ -2158,27 +2200,27 @@ function Vn(e, t) {
|
|
|
2158
2200
|
}
|
|
2159
2201
|
//#endregion
|
|
2160
2202
|
//#region src/composables/useMemiBoardSections.ts
|
|
2161
|
-
var
|
|
2162
|
-
function
|
|
2203
|
+
var qn = [];
|
|
2204
|
+
function Jn(e) {
|
|
2163
2205
|
let t = Number(e.cols);
|
|
2164
|
-
if (
|
|
2206
|
+
if (An.includes(t)) return t;
|
|
2165
2207
|
let n = e.width;
|
|
2166
2208
|
return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
|
|
2167
2209
|
}
|
|
2168
|
-
function
|
|
2210
|
+
function Yn(e) {
|
|
2169
2211
|
let t = e.height ?? e.size;
|
|
2170
2212
|
return t === "sm" || t === "lg" ? t : "md";
|
|
2171
2213
|
}
|
|
2172
|
-
function
|
|
2214
|
+
function Xn(e) {
|
|
2173
2215
|
return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
|
|
2174
2216
|
}
|
|
2175
|
-
function
|
|
2217
|
+
function Zn(e) {
|
|
2176
2218
|
return e.sort === "likes" ? "likes" : "latest";
|
|
2177
2219
|
}
|
|
2178
|
-
function
|
|
2220
|
+
function Qn(e) {
|
|
2179
2221
|
return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
|
|
2180
2222
|
}
|
|
2181
|
-
function
|
|
2223
|
+
function $n(e, t) {
|
|
2182
2224
|
let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
|
|
2183
2225
|
for (let e of n) {
|
|
2184
2226
|
let n = String(e || "").trim();
|
|
@@ -2186,44 +2228,44 @@ function Jn(e, t) {
|
|
|
2186
2228
|
}
|
|
2187
2229
|
return r;
|
|
2188
2230
|
}
|
|
2189
|
-
function
|
|
2190
|
-
let n =
|
|
2231
|
+
function er(e, t) {
|
|
2232
|
+
let n = Xn(e), r = Pn(n, e.count);
|
|
2191
2233
|
return {
|
|
2192
2234
|
id: String(e.id || `box-${t + 1}`),
|
|
2193
2235
|
title: String(e.title || `섹션 ${t + 1}`),
|
|
2194
2236
|
showTitle: e.showTitle !== !1,
|
|
2195
2237
|
kind: n,
|
|
2196
|
-
boardId:
|
|
2238
|
+
boardId: Qn(e),
|
|
2197
2239
|
count: r,
|
|
2198
|
-
postIds:
|
|
2199
|
-
sort:
|
|
2200
|
-
cols:
|
|
2201
|
-
height:
|
|
2240
|
+
postIds: $n(e, r),
|
|
2241
|
+
sort: Zn(e),
|
|
2242
|
+
cols: Jn(e),
|
|
2243
|
+
height: Yn(e),
|
|
2202
2244
|
order: t
|
|
2203
2245
|
};
|
|
2204
2246
|
}
|
|
2205
|
-
function
|
|
2206
|
-
let e = Q(), t =
|
|
2247
|
+
function tr() {
|
|
2248
|
+
let e = Q(), t = te(e, "settings", "homeLayout"), { data: n, pending: r } = oe(t), i = A(() => (Array.isArray(n.value?.blocks) ? n.value.blocks : qn).map((e, t) => er(e, t)));
|
|
2207
2249
|
async function a(e) {
|
|
2208
|
-
await
|
|
2250
|
+
await K(t, {
|
|
2209
2251
|
columns: 12,
|
|
2210
2252
|
blocks: e.map((e, t) => {
|
|
2211
|
-
let n = e, r =
|
|
2253
|
+
let n = e, r = Xn(n), i = Pn(r, e.count);
|
|
2212
2254
|
return {
|
|
2213
2255
|
id: e.id,
|
|
2214
2256
|
title: e.title.trim() || `섹션 ${t + 1}`,
|
|
2215
2257
|
showTitle: e.showTitle !== !1,
|
|
2216
2258
|
kind: r,
|
|
2217
|
-
boardId:
|
|
2259
|
+
boardId: Qn(n),
|
|
2218
2260
|
count: i,
|
|
2219
|
-
postIds:
|
|
2220
|
-
sort:
|
|
2221
|
-
cols:
|
|
2222
|
-
height:
|
|
2261
|
+
postIds: $n(n, i),
|
|
2262
|
+
sort: Zn(n),
|
|
2263
|
+
cols: Jn(n),
|
|
2264
|
+
height: Yn(n),
|
|
2223
2265
|
order: t
|
|
2224
2266
|
};
|
|
2225
2267
|
}),
|
|
2226
|
-
updatedAt:
|
|
2268
|
+
updatedAt: G()
|
|
2227
2269
|
});
|
|
2228
2270
|
}
|
|
2229
2271
|
return {
|
|
@@ -2238,19 +2280,19 @@ function Xn() {
|
|
|
2238
2280
|
}
|
|
2239
2281
|
//#endregion
|
|
2240
2282
|
//#region src/composables/useMemiBoardMiniPosts.ts
|
|
2241
|
-
function
|
|
2283
|
+
function nr(e, t) {
|
|
2242
2284
|
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 = [
|
|
2244
|
-
return a && s.unshift(
|
|
2245
|
-
}), { data: s, pending: c, error: l } =
|
|
2285
|
+
let i = Math.max(1, Math.floor(Number(N(t)) || 5)), a = N(e)?.trim() || "", s = [Y("isPublished", "==", !0), Y("listed", "==", !0)];
|
|
2286
|
+
return a && s.unshift(Y("boardId", "==", a)), W(o(n, r()), ...s, U("createdAt", "desc"), V(i));
|
|
2287
|
+
}), { data: s, pending: c, error: l } = ae(a, { ssrKey: S(r(), `mini-list/${i}`) });
|
|
2246
2288
|
return {
|
|
2247
2289
|
posts: A(() => s.value ?? []),
|
|
2248
2290
|
pending: c,
|
|
2249
2291
|
error: l
|
|
2250
2292
|
};
|
|
2251
2293
|
}
|
|
2252
|
-
function
|
|
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 ?
|
|
2294
|
+
function rr(e) {
|
|
2295
|
+
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 ? W(o(t, n()), Y(L(), "in", r.value)) : null), { data: s, pending: c, error: l } = ae(a, { ssrKey: S(n(), `mini-picked/${i}`) });
|
|
2254
2296
|
return {
|
|
2255
2297
|
posts: A(() => {
|
|
2256
2298
|
let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
|
|
@@ -2266,7 +2308,17 @@ function Qn(e) {
|
|
|
2266
2308
|
}
|
|
2267
2309
|
//#endregion
|
|
2268
2310
|
//#region src/data/versionHistory.ts
|
|
2269
|
-
var
|
|
2311
|
+
var ir = [
|
|
2312
|
+
{
|
|
2313
|
+
version: "0.44.1",
|
|
2314
|
+
date: "2026-10-01",
|
|
2315
|
+
highlights: ["Mac Safari에서 한글을 입력하고 바로 등록 버튼을 누를 때 두 번 눌러야 하던 문제를 고쳤어요"]
|
|
2316
|
+
},
|
|
2317
|
+
{
|
|
2318
|
+
version: "0.44.0",
|
|
2319
|
+
date: "2026-10-01",
|
|
2320
|
+
highlights: ["글을 저장하고 미리보기가 뜨기까지 기다리는 시간이 줄었어요 (특히 iPhone·Mac Safari)"]
|
|
2321
|
+
},
|
|
2270
2322
|
{
|
|
2271
2323
|
version: "0.42.0",
|
|
2272
2324
|
date: "2026-08-27",
|
|
@@ -2536,7 +2588,7 @@ var $n = [
|
|
|
2536
2588
|
highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
|
|
2537
2589
|
note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
|
|
2538
2590
|
}
|
|
2539
|
-
],
|
|
2591
|
+
], ar = /* @__PURE__ */ Ae(((e, t) => {
|
|
2540
2592
|
(function(n, r) {
|
|
2541
2593
|
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();
|
|
2542
2594
|
})(e, (function() {
|
|
@@ -2830,7 +2882,7 @@ var $n = [
|
|
|
2830
2882
|
return w(1e3 * e);
|
|
2831
2883
|
}, w.en = b[y], w.Ls = b, w.p = {}, w;
|
|
2832
2884
|
}));
|
|
2833
|
-
})),
|
|
2885
|
+
})), or = /* @__PURE__ */ Ae(((e, t) => {
|
|
2834
2886
|
(function(n, r) {
|
|
2835
2887
|
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();
|
|
2836
2888
|
})(e, (function() {
|
|
@@ -2934,9 +2986,9 @@ var $n = [
|
|
|
2934
2986
|
};
|
|
2935
2987
|
};
|
|
2936
2988
|
}));
|
|
2937
|
-
})),
|
|
2989
|
+
})), sr = /* @__PURE__ */ Ae(((e, t) => {
|
|
2938
2990
|
(function(n, r) {
|
|
2939
|
-
typeof e == "object" && t !== void 0 ? t.exports = r(
|
|
2991
|
+
typeof e == "object" && t !== void 0 ? t.exports = r(ar()) : typeof define == "function" && define.amd ? define(["dayjs"], r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_locale_ko = r(n.dayjs);
|
|
2940
2992
|
})(e, (function(e) {
|
|
2941
2993
|
function t(e) {
|
|
2942
2994
|
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
@@ -2984,24 +3036,24 @@ var $n = [
|
|
|
2984
3036
|
};
|
|
2985
3037
|
return n.default.locale(r, null, !0), r;
|
|
2986
3038
|
}));
|
|
2987
|
-
})),
|
|
2988
|
-
|
|
2989
|
-
function
|
|
3039
|
+
})), cr = /* @__PURE__ */ Me(ar(), 1), lr = /* @__PURE__ */ Me(or(), 1);
|
|
3040
|
+
sr(), cr.default.extend(lr.default), cr.default.locale("ko");
|
|
3041
|
+
function ur(e) {
|
|
2990
3042
|
return e?.toDate ? e.toDate().toLocaleDateString("ko-KR") : "";
|
|
2991
3043
|
}
|
|
2992
|
-
function
|
|
2993
|
-
return e?.toDate ? (0,
|
|
3044
|
+
function dr(e, t = Date.now()) {
|
|
3045
|
+
return e?.toDate ? (0, cr.default)(e.toDate()).from((0, cr.default)(t)) : "방금 전";
|
|
2994
3046
|
}
|
|
2995
|
-
function
|
|
2996
|
-
return e?.toDate ? (0,
|
|
3047
|
+
function fr(e) {
|
|
3048
|
+
return e?.toDate ? (0, cr.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
|
|
2997
3049
|
}
|
|
2998
|
-
function
|
|
2999
|
-
let n =
|
|
3000
|
-
return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${
|
|
3050
|
+
function pr(e, t) {
|
|
3051
|
+
let n = fr(e), r = e?.toMillis?.(), i = t?.toMillis?.();
|
|
3052
|
+
return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${fr(t)}`];
|
|
3001
3053
|
}
|
|
3002
3054
|
//#endregion
|
|
3003
3055
|
//#region src/composables/useMemiBoardWritingAssistant.ts
|
|
3004
|
-
var
|
|
3056
|
+
var mr = 10, hr = 864e5, gr = 200, _r = {
|
|
3005
3057
|
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
3006
3058
|
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
3007
3059
|
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
@@ -3010,40 +3062,40 @@ var lr = 10, ur = 864e5, dr = 200, fr = {
|
|
|
3010
3062
|
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
3011
3063
|
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
3012
3064
|
};
|
|
3013
|
-
function
|
|
3014
|
-
if (e.action !== "custom") return
|
|
3015
|
-
let t = e.customInstruction?.trim().slice(0,
|
|
3065
|
+
function vr(e) {
|
|
3066
|
+
if (e.action !== "custom") return _r[e.action];
|
|
3067
|
+
let t = e.customInstruction?.trim().slice(0, gr);
|
|
3016
3068
|
if (!t) throw Error("어떻게 바꿀지 지시문을 입력해 주세요.");
|
|
3017
3069
|
return `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${t}`;
|
|
3018
3070
|
}
|
|
3019
|
-
function
|
|
3071
|
+
function yr(e) {
|
|
3020
3072
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
3021
3073
|
}
|
|
3022
|
-
function
|
|
3074
|
+
function br(e) {
|
|
3023
3075
|
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
3024
3076
|
}
|
|
3025
|
-
function
|
|
3026
|
-
let e = se(), t = Q(), n =
|
|
3077
|
+
function xr() {
|
|
3078
|
+
let e = se(), t = Q(), n = Z(), r = c();
|
|
3027
3079
|
async function i() {
|
|
3028
3080
|
let e = n.value?.uid;
|
|
3029
3081
|
if (!e) throw Error("AI 글쓰기 도우미는 로그인 후 사용할 수 있습니다.");
|
|
3030
|
-
await
|
|
3082
|
+
await ie(t, async (n) => {
|
|
3031
3083
|
let r = y(t, h(), e), i = await n.get(r);
|
|
3032
3084
|
if (!i.exists()) throw Error("사용자 정보를 확인한 뒤 다시 시도해 주세요.");
|
|
3033
|
-
let a = i.data(), o =
|
|
3085
|
+
let a = i.data(), o = br(a.aiWritingWindowAt), s = Math.max(0, Math.floor(Number(a.aiWritingCount) || 0)), c = Date.now(), l = o != null && c - o < hr;
|
|
3034
3086
|
if (l && s >= 10) {
|
|
3035
|
-
let e = o +
|
|
3087
|
+
let e = o + hr, t = Math.max(1, Math.ceil((e - c) / 36e5));
|
|
3036
3088
|
throw Error(`AI 글쓰기 도우미는 하루 10회까지 사용할 수 있습니다. 약 ${t}시간 후 다시 이용해 주세요.`);
|
|
3037
3089
|
}
|
|
3038
3090
|
n.update(r, {
|
|
3039
3091
|
aiWritingCount: l ? s + 1 : 1,
|
|
3040
|
-
aiWritingWindowAt: l ? a.aiWritingWindowAt :
|
|
3041
|
-
updatedAt:
|
|
3092
|
+
aiWritingWindowAt: l ? a.aiWritingWindowAt : G(),
|
|
3093
|
+
updatedAt: G()
|
|
3042
3094
|
});
|
|
3043
3095
|
});
|
|
3044
3096
|
}
|
|
3045
3097
|
async function a(t) {
|
|
3046
|
-
let n =
|
|
3098
|
+
let n = vr(t);
|
|
3047
3099
|
if (!t.content.trim()) throw Error("AI로 다듬을 내용을 먼저 입력해 주세요.");
|
|
3048
3100
|
await i();
|
|
3049
3101
|
let a = r.moderation ?? {}, o = Se(e, {
|
|
@@ -3064,7 +3116,7 @@ function gr() {
|
|
|
3064
3116
|
`작업: ${n}`,
|
|
3065
3117
|
t.title ? `현재 제목: ${t.title}` : "",
|
|
3066
3118
|
`본문:\n${c.slice(0, 12e3)}`
|
|
3067
|
-
].filter(Boolean).join("\n\n"), u =
|
|
3119
|
+
].filter(Boolean).join("\n\n"), u = yr((await s.generateContent(l)).response.text());
|
|
3068
3120
|
if (!u) throw Error("AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.");
|
|
3069
3121
|
return u;
|
|
3070
3122
|
}
|
|
@@ -3072,14 +3124,14 @@ function gr() {
|
|
|
3072
3124
|
}
|
|
3073
3125
|
//#endregion
|
|
3074
3126
|
//#region src/utils/renderMarkdown.ts
|
|
3075
|
-
function
|
|
3127
|
+
function Sr(e) {
|
|
3076
3128
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3077
3129
|
}
|
|
3078
|
-
function
|
|
3130
|
+
function Cr(e) {
|
|
3079
3131
|
let t = e;
|
|
3080
3132
|
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;
|
|
3081
3133
|
}
|
|
3082
|
-
function
|
|
3134
|
+
function wr(e) {
|
|
3083
3135
|
if (!e?.trim()) return "";
|
|
3084
3136
|
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
|
|
3085
3137
|
function c() {
|
|
@@ -3088,7 +3140,7 @@ function yr(e) {
|
|
|
3088
3140
|
return;
|
|
3089
3141
|
}
|
|
3090
3142
|
let e = o;
|
|
3091
|
-
n.push(`<${e}>${s.map((e) => `<li>${
|
|
3143
|
+
n.push(`<${e}>${s.map((e) => `<li>${Cr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
|
|
3092
3144
|
}
|
|
3093
3145
|
for (; r < t.length;) {
|
|
3094
3146
|
let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
|
|
@@ -3097,7 +3149,7 @@ function yr(e) {
|
|
|
3097
3149
|
continue;
|
|
3098
3150
|
}
|
|
3099
3151
|
if (i) {
|
|
3100
|
-
a.push(
|
|
3152
|
+
a.push(Sr(e)), r++;
|
|
3101
3153
|
continue;
|
|
3102
3154
|
}
|
|
3103
3155
|
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
|
|
@@ -3108,24 +3160,24 @@ function yr(e) {
|
|
|
3108
3160
|
if (u) {
|
|
3109
3161
|
c();
|
|
3110
3162
|
let e = u[1].length;
|
|
3111
|
-
n.push(`<h${e} class="font-semibold mt-4 mb-2">${
|
|
3163
|
+
n.push(`<h${e} class="font-semibold mt-4 mb-2">${Cr(Sr(u[2]))}</h${e}>`), r++;
|
|
3112
3164
|
continue;
|
|
3113
3165
|
}
|
|
3114
3166
|
if (e.startsWith("> ")) {
|
|
3115
3167
|
c();
|
|
3116
3168
|
let e = [];
|
|
3117
|
-
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(
|
|
3118
|
-
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${
|
|
3169
|
+
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(Sr((t[r] ?? "").slice(2))), r++;
|
|
3170
|
+
n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Cr(e.join("<br />"))}</blockquote>`);
|
|
3119
3171
|
continue;
|
|
3120
3172
|
}
|
|
3121
3173
|
let d = e.match(/^[-*+]\s+(.+)$/);
|
|
3122
3174
|
if (d) {
|
|
3123
|
-
o && o !== "ul" && c(), o = "ul", s.push(
|
|
3175
|
+
o && o !== "ul" && c(), o = "ul", s.push(Sr(d[1])), r++;
|
|
3124
3176
|
continue;
|
|
3125
3177
|
}
|
|
3126
3178
|
let f = e.match(/^\d+\.\s+(.+)$/);
|
|
3127
3179
|
if (f) {
|
|
3128
|
-
o && o !== "ol" && c(), o = "ol", s.push(
|
|
3180
|
+
o && o !== "ol" && c(), o = "ol", s.push(Sr(f[1])), r++;
|
|
3129
3181
|
continue;
|
|
3130
3182
|
}
|
|
3131
3183
|
if (!e.trim()) {
|
|
@@ -3137,13 +3189,13 @@ function yr(e) {
|
|
|
3137
3189
|
for (; r < t.length;) {
|
|
3138
3190
|
let e = t[r] ?? "";
|
|
3139
3191
|
if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
|
|
3140
|
-
p.push(
|
|
3192
|
+
p.push(Sr(e)), r++;
|
|
3141
3193
|
}
|
|
3142
|
-
n.push(`<p class="my-2 leading-relaxed">${
|
|
3194
|
+
n.push(`<p class="my-2 leading-relaxed">${Cr(p.join("<br />"))}</p>`);
|
|
3143
3195
|
}
|
|
3144
3196
|
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");
|
|
3145
3197
|
}
|
|
3146
3198
|
//#endregion
|
|
3147
|
-
export {
|
|
3199
|
+
export { Qt as AUTHOR_MEMO_MAX_LENGTH, An as BOARD_SECTION_COLS, jn as BOARD_SECTION_KINDS, Mn as BOARD_SECTION_SORTS, Dn as BOARD_USER_ROLES, rn as COMMENT_BODY_MAX_LENGTH, et as DEFAULT_BLOCK_BAN_DECAY_MS, $e as DEFAULT_BLOCK_BAN_THRESHOLD, Pt as DEFAULT_BOARDS, Ft 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, dn as REPORT_DETAIL_MAX_LENGTH, fn as REPORT_REASONS, mr 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, Nt as buildPostPreview, Je as canManageBoardByRole, Ye as canWriteCommentByRole, Pn as clampSectionCount, s as commentDoc, E as commentsCol, C as configureMemiBoard, Nn as defaultSectionCount, tt as effectiveModerationBlockCount, pt as extractEditorImageUrls, Ge as fetchPublicListForSeo, We as fetchPublicPostForSeo, ur as formatDate, fr as formatFullDate, dr as formatRelativeDate, it as formatRestrictedUntilLabel, pr as formatTimestampDetails, Ot as hasBodyImage, Dt as hasBodyText, ft as imeSafeSubmitClick, dt as imeSafeSubmitPointerDown, qe as isAssignedStaff, kt as isContentEmpty, Bt as isFirestorePermissionDenied, rt as isModerationWriteRestricted, k as likeDoc, l as likeDocId, O as likesCol, ln as memiBoardCommentLikesKey, Gn as miniBoardView, Bn as miniCommentLink, zn as miniMoreLink, Vn as miniPostImage, Rn as miniPostLink, Hn as miniPostTitle, Kn as miniPostsView, Un as miniViewGroup, Wn as miniViewLabel, nt as moderationWriteRestrictedUntilMs, Be as normalizeBasePath, er as normalizeBoardSection, Fn as pairSectionCols, Tt as plainTextFromHtml, a as postBodyDoc, t as postDoc, ht as postNamespaceFromStoragePath, D as postStorageFolder, o as postsCol, wr as renderMarkdownToHtml, r as reportDoc, n as reportDocId, pn as reportReasonLabel, i as reportsCol, _ as resolveBoardPathConfig, Ve as resolvePublicSeoDb, In as sectionColClass, Ln as sectionMinHeight, e as settingsCol, g as settingsDoc, b as slugify, mt as storagePathFromDownloadUrl, Et as titleFromBody, Fe as toAbsoluteUrl, Pe as toBoardOgImageUrl, h as useBoardPathConfig, ct as useMemiBoardAuth, en as useMemiBoardAuthorMemo, Zt as useMemiBoardCommentFeed, un as useMemiBoardCommentLikes, on as useMemiBoardComments, c as useMemiBoardConfig, cn as useMemiBoardLikes, nr as useMemiBoardMiniLatest, rr as useMemiBoardMiniPicked, En as useMemiBoardModeration, Gt as useMemiBoardPost, Wt as useMemiBoardPostList, Ht as useMemiBoardPosts, sn as useMemiBoardReplies, gn as useMemiBoardReportQueue, mn as useMemiBoardReports, tr as useMemiBoardSections, Rt as useMemiBoardSettings, Yt as useMemiBoardUserComments, qt as useMemiBoardUserPosts, kn as useMemiBoardUserProfile, On as useMemiBoardUsers, _n as useMemiBoardViews, xr as useMemiBoardWritingAssistant, ir as versionHistory, Mt as videoListCoverUrl, jt as youtubeId };
|
|
3148
3200
|
|
|
3149
3201
|
//# sourceMappingURL=index.js.map
|