@btst/stack 2.7.0 → 2.8.0

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 +67 -2
  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
package/README.md CHANGED
@@ -40,6 +40,7 @@ Enable the features you need and keep building your product.
40
40
  | **OpenAPI** | Auto-generated API documentation with interactive Scalar UI |
41
41
  | **Route Docs** | Auto-generated client route documentation with interactive navigation |
42
42
  | **Better Auth UI** | Beautiful shadcn/ui authentication components for better-auth |
43
+ | **Comments** | Commenting system with moderation, likes, and nested replies |
43
44
 
44
45
  Each plugin ships **frontend + backend together**:
45
46
  routes, APIs, database models, React components, SSR, and SEO — already wired.
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const jsxRuntime = require('react/jsx-runtime');
4
+ const skeleton = require('../../../../../../../ui/src/components/skeleton.cjs');
5
+
6
+ function PostNavigationSkeleton() {
7
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t mt-4 pt-4 w-full flex flex-col sm:flex-row gap-4", children: [
8
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-14 flex-1 rounded-md" }),
9
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-14 flex-1 rounded-md" })
10
+ ] });
11
+ }
12
+
13
+ exports.PostNavigationSkeleton = PostNavigationSkeleton;
@@ -0,0 +1,11 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Skeleton } from '../../../../../../../ui/src/components/skeleton.mjs';
3
+
4
+ function PostNavigationSkeleton() {
5
+ return /* @__PURE__ */ jsxs("div", { className: "border-t mt-4 pt-4 w-full flex flex-col sm:flex-row gap-4", children: [
6
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-14 flex-1 rounded-md" }),
7
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-14 flex-1 rounded-md" })
8
+ ] });
9
+ }
10
+
11
+ export { PostNavigationSkeleton };
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const jsxRuntime = require('react/jsx-runtime');
4
+ const skeleton = require('../../../../../../../ui/src/components/skeleton.cjs');
5
+ const postCardSkeleton = require('./post-card-skeleton.cjs');
6
+
7
+ function RecentPostsCarouselSkeleton() {
8
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full mt-4 py-4 border-t", children: [
9
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
10
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-7 w-36" }),
11
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-16" })
12
+ ] }),
13
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsx(postCardSkeleton.PostCardSkeleton, {}, i)) })
14
+ ] });
15
+ }
16
+
17
+ exports.RecentPostsCarouselSkeleton = RecentPostsCarouselSkeleton;
@@ -0,0 +1,15 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Skeleton } from '../../../../../../../ui/src/components/skeleton.mjs';
3
+ import { PostCardSkeleton } from './post-card-skeleton.mjs';
4
+
5
+ function RecentPostsCarouselSkeleton() {
6
+ return /* @__PURE__ */ jsxs("div", { className: "w-full mt-4 py-4 border-t", children: [
7
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
8
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-36" }),
9
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" })
10
+ ] }),
11
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsx(PostCardSkeleton, {}, i)) })
12
+ ] });
13
+ }
14
+
15
+ export { RecentPostsCarouselSkeleton };
@@ -17,6 +17,9 @@ const badge = require('../../../../../../../ui/src/components/badge.cjs');
17
17
  const useRouteLifecycle = require('../../../../../../../ui/src/hooks/use-route-lifecycle.cjs');
18
18
  const onThisPage = require('../shared/on-this-page.cjs');
19
19
  const context$1 = require('@btst/stack/plugins/ai-chat/client/context');
20
+ const whenVisible = require('../../../../../../../ui/src/components/when-visible.cjs');
21
+ const postNavigationSkeleton = require('../loading/post-navigation-skeleton.cjs');
22
+ const recentPostsCarouselSkeleton = require('../loading/recent-posts-carousel-skeleton.cjs');
20
23
 
21
24
  function PostPage({ slug }) {
22
25
  const overrides = context.usePluginOverrides("blog", {
@@ -40,13 +43,13 @@ function PostPage({ slug }) {
40
43
  }
41
44
  });
42
45
  const { post } = blogHooks.useSuspensePost(slug ?? "");
43
- const { previousPost, nextPost, ref } = blogHooks.useNextPreviousPosts(
46
+ const { previousPost, nextPost } = blogHooks.useNextPreviousPosts(
44
47
  post?.createdAt ?? /* @__PURE__ */ new Date(),
45
48
  {
46
49
  enabled: !!post
47
50
  }
48
51
  );
49
- const { recentPosts, ref: recentPostsRef } = blogHooks.useRecentPosts({
52
+ const { recentPosts } = blogHooks.useRecentPosts({
50
53
  limit: 5,
51
54
  excludeSlug: slug,
52
55
  enabled: !!post
@@ -94,14 +97,22 @@ ${post.content ?? ""}`.slice(
94
97
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full px-3", children: /* @__PURE__ */ jsxRuntime.jsx(markdownContent.MarkdownContent, { markdown: post.content }) }),
95
98
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 w-full", children: [
96
99
  /* @__PURE__ */ jsxRuntime.jsx(
97
- postNavigation.PostNavigation,
100
+ whenVisible.WhenVisible,
98
101
  {
99
- previousPost,
100
- nextPost,
101
- ref
102
+ rootMargin: "200px",
103
+ fallback: /* @__PURE__ */ jsxRuntime.jsx(postNavigationSkeleton.PostNavigationSkeleton, {}),
104
+ children: /* @__PURE__ */ jsxRuntime.jsx(postNavigation.PostNavigation, { previousPost, nextPost })
102
105
  }
103
106
  ),
104
- /* @__PURE__ */ jsxRuntime.jsx(recentPostsCarousel.RecentPostsCarousel, { posts: recentPosts, ref: recentPostsRef })
107
+ /* @__PURE__ */ jsxRuntime.jsx(
108
+ whenVisible.WhenVisible,
109
+ {
110
+ rootMargin: "200px",
111
+ fallback: /* @__PURE__ */ jsxRuntime.jsx(recentPostsCarouselSkeleton.RecentPostsCarouselSkeleton, {}),
112
+ children: /* @__PURE__ */ jsxRuntime.jsx(recentPostsCarousel.RecentPostsCarousel, { posts: recentPosts })
113
+ }
114
+ ),
115
+ overrides.postBottomSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "post-bottom-slot", children: overrides.postBottomSlot(post) })
105
116
  ] })
106
117
  ] }),
107
118
  /* @__PURE__ */ jsxRuntime.jsx(onThisPage.OnThisPage, { markdown: post.content })
@@ -15,6 +15,9 @@ import { Badge } from '../../../../../../../ui/src/components/badge.mjs';
15
15
  import { useRouteLifecycle } from '../../../../../../../ui/src/hooks/use-route-lifecycle.mjs';
16
16
  import { OnThisPageSelect, OnThisPage } from '../shared/on-this-page.mjs';
17
17
  import { useRegisterPageAIContext } from '@btst/stack/plugins/ai-chat/client/context';
18
+ import { WhenVisible } from '../../../../../../../ui/src/components/when-visible.mjs';
19
+ import { PostNavigationSkeleton } from '../loading/post-navigation-skeleton.mjs';
20
+ import { RecentPostsCarouselSkeleton } from '../loading/recent-posts-carousel-skeleton.mjs';
18
21
 
19
22
  function PostPage({ slug }) {
20
23
  const overrides = usePluginOverrides("blog", {
@@ -38,13 +41,13 @@ function PostPage({ slug }) {
38
41
  }
39
42
  });
40
43
  const { post } = useSuspensePost(slug ?? "");
41
- const { previousPost, nextPost, ref } = useNextPreviousPosts(
44
+ const { previousPost, nextPost } = useNextPreviousPosts(
42
45
  post?.createdAt ?? /* @__PURE__ */ new Date(),
43
46
  {
44
47
  enabled: !!post
45
48
  }
46
49
  );
47
- const { recentPosts, ref: recentPostsRef } = useRecentPosts({
50
+ const { recentPosts } = useRecentPosts({
48
51
  limit: 5,
49
52
  excludeSlug: slug,
50
53
  enabled: !!post
@@ -92,14 +95,22 @@ ${post.content ?? ""}`.slice(
92
95
  /* @__PURE__ */ jsx("div", { className: "w-full px-3", children: /* @__PURE__ */ jsx(MarkdownContent, { markdown: post.content }) }),
93
96
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 w-full", children: [
94
97
  /* @__PURE__ */ jsx(
95
- PostNavigation,
98
+ WhenVisible,
96
99
  {
97
- previousPost,
98
- nextPost,
99
- ref
100
+ rootMargin: "200px",
101
+ fallback: /* @__PURE__ */ jsx(PostNavigationSkeleton, {}),
102
+ children: /* @__PURE__ */ jsx(PostNavigation, { previousPost, nextPost })
100
103
  }
101
104
  ),
102
- /* @__PURE__ */ jsx(RecentPostsCarousel, { posts: recentPosts, ref: recentPostsRef })
105
+ /* @__PURE__ */ jsx(
106
+ WhenVisible,
107
+ {
108
+ rootMargin: "200px",
109
+ fallback: /* @__PURE__ */ jsx(RecentPostsCarouselSkeleton, {}),
110
+ children: /* @__PURE__ */ jsx(RecentPostsCarousel, { posts: recentPosts })
111
+ }
112
+ ),
113
+ overrides.postBottomSlot && /* @__PURE__ */ jsx("div", { "data-testid": "post-bottom-slot", children: overrides.postBottomSlot(post) })
103
114
  ] })
104
115
  ] }),
105
116
  /* @__PURE__ */ jsx(OnThisPage, { markdown: post.content })
@@ -9,66 +9,62 @@ const defaults = require('./defaults.cjs');
9
9
 
10
10
  function PostNavigation({
11
11
  previousPost,
12
- nextPost,
13
- ref
12
+ nextPost
14
13
  }) {
15
14
  const { Link } = context.usePluginOverrides("blog", {
16
15
  Link: defaults.DefaultLink
17
16
  });
18
17
  const basePath = context.useBasePath();
19
18
  const blogPath = `${basePath}/blog`;
20
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
21
- ref && /* @__PURE__ */ jsxRuntime.jsx("div", { ref }),
22
- (previousPost || nextPost) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t mt-4 pt-4 w-full" }),
24
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row gap-4 w-full justify-between", children: [
25
- previousPost ? /* @__PURE__ */ jsxRuntime.jsx(
26
- Link,
27
- {
28
- "data-testid": "previous-post-link",
29
- href: `${blogPath}/${previousPost.slug}`,
30
- className: "flex-1 sm:max-w-1/3",
31
- children: /* @__PURE__ */ jsxRuntime.jsx(
32
- button.Button,
33
- {
34
- variant: "outline",
35
- className: "w-full justify-start py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
36
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
37
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronLeft, { className: "h-4 w-4 shrink-0" }),
38
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0 flex-1", children: [
39
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Previous" }),
40
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: previousPost.title })
41
- ] })
19
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (previousPost || nextPost) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t mt-4 pt-4 w-full" }),
21
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row gap-4 w-full justify-between", children: [
22
+ previousPost ? /* @__PURE__ */ jsxRuntime.jsx(
23
+ Link,
24
+ {
25
+ "data-testid": "previous-post-link",
26
+ href: `${blogPath}/${previousPost.slug}`,
27
+ className: "flex-1 sm:max-w-1/3",
28
+ children: /* @__PURE__ */ jsxRuntime.jsx(
29
+ button.Button,
30
+ {
31
+ variant: "outline",
32
+ className: "w-full justify-start py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
33
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
34
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronLeft, { className: "h-4 w-4 shrink-0" }),
35
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0 flex-1", children: [
36
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Previous" }),
37
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: previousPost.title })
42
38
  ] })
43
- }
44
- )
45
- }
46
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
47
- nextPost ? /* @__PURE__ */ jsxRuntime.jsx(
48
- Link,
49
- {
50
- "data-testid": "next-post-link",
51
- href: `${blogPath}/${nextPost.slug}`,
52
- className: "flex-1 sm:max-w-1/3",
53
- children: /* @__PURE__ */ jsxRuntime.jsx(
54
- button.Button,
55
- {
56
- variant: "outline",
57
- className: "w-full justify-end py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
58
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
59
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end min-w-0 flex-1", children: [
60
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Next" }),
61
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: nextPost.title })
62
- ] }),
63
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronRight, { className: "h-4 w-4 shrink-0" })
64
- ] })
65
- }
66
- )
67
- }
68
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" })
69
- ] })
39
+ ] })
40
+ }
41
+ )
42
+ }
43
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
44
+ nextPost ? /* @__PURE__ */ jsxRuntime.jsx(
45
+ Link,
46
+ {
47
+ "data-testid": "next-post-link",
48
+ href: `${blogPath}/${nextPost.slug}`,
49
+ className: "flex-1 sm:max-w-1/3",
50
+ children: /* @__PURE__ */ jsxRuntime.jsx(
51
+ button.Button,
52
+ {
53
+ variant: "outline",
54
+ className: "w-full justify-end py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
55
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
56
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end min-w-0 flex-1", children: [
57
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Next" }),
58
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: nextPost.title })
59
+ ] }),
60
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronRight, { className: "h-4 w-4 shrink-0" })
61
+ ] })
62
+ }
63
+ )
64
+ }
65
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" })
70
66
  ] })
71
- ] });
67
+ ] }) });
72
68
  }
73
69
 
74
70
  exports.PostNavigation = PostNavigation;
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
3
  import { usePluginOverrides, useBasePath } from '@btst/stack/context';
4
4
  import { Button } from '../../../../../../../ui/src/components/button.mjs';
5
5
  import { ChevronLeft, ChevronRight } from 'lucide-react';
@@ -7,66 +7,62 @@ import { DefaultLink } from './defaults.mjs';
7
7
 
8
8
  function PostNavigation({
9
9
  previousPost,
10
- nextPost,
11
- ref
10
+ nextPost
12
11
  }) {
13
12
  const { Link } = usePluginOverrides("blog", {
14
13
  Link: DefaultLink
15
14
  });
16
15
  const basePath = useBasePath();
17
16
  const blogPath = `${basePath}/blog`;
18
- return /* @__PURE__ */ jsxs(Fragment, { children: [
19
- ref && /* @__PURE__ */ jsx("div", { ref }),
20
- (previousPost || nextPost) && /* @__PURE__ */ jsxs(Fragment, { children: [
21
- /* @__PURE__ */ jsx("div", { className: "border-t mt-4 pt-4 w-full" }),
22
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-4 w-full justify-between", children: [
23
- previousPost ? /* @__PURE__ */ jsx(
24
- Link,
25
- {
26
- "data-testid": "previous-post-link",
27
- href: `${blogPath}/${previousPost.slug}`,
28
- className: "flex-1 sm:max-w-1/3",
29
- children: /* @__PURE__ */ jsx(
30
- Button,
31
- {
32
- variant: "outline",
33
- className: "w-full justify-start py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
34
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
35
- /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4 shrink-0" }),
36
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0 flex-1", children: [
37
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Previous" }),
38
- /* @__PURE__ */ jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: previousPost.title })
39
- ] })
17
+ return /* @__PURE__ */ jsx(Fragment, { children: (previousPost || nextPost) && /* @__PURE__ */ jsxs(Fragment, { children: [
18
+ /* @__PURE__ */ jsx("div", { className: "border-t mt-4 pt-4 w-full" }),
19
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-4 w-full justify-between", children: [
20
+ previousPost ? /* @__PURE__ */ jsx(
21
+ Link,
22
+ {
23
+ "data-testid": "previous-post-link",
24
+ href: `${blogPath}/${previousPost.slug}`,
25
+ className: "flex-1 sm:max-w-1/3",
26
+ children: /* @__PURE__ */ jsx(
27
+ Button,
28
+ {
29
+ variant: "outline",
30
+ className: "w-full justify-start py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
31
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
32
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4 shrink-0" }),
33
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0 flex-1", children: [
34
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Previous" }),
35
+ /* @__PURE__ */ jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: previousPost.title })
40
36
  ] })
41
- }
42
- )
43
- }
44
- ) : /* @__PURE__ */ jsx("div", { className: "flex-1" }),
45
- nextPost ? /* @__PURE__ */ jsx(
46
- Link,
47
- {
48
- "data-testid": "next-post-link",
49
- href: `${blogPath}/${nextPost.slug}`,
50
- className: "flex-1 sm:max-w-1/3",
51
- children: /* @__PURE__ */ jsx(
52
- Button,
53
- {
54
- variant: "outline",
55
- className: "w-full justify-end py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
56
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
57
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end min-w-0 flex-1", children: [
58
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Next" }),
59
- /* @__PURE__ */ jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: nextPost.title })
60
- ] }),
61
- /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })
62
- ] })
63
- }
64
- )
65
- }
66
- ) : /* @__PURE__ */ jsx("div", { className: "flex-1" })
67
- ] })
37
+ ] })
38
+ }
39
+ )
40
+ }
41
+ ) : /* @__PURE__ */ jsx("div", { className: "flex-1" }),
42
+ nextPost ? /* @__PURE__ */ jsx(
43
+ Link,
44
+ {
45
+ "data-testid": "next-post-link",
46
+ href: `${blogPath}/${nextPost.slug}`,
47
+ className: "flex-1 sm:max-w-1/3",
48
+ children: /* @__PURE__ */ jsx(
49
+ Button,
50
+ {
51
+ variant: "outline",
52
+ className: "w-full justify-end py-4 px-4 whitespace-normal! h-full hover:cursor-pointer",
53
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full min-w-0", children: [
54
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end min-w-0 flex-1", children: [
55
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Next" }),
56
+ /* @__PURE__ */ jsx("div", { className: "font-semibold line-clamp-2 text-sm leading-tight transition-colors text-start", children: nextPost.title })
57
+ ] }),
58
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })
59
+ ] })
60
+ }
61
+ )
62
+ }
63
+ ) : /* @__PURE__ */ jsx("div", { className: "flex-1" })
68
64
  ] })
69
- ] });
65
+ ] }) });
70
66
  }
71
67
 
72
68
  export { PostNavigation };
@@ -8,7 +8,7 @@ const postCard = require('./post-card.cjs');
8
8
  const defaults = require('./defaults.cjs');
9
9
  const index = require('../../localization/index.cjs');
10
10
 
11
- function RecentPostsCarousel({ posts, ref }) {
11
+ function RecentPostsCarousel({ posts }) {
12
12
  const { PostCard, Link, localization } = context.usePluginOverrides("blog", {
13
13
  PostCard: postCard.PostCard,
14
14
  Link: defaults.DefaultLink,
@@ -16,44 +16,41 @@ function RecentPostsCarousel({ posts, ref }) {
16
16
  });
17
17
  const PostCardComponent = PostCard || postCard.PostCard;
18
18
  const basePath = context.useBasePath();
19
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
20
- ref && /* @__PURE__ */ jsxRuntime.jsx("div", { ref }),
21
- posts && posts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
22
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 py-4 w-full text-start border-t", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between", children: [
23
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold", children: localization.BLOG_POST_KEEP_READING }),
24
- /* @__PURE__ */ jsxRuntime.jsx(
25
- Link,
26
- {
27
- href: `${basePath}/blog`,
28
- className: "text-sm text-muted-foreground hover:text-foreground transition-colors",
29
- children: localization.BLOG_POST_VIEW_ALL
30
- }
31
- )
32
- ] }) }),
33
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "recent-posts-carousel", children: /* @__PURE__ */ jsxRuntime.jsxs(
34
- carousel.Carousel,
19
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", children: posts && posts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 py-4 w-full text-start border-t", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between", children: [
21
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold", children: localization.BLOG_POST_KEEP_READING }),
22
+ /* @__PURE__ */ jsxRuntime.jsx(
23
+ Link,
35
24
  {
36
- opts: {
37
- align: "start",
38
- loop: false
39
- },
40
- className: "w-full",
41
- children: [
42
- /* @__PURE__ */ jsxRuntime.jsx(carousel.CarouselContent, { className: "-ml-2 md:-ml-4", children: posts.map((post) => /* @__PURE__ */ jsxRuntime.jsx(
43
- carousel.CarouselItem,
44
- {
45
- className: "pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3",
46
- children: /* @__PURE__ */ jsxRuntime.jsx(PostCardComponent, { post })
47
- },
48
- post.id
49
- )) }),
50
- /* @__PURE__ */ jsxRuntime.jsx(carousel.CarouselPrevious, { className: "-left-4 z-50 hover:cursor-pointer" }),
51
- /* @__PURE__ */ jsxRuntime.jsx(carousel.CarouselNext, { className: "-right-4 z-50 hover:cursor-pointer" })
52
- ]
25
+ href: `${basePath}/blog`,
26
+ className: "text-sm text-muted-foreground hover:text-foreground transition-colors",
27
+ children: localization.BLOG_POST_VIEW_ALL
53
28
  }
54
- ) })
55
- ] })
56
- ] });
29
+ )
30
+ ] }) }),
31
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "recent-posts-carousel", children: /* @__PURE__ */ jsxRuntime.jsxs(
32
+ carousel.Carousel,
33
+ {
34
+ opts: {
35
+ align: "start",
36
+ loop: false
37
+ },
38
+ className: "w-full",
39
+ children: [
40
+ /* @__PURE__ */ jsxRuntime.jsx(carousel.CarouselContent, { className: "-ml-2 md:-ml-4", children: posts.map((post) => /* @__PURE__ */ jsxRuntime.jsx(
41
+ carousel.CarouselItem,
42
+ {
43
+ className: "pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3",
44
+ children: /* @__PURE__ */ jsxRuntime.jsx(PostCardComponent, { post })
45
+ },
46
+ post.id
47
+ )) }),
48
+ /* @__PURE__ */ jsxRuntime.jsx(carousel.CarouselPrevious, { className: "-left-4 z-50 hover:cursor-pointer" }),
49
+ /* @__PURE__ */ jsxRuntime.jsx(carousel.CarouselNext, { className: "-right-4 z-50 hover:cursor-pointer" })
50
+ ]
51
+ }
52
+ ) })
53
+ ] }) });
57
54
  }
58
55
 
59
56
  exports.RecentPostsCarousel = RecentPostsCarousel;
@@ -1,12 +1,12 @@
1
1
  "use client";
2
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { usePluginOverrides, useBasePath } from '@btst/stack/context';
4
4
  import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from '../../../../../../../ui/src/components/carousel.mjs';
5
5
  import { PostCard } from './post-card.mjs';
6
6
  import { DefaultLink } from './defaults.mjs';
7
7
  import { BLOG_LOCALIZATION } from '../../localization/index.mjs';
8
8
 
9
- function RecentPostsCarousel({ posts, ref }) {
9
+ function RecentPostsCarousel({ posts }) {
10
10
  const { PostCard: PostCard$1, Link, localization } = usePluginOverrides("blog", {
11
11
  PostCard: PostCard,
12
12
  Link: DefaultLink,
@@ -14,44 +14,41 @@ function RecentPostsCarousel({ posts, ref }) {
14
14
  });
15
15
  const PostCardComponent = PostCard$1 || PostCard;
16
16
  const basePath = useBasePath();
17
- return /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
18
- ref && /* @__PURE__ */ jsx("div", { ref }),
19
- posts && posts.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
20
- /* @__PURE__ */ jsx("div", { className: "mt-4 py-4 w-full text-start border-t", children: /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between", children: [
21
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: localization.BLOG_POST_KEEP_READING }),
22
- /* @__PURE__ */ jsx(
23
- Link,
24
- {
25
- href: `${basePath}/blog`,
26
- className: "text-sm text-muted-foreground hover:text-foreground transition-colors",
27
- children: localization.BLOG_POST_VIEW_ALL
28
- }
29
- )
30
- ] }) }),
31
- /* @__PURE__ */ jsx("div", { "data-testid": "recent-posts-carousel", children: /* @__PURE__ */ jsxs(
32
- Carousel,
17
+ return /* @__PURE__ */ jsx("div", { className: "w-full", children: posts && posts.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
18
+ /* @__PURE__ */ jsx("div", { className: "mt-4 py-4 w-full text-start border-t", children: /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between", children: [
19
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: localization.BLOG_POST_KEEP_READING }),
20
+ /* @__PURE__ */ jsx(
21
+ Link,
33
22
  {
34
- opts: {
35
- align: "start",
36
- loop: false
37
- },
38
- className: "w-full",
39
- children: [
40
- /* @__PURE__ */ jsx(CarouselContent, { className: "-ml-2 md:-ml-4", children: posts.map((post) => /* @__PURE__ */ jsx(
41
- CarouselItem,
42
- {
43
- className: "pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3",
44
- children: /* @__PURE__ */ jsx(PostCardComponent, { post })
45
- },
46
- post.id
47
- )) }),
48
- /* @__PURE__ */ jsx(CarouselPrevious, { className: "-left-4 z-50 hover:cursor-pointer" }),
49
- /* @__PURE__ */ jsx(CarouselNext, { className: "-right-4 z-50 hover:cursor-pointer" })
50
- ]
23
+ href: `${basePath}/blog`,
24
+ className: "text-sm text-muted-foreground hover:text-foreground transition-colors",
25
+ children: localization.BLOG_POST_VIEW_ALL
51
26
  }
52
- ) })
53
- ] })
54
- ] });
27
+ )
28
+ ] }) }),
29
+ /* @__PURE__ */ jsx("div", { "data-testid": "recent-posts-carousel", children: /* @__PURE__ */ jsxs(
30
+ Carousel,
31
+ {
32
+ opts: {
33
+ align: "start",
34
+ loop: false
35
+ },
36
+ className: "w-full",
37
+ children: [
38
+ /* @__PURE__ */ jsx(CarouselContent, { className: "-ml-2 md:-ml-4", children: posts.map((post) => /* @__PURE__ */ jsx(
39
+ CarouselItem,
40
+ {
41
+ className: "pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3",
42
+ children: /* @__PURE__ */ jsx(PostCardComponent, { post })
43
+ },
44
+ post.id
45
+ )) }),
46
+ /* @__PURE__ */ jsx(CarouselPrevious, { className: "-left-4 z-50 hover:cursor-pointer" }),
47
+ /* @__PURE__ */ jsx(CarouselNext, { className: "-right-4 z-50 hover:cursor-pointer" })
48
+ ]
49
+ }
50
+ ) })
51
+ ] }) });
55
52
  }
56
53
 
57
54
  export { RecentPostsCarousel };