memi-board 0.10.0 → 0.10.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 +3 -1
- package/dist/composables/useMemiBoardAuth.d.ts +1 -0
- package/dist/composables/useMemiBoardComments.d.ts +63 -0
- package/dist/composables/useMemiBoardStorage.d.ts +2 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +729 -203
- package/dist/index.js.map +1 -1
- package/dist/runtime/components/CategorySettings.vue +90 -0
- package/dist/runtime/components/CommentForm.vue +3 -1
- package/dist/runtime/components/CommentItem.vue +186 -21
- package/dist/runtime/components/CommentThread.vue +2 -0
- package/dist/runtime/components/Detail.vue +22 -4
- package/dist/runtime/components/Editor.vue +4 -4
- package/dist/runtime/components/Footer.vue +45 -0
- package/dist/runtime/components/List.vue +12 -9
- package/dist/runtime/components/ListDefault.vue +13 -2
- package/dist/runtime/components/ListImage.vue +13 -2
- package/dist/runtime/components/ListVideo.vue +13 -2
- package/dist/runtime/components/Settings.vue +19 -7
- package/dist/types.d.ts +6 -0
- package/dist/utils/formatDate.d.ts +4 -0
- package/docs/firestore.rules.example +37 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -264,7 +264,9 @@ const router = useRouter()
|
|
|
264
264
|
본문은 Nuxt UI **`UEditor`**(TipTap, `content-type="html"`). 호스트 `@nuxt/ui` 4.x 에 Editor 포함 필요.
|
|
265
265
|
|
|
266
266
|
**에디터 이미지:** 툴바 / 붙여넣기 / 드롭 → Firebase Storage
|
|
267
|
-
`{prefix}/posts/{postId}/images/*` + `.../images/thumbnails/*` (
|
|
267
|
+
`{prefix}/posts/{postId}/images/*` + `.../images/thumbnails/*` (최적화 이미지+썸네일).
|
|
268
|
+
|
|
269
|
+
본문 이미지는 휴대폰 원본 기준 최대 25MB까지 선택할 수 있다. 5MB를 넘으면 브라우저에서 최대 2560px·JPEG 85%로 최적화하고, 결과가 여전히 5MB를 넘으면 2048px·75%로 한 번 더 줄인 뒤 업로드한다. 5MB 이하 이미지는 원본을 유지한다.
|
|
268
270
|
본문 HTML에는 원본 URL. 수정 중 버려진 파일은 호스트 스케줄러로 정리 (`extractEditorImageUrls` 로 본문 참조 비교).
|
|
269
271
|
|
|
270
272
|
**composables:**
|
|
@@ -22,6 +22,7 @@ export interface UseMemiBoardAuthReturn {
|
|
|
22
22
|
signOut: () => Promise<void>;
|
|
23
23
|
canEdit: (post: Pick<PostModel, 'authorUid'>) => boolean;
|
|
24
24
|
canDelete: (post: Pick<PostModel, 'authorUid'>) => boolean;
|
|
25
|
+
canEditComment: (comment: Pick<CommentModel, 'authorUid'>) => boolean;
|
|
25
26
|
canDeleteComment: (comment: Pick<CommentModel, 'authorUid'>) => boolean;
|
|
26
27
|
/** 콘텐츠 검열 차단 1회 기록 후 메시지 조각 반환 */
|
|
27
28
|
recordContentModerationBlock: () => Promise<{
|
|
@@ -9,6 +9,7 @@ export interface AddCommentInput {
|
|
|
9
9
|
export interface AddReplyInput extends AddCommentInput {
|
|
10
10
|
parent: CommentModel;
|
|
11
11
|
}
|
|
12
|
+
export declare const COMMENT_BODY_MAX_LENGTH = 1000;
|
|
12
13
|
/** 10개씩 순차 조회한 뒤 마지막 페이지에서만 최신 1개를 실시간 구독한다. */
|
|
13
14
|
export declare function useMemiBoardComments(postId: string | Ref<string>, options?: {
|
|
14
15
|
subscribe?: boolean;
|
|
@@ -20,6 +21,8 @@ export declare function useMemiBoardComments(postId: string | Ref<string>, optio
|
|
|
20
21
|
loadMore: () => Promise<void>;
|
|
21
22
|
addComment: (input: AddCommentInput) => Promise<void>;
|
|
22
23
|
addReply: (input: AddReplyInput) => Promise<void>;
|
|
24
|
+
updateComment: (commentId: string, body: string) => Promise<void>;
|
|
25
|
+
setCommentBlinded: (commentId: string, isBlinded: boolean, moderatorUid: string) => Promise<void>;
|
|
23
26
|
deleteComment: (comment: CommentModel) => Promise<void>;
|
|
24
27
|
};
|
|
25
28
|
/** 펼친 스레드의 답글을 5개씩 일회성 조회한다. */
|
|
@@ -46,6 +49,36 @@ export declare function useMemiBoardReplies(postId: string, rootId: string): {
|
|
|
46
49
|
};
|
|
47
50
|
valueOf: () => string;
|
|
48
51
|
};
|
|
52
|
+
updatedAt?: {
|
|
53
|
+
readonly seconds: number;
|
|
54
|
+
readonly nanoseconds: number;
|
|
55
|
+
toDate: () => Date;
|
|
56
|
+
toMillis: () => number;
|
|
57
|
+
isEqual: (other: import('firebase/firestore').Timestamp) => boolean;
|
|
58
|
+
toString: () => string;
|
|
59
|
+
toJSON: () => {
|
|
60
|
+
seconds: number;
|
|
61
|
+
nanoseconds: number;
|
|
62
|
+
type: string;
|
|
63
|
+
};
|
|
64
|
+
valueOf: () => string;
|
|
65
|
+
} | undefined;
|
|
66
|
+
isBlinded?: boolean | undefined;
|
|
67
|
+
moderatedAt?: {
|
|
68
|
+
readonly seconds: number;
|
|
69
|
+
readonly nanoseconds: number;
|
|
70
|
+
toDate: () => Date;
|
|
71
|
+
toMillis: () => number;
|
|
72
|
+
isEqual: (other: import('firebase/firestore').Timestamp) => boolean;
|
|
73
|
+
toString: () => string;
|
|
74
|
+
toJSON: () => {
|
|
75
|
+
seconds: number;
|
|
76
|
+
nanoseconds: number;
|
|
77
|
+
type: string;
|
|
78
|
+
};
|
|
79
|
+
valueOf: () => string;
|
|
80
|
+
} | undefined;
|
|
81
|
+
moderatedBy?: string | undefined;
|
|
49
82
|
parentId?: string | null | undefined;
|
|
50
83
|
rootId?: string | undefined;
|
|
51
84
|
depth?: number | undefined;
|
|
@@ -75,6 +108,36 @@ export declare function useMemiBoardReplies(postId: string, rootId: string): {
|
|
|
75
108
|
};
|
|
76
109
|
valueOf: () => string;
|
|
77
110
|
};
|
|
111
|
+
updatedAt?: {
|
|
112
|
+
readonly seconds: number;
|
|
113
|
+
readonly nanoseconds: number;
|
|
114
|
+
toDate: () => Date;
|
|
115
|
+
toMillis: () => number;
|
|
116
|
+
isEqual: (other: import('firebase/firestore').Timestamp) => boolean;
|
|
117
|
+
toString: () => string;
|
|
118
|
+
toJSON: () => {
|
|
119
|
+
seconds: number;
|
|
120
|
+
nanoseconds: number;
|
|
121
|
+
type: string;
|
|
122
|
+
};
|
|
123
|
+
valueOf: () => string;
|
|
124
|
+
} | undefined;
|
|
125
|
+
isBlinded?: boolean | undefined;
|
|
126
|
+
moderatedAt?: {
|
|
127
|
+
readonly seconds: number;
|
|
128
|
+
readonly nanoseconds: number;
|
|
129
|
+
toDate: () => Date;
|
|
130
|
+
toMillis: () => number;
|
|
131
|
+
isEqual: (other: import('firebase/firestore').Timestamp) => boolean;
|
|
132
|
+
toString: () => string;
|
|
133
|
+
toJSON: () => {
|
|
134
|
+
seconds: number;
|
|
135
|
+
nanoseconds: number;
|
|
136
|
+
type: string;
|
|
137
|
+
};
|
|
138
|
+
valueOf: () => string;
|
|
139
|
+
} | undefined;
|
|
140
|
+
moderatedBy?: string | undefined;
|
|
78
141
|
parentId?: string | null | undefined;
|
|
79
142
|
rootId?: string | undefined;
|
|
80
143
|
depth?: number | undefined;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Attachment, EditorImageEntry } from '../types';
|
|
2
2
|
/** 에디터 이미지 최대 크기 (바이트) */
|
|
3
3
|
export declare const EDITOR_IMAGE_MAX_BYTES: number;
|
|
4
|
+
/** 휴대폰 원본 이미지 선택 허용 크기. 큰 이미지는 업로드 전에 최적화한다. */
|
|
5
|
+
export declare const EDITOR_IMAGE_SOURCE_MAX_BYTES: number;
|
|
4
6
|
export declare function useMemiBoardStorage(): {
|
|
5
7
|
uploadAttachment: (file: File, postId: string, onProgress?: (ratio: number) => void) => {
|
|
6
8
|
promise: Promise<Attachment>;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type { MemiBoardConfig, MemiBoardAuthOptions, MemiBoardModerationOptions
|
|
|
4
4
|
export { useMemiBoardAuth } from './composables/useMemiBoardAuth';
|
|
5
5
|
export { useMemiBoardPosts } from './composables/useMemiBoardPosts';
|
|
6
6
|
export type { CreatePostInput, UpdatePostInput } from './composables/useMemiBoardPosts';
|
|
7
|
-
export { useMemiBoardComments, useMemiBoardReplies } from './composables/useMemiBoardComments';
|
|
7
|
+
export { COMMENT_BODY_MAX_LENGTH, useMemiBoardComments, useMemiBoardReplies } from './composables/useMemiBoardComments';
|
|
8
8
|
export type { AddCommentInput, AddReplyInput } from './composables/useMemiBoardComments';
|
|
9
9
|
export { useMemiBoardModeration } from './composables/useMemiBoardModeration';
|
|
10
10
|
export { useMemiBoardStorage } from './composables/useMemiBoardStorage';
|
|
@@ -12,7 +12,7 @@ export { useMemiBoardSettings, DEFAULT_CATEGORIES } from './composables/useMemiB
|
|
|
12
12
|
export { useMemiBoardUsers, BOARD_USER_ROLES } from './composables/useMemiBoardUsers';
|
|
13
13
|
export { versionHistory } from './data/versionHistory';
|
|
14
14
|
export type { VersionHistoryEntry } from './data/versionHistory';
|
|
15
|
-
export { formatDate } from './utils/formatDate';
|
|
15
|
+
export { formatDate, formatFullDate, formatRelativeDate, formatTimestampDetails } from './utils/formatDate';
|
|
16
16
|
export { slugify } from './utils/slugify';
|
|
17
17
|
export { DEFAULT_BLOCK_BAN_THRESHOLD, DEFAULT_BLOCK_BAN_DECAY_MS, effectiveModerationBlockCount, isModerationWriteRestricted, moderationWriteRestrictedUntilMs, formatRestrictedUntilLabel, } from './utils/moderation-strike';
|
|
18
18
|
export type { Attachment, EditorImageEntry, ModerationStatus, PostModel, PostDetail, CommentModel, BoardUserRole, BoardUserModel, BoardCategory, BoardListView, BoardWriteRole, BoardSettingsModel, ModerationResult, } from './types';
|
|
@@ -20,4 +20,4 @@ export { compressImage } from './utils/compressImage';
|
|
|
20
20
|
export { extractEditorImageUrls } from './utils/extractEditorImageUrls';
|
|
21
21
|
export { renderMarkdownToHtml } from './utils/renderMarkdown';
|
|
22
22
|
export { storagePathFromDownloadUrl, postNamespaceFromStoragePath } from './utils/storagePath';
|
|
23
|
-
export { EDITOR_IMAGE_MAX_BYTES } from './composables/useMemiBoardStorage';
|
|
23
|
+
export { EDITOR_IMAGE_MAX_BYTES, EDITOR_IMAGE_SOURCE_MAX_BYTES } from './composables/useMemiBoardStorage';
|