@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.
Files changed (181) hide show
  1. package/README.md +1 -0
  2. package/dist/packages/stack/src/plugins/blog/client/components/loading/post-navigation-skeleton.cjs +13 -0
  3. package/dist/packages/stack/src/plugins/blog/client/components/loading/post-navigation-skeleton.mjs +11 -0
  4. package/dist/packages/stack/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.cjs +17 -0
  5. package/dist/packages/stack/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.mjs +15 -0
  6. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -7
  7. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -7
  8. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-navigation.cjs +48 -52
  9. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-navigation.mjs +49 -53
  10. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +34 -37
  11. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +35 -38
  12. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-hooks.cjs +4 -21
  13. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-hooks.mjs +4 -21
  14. package/dist/packages/stack/src/plugins/comments/api/getters.cjs +284 -0
  15. package/dist/packages/stack/src/plugins/comments/api/getters.mjs +280 -0
  16. package/dist/packages/stack/src/plugins/comments/api/mutations.cjs +118 -0
  17. package/dist/packages/stack/src/plugins/comments/api/mutations.mjs +112 -0
  18. package/dist/packages/stack/src/plugins/comments/api/plugin.cjs +335 -0
  19. package/dist/packages/stack/src/plugins/comments/api/plugin.mjs +333 -0
  20. package/dist/packages/stack/src/plugins/comments/api/query-key-defs.cjs +60 -0
  21. package/dist/packages/stack/src/plugins/comments/api/query-key-defs.mjs +55 -0
  22. package/dist/packages/stack/src/plugins/comments/api/serializers.cjs +23 -0
  23. package/dist/packages/stack/src/plugins/comments/api/serializers.mjs +21 -0
  24. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.cjs +46 -0
  25. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.mjs +44 -0
  26. package/dist/packages/stack/src/plugins/comments/client/components/comment-form.cjs +86 -0
  27. package/dist/packages/stack/src/plugins/comments/client/components/comment-form.mjs +84 -0
  28. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.cjs +540 -0
  29. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.mjs +538 -0
  30. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.cjs +64 -0
  31. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.cjs +426 -0
  32. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.mjs +424 -0
  33. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.mjs +62 -0
  34. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.cjs +66 -0
  35. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.cjs +256 -0
  36. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.mjs +254 -0
  37. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.mjs +64 -0
  38. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.cjs +86 -0
  39. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.cjs +191 -0
  40. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.mjs +189 -0
  41. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.mjs +84 -0
  42. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.cjs +27 -0
  43. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.mjs +25 -0
  44. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.cjs +37 -0
  45. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.mjs +35 -0
  46. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.cjs +476 -0
  47. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.mjs +464 -0
  48. package/dist/packages/stack/src/plugins/comments/client/localization/comments-moderation.cjs +67 -0
  49. package/dist/packages/stack/src/plugins/comments/client/localization/comments-moderation.mjs +65 -0
  50. package/dist/packages/stack/src/plugins/comments/client/localization/comments-my.cjs +27 -0
  51. package/dist/packages/stack/src/plugins/comments/client/localization/comments-my.mjs +25 -0
  52. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.cjs +30 -0
  53. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.mjs +28 -0
  54. package/dist/packages/stack/src/plugins/comments/client/localization/index.cjs +13 -0
  55. package/dist/packages/stack/src/plugins/comments/client/localization/index.mjs +11 -0
  56. package/dist/packages/stack/src/plugins/comments/client/plugin.cjs +116 -0
  57. package/dist/packages/stack/src/plugins/comments/client/plugin.mjs +114 -0
  58. package/dist/packages/stack/src/plugins/comments/client/utils.cjs +41 -0
  59. package/dist/packages/stack/src/plugins/comments/client/utils.mjs +37 -0
  60. package/dist/packages/stack/src/plugins/comments/db.cjs +75 -0
  61. package/dist/packages/stack/src/plugins/comments/db.mjs +73 -0
  62. package/dist/packages/stack/src/plugins/comments/schemas.cjs +45 -0
  63. package/dist/packages/stack/src/plugins/comments/schemas.mjs +38 -0
  64. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +0 -1
  65. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +0 -1
  66. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +39 -22
  67. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +40 -23
  68. package/dist/packages/ui/src/components/avatar.mjs +1 -1
  69. package/dist/packages/ui/src/components/pagination-controls.cjs +64 -0
  70. package/dist/packages/ui/src/components/pagination-controls.mjs +62 -0
  71. package/dist/packages/ui/src/components/when-visible.cjs +39 -0
  72. package/dist/packages/ui/src/components/when-visible.mjs +37 -0
  73. package/dist/plugins/blog/client/hooks/index.d.cts +1 -1
  74. package/dist/plugins/blog/client/hooks/index.d.mts +1 -1
  75. package/dist/plugins/blog/client/hooks/index.d.ts +1 -1
  76. package/dist/plugins/blog/client/index.d.cts +24 -2
  77. package/dist/plugins/blog/client/index.d.mts +24 -2
  78. package/dist/plugins/blog/client/index.d.ts +24 -2
  79. package/dist/plugins/comments/api/index.cjs +21 -0
  80. package/dist/plugins/comments/api/index.d.cts +126 -0
  81. package/dist/plugins/comments/api/index.d.mts +126 -0
  82. package/dist/plugins/comments/api/index.d.ts +126 -0
  83. package/dist/plugins/comments/api/index.mjs +5 -0
  84. package/dist/plugins/comments/client/components/index.cjs +15 -0
  85. package/dist/plugins/comments/client/components/index.d.cts +125 -0
  86. package/dist/plugins/comments/client/components/index.d.mts +125 -0
  87. package/dist/plugins/comments/client/components/index.d.ts +125 -0
  88. package/dist/plugins/comments/client/components/index.mjs +5 -0
  89. package/dist/plugins/comments/client/hooks/index.cjs +17 -0
  90. package/dist/plugins/comments/client/hooks/index.d.cts +200 -0
  91. package/dist/plugins/comments/client/hooks/index.d.mts +200 -0
  92. package/dist/plugins/comments/client/hooks/index.d.ts +200 -0
  93. package/dist/plugins/comments/client/hooks/index.mjs +1 -0
  94. package/dist/plugins/comments/client/index.cjs +9 -0
  95. package/dist/plugins/comments/client/index.d.cts +262 -0
  96. package/dist/plugins/comments/client/index.d.mts +262 -0
  97. package/dist/plugins/comments/client/index.d.ts +262 -0
  98. package/dist/plugins/comments/client/index.mjs +2 -0
  99. package/dist/plugins/comments/client.css +2 -0
  100. package/dist/plugins/comments/query-keys.cjs +113 -0
  101. package/dist/plugins/comments/query-keys.d.cts +71 -0
  102. package/dist/plugins/comments/query-keys.d.mts +71 -0
  103. package/dist/plugins/comments/query-keys.d.ts +71 -0
  104. package/dist/plugins/comments/query-keys.mjs +111 -0
  105. package/dist/plugins/comments/style.css +15 -0
  106. package/dist/plugins/kanban/api/index.d.cts +1 -1
  107. package/dist/plugins/kanban/api/index.d.mts +1 -1
  108. package/dist/plugins/kanban/api/index.d.ts +1 -1
  109. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  110. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  111. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  112. package/dist/plugins/kanban/client/index.d.cts +1 -1
  113. package/dist/plugins/kanban/client/index.d.mts +1 -1
  114. package/dist/plugins/kanban/client/index.d.ts +1 -1
  115. package/dist/plugins/kanban/query-keys.d.cts +1 -1
  116. package/dist/plugins/kanban/query-keys.d.mts +1 -1
  117. package/dist/plugins/kanban/query-keys.d.ts +1 -1
  118. package/dist/shared/{stack.FeaWkglm.d.ts → stack.BxFl46lB.d.cts} +24 -1
  119. package/dist/shared/stack.C-b3Sn8j.d.cts +142 -0
  120. package/dist/shared/stack.C-b3Sn8j.d.mts +142 -0
  121. package/dist/shared/stack.C-b3Sn8j.d.ts +142 -0
  122. package/dist/shared/stack.CJE9sAjV.d.ts +335 -0
  123. package/dist/shared/stack.CmHRdhl8.d.cts +335 -0
  124. package/dist/shared/{stack.CNLHlv7r.d.mts → stack.DOZ1EXjM.d.mts} +6 -12
  125. package/dist/shared/{stack.FeaWkglm.d.mts → stack.DRpeDS6X.d.ts} +24 -1
  126. package/dist/shared/{stack.CQAZwXhV.d.cts → stack.DX-tQ93o.d.cts} +6 -12
  127. package/dist/shared/stack.Dcz6636A.d.mts +335 -0
  128. package/dist/shared/{stack.FeaWkglm.d.cts → stack.Jb0kQDJC.d.mts} +24 -1
  129. package/dist/shared/stack.Ldfkr5b2.d.cts +112 -0
  130. package/dist/shared/stack.Ldfkr5b2.d.mts +112 -0
  131. package/dist/shared/stack.Ldfkr5b2.d.ts +112 -0
  132. package/dist/shared/{stack.D3BsrpAz.d.ts → stack.VF6FhyZw.d.ts} +6 -12
  133. package/package.json +69 -4
  134. package/src/plugins/blog/client/components/loading/post-navigation-skeleton.tsx +10 -0
  135. package/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.tsx +18 -0
  136. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +23 -8
  137. package/src/plugins/blog/client/components/shared/post-navigation.tsx +0 -5
  138. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +1 -5
  139. package/src/plugins/blog/client/hooks/blog-hooks.tsx +8 -33
  140. package/src/plugins/blog/client/overrides.ts +26 -1
  141. package/src/plugins/cms/client/components/shared/pagination.tsx +14 -42
  142. package/src/plugins/comments/api/getters.ts +444 -0
  143. package/src/plugins/comments/api/index.ts +21 -0
  144. package/src/plugins/comments/api/mutations.ts +206 -0
  145. package/src/plugins/comments/api/plugin.ts +628 -0
  146. package/src/plugins/comments/api/query-key-defs.ts +143 -0
  147. package/src/plugins/comments/api/serializers.ts +37 -0
  148. package/src/plugins/comments/client/components/comment-count.tsx +66 -0
  149. package/src/plugins/comments/client/components/comment-form.tsx +112 -0
  150. package/src/plugins/comments/client/components/comment-thread.tsx +799 -0
  151. package/src/plugins/comments/client/components/index.tsx +11 -0
  152. package/src/plugins/comments/client/components/pages/moderation-page.internal.tsx +550 -0
  153. package/src/plugins/comments/client/components/pages/moderation-page.tsx +70 -0
  154. package/src/plugins/comments/client/components/pages/my-comments-page.internal.tsx +367 -0
  155. package/src/plugins/comments/client/components/pages/my-comments-page.tsx +72 -0
  156. package/src/plugins/comments/client/components/pages/resource-comments-page.internal.tsx +225 -0
  157. package/src/plugins/comments/client/components/pages/resource-comments-page.tsx +97 -0
  158. package/src/plugins/comments/client/components/shared/page-wrapper.tsx +32 -0
  159. package/src/plugins/comments/client/components/shared/pagination.tsx +44 -0
  160. package/src/plugins/comments/client/hooks/index.tsx +13 -0
  161. package/src/plugins/comments/client/hooks/use-comments.tsx +717 -0
  162. package/src/plugins/comments/client/index.ts +14 -0
  163. package/src/plugins/comments/client/localization/comments-moderation.ts +75 -0
  164. package/src/plugins/comments/client/localization/comments-my.ts +32 -0
  165. package/src/plugins/comments/client/localization/comments-thread.ts +32 -0
  166. package/src/plugins/comments/client/localization/index.ts +11 -0
  167. package/src/plugins/comments/client/overrides.ts +164 -0
  168. package/src/plugins/comments/client/plugin.tsx +195 -0
  169. package/src/plugins/comments/client/utils.ts +67 -0
  170. package/src/plugins/comments/client.css +2 -0
  171. package/src/plugins/comments/db.ts +77 -0
  172. package/src/plugins/comments/query-keys.ts +189 -0
  173. package/src/plugins/comments/schemas.ts +72 -0
  174. package/src/plugins/comments/style.css +15 -0
  175. package/src/plugins/comments/types.ts +73 -0
  176. package/src/plugins/kanban/client/components/forms/task-form.tsx +0 -1
  177. package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +46 -27
  178. package/src/plugins/kanban/client/overrides.ts +27 -1
  179. package/dist/shared/{stack.Rtcvl8sS.d.cts → stack.BOokfhZD.d.cts} +3 -3
  180. package/dist/shared/{stack.D4Cea8II.d.ts → stack.BvCR4-9H.d.ts} +3 -3
  181. package/dist/shared/{stack.HE_IvqV5.d.mts → stack.CWxAl9K3.d.mts} +3 -3
@@ -0,0 +1,112 @@
1
+ declare const COMMENTS_LOCALIZATION: {
2
+ COMMENTS_MY_LOGIN_TITLE: string;
3
+ COMMENTS_MY_LOGIN_DESCRIPTION: string;
4
+ COMMENTS_MY_EMPTY_TITLE: string;
5
+ COMMENTS_MY_EMPTY_DESCRIPTION: string;
6
+ COMMENTS_MY_PAGE_TITLE: string;
7
+ COMMENTS_MY_COL_COMMENT: string;
8
+ COMMENTS_MY_COL_RESOURCE: string;
9
+ COMMENTS_MY_COL_STATUS: string;
10
+ COMMENTS_MY_COL_DATE: string;
11
+ COMMENTS_MY_REPLY_INDICATOR: string;
12
+ COMMENTS_MY_VIEW_LINK: string;
13
+ COMMENTS_MY_STATUS_APPROVED: string;
14
+ COMMENTS_MY_STATUS_PENDING: string;
15
+ COMMENTS_MY_STATUS_SPAM: string;
16
+ COMMENTS_MY_TOAST_DELETED: string;
17
+ COMMENTS_MY_TOAST_DELETE_ERROR: string;
18
+ COMMENTS_MY_DELETE_TITLE: string;
19
+ COMMENTS_MY_DELETE_DESCRIPTION: string;
20
+ COMMENTS_MY_DELETE_CANCEL: string;
21
+ COMMENTS_MY_DELETE_CONFIRM: string;
22
+ COMMENTS_MY_DELETE_BUTTON_SR: string;
23
+ COMMENTS_MODERATION_TITLE: string;
24
+ COMMENTS_MODERATION_DESCRIPTION: string;
25
+ COMMENTS_MODERATION_TAB_PENDING: string;
26
+ COMMENTS_MODERATION_TAB_APPROVED: string;
27
+ COMMENTS_MODERATION_TAB_SPAM: string;
28
+ COMMENTS_MODERATION_SELECTED: string;
29
+ COMMENTS_MODERATION_APPROVE_SELECTED: string;
30
+ COMMENTS_MODERATION_DELETE_SELECTED: string;
31
+ COMMENTS_MODERATION_EMPTY: string;
32
+ COMMENTS_MODERATION_COL_AUTHOR: string;
33
+ COMMENTS_MODERATION_COL_COMMENT: string;
34
+ COMMENTS_MODERATION_COL_RESOURCE: string;
35
+ COMMENTS_MODERATION_COL_DATE: string;
36
+ COMMENTS_MODERATION_COL_ACTIONS: string;
37
+ COMMENTS_MODERATION_SELECT_ALL: string;
38
+ COMMENTS_MODERATION_SELECT_ONE: string;
39
+ COMMENTS_MODERATION_ACTION_VIEW: string;
40
+ COMMENTS_MODERATION_ACTION_APPROVE: string;
41
+ COMMENTS_MODERATION_ACTION_SPAM: string;
42
+ COMMENTS_MODERATION_ACTION_DELETE: string;
43
+ COMMENTS_MODERATION_TOAST_APPROVED: string;
44
+ COMMENTS_MODERATION_TOAST_APPROVE_ERROR: string;
45
+ COMMENTS_MODERATION_TOAST_SPAM: string;
46
+ COMMENTS_MODERATION_TOAST_SPAM_ERROR: string;
47
+ COMMENTS_MODERATION_TOAST_DELETED: string;
48
+ COMMENTS_MODERATION_TOAST_DELETED_PLURAL: string;
49
+ COMMENTS_MODERATION_TOAST_DELETE_ERROR: string;
50
+ COMMENTS_MODERATION_TOAST_BULK_APPROVED: string;
51
+ COMMENTS_MODERATION_TOAST_BULK_APPROVE_ERROR: string;
52
+ COMMENTS_MODERATION_DIALOG_TITLE: string;
53
+ COMMENTS_MODERATION_DIALOG_RESOURCE: string;
54
+ COMMENTS_MODERATION_DIALOG_LIKES: string;
55
+ COMMENTS_MODERATION_DIALOG_REPLY_TO: string;
56
+ COMMENTS_MODERATION_DIALOG_EDITED: string;
57
+ COMMENTS_MODERATION_DIALOG_BODY: string;
58
+ COMMENTS_MODERATION_DIALOG_APPROVE: string;
59
+ COMMENTS_MODERATION_DIALOG_MARK_SPAM: string;
60
+ COMMENTS_MODERATION_DIALOG_DELETE: string;
61
+ COMMENTS_MODERATION_DELETE_TITLE_SINGULAR: string;
62
+ COMMENTS_MODERATION_DELETE_TITLE_PLURAL: string;
63
+ COMMENTS_MODERATION_DELETE_DESCRIPTION_SINGULAR: string;
64
+ COMMENTS_MODERATION_DELETE_DESCRIPTION_PLURAL: string;
65
+ COMMENTS_MODERATION_DELETE_CANCEL: string;
66
+ COMMENTS_MODERATION_DELETE_CONFIRM: string;
67
+ COMMENTS_MODERATION_DELETE_DELETING: string;
68
+ COMMENTS_MODERATION_PAGINATION_PREVIOUS: string;
69
+ COMMENTS_MODERATION_PAGINATION_NEXT: string;
70
+ COMMENTS_MODERATION_PAGINATION_SHOWING: string;
71
+ COMMENTS_RESOURCE_TITLE: string;
72
+ COMMENTS_RESOURCE_PENDING_SECTION: string;
73
+ COMMENTS_RESOURCE_THREAD_SECTION: string;
74
+ COMMENTS_RESOURCE_ACTION_APPROVE: string;
75
+ COMMENTS_RESOURCE_ACTION_SPAM: string;
76
+ COMMENTS_RESOURCE_ACTION_DELETE: string;
77
+ COMMENTS_RESOURCE_DELETE_CONFIRM: string;
78
+ COMMENTS_RESOURCE_TOAST_APPROVED: string;
79
+ COMMENTS_RESOURCE_TOAST_APPROVE_ERROR: string;
80
+ COMMENTS_RESOURCE_TOAST_SPAM: string;
81
+ COMMENTS_RESOURCE_TOAST_SPAM_ERROR: string;
82
+ COMMENTS_RESOURCE_TOAST_DELETED: string;
83
+ COMMENTS_RESOURCE_TOAST_DELETE_ERROR: string;
84
+ COMMENTS_TITLE: string;
85
+ COMMENTS_EMPTY: string;
86
+ COMMENTS_EDITED_BADGE: string;
87
+ COMMENTS_PENDING_BADGE: string;
88
+ COMMENTS_LIKE_ARIA: string;
89
+ COMMENTS_UNLIKE_ARIA: string;
90
+ COMMENTS_REPLY_BUTTON: string;
91
+ COMMENTS_EDIT_BUTTON: string;
92
+ COMMENTS_DELETE_BUTTON: string;
93
+ COMMENTS_SAVE_EDIT: string;
94
+ COMMENTS_REPLIES_SINGULAR: string;
95
+ COMMENTS_REPLIES_PLURAL: string;
96
+ COMMENTS_HIDE_REPLIES: string;
97
+ COMMENTS_DELETE_CONFIRM: string;
98
+ COMMENTS_LOGIN_PROMPT: string;
99
+ COMMENTS_LOGIN_LINK: string;
100
+ COMMENTS_FORM_PLACEHOLDER: string;
101
+ COMMENTS_FORM_CANCEL: string;
102
+ COMMENTS_FORM_POST_COMMENT: string;
103
+ COMMENTS_FORM_POST_REPLY: string;
104
+ COMMENTS_FORM_POSTING: string;
105
+ COMMENTS_FORM_SUBMIT_ERROR: string;
106
+ COMMENTS_LOAD_MORE: string;
107
+ COMMENTS_LOADING_MORE: string;
108
+ };
109
+ type CommentsLocalization = typeof COMMENTS_LOCALIZATION;
110
+
111
+ export { COMMENTS_LOCALIZATION as a };
112
+ export type { CommentsLocalization as C };
@@ -184,13 +184,10 @@ interface UseNextPreviousPostsResult {
184
184
  refetch: () => void;
185
185
  }
186
186
  /**
187
- * Hook for fetching previous and next posts relative to a given date
188
- * Uses useInView to only fetch when the component is in view
187
+ * Hook for fetching previous and next posts relative to a given date.
188
+ * Pair with `<WhenVisible>` in the render tree for lazy loading.
189
189
  */
190
- declare function useNextPreviousPosts(createdAt: string | Date, options?: UseNextPreviousPostsOptions): UseNextPreviousPostsResult & {
191
- ref: (node: Element | null) => void;
192
- inView: boolean;
193
- };
190
+ declare function useNextPreviousPosts(createdAt: string | Date, options?: UseNextPreviousPostsOptions): UseNextPreviousPostsResult;
194
191
  /**
195
192
  * Options for the useRecentPosts hook
196
193
  */
@@ -216,13 +213,10 @@ interface UseRecentPostsResult {
216
213
  refetch: () => void;
217
214
  }
218
215
  /**
219
- * Hook for fetching recent posts
220
- * Uses useInView to only fetch when the component is in view
216
+ * Hook for fetching recent posts.
217
+ * Pair with `<WhenVisible>` in the render tree for lazy loading.
221
218
  */
222
- declare function useRecentPosts(options?: UseRecentPostsOptions): UseRecentPostsResult & {
223
- ref: (node: Element | null) => void;
224
- inView: boolean;
225
- };
219
+ declare function useRecentPosts(options?: UseRecentPostsOptions): UseRecentPostsResult;
226
220
 
227
221
  export { useSuspensePosts as f, usePost as g, useSuspensePost as h, useTags as i, useSuspenseTags as j, useCreatePost as k, useUpdatePost as l, useDeletePost as m, usePostSearch as n, useNextPreviousPosts as q, useRecentPosts as t, usePosts as u };
228
222
  export type { PostCreateInput as P, UsePostsOptions as U, UsePostsResult as a, UsePostSearchOptions as b, UsePostSearchResult as c, UsePostResult as d, PostUpdateInput as e, UseNextPreviousPostsOptions as o, UseNextPreviousPostsResult as p, UseRecentPostsOptions as r, UseRecentPostsResult as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btst/stack",
3
- "version": "2.7.0",
3
+ "version": "2.8.1",
4
4
  "description": "A composable, plugin-based library for building full-stack applications.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -363,6 +363,57 @@
363
363
  }
364
364
  },
365
365
  "./plugins/kanban/css": "./dist/plugins/kanban/style.css",
366
+ "./plugins/comments/api": {
367
+ "import": {
368
+ "types": "./dist/plugins/comments/api/index.d.ts",
369
+ "default": "./dist/plugins/comments/api/index.mjs"
370
+ },
371
+ "require": {
372
+ "types": "./dist/plugins/comments/api/index.d.cts",
373
+ "default": "./dist/plugins/comments/api/index.cjs"
374
+ }
375
+ },
376
+ "./plugins/comments/client": {
377
+ "import": {
378
+ "types": "./dist/plugins/comments/client/index.d.ts",
379
+ "default": "./dist/plugins/comments/client/index.mjs"
380
+ },
381
+ "require": {
382
+ "types": "./dist/plugins/comments/client/index.d.cts",
383
+ "default": "./dist/plugins/comments/client/index.cjs"
384
+ }
385
+ },
386
+ "./plugins/comments/client/components": {
387
+ "import": {
388
+ "types": "./dist/plugins/comments/client/components/index.d.ts",
389
+ "default": "./dist/plugins/comments/client/components/index.mjs"
390
+ },
391
+ "require": {
392
+ "types": "./dist/plugins/comments/client/components/index.d.cts",
393
+ "default": "./dist/plugins/comments/client/components/index.cjs"
394
+ }
395
+ },
396
+ "./plugins/comments/client/hooks": {
397
+ "import": {
398
+ "types": "./dist/plugins/comments/client/hooks/index.d.ts",
399
+ "default": "./dist/plugins/comments/client/hooks/index.mjs"
400
+ },
401
+ "require": {
402
+ "types": "./dist/plugins/comments/client/hooks/index.d.cts",
403
+ "default": "./dist/plugins/comments/client/hooks/index.cjs"
404
+ }
405
+ },
406
+ "./plugins/comments/query-keys": {
407
+ "import": {
408
+ "types": "./dist/plugins/comments/query-keys.d.ts",
409
+ "default": "./dist/plugins/comments/query-keys.mjs"
410
+ },
411
+ "require": {
412
+ "types": "./dist/plugins/comments/query-keys.d.cts",
413
+ "default": "./dist/plugins/comments/query-keys.cjs"
414
+ }
415
+ },
416
+ "./plugins/comments/css": "./dist/plugins/comments/style.css",
366
417
  "./plugins/route-docs/client": {
367
418
  "import": {
368
419
  "types": "./dist/plugins/route-docs/client/index.d.ts",
@@ -544,6 +595,21 @@
544
595
  "plugins/kanban/client/hooks": [
545
596
  "./dist/plugins/kanban/client/hooks/index.d.ts"
546
597
  ],
598
+ "plugins/comments/api": [
599
+ "./dist/plugins/comments/api/index.d.ts"
600
+ ],
601
+ "plugins/comments/client": [
602
+ "./dist/plugins/comments/client/index.d.ts"
603
+ ],
604
+ "plugins/comments/client/components": [
605
+ "./dist/plugins/comments/client/components/index.d.ts"
606
+ ],
607
+ "plugins/comments/client/hooks": [
608
+ "./dist/plugins/comments/client/hooks/index.d.ts"
609
+ ],
610
+ "plugins/comments/query-keys": [
611
+ "./dist/plugins/comments/query-keys.d.ts"
612
+ ],
547
613
  "plugins/route-docs/client": [
548
614
  "./dist/plugins/route-docs/client/index.d.ts"
549
615
  ],
@@ -571,7 +637,7 @@
571
637
  }
572
638
  },
573
639
  "dependencies": {
574
- "@btst/db": "2.1.0",
640
+ "@btst/db": "2.1.1",
575
641
  "@lukemorales/query-key-factory": "^1.3.4",
576
642
  "@milkdown/crepe": "^7.17.1",
577
643
  "@milkdown/kit": "^7.17.1",
@@ -600,7 +666,6 @@
600
666
  "react-dom": "^18.0.0 || ^19.0.0",
601
667
  "react-error-boundary": ">=4.0.0",
602
668
  "react-hook-form": ">=7.55.0",
603
- "react-intersection-observer": ">=9.0.0",
604
669
  "react-markdown": ">=9.1.0",
605
670
  "rehype-highlight": ">=7.0.0",
606
671
  "rehype-katex": ">=7.0.0",
@@ -616,7 +681,7 @@
616
681
  "devDependencies": {
617
682
  "tsx": "catalog:",
618
683
  "@ai-sdk/react": "^2.0.94",
619
- "@btst/adapter-memory": "2.1.0",
684
+ "@btst/adapter-memory": "2.1.1",
620
685
  "@btst/yar": "1.2.0",
621
686
  "@types/react": "^19.0.0",
622
687
  "@types/slug": "^5.0.9",
@@ -0,0 +1,10 @@
1
+ import { Skeleton } from "@workspace/ui/components/skeleton";
2
+
3
+ export function PostNavigationSkeleton() {
4
+ return (
5
+ <div className="border-t mt-4 pt-4 w-full flex flex-col sm:flex-row gap-4">
6
+ <Skeleton className="h-14 flex-1 rounded-md" />
7
+ <Skeleton className="h-14 flex-1 rounded-md" />
8
+ </div>
9
+ );
10
+ }
@@ -0,0 +1,18 @@
1
+ import { Skeleton } from "@workspace/ui/components/skeleton";
2
+ import { PostCardSkeleton } from "./post-card-skeleton";
3
+
4
+ export function RecentPostsCarouselSkeleton() {
5
+ return (
6
+ <div className="w-full mt-4 py-4 border-t">
7
+ <div className="flex items-center justify-between mb-4">
8
+ <Skeleton className="h-7 w-36" />
9
+ <Skeleton className="h-4 w-16" />
10
+ </div>
11
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
12
+ {[1, 2, 3].map((i) => (
13
+ <PostCardSkeleton key={i} />
14
+ ))}
15
+ </div>
16
+ </div>
17
+ );
18
+ }
@@ -21,6 +21,9 @@ import { useRouteLifecycle } from "@workspace/ui/hooks/use-route-lifecycle";
21
21
  import { OnThisPage, OnThisPageSelect } from "../shared/on-this-page";
22
22
  import type { SerializedPost } from "../../../types";
23
23
  import { useRegisterPageAIContext } from "@btst/stack/plugins/ai-chat/client/context";
24
+ import { WhenVisible } from "@workspace/ui/components/when-visible";
25
+ import { PostNavigationSkeleton } from "../loading/post-navigation-skeleton";
26
+ import { RecentPostsCarouselSkeleton } from "../loading/recent-posts-carousel-skeleton";
24
27
 
25
28
  // Internal component with actual page content
26
29
  export function PostPage({ slug }: { slug: string }) {
@@ -52,14 +55,14 @@ export function PostPage({ slug }: { slug: string }) {
52
55
 
53
56
  const { post } = useSuspensePost(slug ?? "");
54
57
 
55
- const { previousPost, nextPost, ref } = useNextPreviousPosts(
58
+ const { previousPost, nextPost } = useNextPreviousPosts(
56
59
  post?.createdAt ?? new Date(),
57
60
  {
58
61
  enabled: !!post,
59
62
  },
60
63
  );
61
64
 
62
- const { recentPosts, ref: recentPostsRef } = useRecentPosts({
65
+ const { recentPosts } = useRecentPosts({
63
66
  limit: 5,
64
67
  excludeSlug: slug,
65
68
  enabled: !!post,
@@ -120,13 +123,25 @@ export function PostPage({ slug }: { slug: string }) {
120
123
  </div>
121
124
 
122
125
  <div className="flex flex-col gap-4 w-full">
123
- <PostNavigation
124
- previousPost={previousPost}
125
- nextPost={nextPost}
126
- ref={ref}
127
- />
126
+ <WhenVisible
127
+ rootMargin="200px"
128
+ fallback={<PostNavigationSkeleton />}
129
+ >
130
+ <PostNavigation previousPost={previousPost} nextPost={nextPost} />
131
+ </WhenVisible>
128
132
 
129
- <RecentPostsCarousel posts={recentPosts} ref={recentPostsRef} />
133
+ <WhenVisible
134
+ rootMargin="200px"
135
+ fallback={<RecentPostsCarouselSkeleton />}
136
+ >
137
+ <RecentPostsCarousel posts={recentPosts} />
138
+ </WhenVisible>
139
+
140
+ {overrides.postBottomSlot && (
141
+ <div data-testid="post-bottom-slot">
142
+ {overrides.postBottomSlot(post)}
143
+ </div>
144
+ )}
130
145
  </div>
131
146
  </div>
132
147
  <OnThisPage markdown={post.content} />
@@ -10,13 +10,11 @@ import type { SerializedPost } from "../../../types";
10
10
  interface PostNavigationProps {
11
11
  previousPost: SerializedPost | null;
12
12
  nextPost: SerializedPost | null;
13
- ref?: (node: Element | null) => void;
14
13
  }
15
14
 
16
15
  export function PostNavigation({
17
16
  previousPost,
18
17
  nextPost,
19
- ref,
20
18
  }: PostNavigationProps) {
21
19
  const { Link } = usePluginOverrides<
22
20
  BlogPluginOverrides,
@@ -29,9 +27,6 @@ export function PostNavigation({
29
27
 
30
28
  return (
31
29
  <>
32
- {/* Ref div to trigger intersection observer when scrolled into view */}
33
- {ref && <div ref={ref} />}
34
-
35
30
  {/* Only show navigation buttons if posts are available */}
36
31
  {(previousPost || nextPost) && (
37
32
  <>
@@ -16,10 +16,9 @@ import { BLOG_LOCALIZATION } from "../../localization";
16
16
 
17
17
  interface RecentPostsCarouselProps {
18
18
  posts: SerializedPost[];
19
- ref?: (node: Element | null) => void;
20
19
  }
21
20
 
22
- export function RecentPostsCarousel({ posts, ref }: RecentPostsCarouselProps) {
21
+ export function RecentPostsCarousel({ posts }: RecentPostsCarouselProps) {
23
22
  const { PostCard, Link, localization } = usePluginOverrides<
24
23
  BlogPluginOverrides,
25
24
  Partial<BlogPluginOverrides>
@@ -32,9 +31,6 @@ export function RecentPostsCarousel({ posts, ref }: RecentPostsCarouselProps) {
32
31
  const basePath = useBasePath();
33
32
  return (
34
33
  <div className="w-full">
35
- {/* Ref div to trigger intersection observer when scrolled into view */}
36
- {ref && <div ref={ref} />}
37
-
38
34
  {posts && posts.length > 0 && (
39
35
  <>
40
36
  <div className="mt-4 py-4 w-full text-start border-t">
@@ -15,7 +15,6 @@ import type { BlogApiRouter } from "../../api/plugin";
15
15
  import { useDebounce } from "./use-debounce";
16
16
  import { useEffect, useRef } from "react";
17
17
  import { z } from "zod";
18
- import { useInView } from "react-intersection-observer";
19
18
  import { createPostSchema, updatePostSchema } from "../../schemas";
20
19
  import { createBlogQueryKeys } from "../../query-keys";
21
20
  import { usePluginOverrides } from "@btst/stack/context";
@@ -604,16 +603,13 @@ export interface UseNextPreviousPostsResult {
604
603
  }
605
604
 
606
605
  /**
607
- * Hook for fetching previous and next posts relative to a given date
608
- * Uses useInView to only fetch when the component is in view
606
+ * Hook for fetching previous and next posts relative to a given date.
607
+ * Pair with `<WhenVisible>` in the render tree for lazy loading.
609
608
  */
610
609
  export function useNextPreviousPosts(
611
610
  createdAt: string | Date,
612
611
  options: UseNextPreviousPostsOptions = {},
613
- ): UseNextPreviousPostsResult & {
614
- ref: (node: Element | null) => void;
615
- inView: boolean;
616
- } {
612
+ ): UseNextPreviousPostsResult {
617
613
  const { apiBaseURL, apiBasePath, headers } =
618
614
  usePluginOverrides<BlogPluginOverrides>("blog");
619
615
  const client = createApiClient<BlogApiRouter>({
@@ -622,13 +618,6 @@ export function useNextPreviousPosts(
622
618
  });
623
619
  const queries = createBlogQueryKeys(client, headers);
624
620
 
625
- const { ref, inView } = useInView({
626
- // start a little early so the data is ready as it scrolls in
627
- rootMargin: "200px 0px",
628
- // run once; keep data cached after
629
- triggerOnce: true,
630
- });
631
-
632
621
  const dateValue =
633
622
  typeof createdAt === "string" ? new Date(createdAt) : createdAt;
634
623
  const baseQuery = queries.posts.nextPrevious(dateValue);
@@ -641,7 +630,7 @@ export function useNextPreviousPosts(
641
630
  >({
642
631
  ...baseQuery,
643
632
  ...SHARED_QUERY_CONFIG,
644
- enabled: (options.enabled ?? true) && inView && !!client,
633
+ enabled: (options.enabled ?? true) && !!client,
645
634
  });
646
635
 
647
636
  return {
@@ -650,8 +639,6 @@ export function useNextPreviousPosts(
650
639
  isLoading,
651
640
  error,
652
641
  refetch,
653
- ref,
654
- inView,
655
642
  };
656
643
  }
657
644
 
@@ -682,15 +669,12 @@ export interface UseRecentPostsResult {
682
669
  }
683
670
 
684
671
  /**
685
- * Hook for fetching recent posts
686
- * Uses useInView to only fetch when the component is in view
672
+ * Hook for fetching recent posts.
673
+ * Pair with `<WhenVisible>` in the render tree for lazy loading.
687
674
  */
688
675
  export function useRecentPosts(
689
676
  options: UseRecentPostsOptions = {},
690
- ): UseRecentPostsResult & {
691
- ref: (node: Element | null) => void;
692
- inView: boolean;
693
- } {
677
+ ): UseRecentPostsResult {
694
678
  const { apiBaseURL, apiBasePath, headers } =
695
679
  usePluginOverrides<BlogPluginOverrides>("blog");
696
680
  const client = createApiClient<BlogApiRouter>({
@@ -699,13 +683,6 @@ export function useRecentPosts(
699
683
  });
700
684
  const queries = createBlogQueryKeys(client, headers);
701
685
 
702
- const { ref, inView } = useInView({
703
- // start a little early so the data is ready as it scrolls in
704
- rootMargin: "200px 0px",
705
- // run once; keep data cached after
706
- triggerOnce: true,
707
- });
708
-
709
686
  const baseQuery = queries.posts.recent({
710
687
  limit: options.limit ?? 5,
711
688
  excludeSlug: options.excludeSlug,
@@ -719,7 +696,7 @@ export function useRecentPosts(
719
696
  >({
720
697
  ...baseQuery,
721
698
  ...SHARED_QUERY_CONFIG,
722
- enabled: (options.enabled ?? true) && inView && !!client,
699
+ enabled: (options.enabled ?? true) && !!client,
723
700
  });
724
701
 
725
702
  return {
@@ -727,7 +704,5 @@ export function useRecentPosts(
727
704
  isLoading,
728
705
  error,
729
706
  refetch,
730
- ref,
731
- inView,
732
707
  };
733
708
  }
@@ -1,5 +1,5 @@
1
1
  import type { SerializedPost } from "../types";
2
- import type { ComponentType } from "react";
2
+ import type { ComponentType, ReactNode } from "react";
3
3
  import type { BlogLocalization } from "./localization";
4
4
 
5
5
  /**
@@ -134,4 +134,29 @@ export interface BlogPluginOverrides {
134
134
  * @param context - Route context
135
135
  */
136
136
  onBeforeDraftsPageRendered?: (context: RouteContext) => boolean;
137
+
138
+ // ============ Slot Overrides ============
139
+
140
+ /**
141
+ * Optional slot rendered below the blog post body.
142
+ * Use this to inject a comment thread or any custom content without
143
+ * coupling the blog plugin to the comments plugin.
144
+ *
145
+ * @example
146
+ * ```tsx
147
+ * blog: {
148
+ * postBottomSlot: (post) => (
149
+ * <CommentThread
150
+ * resourceId={post.slug}
151
+ * resourceType="blog-post"
152
+ * apiBaseURL={apiBaseURL}
153
+ * apiBasePath="/api/data"
154
+ * currentUserId={session?.userId}
155
+ * loginHref="/login"
156
+ * />
157
+ * ),
158
+ * }
159
+ * ```
160
+ */
161
+ postBottomSlot?: (post: SerializedPost) => ReactNode;
137
162
  }
@@ -1,10 +1,9 @@
1
1
  "use client";
2
2
 
3
- import { Button } from "@workspace/ui/components/button";
4
- import { ChevronLeft, ChevronRight } from "lucide-react";
5
3
  import { usePluginOverrides } from "@btst/stack/context";
6
4
  import type { CMSPluginOverrides } from "../../overrides";
7
5
  import { CMS_LOCALIZATION } from "../../localization";
6
+ import { PaginationControls } from "@workspace/ui/components/pagination-controls";
8
7
 
9
8
  interface PaginationProps {
10
9
  currentPage: number;
@@ -27,46 +26,19 @@ export function Pagination({
27
26
  usePluginOverrides<CMSPluginOverrides>("cms");
28
27
  const localization = { ...CMS_LOCALIZATION, ...customLocalization };
29
28
 
30
- const from = offset + 1;
31
- const to = Math.min(offset + limit, total);
32
-
33
- if (totalPages <= 1) {
34
- return null;
35
- }
36
-
37
29
  return (
38
- <div className="flex items-center justify-between px-4 py-3 border-t">
39
- <p className="text-sm text-muted-foreground">
40
- {localization.CMS_LIST_PAGINATION_SHOWING.replace(
41
- "{from}",
42
- String(from),
43
- )
44
- .replace("{to}", String(to))
45
- .replace("{total}", String(total))}
46
- </p>
47
- <div className="flex items-center gap-2">
48
- <Button
49
- variant="outline"
50
- size="sm"
51
- onClick={() => onPageChange(currentPage - 1)}
52
- disabled={currentPage === 1}
53
- >
54
- <ChevronLeft className="h-4 w-4 mr-1" />
55
- {localization.CMS_LIST_PAGINATION_PREVIOUS}
56
- </Button>
57
- <span className="text-sm text-muted-foreground">
58
- {currentPage} / {totalPages}
59
- </span>
60
- <Button
61
- variant="outline"
62
- size="sm"
63
- onClick={() => onPageChange(currentPage + 1)}
64
- disabled={currentPage === totalPages}
65
- >
66
- {localization.CMS_LIST_PAGINATION_NEXT}
67
- <ChevronRight className="h-4 w-4 ml-1" />
68
- </Button>
69
- </div>
70
- </div>
30
+ <PaginationControls
31
+ currentPage={currentPage}
32
+ totalPages={totalPages}
33
+ onPageChange={onPageChange}
34
+ total={total}
35
+ limit={limit}
36
+ offset={offset}
37
+ labels={{
38
+ previous: localization.CMS_LIST_PAGINATION_PREVIOUS,
39
+ next: localization.CMS_LIST_PAGINATION_NEXT,
40
+ showing: localization.CMS_LIST_PAGINATION_SHOWING,
41
+ }}
42
+ />
71
43
  );
72
44
  }