memi-board 0.44.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/dist/index.d.ts +1 -0
- package/dist/index.js +251 -225
- 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 +4 -0
- package/dist/runtime/components/ReportButton.vue +4 -0
- package/dist/runtime/components/SignIn.vue +4 -0
- package/dist/utils/imeSafeSubmit.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -421,8 +421,29 @@ function ct() {
|
|
|
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
|
|
483
|
+
var yt = 450;
|
|
484
|
+
async function bt(e, t) {
|
|
464
485
|
let n = await z(t);
|
|
465
|
-
for (let t = 0; t < n.docs.length; t +=
|
|
486
|
+
for (let t = 0; t < n.docs.length; t += yt) {
|
|
466
487
|
let r = X(e);
|
|
467
|
-
n.docs.slice(t, t +
|
|
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
|
|
500
|
+
async function wt(e, n, r, i) {
|
|
480
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(() => W(e(n, t()), U("order", "asc"))), { data: u, pending: d } = ae(l, { ssrKey: S(t(), "boards") }), f = A(() => u.value.map((e, t) =>
|
|
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
|
}
|
|
@@ -641,7 +662,7 @@ 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",
|
|
@@ -655,7 +676,7 @@ function Pt() {
|
|
|
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
|
|
@@ -669,7 +690,7 @@ function Pt() {
|
|
|
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
|
|
@@ -689,7 +710,7 @@ function Pt() {
|
|
|
689
710
|
for (;;) {
|
|
690
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
|
}
|
|
@@ -742,25 +763,25 @@ function Pt() {
|
|
|
742
763
|
saveCategories: ne,
|
|
743
764
|
deleteBoard: R,
|
|
744
765
|
deleteCategory: B,
|
|
745
|
-
DEFAULT_BOARDS:
|
|
746
|
-
DEFAULT_CATEGORIES:
|
|
766
|
+
DEFAULT_BOARDS: Pt,
|
|
767
|
+
DEFAULT_CATEGORIES: Ft
|
|
747
768
|
};
|
|
748
769
|
}
|
|
749
770
|
//#endregion
|
|
750
771
|
//#region src/composables/useMemiBoardPosts.ts
|
|
751
|
-
var
|
|
752
|
-
function
|
|
772
|
+
var zt = /* @__PURE__ */ new Map();
|
|
773
|
+
function Bt(e) {
|
|
753
774
|
if (!e || typeof e != "object") return !1;
|
|
754
775
|
let t = "code" in e ? String(e.code) : "";
|
|
755
776
|
return t === "permission-denied" || t === "firestore/permission-denied";
|
|
756
777
|
}
|
|
757
|
-
function
|
|
778
|
+
function Vt(e) {
|
|
758
779
|
let t = N(e)?.trim();
|
|
759
780
|
if (!t) throw Error("[memi-board] boardId 가 필요합니다.");
|
|
760
781
|
return t;
|
|
761
782
|
}
|
|
762
|
-
function
|
|
763
|
-
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);
|
|
764
785
|
function p() {
|
|
765
786
|
return !i(l());
|
|
766
787
|
}
|
|
@@ -768,7 +789,7 @@ function Rt(e) {
|
|
|
768
789
|
return s(l())?.editorType === "image";
|
|
769
790
|
}
|
|
770
791
|
function g(e) {
|
|
771
|
-
let t = m(), n =
|
|
792
|
+
let t = m(), n = Dt(e.content), r = Ot(e.content, e.attachments);
|
|
772
793
|
if (t) {
|
|
773
794
|
if (!r) throw Error("사진을 올려 주세요.");
|
|
774
795
|
return;
|
|
@@ -811,20 +832,20 @@ function Rt(e) {
|
|
|
811
832
|
post: e
|
|
812
833
|
} : { status: "not-found" };
|
|
813
834
|
} catch (e) {
|
|
814
|
-
return
|
|
835
|
+
return Bt(e) ? { status: "permission-denied" } : {
|
|
815
836
|
status: "error",
|
|
816
837
|
message: e instanceof Error ? e.message : String(e)
|
|
817
838
|
};
|
|
818
839
|
}
|
|
819
840
|
} catch (e) {
|
|
820
|
-
return
|
|
841
|
+
return Bt(e) ? { status: "permission-denied" } : {
|
|
821
842
|
status: "error",
|
|
822
843
|
message: e instanceof Error ? e.message : String(e)
|
|
823
844
|
};
|
|
824
845
|
}
|
|
825
846
|
}
|
|
826
847
|
async function S(e) {
|
|
827
|
-
let t = e.trim(), n =
|
|
848
|
+
let t = e.trim(), n = zt.get(`${l()}/${t}`);
|
|
828
849
|
if (n) return {
|
|
829
850
|
status: "ok",
|
|
830
851
|
id: n
|
|
@@ -836,7 +857,7 @@ function Rt(e) {
|
|
|
836
857
|
id: e.id
|
|
837
858
|
} : { status: "not-found" };
|
|
838
859
|
} catch (e) {
|
|
839
|
-
return
|
|
860
|
+
return Bt(e) ? { status: "permission-denied" } : {
|
|
840
861
|
status: "error",
|
|
841
862
|
message: e instanceof Error ? e.message : String(e)
|
|
842
863
|
};
|
|
@@ -879,8 +900,8 @@ function Rt(e) {
|
|
|
879
900
|
async function T(e) {
|
|
880
901
|
g(e);
|
|
881
902
|
let t = e.postId || _(), r = m(), i, a;
|
|
882
|
-
r ? (i = t, a =
|
|
883
|
-
let o =
|
|
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);
|
|
884
905
|
return c.set(d(t), {
|
|
885
906
|
boardId: l(),
|
|
886
907
|
slug: i,
|
|
@@ -900,11 +921,11 @@ function Rt(e) {
|
|
|
900
921
|
moderationModel: e.moderationModel ?? null,
|
|
901
922
|
createdAt: G(),
|
|
902
923
|
updatedAt: G()
|
|
903
|
-
}), c.set(f(t), { content: e.content }), await c.commit(),
|
|
924
|
+
}), c.set(f(t), { content: e.content }), await c.commit(), zt.set(`${l()}/${i}`, t), i;
|
|
904
925
|
}
|
|
905
926
|
async function E(e, t) {
|
|
906
927
|
g(t);
|
|
907
|
-
let n = m() ?
|
|
928
|
+
let n = m() ? Et(t.content) : t.title.trim(), r = Nt(t.content, t.attachments), i = p();
|
|
908
929
|
await Promise.all([J(d(e), {
|
|
909
930
|
title: n,
|
|
910
931
|
...r,
|
|
@@ -924,8 +945,8 @@ function Rt(e) {
|
|
|
924
945
|
});
|
|
925
946
|
}
|
|
926
947
|
async function O(e) {
|
|
927
|
-
await
|
|
928
|
-
for (let [t, n] of
|
|
948
|
+
await wt(n, _e(r), c(), e);
|
|
949
|
+
for (let [t, n] of zt) n === e && zt.delete(t);
|
|
929
950
|
}
|
|
930
951
|
return {
|
|
931
952
|
createPostId: _,
|
|
@@ -941,9 +962,9 @@ function Rt(e) {
|
|
|
941
962
|
deletePost: O
|
|
942
963
|
};
|
|
943
964
|
}
|
|
944
|
-
var
|
|
945
|
-
function
|
|
946
|
-
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;
|
|
947
968
|
function T(e) {
|
|
948
969
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
949
970
|
}
|
|
@@ -1026,8 +1047,8 @@ function Bt(e, t = {}) {
|
|
|
1026
1047
|
loadMore: ee
|
|
1027
1048
|
};
|
|
1028
1049
|
}
|
|
1029
|
-
function
|
|
1030
|
-
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);
|
|
1031
1052
|
return {
|
|
1032
1053
|
post: A(() => !u.value || u.value.boardId !== o.value ? null : {
|
|
1033
1054
|
...u.value,
|
|
@@ -1039,9 +1060,9 @@ function Vt(e, n) {
|
|
|
1039
1060
|
}
|
|
1040
1061
|
//#endregion
|
|
1041
1062
|
//#region src/composables/useMemiBoardUserPosts.ts
|
|
1042
|
-
var
|
|
1043
|
-
function
|
|
1044
|
-
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, _;
|
|
1045
1066
|
function v(e) {
|
|
1046
1067
|
return {
|
|
1047
1068
|
id: e.id,
|
|
@@ -1107,9 +1128,9 @@ function Ut(e, t = {}) {
|
|
|
1107
1128
|
}
|
|
1108
1129
|
//#endregion
|
|
1109
1130
|
//#region src/composables/useMemiBoardUserComments.ts
|
|
1110
|
-
var
|
|
1111
|
-
function
|
|
1112
|
-
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;
|
|
1113
1134
|
function _(e) {
|
|
1114
1135
|
return {
|
|
1115
1136
|
id: e.id,
|
|
@@ -1171,11 +1192,11 @@ function Gt(e, t = {}) {
|
|
|
1171
1192
|
}
|
|
1172
1193
|
//#endregion
|
|
1173
1194
|
//#region src/composables/useMemiBoardCommentFeed.ts
|
|
1174
|
-
var
|
|
1175
|
-
function
|
|
1195
|
+
var Xt = 10;
|
|
1196
|
+
function Zt(e = "latest", t = {}) {
|
|
1176
1197
|
let n = Q(), r = () => h(), i = () => E(n, r()), a = A(() => {
|
|
1177
1198
|
let e = Math.floor(Number(N(t.pageSize)));
|
|
1178
|
-
return Number.isFinite(e) && e > 0 ? e :
|
|
1199
|
+
return Number.isFinite(e) && e > 0 ? e : Xt;
|
|
1179
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;
|
|
1180
1201
|
function _(e) {
|
|
1181
1202
|
return {
|
|
@@ -1245,9 +1266,9 @@ function qt(e = "latest", t = {}) {
|
|
|
1245
1266
|
}
|
|
1246
1267
|
//#endregion
|
|
1247
1268
|
//#region src/composables/useMemiBoardAuthorMemo.ts
|
|
1248
|
-
var
|
|
1269
|
+
var Qt = 100, $t = /* @__PURE__ */ new Map();
|
|
1249
1270
|
function $(e) {
|
|
1250
|
-
let t =
|
|
1271
|
+
let t = $t.get(e);
|
|
1251
1272
|
return t || (t = ee({
|
|
1252
1273
|
text: "",
|
|
1253
1274
|
sentiment: null,
|
|
@@ -1255,9 +1276,9 @@ function $(e) {
|
|
|
1255
1276
|
pending: !1,
|
|
1256
1277
|
saving: !1,
|
|
1257
1278
|
error: ""
|
|
1258
|
-
}),
|
|
1279
|
+
}), $t.set(e, t)), t;
|
|
1259
1280
|
}
|
|
1260
|
-
function
|
|
1281
|
+
function en(e) {
|
|
1261
1282
|
let t = Q(), n = () => h(), { user: r } = ct(), i = A(() => N(e)), a = A(() => `${r.value?.uid ?? ""}:${i.value}`), o = A(() => {
|
|
1262
1283
|
let e = r.value?.uid, a = i.value;
|
|
1263
1284
|
return !e || !a ? null : f(t, n(), e, a);
|
|
@@ -1327,15 +1348,15 @@ function Xt(e) {
|
|
|
1327
1348
|
}
|
|
1328
1349
|
//#endregion
|
|
1329
1350
|
//#region src/composables/useMemiBoardComments.ts
|
|
1330
|
-
var
|
|
1331
|
-
function
|
|
1351
|
+
var tn = 10, nn = 5, rn = 1e3;
|
|
1352
|
+
function an(e) {
|
|
1332
1353
|
let t = e.trim();
|
|
1333
1354
|
if (!t) throw Error("댓글 내용을 입력해 주세요.");
|
|
1334
|
-
if (t.length > 1e3) throw Error(`댓글은 ${
|
|
1355
|
+
if (t.length > 1e3) throw Error(`댓글은 ${rn.toLocaleString()}자까지 작성할 수 있습니다.`);
|
|
1335
1356
|
return t;
|
|
1336
1357
|
}
|
|
1337
|
-
function
|
|
1338
|
-
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;
|
|
1339
1360
|
function C(e) {
|
|
1340
1361
|
return e.createdAt?.toMillis?.() ?? 0;
|
|
1341
1362
|
}
|
|
@@ -1389,11 +1410,11 @@ function tn(e, n, r = {}) {
|
|
|
1389
1410
|
U(L(), "asc"),
|
|
1390
1411
|
...b ? [q(b)] : [],
|
|
1391
1412
|
V(11)
|
|
1392
|
-
], t = await z(W(c(), ...e)), n = t.docs.slice(0,
|
|
1413
|
+
], t = await z(W(c(), ...e)), n = t.docs.slice(0, tn), r = n.map((e) => ({
|
|
1393
1414
|
id: e.id,
|
|
1394
1415
|
...e.data()
|
|
1395
1416
|
})), i = new Set(g.value.map((e) => e.id));
|
|
1396
|
-
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(() => {
|
|
1397
1418
|
x = void 0, T();
|
|
1398
1419
|
}, 1e3));
|
|
1399
1420
|
} finally {
|
|
@@ -1405,7 +1426,7 @@ function tn(e, n, r = {}) {
|
|
|
1405
1426
|
clearTimeout(x), S?.();
|
|
1406
1427
|
});
|
|
1407
1428
|
async function O(e) {
|
|
1408
|
-
let n =
|
|
1429
|
+
let n = an(e.body), r = X(i), o = te(c());
|
|
1409
1430
|
r.set(o, {
|
|
1410
1431
|
postId: u.value,
|
|
1411
1432
|
boardId: l.value,
|
|
@@ -1428,7 +1449,7 @@ function tn(e, n, r = {}) {
|
|
|
1428
1449
|
}), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
|
|
1429
1450
|
}
|
|
1430
1451
|
async function k(e) {
|
|
1431
|
-
let n =
|
|
1452
|
+
let n = an(e.body);
|
|
1432
1453
|
if (!e.parent.id) throw Error("답글 대상 댓글을 찾을 수 없습니다.");
|
|
1433
1454
|
let r = X(i), o = te(c()), f = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
|
|
1434
1455
|
if (!f) throw Error("댓글 스레드를 찾을 수 없습니다.");
|
|
@@ -1457,12 +1478,12 @@ function tn(e, n, r = {}) {
|
|
|
1457
1478
|
async function ee(e) {
|
|
1458
1479
|
if (!e.id) return;
|
|
1459
1480
|
if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error("답글이 있는 댓글은 현재 삭제할 수 없습니다.");
|
|
1460
|
-
await
|
|
1481
|
+
await Ct(i, a(), e.id);
|
|
1461
1482
|
let n = X(i);
|
|
1462
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);
|
|
1463
1484
|
}
|
|
1464
1485
|
async function F(e, t) {
|
|
1465
|
-
let n =
|
|
1486
|
+
let n = an(t);
|
|
1466
1487
|
await J(s(i, a(), e), {
|
|
1467
1488
|
body: n,
|
|
1468
1489
|
updatedAt: G()
|
|
@@ -1488,7 +1509,7 @@ function tn(e, n, r = {}) {
|
|
|
1488
1509
|
deleteComment: ee
|
|
1489
1510
|
};
|
|
1490
1511
|
}
|
|
1491
|
-
function
|
|
1512
|
+
function sn(e, t, n) {
|
|
1492
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;
|
|
1493
1514
|
function p(e) {
|
|
1494
1515
|
return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
|
|
@@ -1517,11 +1538,11 @@ function nn(e, t, n) {
|
|
|
1517
1538
|
U(L(), "asc"),
|
|
1518
1539
|
...d ? [q(d)] : [],
|
|
1519
1540
|
V(6)
|
|
1520
|
-
], t = await z(W(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0,
|
|
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) => ({
|
|
1521
1542
|
id: e.id,
|
|
1522
1543
|
...e.data()
|
|
1523
1544
|
})).filter((e) => !r.has(e.id));
|
|
1524
|
-
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());
|
|
1525
1546
|
} finally {
|
|
1526
1547
|
c.value = !1;
|
|
1527
1548
|
}
|
|
@@ -1544,7 +1565,7 @@ function nn(e, t, n) {
|
|
|
1544
1565
|
}
|
|
1545
1566
|
//#endregion
|
|
1546
1567
|
//#region src/composables/useMemiBoardLikes.ts
|
|
1547
|
-
function
|
|
1568
|
+
function cn(e, n) {
|
|
1548
1569
|
let r = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
|
|
1549
1570
|
function l(e) {
|
|
1550
1571
|
return k(i, r(), n, e);
|
|
@@ -1583,8 +1604,8 @@ function rn(e, n) {
|
|
|
1583
1604
|
toggleLike: u
|
|
1584
1605
|
};
|
|
1585
1606
|
}
|
|
1586
|
-
var
|
|
1587
|
-
function
|
|
1607
|
+
var ln = Symbol.for("memi-board:comment-likes");
|
|
1608
|
+
function un(e, t) {
|
|
1588
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;
|
|
1589
1610
|
P([i, o], ([e, t]) => {
|
|
1590
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) => {
|
|
@@ -1637,7 +1658,7 @@ function on(e, t) {
|
|
|
1637
1658
|
}
|
|
1638
1659
|
//#endregion
|
|
1639
1660
|
//#region src/composables/useMemiBoardReports.ts
|
|
1640
|
-
var
|
|
1661
|
+
var dn = 200, fn = [
|
|
1641
1662
|
{
|
|
1642
1663
|
value: "spam",
|
|
1643
1664
|
label: "스팸·광고"
|
|
@@ -1659,10 +1680,10 @@ var sn = 200, cn = [
|
|
|
1659
1680
|
label: "기타"
|
|
1660
1681
|
}
|
|
1661
1682
|
];
|
|
1662
|
-
function
|
|
1663
|
-
return
|
|
1683
|
+
function pn(e) {
|
|
1684
|
+
return fn.find((t) => t.value === e)?.label || e || "신고";
|
|
1664
1685
|
}
|
|
1665
|
-
function
|
|
1686
|
+
function mn(e, t) {
|
|
1666
1687
|
let n = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
|
|
1667
1688
|
P(a, (e) => {
|
|
1668
1689
|
if (c?.(), c = void 0, !e) {
|
|
@@ -1680,7 +1701,7 @@ function un(e, t) {
|
|
|
1680
1701
|
if (!l) throw Error("로그인이 필요합니다.");
|
|
1681
1702
|
if (s.value) return;
|
|
1682
1703
|
if (c.authorUid && c.authorUid === l) throw Error("자신의 글은 신고할 수 없습니다.");
|
|
1683
|
-
let u =
|
|
1704
|
+
let u = fn.some((e) => e.value === c.reason) ? c.reason : null;
|
|
1684
1705
|
if (!u) throw Error("신고 사유를 선택해 주세요.");
|
|
1685
1706
|
let d = (c.detail || "").trim();
|
|
1686
1707
|
if (d.length > 200) throw Error("자세한 내용은 200자까지입니다.");
|
|
@@ -1709,9 +1730,9 @@ function un(e, t) {
|
|
|
1709
1730
|
submitReport: l
|
|
1710
1731
|
};
|
|
1711
1732
|
}
|
|
1712
|
-
var
|
|
1713
|
-
function
|
|
1714
|
-
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;
|
|
1715
1736
|
function _(e) {
|
|
1716
1737
|
return {
|
|
1717
1738
|
id: e.id,
|
|
@@ -1765,7 +1786,7 @@ function fn(e = {}) {
|
|
|
1765
1786
|
}
|
|
1766
1787
|
//#endregion
|
|
1767
1788
|
//#region src/composables/useMemiBoardViews.ts
|
|
1768
|
-
function
|
|
1789
|
+
function _n() {
|
|
1769
1790
|
let e = () => h(), n = Q();
|
|
1770
1791
|
function r(t, n) {
|
|
1771
1792
|
let { postsCollection: r } = e();
|
|
@@ -1805,7 +1826,7 @@ function pn() {
|
|
|
1805
1826
|
}
|
|
1806
1827
|
//#endregion
|
|
1807
1828
|
//#region src/utils/moderation-prompt.ts
|
|
1808
|
-
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 = {
|
|
1809
1830
|
abuse: "욕설·비속어·모욕",
|
|
1810
1831
|
spam: "스팸·광고",
|
|
1811
1832
|
adult: "선정적·성인 내용",
|
|
@@ -1813,17 +1834,17 @@ var mn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
|
|
|
1813
1834
|
other: "부적절한 내용",
|
|
1814
1835
|
none: ""
|
|
1815
1836
|
};
|
|
1816
|
-
function
|
|
1837
|
+
function bn(e) {
|
|
1817
1838
|
if (e.via === "local" && e.localHit) {
|
|
1818
1839
|
let t = e.localHit.trim();
|
|
1819
1840
|
return t.length > 0 && t.length <= 12 ? `「${t}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.` : "욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.";
|
|
1820
1841
|
}
|
|
1821
1842
|
let t = (e.reason || "").trim();
|
|
1822
1843
|
if (t) return t;
|
|
1823
|
-
let n = e.category && e.category !== "none" ?
|
|
1844
|
+
let n = e.category && e.category !== "none" ? yn[e.category] || e.category : "";
|
|
1824
1845
|
return n ? `${n}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.` : "게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.";
|
|
1825
1846
|
}
|
|
1826
|
-
var
|
|
1847
|
+
var xn = [
|
|
1827
1848
|
"씨발",
|
|
1828
1849
|
"시발",
|
|
1829
1850
|
"시이발",
|
|
@@ -1849,10 +1870,10 @@ var _n = [
|
|
|
1849
1870
|
"bitch",
|
|
1850
1871
|
"asshole"
|
|
1851
1872
|
];
|
|
1852
|
-
function
|
|
1873
|
+
function Sn(e) {
|
|
1853
1874
|
return new RegExp(e.join("|"), "i");
|
|
1854
1875
|
}
|
|
1855
|
-
var
|
|
1876
|
+
var Cn = /* @__PURE__ */ new Set([
|
|
1856
1877
|
"none",
|
|
1857
1878
|
"abuse",
|
|
1858
1879
|
"spam",
|
|
@@ -1860,7 +1881,7 @@ var yn = /* @__PURE__ */ new Set([
|
|
|
1860
1881
|
"violence",
|
|
1861
1882
|
"other"
|
|
1862
1883
|
]);
|
|
1863
|
-
function
|
|
1884
|
+
function wn(e) {
|
|
1864
1885
|
let t = e.trim();
|
|
1865
1886
|
if (!t) return null;
|
|
1866
1887
|
let n;
|
|
@@ -1878,7 +1899,7 @@ function bn(e) {
|
|
|
1878
1899
|
if (typeof n != "object" || !n) return null;
|
|
1879
1900
|
let r = n;
|
|
1880
1901
|
if (typeof r.flagged != "boolean") return null;
|
|
1881
|
-
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 : "";
|
|
1882
1903
|
return {
|
|
1883
1904
|
flagged: r.flagged,
|
|
1884
1905
|
category: i,
|
|
@@ -1887,20 +1908,20 @@ function bn(e) {
|
|
|
1887
1908
|
}
|
|
1888
1909
|
//#endregion
|
|
1889
1910
|
//#region src/composables/useMemiBoardModeration.ts
|
|
1890
|
-
var
|
|
1911
|
+
var Tn = {
|
|
1891
1912
|
flagged: !1,
|
|
1892
1913
|
category: "none",
|
|
1893
1914
|
reason: "",
|
|
1894
1915
|
via: "empty"
|
|
1895
1916
|
};
|
|
1896
|
-
function
|
|
1897
|
-
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 ?? []]);
|
|
1898
1919
|
function o(e) {
|
|
1899
1920
|
let t = e.match(a);
|
|
1900
1921
|
return t ? {
|
|
1901
1922
|
flagged: !0,
|
|
1902
1923
|
category: "abuse",
|
|
1903
|
-
reason:
|
|
1924
|
+
reason: bn({
|
|
1904
1925
|
via: "local",
|
|
1905
1926
|
localHit: t[0] || "",
|
|
1906
1927
|
category: "abuse"
|
|
@@ -1915,7 +1936,7 @@ function Sn() {
|
|
|
1915
1936
|
});
|
|
1916
1937
|
return Ce(i, {
|
|
1917
1938
|
model: n,
|
|
1918
|
-
systemInstruction:
|
|
1939
|
+
systemInstruction: vn,
|
|
1919
1940
|
generationConfig: {
|
|
1920
1941
|
temperature: 0,
|
|
1921
1942
|
maxOutputTokens: 256,
|
|
@@ -1944,7 +1965,7 @@ function Sn() {
|
|
|
1944
1965
|
};
|
|
1945
1966
|
}
|
|
1946
1967
|
function u(e, t = "") {
|
|
1947
|
-
let n =
|
|
1968
|
+
let n = bn({
|
|
1948
1969
|
reason: e.reason,
|
|
1949
1970
|
category: e.category,
|
|
1950
1971
|
via: e.via
|
|
@@ -1972,26 +1993,26 @@ function Sn() {
|
|
|
1972
1993
|
};
|
|
1973
1994
|
let a = t.trim();
|
|
1974
1995
|
if (!a) return {
|
|
1975
|
-
...
|
|
1996
|
+
...Tn,
|
|
1976
1997
|
via: "empty"
|
|
1977
1998
|
};
|
|
1978
1999
|
if (i?.skipFilter) return {
|
|
1979
|
-
...
|
|
2000
|
+
...Tn,
|
|
1980
2001
|
via: "admin-override"
|
|
1981
2002
|
};
|
|
1982
2003
|
let c = o(a);
|
|
1983
2004
|
if (c) return d(c);
|
|
1984
2005
|
if (e.enabled === !1) return {
|
|
1985
|
-
...
|
|
2006
|
+
...Tn,
|
|
1986
2007
|
via: "disabled"
|
|
1987
2008
|
};
|
|
1988
2009
|
try {
|
|
1989
|
-
let e =
|
|
2010
|
+
let e = wn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
|
|
1990
2011
|
if (!e) return l();
|
|
1991
2012
|
let t = {
|
|
1992
2013
|
flagged: e.flagged,
|
|
1993
2014
|
category: e.category,
|
|
1994
|
-
reason:
|
|
2015
|
+
reason: bn({
|
|
1995
2016
|
reason: e.reason,
|
|
1996
2017
|
category: e.category,
|
|
1997
2018
|
via: "ai"
|
|
@@ -2011,14 +2032,14 @@ function Sn() {
|
|
|
2011
2032
|
via: "restricted"
|
|
2012
2033
|
};
|
|
2013
2034
|
if (e.enabled === !1 || !e.moderateImages) return {
|
|
2014
|
-
...
|
|
2035
|
+
...Tn,
|
|
2015
2036
|
via: "disabled"
|
|
2016
2037
|
};
|
|
2017
2038
|
try {
|
|
2018
2039
|
let e = await new Promise((e, n) => {
|
|
2019
2040
|
let r = new FileReader();
|
|
2020
2041
|
r.onload = () => e(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(t);
|
|
2021
|
-
}), n =
|
|
2042
|
+
}), n = wn((await s().generateContent([{ inlineData: {
|
|
2022
2043
|
mimeType: t.type || "image/jpeg",
|
|
2023
2044
|
data: e
|
|
2024
2045
|
} }, "이 이미지를 심사해 주세요."])).response.text());
|
|
@@ -2026,7 +2047,7 @@ function Sn() {
|
|
|
2026
2047
|
let r = {
|
|
2027
2048
|
flagged: n.flagged,
|
|
2028
2049
|
category: n.category,
|
|
2029
|
-
reason:
|
|
2050
|
+
reason: bn({
|
|
2030
2051
|
reason: n.reason,
|
|
2031
2052
|
category: n.category,
|
|
2032
2053
|
via: "ai"
|
|
@@ -2045,7 +2066,7 @@ function Sn() {
|
|
|
2045
2066
|
}
|
|
2046
2067
|
//#endregion
|
|
2047
2068
|
//#region src/composables/useMemiBoardUsers.ts
|
|
2048
|
-
var
|
|
2069
|
+
var Dn = [
|
|
2049
2070
|
{
|
|
2050
2071
|
value: "admin",
|
|
2051
2072
|
label: "관리자",
|
|
@@ -2062,10 +2083,10 @@ var Cn = [
|
|
|
2062
2083
|
description: "글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다."
|
|
2063
2084
|
}
|
|
2064
2085
|
];
|
|
2065
|
-
function
|
|
2086
|
+
function On(e = {}) {
|
|
2066
2087
|
let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i = ae(r, { ssrKey: S(t(), "users-management") });
|
|
2067
2088
|
async function a(e, r) {
|
|
2068
|
-
if (!
|
|
2089
|
+
if (!Dn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
|
|
2069
2090
|
await J(y(n, t(), e), {
|
|
2070
2091
|
role: r,
|
|
2071
2092
|
updatedAt: G()
|
|
@@ -2079,7 +2100,7 @@ function wn(e = {}) {
|
|
|
2079
2100
|
}
|
|
2080
2101
|
//#endregion
|
|
2081
2102
|
//#region src/composables/useMemiBoardUserProfile.ts
|
|
2082
|
-
function
|
|
2103
|
+
function kn(e) {
|
|
2083
2104
|
let t = Q(), n = () => h(), r = A(() => N(e)), i = A(() => {
|
|
2084
2105
|
let e = r.value;
|
|
2085
2106
|
return e ? y(t, n(), e) : null;
|
|
@@ -2091,7 +2112,7 @@ function Tn(e) {
|
|
|
2091
2112
|
}
|
|
2092
2113
|
//#endregion
|
|
2093
2114
|
//#region src/utils/section.ts
|
|
2094
|
-
var
|
|
2115
|
+
var An = [
|
|
2095
2116
|
3,
|
|
2096
2117
|
4,
|
|
2097
2118
|
5,
|
|
@@ -2100,7 +2121,7 @@ var En = [
|
|
|
2100
2121
|
8,
|
|
2101
2122
|
9,
|
|
2102
2123
|
12
|
|
2103
|
-
],
|
|
2124
|
+
], jn = [
|
|
2104
2125
|
{
|
|
2105
2126
|
value: "list",
|
|
2106
2127
|
label: "게시목록"
|
|
@@ -2113,24 +2134,24 @@ var En = [
|
|
|
2113
2134
|
value: "comments",
|
|
2114
2135
|
label: "댓글모음"
|
|
2115
2136
|
}
|
|
2116
|
-
],
|
|
2137
|
+
], Mn = [{
|
|
2117
2138
|
value: "latest",
|
|
2118
2139
|
label: "최신순"
|
|
2119
2140
|
}, {
|
|
2120
2141
|
value: "likes",
|
|
2121
2142
|
label: "좋아요순"
|
|
2122
2143
|
}];
|
|
2123
|
-
function
|
|
2144
|
+
function Nn(e) {
|
|
2124
2145
|
return e === "list" ? 5 : 4;
|
|
2125
2146
|
}
|
|
2126
|
-
function
|
|
2147
|
+
function Pn(e, t) {
|
|
2127
2148
|
let n = Math.floor(Number(t));
|
|
2128
|
-
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);
|
|
2129
2150
|
}
|
|
2130
|
-
function
|
|
2151
|
+
function Fn(e) {
|
|
2131
2152
|
return e === 12 ? null : 12 - e;
|
|
2132
2153
|
}
|
|
2133
|
-
function
|
|
2154
|
+
function In(e) {
|
|
2134
2155
|
return {
|
|
2135
2156
|
3: "col-span-12 md:col-span-3",
|
|
2136
2157
|
4: "col-span-12 md:col-span-4",
|
|
@@ -2142,36 +2163,36 @@ function Mn(e) {
|
|
|
2142
2163
|
12: "col-span-12"
|
|
2143
2164
|
}[e];
|
|
2144
2165
|
}
|
|
2145
|
-
function
|
|
2166
|
+
function Ln(e) {
|
|
2146
2167
|
return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
|
|
2147
2168
|
}
|
|
2148
|
-
function
|
|
2169
|
+
function Rn(e) {
|
|
2149
2170
|
let t = e.boardId || e.category || "free";
|
|
2150
2171
|
return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
|
|
2151
2172
|
}
|
|
2152
|
-
function
|
|
2173
|
+
function zn(e) {
|
|
2153
2174
|
return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
|
|
2154
2175
|
}
|
|
2155
|
-
function
|
|
2176
|
+
function Bn(e) {
|
|
2156
2177
|
if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
|
|
2157
2178
|
}
|
|
2158
|
-
function
|
|
2179
|
+
function Vn(e) {
|
|
2159
2180
|
return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
|
|
2160
2181
|
}
|
|
2161
|
-
function
|
|
2182
|
+
function Hn(e) {
|
|
2162
2183
|
return e.title?.trim() || e.summary || "게시물";
|
|
2163
2184
|
}
|
|
2164
|
-
function
|
|
2185
|
+
function Un(e) {
|
|
2165
2186
|
return e === "image" || e === "video" ? "media" : "list";
|
|
2166
2187
|
}
|
|
2167
|
-
function
|
|
2168
|
-
return
|
|
2188
|
+
function Wn(e) {
|
|
2189
|
+
return Un(e) === "media" ? "미디어" : "목록";
|
|
2169
2190
|
}
|
|
2170
|
-
function
|
|
2191
|
+
function Gn(e, t) {
|
|
2171
2192
|
return e ? t(e)?.listView ?? "default" : "default";
|
|
2172
2193
|
}
|
|
2173
|
-
function
|
|
2174
|
-
let n = e.map((e) =>
|
|
2194
|
+
function Kn(e, t) {
|
|
2195
|
+
let n = e.map((e) => Gn(e.boardId, t));
|
|
2175
2196
|
if (!n.length) return "default";
|
|
2176
2197
|
if (n.every((e) => e === n[0])) return n[0];
|
|
2177
2198
|
let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
|
|
@@ -2179,27 +2200,27 @@ function Hn(e, t) {
|
|
|
2179
2200
|
}
|
|
2180
2201
|
//#endregion
|
|
2181
2202
|
//#region src/composables/useMemiBoardSections.ts
|
|
2182
|
-
var
|
|
2183
|
-
function
|
|
2203
|
+
var qn = [];
|
|
2204
|
+
function Jn(e) {
|
|
2184
2205
|
let t = Number(e.cols);
|
|
2185
|
-
if (
|
|
2206
|
+
if (An.includes(t)) return t;
|
|
2186
2207
|
let n = e.width;
|
|
2187
2208
|
return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
|
|
2188
2209
|
}
|
|
2189
|
-
function
|
|
2210
|
+
function Yn(e) {
|
|
2190
2211
|
let t = e.height ?? e.size;
|
|
2191
2212
|
return t === "sm" || t === "lg" ? t : "md";
|
|
2192
2213
|
}
|
|
2193
|
-
function
|
|
2214
|
+
function Xn(e) {
|
|
2194
2215
|
return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
|
|
2195
2216
|
}
|
|
2196
|
-
function
|
|
2217
|
+
function Zn(e) {
|
|
2197
2218
|
return e.sort === "likes" ? "likes" : "latest";
|
|
2198
2219
|
}
|
|
2199
|
-
function
|
|
2220
|
+
function Qn(e) {
|
|
2200
2221
|
return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
|
|
2201
2222
|
}
|
|
2202
|
-
function
|
|
2223
|
+
function $n(e, t) {
|
|
2203
2224
|
let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
|
|
2204
2225
|
for (let e of n) {
|
|
2205
2226
|
let n = String(e || "").trim();
|
|
@@ -2207,40 +2228,40 @@ function Yn(e, t) {
|
|
|
2207
2228
|
}
|
|
2208
2229
|
return r;
|
|
2209
2230
|
}
|
|
2210
|
-
function
|
|
2211
|
-
let n =
|
|
2231
|
+
function er(e, t) {
|
|
2232
|
+
let n = Xn(e), r = Pn(n, e.count);
|
|
2212
2233
|
return {
|
|
2213
2234
|
id: String(e.id || `box-${t + 1}`),
|
|
2214
2235
|
title: String(e.title || `섹션 ${t + 1}`),
|
|
2215
2236
|
showTitle: e.showTitle !== !1,
|
|
2216
2237
|
kind: n,
|
|
2217
|
-
boardId:
|
|
2238
|
+
boardId: Qn(e),
|
|
2218
2239
|
count: r,
|
|
2219
|
-
postIds:
|
|
2220
|
-
sort:
|
|
2221
|
-
cols:
|
|
2222
|
-
height:
|
|
2240
|
+
postIds: $n(e, r),
|
|
2241
|
+
sort: Zn(e),
|
|
2242
|
+
cols: Jn(e),
|
|
2243
|
+
height: Yn(e),
|
|
2223
2244
|
order: t
|
|
2224
2245
|
};
|
|
2225
2246
|
}
|
|
2226
|
-
function
|
|
2227
|
-
let e = Q(), t = te(e, "settings", "homeLayout"), { data: n, pending: r } = oe(t), i = A(() => (Array.isArray(n.value?.blocks) ? n.value.blocks :
|
|
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)));
|
|
2228
2249
|
async function a(e) {
|
|
2229
2250
|
await K(t, {
|
|
2230
2251
|
columns: 12,
|
|
2231
2252
|
blocks: e.map((e, t) => {
|
|
2232
|
-
let n = e, r =
|
|
2253
|
+
let n = e, r = Xn(n), i = Pn(r, e.count);
|
|
2233
2254
|
return {
|
|
2234
2255
|
id: e.id,
|
|
2235
2256
|
title: e.title.trim() || `섹션 ${t + 1}`,
|
|
2236
2257
|
showTitle: e.showTitle !== !1,
|
|
2237
2258
|
kind: r,
|
|
2238
|
-
boardId:
|
|
2259
|
+
boardId: Qn(n),
|
|
2239
2260
|
count: i,
|
|
2240
|
-
postIds:
|
|
2241
|
-
sort:
|
|
2242
|
-
cols:
|
|
2243
|
-
height:
|
|
2261
|
+
postIds: $n(n, i),
|
|
2262
|
+
sort: Zn(n),
|
|
2263
|
+
cols: Jn(n),
|
|
2264
|
+
height: Yn(n),
|
|
2244
2265
|
order: t
|
|
2245
2266
|
};
|
|
2246
2267
|
}),
|
|
@@ -2259,7 +2280,7 @@ function Zn() {
|
|
|
2259
2280
|
}
|
|
2260
2281
|
//#endregion
|
|
2261
2282
|
//#region src/composables/useMemiBoardMiniPosts.ts
|
|
2262
|
-
function
|
|
2283
|
+
function nr(e, t) {
|
|
2263
2284
|
let n = Q(), r = () => h(), i = N(e)?.trim() || "all", a = A(() => {
|
|
2264
2285
|
let i = Math.max(1, Math.floor(Number(N(t)) || 5)), a = N(e)?.trim() || "", s = [Y("isPublished", "==", !0), Y("listed", "==", !0)];
|
|
2265
2286
|
return a && s.unshift(Y("boardId", "==", a)), W(o(n, r()), ...s, U("createdAt", "desc"), V(i));
|
|
@@ -2270,7 +2291,7 @@ function Qn(e, t) {
|
|
|
2270
2291
|
error: l
|
|
2271
2292
|
};
|
|
2272
2293
|
}
|
|
2273
|
-
function
|
|
2294
|
+
function rr(e) {
|
|
2274
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}`) });
|
|
2275
2296
|
return {
|
|
2276
2297
|
posts: A(() => {
|
|
@@ -2287,7 +2308,12 @@ function $n(e) {
|
|
|
2287
2308
|
}
|
|
2288
2309
|
//#endregion
|
|
2289
2310
|
//#region src/data/versionHistory.ts
|
|
2290
|
-
var
|
|
2311
|
+
var ir = [
|
|
2312
|
+
{
|
|
2313
|
+
version: "0.44.1",
|
|
2314
|
+
date: "2026-10-01",
|
|
2315
|
+
highlights: ["Mac Safari에서 한글을 입력하고 바로 등록 버튼을 누를 때 두 번 눌러야 하던 문제를 고쳤어요"]
|
|
2316
|
+
},
|
|
2291
2317
|
{
|
|
2292
2318
|
version: "0.44.0",
|
|
2293
2319
|
date: "2026-10-01",
|
|
@@ -2562,7 +2588,7 @@ var er = [
|
|
|
2562
2588
|
highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
|
|
2563
2589
|
note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
|
|
2564
2590
|
}
|
|
2565
|
-
],
|
|
2591
|
+
], ar = /* @__PURE__ */ Ae(((e, t) => {
|
|
2566
2592
|
(function(n, r) {
|
|
2567
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();
|
|
2568
2594
|
})(e, (function() {
|
|
@@ -2856,7 +2882,7 @@ var er = [
|
|
|
2856
2882
|
return w(1e3 * e);
|
|
2857
2883
|
}, w.en = b[y], w.Ls = b, w.p = {}, w;
|
|
2858
2884
|
}));
|
|
2859
|
-
})),
|
|
2885
|
+
})), or = /* @__PURE__ */ Ae(((e, t) => {
|
|
2860
2886
|
(function(n, r) {
|
|
2861
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();
|
|
2862
2888
|
})(e, (function() {
|
|
@@ -2960,9 +2986,9 @@ var er = [
|
|
|
2960
2986
|
};
|
|
2961
2987
|
};
|
|
2962
2988
|
}));
|
|
2963
|
-
})),
|
|
2989
|
+
})), sr = /* @__PURE__ */ Ae(((e, t) => {
|
|
2964
2990
|
(function(n, r) {
|
|
2965
|
-
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);
|
|
2966
2992
|
})(e, (function(e) {
|
|
2967
2993
|
function t(e) {
|
|
2968
2994
|
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
@@ -3010,24 +3036,24 @@ var er = [
|
|
|
3010
3036
|
};
|
|
3011
3037
|
return n.default.locale(r, null, !0), r;
|
|
3012
3038
|
}));
|
|
3013
|
-
})),
|
|
3014
|
-
|
|
3015
|
-
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) {
|
|
3016
3042
|
return e?.toDate ? e.toDate().toLocaleDateString("ko-KR") : "";
|
|
3017
3043
|
}
|
|
3018
|
-
function
|
|
3019
|
-
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)) : "방금 전";
|
|
3020
3046
|
}
|
|
3021
|
-
function
|
|
3022
|
-
return e?.toDate ? (0,
|
|
3047
|
+
function fr(e) {
|
|
3048
|
+
return e?.toDate ? (0, cr.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
|
|
3023
3049
|
}
|
|
3024
|
-
function
|
|
3025
|
-
let n =
|
|
3026
|
-
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)}`];
|
|
3027
3053
|
}
|
|
3028
3054
|
//#endregion
|
|
3029
3055
|
//#region src/composables/useMemiBoardWritingAssistant.ts
|
|
3030
|
-
var
|
|
3056
|
+
var mr = 10, hr = 864e5, gr = 200, _r = {
|
|
3031
3057
|
proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
|
|
3032
3058
|
polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
|
|
3033
3059
|
continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
|
|
@@ -3036,19 +3062,19 @@ var ur = 10, dr = 864e5, fr = 200, pr = {
|
|
|
3036
3062
|
"translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
|
|
3037
3063
|
title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
|
|
3038
3064
|
};
|
|
3039
|
-
function
|
|
3040
|
-
if (e.action !== "custom") return
|
|
3041
|
-
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);
|
|
3042
3068
|
if (!t) throw Error("어떻게 바꿀지 지시문을 입력해 주세요.");
|
|
3043
3069
|
return `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${t}`;
|
|
3044
3070
|
}
|
|
3045
|
-
function
|
|
3071
|
+
function yr(e) {
|
|
3046
3072
|
return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
3047
3073
|
}
|
|
3048
|
-
function
|
|
3074
|
+
function br(e) {
|
|
3049
3075
|
return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
|
|
3050
3076
|
}
|
|
3051
|
-
function
|
|
3077
|
+
function xr() {
|
|
3052
3078
|
let e = se(), t = Q(), n = Z(), r = c();
|
|
3053
3079
|
async function i() {
|
|
3054
3080
|
let e = n.value?.uid;
|
|
@@ -3056,9 +3082,9 @@ function _r() {
|
|
|
3056
3082
|
await ie(t, async (n) => {
|
|
3057
3083
|
let r = y(t, h(), e), i = await n.get(r);
|
|
3058
3084
|
if (!i.exists()) throw Error("사용자 정보를 확인한 뒤 다시 시도해 주세요.");
|
|
3059
|
-
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;
|
|
3060
3086
|
if (l && s >= 10) {
|
|
3061
|
-
let e = o +
|
|
3087
|
+
let e = o + hr, t = Math.max(1, Math.ceil((e - c) / 36e5));
|
|
3062
3088
|
throw Error(`AI 글쓰기 도우미는 하루 10회까지 사용할 수 있습니다. 약 ${t}시간 후 다시 이용해 주세요.`);
|
|
3063
3089
|
}
|
|
3064
3090
|
n.update(r, {
|
|
@@ -3069,7 +3095,7 @@ function _r() {
|
|
|
3069
3095
|
});
|
|
3070
3096
|
}
|
|
3071
3097
|
async function a(t) {
|
|
3072
|
-
let n =
|
|
3098
|
+
let n = vr(t);
|
|
3073
3099
|
if (!t.content.trim()) throw Error("AI로 다듬을 내용을 먼저 입력해 주세요.");
|
|
3074
3100
|
await i();
|
|
3075
3101
|
let a = r.moderation ?? {}, o = Se(e, {
|
|
@@ -3090,7 +3116,7 @@ function _r() {
|
|
|
3090
3116
|
`작업: ${n}`,
|
|
3091
3117
|
t.title ? `현재 제목: ${t.title}` : "",
|
|
3092
3118
|
`본문:\n${c.slice(0, 12e3)}`
|
|
3093
|
-
].filter(Boolean).join("\n\n"), u =
|
|
3119
|
+
].filter(Boolean).join("\n\n"), u = yr((await s.generateContent(l)).response.text());
|
|
3094
3120
|
if (!u) throw Error("AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.");
|
|
3095
3121
|
return u;
|
|
3096
3122
|
}
|
|
@@ -3098,14 +3124,14 @@ function _r() {
|
|
|
3098
3124
|
}
|
|
3099
3125
|
//#endregion
|
|
3100
3126
|
//#region src/utils/renderMarkdown.ts
|
|
3101
|
-
function
|
|
3127
|
+
function Sr(e) {
|
|
3102
3128
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3103
3129
|
}
|
|
3104
|
-
function
|
|
3130
|
+
function Cr(e) {
|
|
3105
3131
|
let t = e;
|
|
3106
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;
|
|
3107
3133
|
}
|
|
3108
|
-
function
|
|
3134
|
+
function wr(e) {
|
|
3109
3135
|
if (!e?.trim()) return "";
|
|
3110
3136
|
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
|
|
3111
3137
|
function c() {
|
|
@@ -3114,7 +3140,7 @@ function br(e) {
|
|
|
3114
3140
|
return;
|
|
3115
3141
|
}
|
|
3116
3142
|
let e = o;
|
|
3117
|
-
n.push(`<${e}>${s.map((e) => `<li>${
|
|
3143
|
+
n.push(`<${e}>${s.map((e) => `<li>${Cr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
|
|
3118
3144
|
}
|
|
3119
3145
|
for (; r < t.length;) {
|
|
3120
3146
|
let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
|
|
@@ -3123,7 +3149,7 @@ function br(e) {
|
|
|
3123
3149
|
continue;
|
|
3124
3150
|
}
|
|
3125
3151
|
if (i) {
|
|
3126
|
-
a.push(
|
|
3152
|
+
a.push(Sr(e)), r++;
|
|
3127
3153
|
continue;
|
|
3128
3154
|
}
|
|
3129
3155
|
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
|
|
@@ -3134,24 +3160,24 @@ function br(e) {
|
|
|
3134
3160
|
if (u) {
|
|
3135
3161
|
c();
|
|
3136
3162
|
let e = u[1].length;
|
|
3137
|
-
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++;
|
|
3138
3164
|
continue;
|
|
3139
3165
|
}
|
|
3140
3166
|
if (e.startsWith("> ")) {
|
|
3141
3167
|
c();
|
|
3142
3168
|
let e = [];
|
|
3143
|
-
for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(
|
|
3144
|
-
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>`);
|
|
3145
3171
|
continue;
|
|
3146
3172
|
}
|
|
3147
3173
|
let d = e.match(/^[-*+]\s+(.+)$/);
|
|
3148
3174
|
if (d) {
|
|
3149
|
-
o && o !== "ul" && c(), o = "ul", s.push(
|
|
3175
|
+
o && o !== "ul" && c(), o = "ul", s.push(Sr(d[1])), r++;
|
|
3150
3176
|
continue;
|
|
3151
3177
|
}
|
|
3152
3178
|
let f = e.match(/^\d+\.\s+(.+)$/);
|
|
3153
3179
|
if (f) {
|
|
3154
|
-
o && o !== "ol" && c(), o = "ol", s.push(
|
|
3180
|
+
o && o !== "ol" && c(), o = "ol", s.push(Sr(f[1])), r++;
|
|
3155
3181
|
continue;
|
|
3156
3182
|
}
|
|
3157
3183
|
if (!e.trim()) {
|
|
@@ -3163,13 +3189,13 @@ function br(e) {
|
|
|
3163
3189
|
for (; r < t.length;) {
|
|
3164
3190
|
let e = t[r] ?? "";
|
|
3165
3191
|
if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
|
|
3166
|
-
p.push(
|
|
3192
|
+
p.push(Sr(e)), r++;
|
|
3167
3193
|
}
|
|
3168
|
-
n.push(`<p class="my-2 leading-relaxed">${
|
|
3194
|
+
n.push(`<p class="my-2 leading-relaxed">${Cr(p.join("<br />"))}</p>`);
|
|
3169
3195
|
}
|
|
3170
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");
|
|
3171
3197
|
}
|
|
3172
3198
|
//#endregion
|
|
3173
|
-
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 };
|
|
3174
3200
|
|
|
3175
3201
|
//# sourceMappingURL=index.js.map
|