@btst/stack 2.7.0 → 2.8.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 +1 -0
- package/dist/packages/stack/src/plugins/blog/client/components/loading/post-navigation-skeleton.cjs +13 -0
- package/dist/packages/stack/src/plugins/blog/client/components/loading/post-navigation-skeleton.mjs +11 -0
- package/dist/packages/stack/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.cjs +17 -0
- package/dist/packages/stack/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.mjs +15 -0
- package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -7
- package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -7
- package/dist/packages/stack/src/plugins/blog/client/components/shared/post-navigation.cjs +48 -52
- package/dist/packages/stack/src/plugins/blog/client/components/shared/post-navigation.mjs +49 -53
- package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +34 -37
- package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +35 -38
- package/dist/packages/stack/src/plugins/blog/client/hooks/blog-hooks.cjs +4 -21
- package/dist/packages/stack/src/plugins/blog/client/hooks/blog-hooks.mjs +4 -21
- package/dist/packages/stack/src/plugins/comments/api/getters.cjs +284 -0
- package/dist/packages/stack/src/plugins/comments/api/getters.mjs +280 -0
- package/dist/packages/stack/src/plugins/comments/api/mutations.cjs +118 -0
- package/dist/packages/stack/src/plugins/comments/api/mutations.mjs +112 -0
- package/dist/packages/stack/src/plugins/comments/api/plugin.cjs +335 -0
- package/dist/packages/stack/src/plugins/comments/api/plugin.mjs +333 -0
- package/dist/packages/stack/src/plugins/comments/api/query-key-defs.cjs +60 -0
- package/dist/packages/stack/src/plugins/comments/api/query-key-defs.mjs +55 -0
- package/dist/packages/stack/src/plugins/comments/api/serializers.cjs +23 -0
- package/dist/packages/stack/src/plugins/comments/api/serializers.mjs +21 -0
- package/dist/packages/stack/src/plugins/comments/client/components/comment-count.cjs +46 -0
- package/dist/packages/stack/src/plugins/comments/client/components/comment-count.mjs +44 -0
- package/dist/packages/stack/src/plugins/comments/client/components/comment-form.cjs +86 -0
- package/dist/packages/stack/src/plugins/comments/client/components/comment-form.mjs +84 -0
- package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.cjs +540 -0
- package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.mjs +538 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.cjs +64 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.cjs +426 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.mjs +424 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.mjs +62 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.cjs +66 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.cjs +256 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.mjs +254 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.mjs +64 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.cjs +86 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.cjs +191 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.mjs +189 -0
- package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.mjs +84 -0
- package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.cjs +27 -0
- package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.mjs +25 -0
- package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.cjs +37 -0
- package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.mjs +35 -0
- package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.cjs +476 -0
- package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.mjs +464 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/comments-moderation.cjs +67 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/comments-moderation.mjs +65 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/comments-my.cjs +27 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/comments-my.mjs +25 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.cjs +30 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.mjs +28 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/index.cjs +13 -0
- package/dist/packages/stack/src/plugins/comments/client/localization/index.mjs +11 -0
- package/dist/packages/stack/src/plugins/comments/client/plugin.cjs +116 -0
- package/dist/packages/stack/src/plugins/comments/client/plugin.mjs +114 -0
- package/dist/packages/stack/src/plugins/comments/client/utils.cjs +41 -0
- package/dist/packages/stack/src/plugins/comments/client/utils.mjs +37 -0
- package/dist/packages/stack/src/plugins/comments/db.cjs +75 -0
- package/dist/packages/stack/src/plugins/comments/db.mjs +73 -0
- package/dist/packages/stack/src/plugins/comments/schemas.cjs +45 -0
- package/dist/packages/stack/src/plugins/comments/schemas.mjs +38 -0
- package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +0 -1
- package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +0 -1
- package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +39 -22
- package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +40 -23
- package/dist/packages/ui/src/components/avatar.mjs +1 -1
- package/dist/packages/ui/src/components/pagination-controls.cjs +64 -0
- package/dist/packages/ui/src/components/pagination-controls.mjs +62 -0
- package/dist/packages/ui/src/components/when-visible.cjs +39 -0
- package/dist/packages/ui/src/components/when-visible.mjs +37 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +1 -1
- package/dist/plugins/blog/client/hooks/index.d.mts +1 -1
- package/dist/plugins/blog/client/hooks/index.d.ts +1 -1
- package/dist/plugins/blog/client/index.d.cts +24 -2
- package/dist/plugins/blog/client/index.d.mts +24 -2
- package/dist/plugins/blog/client/index.d.ts +24 -2
- package/dist/plugins/comments/api/index.cjs +21 -0
- package/dist/plugins/comments/api/index.d.cts +126 -0
- package/dist/plugins/comments/api/index.d.mts +126 -0
- package/dist/plugins/comments/api/index.d.ts +126 -0
- package/dist/plugins/comments/api/index.mjs +5 -0
- package/dist/plugins/comments/client/components/index.cjs +15 -0
- package/dist/plugins/comments/client/components/index.d.cts +125 -0
- package/dist/plugins/comments/client/components/index.d.mts +125 -0
- package/dist/plugins/comments/client/components/index.d.ts +125 -0
- package/dist/plugins/comments/client/components/index.mjs +5 -0
- package/dist/plugins/comments/client/hooks/index.cjs +17 -0
- package/dist/plugins/comments/client/hooks/index.d.cts +200 -0
- package/dist/plugins/comments/client/hooks/index.d.mts +200 -0
- package/dist/plugins/comments/client/hooks/index.d.ts +200 -0
- package/dist/plugins/comments/client/hooks/index.mjs +1 -0
- package/dist/plugins/comments/client/index.cjs +9 -0
- package/dist/plugins/comments/client/index.d.cts +262 -0
- package/dist/plugins/comments/client/index.d.mts +262 -0
- package/dist/plugins/comments/client/index.d.ts +262 -0
- package/dist/plugins/comments/client/index.mjs +2 -0
- package/dist/plugins/comments/client.css +2 -0
- package/dist/plugins/comments/query-keys.cjs +113 -0
- package/dist/plugins/comments/query-keys.d.cts +71 -0
- package/dist/plugins/comments/query-keys.d.mts +71 -0
- package/dist/plugins/comments/query-keys.d.ts +71 -0
- package/dist/plugins/comments/query-keys.mjs +111 -0
- package/dist/plugins/comments/style.css +15 -0
- package/dist/plugins/kanban/api/index.d.cts +1 -1
- package/dist/plugins/kanban/api/index.d.mts +1 -1
- package/dist/plugins/kanban/api/index.d.ts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
- package/dist/plugins/kanban/client/index.d.cts +1 -1
- package/dist/plugins/kanban/client/index.d.mts +1 -1
- package/dist/plugins/kanban/client/index.d.ts +1 -1
- package/dist/plugins/kanban/query-keys.d.cts +1 -1
- package/dist/plugins/kanban/query-keys.d.mts +1 -1
- package/dist/plugins/kanban/query-keys.d.ts +1 -1
- package/dist/shared/{stack.FeaWkglm.d.ts → stack.BxFl46lB.d.cts} +24 -1
- package/dist/shared/stack.C-b3Sn8j.d.cts +142 -0
- package/dist/shared/stack.C-b3Sn8j.d.mts +142 -0
- package/dist/shared/stack.C-b3Sn8j.d.ts +142 -0
- package/dist/shared/stack.CJE9sAjV.d.ts +335 -0
- package/dist/shared/stack.CmHRdhl8.d.cts +335 -0
- package/dist/shared/{stack.CNLHlv7r.d.mts → stack.DOZ1EXjM.d.mts} +6 -12
- package/dist/shared/{stack.FeaWkglm.d.mts → stack.DRpeDS6X.d.ts} +24 -1
- package/dist/shared/{stack.CQAZwXhV.d.cts → stack.DX-tQ93o.d.cts} +6 -12
- package/dist/shared/stack.Dcz6636A.d.mts +335 -0
- package/dist/shared/{stack.FeaWkglm.d.cts → stack.Jb0kQDJC.d.mts} +24 -1
- package/dist/shared/stack.Ldfkr5b2.d.cts +112 -0
- package/dist/shared/stack.Ldfkr5b2.d.mts +112 -0
- package/dist/shared/stack.Ldfkr5b2.d.ts +112 -0
- package/dist/shared/{stack.D3BsrpAz.d.ts → stack.VF6FhyZw.d.ts} +6 -12
- package/package.json +69 -4
- package/src/plugins/blog/client/components/loading/post-navigation-skeleton.tsx +10 -0
- package/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.tsx +18 -0
- package/src/plugins/blog/client/components/pages/post-page.internal.tsx +23 -8
- package/src/plugins/blog/client/components/shared/post-navigation.tsx +0 -5
- package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +1 -5
- package/src/plugins/blog/client/hooks/blog-hooks.tsx +8 -33
- package/src/plugins/blog/client/overrides.ts +26 -1
- package/src/plugins/cms/client/components/shared/pagination.tsx +14 -42
- package/src/plugins/comments/api/getters.ts +444 -0
- package/src/plugins/comments/api/index.ts +21 -0
- package/src/plugins/comments/api/mutations.ts +206 -0
- package/src/plugins/comments/api/plugin.ts +628 -0
- package/src/plugins/comments/api/query-key-defs.ts +143 -0
- package/src/plugins/comments/api/serializers.ts +37 -0
- package/src/plugins/comments/client/components/comment-count.tsx +66 -0
- package/src/plugins/comments/client/components/comment-form.tsx +112 -0
- package/src/plugins/comments/client/components/comment-thread.tsx +799 -0
- package/src/plugins/comments/client/components/index.tsx +11 -0
- package/src/plugins/comments/client/components/pages/moderation-page.internal.tsx +550 -0
- package/src/plugins/comments/client/components/pages/moderation-page.tsx +70 -0
- package/src/plugins/comments/client/components/pages/my-comments-page.internal.tsx +367 -0
- package/src/plugins/comments/client/components/pages/my-comments-page.tsx +72 -0
- package/src/plugins/comments/client/components/pages/resource-comments-page.internal.tsx +225 -0
- package/src/plugins/comments/client/components/pages/resource-comments-page.tsx +97 -0
- package/src/plugins/comments/client/components/shared/page-wrapper.tsx +32 -0
- package/src/plugins/comments/client/components/shared/pagination.tsx +44 -0
- package/src/plugins/comments/client/hooks/index.tsx +13 -0
- package/src/plugins/comments/client/hooks/use-comments.tsx +717 -0
- package/src/plugins/comments/client/index.ts +14 -0
- package/src/plugins/comments/client/localization/comments-moderation.ts +75 -0
- package/src/plugins/comments/client/localization/comments-my.ts +32 -0
- package/src/plugins/comments/client/localization/comments-thread.ts +32 -0
- package/src/plugins/comments/client/localization/index.ts +11 -0
- package/src/plugins/comments/client/overrides.ts +164 -0
- package/src/plugins/comments/client/plugin.tsx +195 -0
- package/src/plugins/comments/client/utils.ts +67 -0
- package/src/plugins/comments/client.css +2 -0
- package/src/plugins/comments/db.ts +77 -0
- package/src/plugins/comments/query-keys.ts +189 -0
- package/src/plugins/comments/schemas.ts +72 -0
- package/src/plugins/comments/style.css +15 -0
- package/src/plugins/comments/types.ts +73 -0
- package/src/plugins/kanban/client/components/forms/task-form.tsx +0 -1
- package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +46 -27
- package/src/plugins/kanban/client/overrides.ts +27 -1
- package/dist/shared/{stack.Rtcvl8sS.d.cts → stack.BOokfhZD.d.cts} +3 -3
- package/dist/shared/{stack.D4Cea8II.d.ts → stack.BvCR4-9H.d.ts} +3 -3
- package/dist/shared/{stack.HE_IvqV5.d.mts → stack.CWxAl9K3.d.mts} +3 -3
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
commentsClientPlugin,
|
|
3
|
+
type CommentsClientConfig,
|
|
4
|
+
type CommentsClientHooks,
|
|
5
|
+
type LoaderContext,
|
|
6
|
+
} from "./plugin";
|
|
7
|
+
export {
|
|
8
|
+
type CommentsPluginOverrides,
|
|
9
|
+
type RouteContext,
|
|
10
|
+
} from "./overrides";
|
|
11
|
+
export {
|
|
12
|
+
COMMENTS_LOCALIZATION,
|
|
13
|
+
type CommentsLocalization,
|
|
14
|
+
} from "./localization";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const COMMENTS_MODERATION = {
|
|
2
|
+
COMMENTS_MODERATION_TITLE: "Comment Moderation",
|
|
3
|
+
COMMENTS_MODERATION_DESCRIPTION:
|
|
4
|
+
"Review and manage comments across all resources.",
|
|
5
|
+
|
|
6
|
+
COMMENTS_MODERATION_TAB_PENDING: "Pending",
|
|
7
|
+
COMMENTS_MODERATION_TAB_APPROVED: "Approved",
|
|
8
|
+
COMMENTS_MODERATION_TAB_SPAM: "Spam",
|
|
9
|
+
|
|
10
|
+
COMMENTS_MODERATION_SELECTED: "{n} selected",
|
|
11
|
+
COMMENTS_MODERATION_APPROVE_SELECTED: "Approve selected",
|
|
12
|
+
COMMENTS_MODERATION_DELETE_SELECTED: "Delete selected",
|
|
13
|
+
COMMENTS_MODERATION_EMPTY: "No {status} comments.",
|
|
14
|
+
|
|
15
|
+
COMMENTS_MODERATION_COL_AUTHOR: "Author",
|
|
16
|
+
COMMENTS_MODERATION_COL_COMMENT: "Comment",
|
|
17
|
+
COMMENTS_MODERATION_COL_RESOURCE: "Resource",
|
|
18
|
+
COMMENTS_MODERATION_COL_DATE: "Date",
|
|
19
|
+
COMMENTS_MODERATION_COL_ACTIONS: "Actions",
|
|
20
|
+
COMMENTS_MODERATION_SELECT_ALL: "Select all",
|
|
21
|
+
COMMENTS_MODERATION_SELECT_ONE: "Select comment",
|
|
22
|
+
|
|
23
|
+
COMMENTS_MODERATION_ACTION_VIEW: "View",
|
|
24
|
+
COMMENTS_MODERATION_ACTION_APPROVE: "Approve",
|
|
25
|
+
COMMENTS_MODERATION_ACTION_SPAM: "Mark as spam",
|
|
26
|
+
COMMENTS_MODERATION_ACTION_DELETE: "Delete",
|
|
27
|
+
|
|
28
|
+
COMMENTS_MODERATION_TOAST_APPROVED: "Comment approved",
|
|
29
|
+
COMMENTS_MODERATION_TOAST_APPROVE_ERROR: "Failed to approve comment",
|
|
30
|
+
COMMENTS_MODERATION_TOAST_SPAM: "Marked as spam",
|
|
31
|
+
COMMENTS_MODERATION_TOAST_SPAM_ERROR: "Failed to update status",
|
|
32
|
+
COMMENTS_MODERATION_TOAST_DELETED: "Comment deleted",
|
|
33
|
+
COMMENTS_MODERATION_TOAST_DELETED_PLURAL: "{n} comments deleted",
|
|
34
|
+
COMMENTS_MODERATION_TOAST_DELETE_ERROR: "Failed to delete comment(s)",
|
|
35
|
+
COMMENTS_MODERATION_TOAST_BULK_APPROVED: "{n} comment(s) approved",
|
|
36
|
+
COMMENTS_MODERATION_TOAST_BULK_APPROVE_ERROR: "Failed to approve comments",
|
|
37
|
+
|
|
38
|
+
COMMENTS_MODERATION_DIALOG_TITLE: "Comment Details",
|
|
39
|
+
COMMENTS_MODERATION_DIALOG_RESOURCE: "Resource",
|
|
40
|
+
COMMENTS_MODERATION_DIALOG_LIKES: "Likes",
|
|
41
|
+
COMMENTS_MODERATION_DIALOG_REPLY_TO: "Reply to",
|
|
42
|
+
COMMENTS_MODERATION_DIALOG_EDITED: "Edited",
|
|
43
|
+
COMMENTS_MODERATION_DIALOG_BODY: "Body",
|
|
44
|
+
COMMENTS_MODERATION_DIALOG_APPROVE: "Approve",
|
|
45
|
+
COMMENTS_MODERATION_DIALOG_MARK_SPAM: "Mark spam",
|
|
46
|
+
COMMENTS_MODERATION_DIALOG_DELETE: "Delete",
|
|
47
|
+
|
|
48
|
+
COMMENTS_MODERATION_DELETE_TITLE_SINGULAR: "Delete comment?",
|
|
49
|
+
COMMENTS_MODERATION_DELETE_TITLE_PLURAL: "Delete {n} comments?",
|
|
50
|
+
COMMENTS_MODERATION_DELETE_DESCRIPTION_SINGULAR:
|
|
51
|
+
"This action cannot be undone. The comment will be permanently deleted.",
|
|
52
|
+
COMMENTS_MODERATION_DELETE_DESCRIPTION_PLURAL:
|
|
53
|
+
"This action cannot be undone. The comments will be permanently deleted.",
|
|
54
|
+
COMMENTS_MODERATION_DELETE_CANCEL: "Cancel",
|
|
55
|
+
COMMENTS_MODERATION_DELETE_CONFIRM: "Delete",
|
|
56
|
+
COMMENTS_MODERATION_DELETE_DELETING: "Deleting…",
|
|
57
|
+
|
|
58
|
+
COMMENTS_MODERATION_PAGINATION_PREVIOUS: "Previous",
|
|
59
|
+
COMMENTS_MODERATION_PAGINATION_NEXT: "Next",
|
|
60
|
+
COMMENTS_MODERATION_PAGINATION_SHOWING: "Showing {from}–{to} of {total}",
|
|
61
|
+
|
|
62
|
+
COMMENTS_RESOURCE_TITLE: "Comments",
|
|
63
|
+
COMMENTS_RESOURCE_PENDING_SECTION: "Pending Review",
|
|
64
|
+
COMMENTS_RESOURCE_THREAD_SECTION: "Thread",
|
|
65
|
+
COMMENTS_RESOURCE_ACTION_APPROVE: "Approve",
|
|
66
|
+
COMMENTS_RESOURCE_ACTION_SPAM: "Spam",
|
|
67
|
+
COMMENTS_RESOURCE_ACTION_DELETE: "Delete",
|
|
68
|
+
COMMENTS_RESOURCE_DELETE_CONFIRM: "Delete this comment?",
|
|
69
|
+
COMMENTS_RESOURCE_TOAST_APPROVED: "Comment approved",
|
|
70
|
+
COMMENTS_RESOURCE_TOAST_APPROVE_ERROR: "Failed to approve",
|
|
71
|
+
COMMENTS_RESOURCE_TOAST_SPAM: "Marked as spam",
|
|
72
|
+
COMMENTS_RESOURCE_TOAST_SPAM_ERROR: "Failed to update",
|
|
73
|
+
COMMENTS_RESOURCE_TOAST_DELETED: "Comment deleted",
|
|
74
|
+
COMMENTS_RESOURCE_TOAST_DELETE_ERROR: "Failed to delete",
|
|
75
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const COMMENTS_MY = {
|
|
2
|
+
COMMENTS_MY_LOGIN_TITLE: "Please log in to view your comments",
|
|
3
|
+
COMMENTS_MY_LOGIN_DESCRIPTION:
|
|
4
|
+
"You need to be logged in to see your comment history.",
|
|
5
|
+
|
|
6
|
+
COMMENTS_MY_EMPTY_TITLE: "No comments yet",
|
|
7
|
+
COMMENTS_MY_EMPTY_DESCRIPTION: "Comments you post will appear here.",
|
|
8
|
+
|
|
9
|
+
COMMENTS_MY_PAGE_TITLE: "My Comments",
|
|
10
|
+
|
|
11
|
+
COMMENTS_MY_COL_COMMENT: "Comment",
|
|
12
|
+
COMMENTS_MY_COL_RESOURCE: "Resource",
|
|
13
|
+
COMMENTS_MY_COL_STATUS: "Status",
|
|
14
|
+
COMMENTS_MY_COL_DATE: "Date",
|
|
15
|
+
|
|
16
|
+
COMMENTS_MY_REPLY_INDICATOR: "↩ Reply",
|
|
17
|
+
COMMENTS_MY_VIEW_LINK: "View",
|
|
18
|
+
|
|
19
|
+
COMMENTS_MY_STATUS_APPROVED: "Approved",
|
|
20
|
+
COMMENTS_MY_STATUS_PENDING: "Pending",
|
|
21
|
+
COMMENTS_MY_STATUS_SPAM: "Spam",
|
|
22
|
+
|
|
23
|
+
COMMENTS_MY_TOAST_DELETED: "Comment deleted",
|
|
24
|
+
COMMENTS_MY_TOAST_DELETE_ERROR: "Failed to delete comment",
|
|
25
|
+
|
|
26
|
+
COMMENTS_MY_DELETE_TITLE: "Delete comment?",
|
|
27
|
+
COMMENTS_MY_DELETE_DESCRIPTION:
|
|
28
|
+
"This action cannot be undone. The comment will be permanently removed.",
|
|
29
|
+
COMMENTS_MY_DELETE_CANCEL: "Cancel",
|
|
30
|
+
COMMENTS_MY_DELETE_CONFIRM: "Delete",
|
|
31
|
+
COMMENTS_MY_DELETE_BUTTON_SR: "Delete comment",
|
|
32
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const COMMENTS_THREAD = {
|
|
2
|
+
COMMENTS_TITLE: "Comments",
|
|
3
|
+
COMMENTS_EMPTY: "Be the first to comment.",
|
|
4
|
+
|
|
5
|
+
COMMENTS_EDITED_BADGE: "(edited)",
|
|
6
|
+
COMMENTS_PENDING_BADGE: "Pending approval",
|
|
7
|
+
|
|
8
|
+
COMMENTS_LIKE_ARIA: "Like",
|
|
9
|
+
COMMENTS_UNLIKE_ARIA: "Unlike",
|
|
10
|
+
COMMENTS_REPLY_BUTTON: "Reply",
|
|
11
|
+
COMMENTS_EDIT_BUTTON: "Edit",
|
|
12
|
+
COMMENTS_DELETE_BUTTON: "Delete",
|
|
13
|
+
COMMENTS_SAVE_EDIT: "Save",
|
|
14
|
+
|
|
15
|
+
COMMENTS_REPLIES_SINGULAR: "reply",
|
|
16
|
+
COMMENTS_REPLIES_PLURAL: "replies",
|
|
17
|
+
COMMENTS_HIDE_REPLIES: "Hide replies",
|
|
18
|
+
COMMENTS_DELETE_CONFIRM: "Delete this comment?",
|
|
19
|
+
|
|
20
|
+
COMMENTS_LOGIN_PROMPT: "Please sign in to leave a comment.",
|
|
21
|
+
COMMENTS_LOGIN_LINK: "Sign in",
|
|
22
|
+
|
|
23
|
+
COMMENTS_FORM_PLACEHOLDER: "Write a comment…",
|
|
24
|
+
COMMENTS_FORM_CANCEL: "Cancel",
|
|
25
|
+
COMMENTS_FORM_POST_COMMENT: "Post comment",
|
|
26
|
+
COMMENTS_FORM_POST_REPLY: "Post reply",
|
|
27
|
+
COMMENTS_FORM_POSTING: "Posting…",
|
|
28
|
+
COMMENTS_FORM_SUBMIT_ERROR: "Failed to submit comment",
|
|
29
|
+
|
|
30
|
+
COMMENTS_LOAD_MORE: "Load more comments",
|
|
31
|
+
COMMENTS_LOADING_MORE: "Loading…",
|
|
32
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { COMMENTS_THREAD } from "./comments-thread";
|
|
2
|
+
import { COMMENTS_MODERATION } from "./comments-moderation";
|
|
3
|
+
import { COMMENTS_MY } from "./comments-my";
|
|
4
|
+
|
|
5
|
+
export const COMMENTS_LOCALIZATION = {
|
|
6
|
+
...COMMENTS_THREAD,
|
|
7
|
+
...COMMENTS_MODERATION,
|
|
8
|
+
...COMMENTS_MY,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CommentsLocalization = typeof COMMENTS_LOCALIZATION;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context passed to lifecycle hooks
|
|
3
|
+
*/
|
|
4
|
+
export interface RouteContext {
|
|
5
|
+
/** Current route path */
|
|
6
|
+
path: string;
|
|
7
|
+
/** Route parameters (e.g., { resourceId: "my-post", resourceType: "blog-post" }) */
|
|
8
|
+
params?: Record<string, string>;
|
|
9
|
+
/** Whether rendering on server (true) or client (false) */
|
|
10
|
+
isSSR: boolean;
|
|
11
|
+
/** Additional context properties */
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
import type { CommentsLocalization } from "./localization";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Overridable configuration and hooks for the Comments plugin.
|
|
19
|
+
*
|
|
20
|
+
* Provide these in the layout wrapping your pages via `PluginOverridesProvider`.
|
|
21
|
+
*/
|
|
22
|
+
export interface CommentsPluginOverrides {
|
|
23
|
+
/**
|
|
24
|
+
* Localization strings for all Comments plugin UI.
|
|
25
|
+
* Defaults to English when not provided.
|
|
26
|
+
*/
|
|
27
|
+
localization?: Partial<CommentsLocalization>;
|
|
28
|
+
/**
|
|
29
|
+
* Base URL for API calls (e.g., "https://example.com")
|
|
30
|
+
*/
|
|
31
|
+
apiBaseURL: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Path where the API is mounted (e.g., "/api/data")
|
|
35
|
+
*/
|
|
36
|
+
apiBasePath: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Optional headers for authenticated API calls (e.g., forwarding cookies)
|
|
40
|
+
*/
|
|
41
|
+
headers?: Record<string, string>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Whether to show the "Powered by BTST" attribution on plugin pages.
|
|
45
|
+
* Defaults to true.
|
|
46
|
+
*/
|
|
47
|
+
showAttribution?: boolean;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The ID of the currently authenticated user.
|
|
51
|
+
*
|
|
52
|
+
* Used by the User Comments page and the per-resource comments admin view to
|
|
53
|
+
* scope the comment list to the current user and to enable posting.
|
|
54
|
+
* Can be a static string or an async function (useful when the user ID must
|
|
55
|
+
* be resolved from a session cookie at render time).
|
|
56
|
+
*
|
|
57
|
+
* When absent both pages show a "Please log in" prompt.
|
|
58
|
+
*/
|
|
59
|
+
currentUserId?:
|
|
60
|
+
| string
|
|
61
|
+
| (() => string | undefined | Promise<string | undefined>);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* URL to redirect unauthenticated users to when they try to post a comment.
|
|
65
|
+
*
|
|
66
|
+
* Forwarded to every embedded `CommentThread` (including the one on the
|
|
67
|
+
* per-resource admin comments view). When absent no login link is shown.
|
|
68
|
+
*/
|
|
69
|
+
loginHref?: string;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Default number of top-level comments to load per page in `CommentThread`.
|
|
73
|
+
* Can be overridden per-instance via the `pageSize` prop.
|
|
74
|
+
* Defaults to 100 when not set.
|
|
75
|
+
*/
|
|
76
|
+
defaultCommentPageSize?: number;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* When false, the comment form and reply buttons are hidden in all
|
|
80
|
+
* `CommentThread` instances. Users can still read existing comments.
|
|
81
|
+
* Defaults to true.
|
|
82
|
+
*
|
|
83
|
+
* Can be overridden per-instance via the `allowPosting` prop on `CommentThread`.
|
|
84
|
+
*/
|
|
85
|
+
allowPosting?: boolean;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* When false, the edit button is hidden on all comment cards in all
|
|
89
|
+
* `CommentThread` instances.
|
|
90
|
+
* Defaults to true.
|
|
91
|
+
*
|
|
92
|
+
* Can be overridden per-instance via the `allowEditing` prop on `CommentThread`.
|
|
93
|
+
*/
|
|
94
|
+
allowEditing?: boolean;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Per-resource-type URL builders used to link each comment back to its
|
|
98
|
+
* original resource on the User Comments page.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* resourceLinks: {
|
|
103
|
+
* "blog-post": (slug) => `/pages/blog/${slug}`,
|
|
104
|
+
* "kanban-task": (id) => `/pages/kanban?task=${id}`,
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* When a resource type has no entry the ID is shown as plain text.
|
|
109
|
+
*/
|
|
110
|
+
resourceLinks?: Record<string, (id: string) => string>;
|
|
111
|
+
|
|
112
|
+
// ============ Access Control Hooks ============
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Called before the moderation dashboard page is rendered.
|
|
116
|
+
* Return false to block rendering (e.g., redirect to login or show 403).
|
|
117
|
+
* @param context - Route context
|
|
118
|
+
*/
|
|
119
|
+
onBeforeModerationPageRendered?: (context: RouteContext) => boolean;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Called before the per-resource comments page is rendered.
|
|
123
|
+
* Return false to block rendering (e.g., for authorization).
|
|
124
|
+
* @param resourceType - The type of resource (e.g., "blog-post")
|
|
125
|
+
* @param resourceId - The ID of the resource
|
|
126
|
+
* @param context - Route context
|
|
127
|
+
*/
|
|
128
|
+
onBeforeResourceCommentsRendered?: (
|
|
129
|
+
resourceType: string,
|
|
130
|
+
resourceId: string,
|
|
131
|
+
context: RouteContext,
|
|
132
|
+
) => boolean;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Called before the User Comments page is rendered.
|
|
136
|
+
* Throw to block rendering (e.g., when the user is not authenticated).
|
|
137
|
+
* @param context - Route context
|
|
138
|
+
*/
|
|
139
|
+
onBeforeUserCommentsPageRendered?: (context: RouteContext) => boolean | void;
|
|
140
|
+
|
|
141
|
+
// ============ Lifecycle Hooks ============
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Called when a route is rendered.
|
|
145
|
+
* @param routeName - Name of the route (e.g., 'moderation', 'resourceComments')
|
|
146
|
+
* @param context - Route context
|
|
147
|
+
*/
|
|
148
|
+
onRouteRender?: (
|
|
149
|
+
routeName: string,
|
|
150
|
+
context: RouteContext,
|
|
151
|
+
) => void | Promise<void>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Called when a route encounters an error.
|
|
155
|
+
* @param routeName - Name of the route
|
|
156
|
+
* @param error - The error that occurred
|
|
157
|
+
* @param context - Route context
|
|
158
|
+
*/
|
|
159
|
+
onRouteError?: (
|
|
160
|
+
routeName: string,
|
|
161
|
+
error: Error,
|
|
162
|
+
context: RouteContext,
|
|
163
|
+
) => void | Promise<void>;
|
|
164
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// NO "use client" here! This file runs on both server and client.
|
|
2
|
+
import { lazy } from "react";
|
|
3
|
+
import {
|
|
4
|
+
defineClientPlugin,
|
|
5
|
+
isConnectionError,
|
|
6
|
+
} from "@btst/stack/plugins/client";
|
|
7
|
+
import { createRoute } from "@btst/yar";
|
|
8
|
+
import type { QueryClient } from "@tanstack/react-query";
|
|
9
|
+
|
|
10
|
+
// Lazy load page components for code splitting
|
|
11
|
+
const ModerationPageComponent = lazy(() =>
|
|
12
|
+
import("./components/pages/moderation-page").then((m) => ({
|
|
13
|
+
default: m.ModerationPageComponent,
|
|
14
|
+
})),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const UserCommentsPageComponent = lazy(() =>
|
|
18
|
+
import("./components/pages/my-comments-page").then((m) => ({
|
|
19
|
+
default: m.UserCommentsPageComponent,
|
|
20
|
+
})),
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Context passed to loader hooks
|
|
25
|
+
*/
|
|
26
|
+
export interface LoaderContext {
|
|
27
|
+
/** Current route path */
|
|
28
|
+
path: string;
|
|
29
|
+
/** Route parameters */
|
|
30
|
+
params?: Record<string, string>;
|
|
31
|
+
/** Whether rendering on server (true) or client (false) */
|
|
32
|
+
isSSR: boolean;
|
|
33
|
+
/** Base URL for API calls */
|
|
34
|
+
apiBaseURL: string;
|
|
35
|
+
/** Path where the API is mounted */
|
|
36
|
+
apiBasePath: string;
|
|
37
|
+
/** Optional headers for the request */
|
|
38
|
+
headers?: Headers;
|
|
39
|
+
/** Additional context properties */
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Hooks for Comments client plugin
|
|
45
|
+
*/
|
|
46
|
+
export interface CommentsClientHooks {
|
|
47
|
+
/**
|
|
48
|
+
* Called before loading the moderation page. Throw to cancel.
|
|
49
|
+
*/
|
|
50
|
+
beforeLoadModeration?: (context: LoaderContext) => Promise<void> | void;
|
|
51
|
+
/**
|
|
52
|
+
* Called before loading the User Comments page. Throw to cancel.
|
|
53
|
+
*/
|
|
54
|
+
beforeLoadUserComments?: (context: LoaderContext) => Promise<void> | void;
|
|
55
|
+
/**
|
|
56
|
+
* Called when a loading error occurs.
|
|
57
|
+
*/
|
|
58
|
+
onLoadError?: (error: Error, context: LoaderContext) => Promise<void> | void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Configuration for the Comments client plugin
|
|
63
|
+
*/
|
|
64
|
+
export interface CommentsClientConfig {
|
|
65
|
+
/** Base URL for API calls (e.g., "http://localhost:3000") */
|
|
66
|
+
apiBaseURL: string;
|
|
67
|
+
/** Path where the API is mounted (e.g., "/api/data") */
|
|
68
|
+
apiBasePath: string;
|
|
69
|
+
/** Base URL of your site */
|
|
70
|
+
siteBaseURL: string;
|
|
71
|
+
/** Path where pages are mounted (e.g., "/pages") */
|
|
72
|
+
siteBasePath: string;
|
|
73
|
+
/** React Query client instance */
|
|
74
|
+
queryClient: QueryClient;
|
|
75
|
+
/** Optional headers for SSR */
|
|
76
|
+
headers?: Headers;
|
|
77
|
+
/** Optional lifecycle hooks */
|
|
78
|
+
hooks?: CommentsClientHooks;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function createModerationLoader(config: CommentsClientConfig) {
|
|
82
|
+
return async () => {
|
|
83
|
+
if (typeof window === "undefined") {
|
|
84
|
+
const { apiBasePath, apiBaseURL, headers, hooks } = config;
|
|
85
|
+
const context: LoaderContext = {
|
|
86
|
+
path: "/comments/moderation",
|
|
87
|
+
isSSR: true,
|
|
88
|
+
apiBaseURL,
|
|
89
|
+
apiBasePath,
|
|
90
|
+
headers,
|
|
91
|
+
};
|
|
92
|
+
try {
|
|
93
|
+
if (hooks?.beforeLoadModeration) {
|
|
94
|
+
await hooks.beforeLoadModeration(context);
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (isConnectionError(error)) {
|
|
98
|
+
console.warn(
|
|
99
|
+
"[btst/comments] route.loader() failed — no server running at build time.",
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (hooks?.onLoadError) {
|
|
103
|
+
await hooks.onLoadError(error as Error, context);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function createUserCommentsLoader(config: CommentsClientConfig) {
|
|
111
|
+
return async () => {
|
|
112
|
+
if (typeof window === "undefined") {
|
|
113
|
+
const { apiBasePath, apiBaseURL, headers, hooks } = config;
|
|
114
|
+
const context: LoaderContext = {
|
|
115
|
+
path: "/comments",
|
|
116
|
+
isSSR: true,
|
|
117
|
+
apiBaseURL,
|
|
118
|
+
apiBasePath,
|
|
119
|
+
headers,
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
if (hooks?.beforeLoadUserComments) {
|
|
123
|
+
await hooks.beforeLoadUserComments(context);
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (isConnectionError(error)) {
|
|
127
|
+
console.warn(
|
|
128
|
+
"[btst/comments] route.loader() failed — no server running at build time.",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (hooks?.onLoadError) {
|
|
132
|
+
await hooks.onLoadError(error as Error, context);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function createCommentsRouteMeta(
|
|
140
|
+
config: CommentsClientConfig,
|
|
141
|
+
path: "/comments/moderation" | "/comments",
|
|
142
|
+
title: string,
|
|
143
|
+
description: string,
|
|
144
|
+
) {
|
|
145
|
+
return () => {
|
|
146
|
+
const fullUrl = `${config.siteBaseURL}${config.siteBasePath}${path}`;
|
|
147
|
+
return [
|
|
148
|
+
{ title },
|
|
149
|
+
{ name: "title", content: title },
|
|
150
|
+
{ name: "description", content: description },
|
|
151
|
+
{ name: "robots", content: "noindex, nofollow" },
|
|
152
|
+
{ property: "og:title", content: title },
|
|
153
|
+
{ property: "og:description", content: description },
|
|
154
|
+
{ property: "og:url", content: fullUrl },
|
|
155
|
+
{ name: "twitter:card", content: "summary" },
|
|
156
|
+
{ name: "twitter:title", content: title },
|
|
157
|
+
{ name: "twitter:description", content: description },
|
|
158
|
+
];
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Comments client plugin — registers admin moderation routes.
|
|
164
|
+
*
|
|
165
|
+
* The embeddable `CommentThread` and `CommentCount` components are standalone
|
|
166
|
+
* and do not require this plugin to be registered. Register them manually
|
|
167
|
+
* via the layout overrides pattern or use them directly in your pages.
|
|
168
|
+
*/
|
|
169
|
+
export const commentsClientPlugin = (config: CommentsClientConfig) =>
|
|
170
|
+
defineClientPlugin({
|
|
171
|
+
name: "comments",
|
|
172
|
+
|
|
173
|
+
routes: () => ({
|
|
174
|
+
moderation: createRoute("/comments/moderation", () => ({
|
|
175
|
+
PageComponent: ModerationPageComponent,
|
|
176
|
+
loader: createModerationLoader(config),
|
|
177
|
+
meta: createCommentsRouteMeta(
|
|
178
|
+
config,
|
|
179
|
+
"/comments/moderation",
|
|
180
|
+
"Comment Moderation",
|
|
181
|
+
"Review and manage comments across all resources.",
|
|
182
|
+
),
|
|
183
|
+
})),
|
|
184
|
+
userComments: createRoute("/comments", () => ({
|
|
185
|
+
PageComponent: UserCommentsPageComponent,
|
|
186
|
+
loader: createUserCommentsLoader(config),
|
|
187
|
+
meta: createCommentsRouteMeta(
|
|
188
|
+
config,
|
|
189
|
+
"/comments",
|
|
190
|
+
"User Comments",
|
|
191
|
+
"View and manage your comments across resources.",
|
|
192
|
+
),
|
|
193
|
+
})),
|
|
194
|
+
}),
|
|
195
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
import type { CommentsPluginOverrides } from "./overrides";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves `currentUserId` from the plugin overrides, supporting both a static
|
|
6
|
+
* string and a sync/async function. Returns `undefined` until resolution completes.
|
|
7
|
+
*/
|
|
8
|
+
export function useResolvedCurrentUserId(
|
|
9
|
+
raw: CommentsPluginOverrides["currentUserId"],
|
|
10
|
+
): string | undefined {
|
|
11
|
+
const [resolved, setResolved] = useState<string | undefined>(
|
|
12
|
+
typeof raw === "string" ? raw : undefined,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (typeof raw === "function") {
|
|
17
|
+
void Promise.resolve(raw())
|
|
18
|
+
.then((id) => setResolved(id ?? undefined))
|
|
19
|
+
.catch((err: unknown) => {
|
|
20
|
+
console.error(
|
|
21
|
+
"[btst/comments] Failed to resolve currentUserId:",
|
|
22
|
+
err,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
} else {
|
|
26
|
+
setResolved(raw ?? undefined);
|
|
27
|
+
}
|
|
28
|
+
}, [raw]);
|
|
29
|
+
|
|
30
|
+
return resolved;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Normalise any thrown value into an Error.
|
|
35
|
+
*
|
|
36
|
+
* Handles three shapes:
|
|
37
|
+
* 1. Already an Error — returned as-is.
|
|
38
|
+
* 2. A plain object — message is taken from `.message`, then `.error` (API
|
|
39
|
+
* error-response shape), then JSON.stringify. All original properties are
|
|
40
|
+
* copied onto the Error via Object.assign so callers can inspect them.
|
|
41
|
+
* 3. Anything else — converted via String().
|
|
42
|
+
*/
|
|
43
|
+
export function toError(error: unknown): Error {
|
|
44
|
+
if (error instanceof Error) return error;
|
|
45
|
+
if (typeof error === "object" && error !== null) {
|
|
46
|
+
const obj = error as Record<string, unknown>;
|
|
47
|
+
const message =
|
|
48
|
+
(typeof obj.message === "string" ? obj.message : null) ||
|
|
49
|
+
(typeof obj.error === "string" ? obj.error : null) ||
|
|
50
|
+
JSON.stringify(error);
|
|
51
|
+
const err = new Error(message);
|
|
52
|
+
Object.assign(err, error);
|
|
53
|
+
return err;
|
|
54
|
+
}
|
|
55
|
+
return new Error(String(error));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getInitials(name: string | null | undefined): string {
|
|
59
|
+
if (!name) return "?";
|
|
60
|
+
return name
|
|
61
|
+
.split(" ")
|
|
62
|
+
.filter(Boolean)
|
|
63
|
+
.slice(0, 2)
|
|
64
|
+
.map((n) => n[0])
|
|
65
|
+
.join("")
|
|
66
|
+
.toUpperCase();
|
|
67
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createDbPlugin } from "@btst/db";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comments plugin schema.
|
|
5
|
+
* Defines two tables:
|
|
6
|
+
* - comment: the main comment record (always authenticated, no anonymous)
|
|
7
|
+
* - commentLike: join table for per-user like deduplication
|
|
8
|
+
*/
|
|
9
|
+
export const commentsSchema = createDbPlugin("comments", {
|
|
10
|
+
comment: {
|
|
11
|
+
modelName: "comment",
|
|
12
|
+
fields: {
|
|
13
|
+
resourceId: {
|
|
14
|
+
type: "string",
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
resourceType: {
|
|
18
|
+
type: "string",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
parentId: {
|
|
22
|
+
type: "string",
|
|
23
|
+
required: false,
|
|
24
|
+
},
|
|
25
|
+
authorId: {
|
|
26
|
+
type: "string",
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
body: {
|
|
30
|
+
type: "string",
|
|
31
|
+
required: true,
|
|
32
|
+
},
|
|
33
|
+
status: {
|
|
34
|
+
type: "string",
|
|
35
|
+
defaultValue: "pending",
|
|
36
|
+
},
|
|
37
|
+
likes: {
|
|
38
|
+
type: "number",
|
|
39
|
+
defaultValue: 0,
|
|
40
|
+
},
|
|
41
|
+
editedAt: {
|
|
42
|
+
type: "date",
|
|
43
|
+
required: false,
|
|
44
|
+
},
|
|
45
|
+
createdAt: {
|
|
46
|
+
type: "date",
|
|
47
|
+
defaultValue: () => new Date(),
|
|
48
|
+
},
|
|
49
|
+
updatedAt: {
|
|
50
|
+
type: "date",
|
|
51
|
+
defaultValue: () => new Date(),
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
commentLike: {
|
|
56
|
+
modelName: "commentLike",
|
|
57
|
+
fields: {
|
|
58
|
+
commentId: {
|
|
59
|
+
type: "string",
|
|
60
|
+
required: true,
|
|
61
|
+
references: {
|
|
62
|
+
model: "comment",
|
|
63
|
+
field: "id",
|
|
64
|
+
onDelete: "cascade",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
authorId: {
|
|
68
|
+
type: "string",
|
|
69
|
+
required: true,
|
|
70
|
+
},
|
|
71
|
+
createdAt: {
|
|
72
|
+
type: "date",
|
|
73
|
+
defaultValue: () => new Date(),
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|