@btst/stack 1.0.1 → 1.1.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 (282) hide show
  1. package/README.md +156 -709
  2. package/dist/api/index.cjs +2 -1
  3. package/dist/api/index.d.cts +4 -3
  4. package/dist/api/index.d.mts +4 -3
  5. package/dist/api/index.d.ts +4 -3
  6. package/dist/api/index.mjs +1 -1
  7. package/dist/client/components/compose.cjs +68 -0
  8. package/dist/client/components/compose.mjs +65 -0
  9. package/dist/client/components/error-boundary.cjs +24 -0
  10. package/dist/client/components/error-boundary.mjs +22 -0
  11. package/dist/client/components/index.cjs +10 -0
  12. package/dist/client/components/index.d.cts +52 -0
  13. package/dist/client/components/index.d.mts +52 -0
  14. package/dist/client/components/index.d.ts +52 -0
  15. package/dist/client/components/index.mjs +2 -0
  16. package/dist/client/index.cjs +24 -5
  17. package/dist/client/index.d.cts +125 -8
  18. package/dist/client/index.d.mts +125 -8
  19. package/dist/client/index.d.ts +125 -8
  20. package/dist/client/index.mjs +21 -4
  21. package/dist/client/meta-utils.cjs +162 -0
  22. package/dist/client/meta-utils.mjs +160 -0
  23. package/dist/client/path-utils.cjs +15 -0
  24. package/dist/client/path-utils.mjs +13 -0
  25. package/dist/client/sitemap-utils.cjs +14 -0
  26. package/dist/client/sitemap-utils.mjs +12 -0
  27. package/dist/context/index.cjs +6 -63
  28. package/dist/context/index.d.cts +21 -24
  29. package/dist/context/index.d.mts +21 -24
  30. package/dist/context/index.d.ts +21 -24
  31. package/dist/context/index.mjs +1 -61
  32. package/dist/context/provider.cjs +51 -0
  33. package/dist/context/provider.mjs +46 -0
  34. package/dist/index.cjs +2 -3
  35. package/dist/index.d.cts +3 -2
  36. package/dist/index.d.mts +3 -2
  37. package/dist/index.d.ts +3 -2
  38. package/dist/index.mjs +1 -2
  39. package/dist/plugins/api/index.cjs +13 -0
  40. package/dist/plugins/api/index.d.cts +40 -0
  41. package/dist/plugins/api/index.d.mts +40 -0
  42. package/dist/plugins/api/index.d.ts +40 -0
  43. package/dist/plugins/api/index.mjs +8 -0
  44. package/dist/plugins/blog/api/index.cjs +11 -0
  45. package/dist/plugins/blog/api/index.d.cts +7 -0
  46. package/dist/plugins/blog/api/index.d.mts +7 -0
  47. package/dist/plugins/blog/api/index.d.ts +7 -0
  48. package/dist/plugins/blog/api/index.mjs +2 -0
  49. package/dist/plugins/blog/api/plugin.cjs +569 -0
  50. package/dist/plugins/blog/api/plugin.mjs +565 -0
  51. package/dist/plugins/blog/client/components/forms/image-field.cjs +133 -0
  52. package/dist/plugins/blog/client/components/forms/image-field.mjs +131 -0
  53. package/dist/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
  54. package/dist/plugins/blog/client/components/forms/markdown-editor.cjs +106 -0
  55. package/dist/plugins/blog/client/components/forms/markdown-editor.mjs +104 -0
  56. package/dist/plugins/blog/client/components/forms/post-forms.cjs +401 -0
  57. package/dist/plugins/blog/client/components/forms/post-forms.mjs +398 -0
  58. package/dist/plugins/blog/client/components/forms/tags-multiselect.cjs +71 -0
  59. package/dist/plugins/blog/client/components/forms/tags-multiselect.mjs +65 -0
  60. package/dist/plugins/blog/client/components/index.cjs +17 -0
  61. package/dist/plugins/blog/client/components/index.d.cts +22 -0
  62. package/dist/plugins/blog/client/components/index.d.mts +22 -0
  63. package/dist/plugins/blog/client/components/index.d.ts +22 -0
  64. package/dist/plugins/blog/client/components/index.mjs +12 -0
  65. package/dist/plugins/blog/client/components/loading/form-page-skeleton.cjs +62 -0
  66. package/dist/plugins/blog/client/components/loading/form-page-skeleton.mjs +60 -0
  67. package/dist/plugins/blog/client/components/loading/index.cjs +20 -0
  68. package/dist/plugins/blog/client/components/loading/index.mjs +16 -0
  69. package/dist/plugins/blog/client/components/loading/list-page-skeleton.cjs +26 -0
  70. package/dist/plugins/blog/client/components/loading/list-page-skeleton.mjs +24 -0
  71. package/dist/plugins/blog/client/components/loading/page-header-skeleton.cjs +13 -0
  72. package/dist/plugins/blog/client/components/loading/page-header-skeleton.mjs +11 -0
  73. package/dist/plugins/blog/client/components/loading/post-card-skeleton.cjs +22 -0
  74. package/dist/plugins/blog/client/components/loading/post-card-skeleton.mjs +20 -0
  75. package/dist/plugins/blog/client/components/loading/post-page-skeleton.cjs +56 -0
  76. package/dist/plugins/blog/client/components/loading/post-page-skeleton.mjs +54 -0
  77. package/dist/plugins/blog/client/components/pages/404-page.cjs +19 -0
  78. package/dist/plugins/blog/client/components/pages/404-page.mjs +17 -0
  79. package/dist/plugins/blog/client/components/pages/edit-post-page.cjs +41 -0
  80. package/dist/plugins/blog/client/components/pages/edit-post-page.internal.cjs +57 -0
  81. package/dist/plugins/blog/client/components/pages/edit-post-page.internal.mjs +55 -0
  82. package/dist/plugins/blog/client/components/pages/edit-post-page.mjs +39 -0
  83. package/dist/plugins/blog/client/components/pages/home-page.cjs +41 -0
  84. package/dist/plugins/blog/client/components/pages/home-page.internal.cjs +61 -0
  85. package/dist/plugins/blog/client/components/pages/home-page.internal.mjs +59 -0
  86. package/dist/plugins/blog/client/components/pages/home-page.mjs +39 -0
  87. package/dist/plugins/blog/client/components/pages/new-post-page.cjs +37 -0
  88. package/dist/plugins/blog/client/components/pages/new-post-page.internal.cjs +53 -0
  89. package/dist/plugins/blog/client/components/pages/new-post-page.internal.mjs +51 -0
  90. package/dist/plugins/blog/client/components/pages/new-post-page.mjs +35 -0
  91. package/dist/plugins/blog/client/components/pages/post-page.cjs +39 -0
  92. package/dist/plugins/blog/client/components/pages/post-page.internal.cjs +101 -0
  93. package/dist/plugins/blog/client/components/pages/post-page.internal.mjs +99 -0
  94. package/dist/plugins/blog/client/components/pages/post-page.mjs +37 -0
  95. package/dist/plugins/blog/client/components/pages/tag-page.cjs +39 -0
  96. package/dist/plugins/blog/client/components/pages/tag-page.internal.cjs +61 -0
  97. package/dist/plugins/blog/client/components/pages/tag-page.internal.mjs +59 -0
  98. package/dist/plugins/blog/client/components/pages/tag-page.mjs +37 -0
  99. package/dist/plugins/blog/client/components/shared/better-blog-attribution.cjs +24 -0
  100. package/dist/plugins/blog/client/components/shared/better-blog-attribution.mjs +22 -0
  101. package/dist/plugins/blog/client/components/shared/default-error.cjs +18 -0
  102. package/dist/plugins/blog/client/components/shared/default-error.mjs +16 -0
  103. package/dist/plugins/blog/client/components/shared/defaults.cjs +13 -0
  104. package/dist/plugins/blog/client/components/shared/defaults.mjs +10 -0
  105. package/dist/plugins/blog/client/components/shared/empty-list.cjs +21 -0
  106. package/dist/plugins/blog/client/components/shared/empty-list.mjs +19 -0
  107. package/dist/plugins/blog/client/components/shared/error-placeholder.cjs +24 -0
  108. package/dist/plugins/blog/client/components/shared/error-placeholder.mjs +22 -0
  109. package/dist/plugins/blog/client/components/shared/highlight-text.cjs +53 -0
  110. package/dist/plugins/blog/client/components/shared/highlight-text.mjs +51 -0
  111. package/dist/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
  112. package/dist/plugins/blog/client/components/shared/markdown-content.cjs +324 -0
  113. package/dist/plugins/blog/client/components/shared/markdown-content.mjs +315 -0
  114. package/dist/plugins/blog/client/components/shared/on-this-page.cjs +161 -0
  115. package/dist/plugins/blog/client/components/shared/on-this-page.mjs +158 -0
  116. package/dist/plugins/blog/client/components/shared/page-header.cjs +40 -0
  117. package/dist/plugins/blog/client/components/shared/page-header.mjs +38 -0
  118. package/dist/plugins/blog/client/components/shared/page-layout.cjs +24 -0
  119. package/dist/plugins/blog/client/components/shared/page-layout.mjs +22 -0
  120. package/dist/plugins/blog/client/components/shared/page-wrapper.cjs +23 -0
  121. package/dist/plugins/blog/client/components/shared/page-wrapper.mjs +21 -0
  122. package/dist/plugins/blog/client/components/shared/post-card.cjs +279 -0
  123. package/dist/plugins/blog/client/components/shared/post-card.mjs +277 -0
  124. package/dist/plugins/blog/client/components/shared/post-navigation.cjs +74 -0
  125. package/dist/plugins/blog/client/components/shared/post-navigation.mjs +72 -0
  126. package/dist/plugins/blog/client/components/shared/posts-list.cjs +48 -0
  127. package/dist/plugins/blog/client/components/shared/posts-list.mjs +46 -0
  128. package/dist/plugins/blog/client/components/shared/recent-posts-carousel.cjs +59 -0
  129. package/dist/plugins/blog/client/components/shared/recent-posts-carousel.mjs +57 -0
  130. package/dist/plugins/blog/client/components/shared/search-input.cjs +136 -0
  131. package/dist/plugins/blog/client/components/shared/search-input.mjs +117 -0
  132. package/dist/plugins/blog/client/components/shared/search-modal.cjs +135 -0
  133. package/dist/plugins/blog/client/components/shared/search-modal.mjs +116 -0
  134. package/dist/plugins/blog/client/components/shared/tags-list.cjs +22 -0
  135. package/dist/plugins/blog/client/components/shared/tags-list.mjs +20 -0
  136. package/dist/plugins/blog/client/components/shared/use-route-lifecycle.cjs +50 -0
  137. package/dist/plugins/blog/client/components/shared/use-route-lifecycle.mjs +48 -0
  138. package/dist/plugins/blog/client/hooks/blog-hooks.cjs +380 -0
  139. package/dist/plugins/blog/client/hooks/blog-hooks.mjs +368 -0
  140. package/dist/plugins/blog/client/hooks/index.cjs +17 -0
  141. package/dist/plugins/blog/client/hooks/index.d.cts +150 -0
  142. package/dist/plugins/blog/client/hooks/index.d.mts +150 -0
  143. package/dist/plugins/blog/client/hooks/index.d.ts +150 -0
  144. package/dist/plugins/blog/client/hooks/index.mjs +1 -0
  145. package/dist/plugins/blog/client/hooks/use-debounce.cjs +16 -0
  146. package/dist/plugins/blog/client/hooks/use-debounce.mjs +14 -0
  147. package/dist/plugins/blog/client/index.cjs +7 -0
  148. package/dist/plugins/blog/client/index.d.cts +414 -0
  149. package/dist/plugins/blog/client/index.d.mts +414 -0
  150. package/dist/plugins/blog/client/index.d.ts +414 -0
  151. package/dist/plugins/blog/client/index.mjs +1 -0
  152. package/dist/plugins/blog/client/localization/blog-card.cjs +7 -0
  153. package/dist/plugins/blog/client/localization/blog-card.mjs +5 -0
  154. package/dist/plugins/blog/client/localization/blog-common.cjs +10 -0
  155. package/dist/plugins/blog/client/localization/blog-common.mjs +8 -0
  156. package/dist/plugins/blog/client/localization/blog-forms.cjs +40 -0
  157. package/dist/plugins/blog/client/localization/blog-forms.mjs +38 -0
  158. package/dist/plugins/blog/client/localization/blog-list.cjs +18 -0
  159. package/dist/plugins/blog/client/localization/blog-list.mjs +16 -0
  160. package/dist/plugins/blog/client/localization/blog-post.cjs +13 -0
  161. package/dist/plugins/blog/client/localization/blog-post.mjs +11 -0
  162. package/dist/plugins/blog/client/localization/index.cjs +17 -0
  163. package/dist/plugins/blog/client/localization/index.mjs +15 -0
  164. package/dist/plugins/blog/client/plugin.cjs +462 -0
  165. package/dist/plugins/blog/client/plugin.mjs +460 -0
  166. package/dist/plugins/blog/client.css +3 -0
  167. package/dist/plugins/blog/db.cjs +90 -0
  168. package/dist/plugins/blog/db.mjs +88 -0
  169. package/dist/plugins/blog/query-keys.cjs +181 -0
  170. package/dist/plugins/blog/query-keys.d.cts +530 -0
  171. package/dist/plugins/blog/query-keys.d.mts +530 -0
  172. package/dist/plugins/blog/query-keys.d.ts +530 -0
  173. package/dist/plugins/blog/query-keys.mjs +179 -0
  174. package/dist/plugins/blog/schemas.cjs +39 -0
  175. package/dist/plugins/blog/schemas.mjs +35 -0
  176. package/dist/plugins/blog/style.css +22 -0
  177. package/dist/plugins/blog/utils.cjs +97 -0
  178. package/dist/plugins/blog/utils.mjs +87 -0
  179. package/dist/plugins/client/index.cjs +15 -0
  180. package/dist/plugins/client/index.d.cts +57 -0
  181. package/dist/plugins/client/index.d.mts +57 -0
  182. package/dist/plugins/client/index.d.ts +57 -0
  183. package/dist/plugins/client/index.mjs +9 -0
  184. package/dist/{shared/stack.3OUyGp_E.mjs → plugins/utils.mjs} +1 -1
  185. package/dist/shared/{stack.DORw_1ps.d.cts → stack.ByOugz9d.d.cts} +17 -1
  186. package/dist/shared/{stack.DORw_1ps.d.mts → stack.ByOugz9d.d.mts} +17 -1
  187. package/dist/shared/{stack.DORw_1ps.d.ts → stack.ByOugz9d.d.ts} +17 -1
  188. package/dist/shared/stack.CoPoHVfV.d.cts +76 -0
  189. package/dist/shared/stack.CoPoHVfV.d.mts +76 -0
  190. package/dist/shared/stack.CoPoHVfV.d.ts +76 -0
  191. package/package.json +102 -14
  192. package/src/__tests__/plugins.test.tsx +539 -0
  193. package/src/__tests__/sitemap.test.ts +60 -0
  194. package/src/api/index.ts +75 -0
  195. package/src/client/components/compose.tsx +116 -0
  196. package/src/client/components/error-boundary.tsx +30 -0
  197. package/src/client/components/index.tsx +2 -0
  198. package/src/client/index.ts +109 -0
  199. package/src/client/meta-utils.ts +228 -0
  200. package/src/client/path-utils.ts +38 -0
  201. package/src/client/sitemap-utils.ts +46 -0
  202. package/src/context/index.ts +1 -0
  203. package/src/context/provider.tsx +157 -0
  204. package/src/index.ts +1 -0
  205. package/src/plugins/api/index.ts +50 -0
  206. package/src/plugins/blog/api/index.ts +2 -0
  207. package/src/plugins/blog/api/plugin.ts +759 -0
  208. package/src/plugins/blog/client/components/forms/image-field.tsx +165 -0
  209. package/src/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
  210. package/src/plugins/blog/client/components/forms/markdown-editor.tsx +136 -0
  211. package/src/plugins/blog/client/components/forms/post-forms.tsx +531 -0
  212. package/src/plugins/blog/client/components/forms/tags-multiselect.tsx +79 -0
  213. package/src/plugins/blog/client/components/index.tsx +11 -0
  214. package/src/plugins/blog/client/components/loading/form-page-skeleton.tsx +75 -0
  215. package/src/plugins/blog/client/components/loading/index.tsx +27 -0
  216. package/src/plugins/blog/client/components/loading/list-page-skeleton.tsx +38 -0
  217. package/src/plugins/blog/client/components/loading/page-header-skeleton.tsx +10 -0
  218. package/src/plugins/blog/client/components/loading/post-card-skeleton.tsx +30 -0
  219. package/src/plugins/blog/client/components/loading/post-page-skeleton.tsx +75 -0
  220. package/src/plugins/blog/client/components/pages/404-page.tsx +23 -0
  221. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +60 -0
  222. package/src/plugins/blog/client/components/pages/edit-post-page.tsx +40 -0
  223. package/src/plugins/blog/client/components/pages/home-page.internal.tsx +71 -0
  224. package/src/plugins/blog/client/components/pages/home-page.tsx +42 -0
  225. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +59 -0
  226. package/src/plugins/blog/client/components/pages/new-post-page.tsx +36 -0
  227. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +142 -0
  228. package/src/plugins/blog/client/components/pages/post-page.tsx +38 -0
  229. package/src/plugins/blog/client/components/pages/tag-page.internal.tsx +74 -0
  230. package/src/plugins/blog/client/components/pages/tag-page.tsx +38 -0
  231. package/src/plugins/blog/client/components/shared/better-blog-attribution.tsx +19 -0
  232. package/src/plugins/blog/client/components/shared/default-error.tsx +20 -0
  233. package/src/plugins/blog/client/components/shared/defaults.tsx +9 -0
  234. package/src/plugins/blog/client/components/shared/empty-list.tsx +25 -0
  235. package/src/plugins/blog/client/components/shared/error-placeholder.tsx +20 -0
  236. package/src/plugins/blog/client/components/shared/highlight-text.tsx +80 -0
  237. package/src/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
  238. package/src/plugins/blog/client/components/shared/markdown-content.tsx +448 -0
  239. package/src/plugins/blog/client/components/shared/on-this-page.tsx +234 -0
  240. package/src/plugins/blog/client/components/shared/page-header.tsx +35 -0
  241. package/src/plugins/blog/client/components/shared/page-layout.tsx +23 -0
  242. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +32 -0
  243. package/src/plugins/blog/client/components/shared/post-card.tsx +308 -0
  244. package/src/plugins/blog/client/components/shared/post-navigation.tsx +98 -0
  245. package/src/plugins/blog/client/components/shared/posts-list.tsx +67 -0
  246. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +79 -0
  247. package/src/plugins/blog/client/components/shared/search-input.tsx +146 -0
  248. package/src/plugins/blog/client/components/shared/search-modal.tsx +162 -0
  249. package/src/plugins/blog/client/components/shared/tags-list.tsx +34 -0
  250. package/src/plugins/blog/client/components/shared/use-route-lifecycle.tsx +68 -0
  251. package/src/plugins/blog/client/hooks/blog-hooks.tsx +623 -0
  252. package/src/plugins/blog/client/hooks/index.tsx +1 -0
  253. package/src/plugins/blog/client/hooks/use-debounce.ts +43 -0
  254. package/src/plugins/blog/client/index.ts +9 -0
  255. package/src/plugins/blog/client/localization/blog-card.ts +3 -0
  256. package/src/plugins/blog/client/localization/blog-common.ts +7 -0
  257. package/src/plugins/blog/client/localization/blog-forms.ts +45 -0
  258. package/src/plugins/blog/client/localization/blog-list.ts +14 -0
  259. package/src/plugins/blog/client/localization/blog-post.ts +9 -0
  260. package/src/plugins/blog/client/localization/index.ts +15 -0
  261. package/src/plugins/blog/client/overrides.ts +123 -0
  262. package/src/plugins/blog/client/plugin.tsx +672 -0
  263. package/src/plugins/blog/client.css +3 -0
  264. package/src/plugins/blog/db.ts +90 -0
  265. package/src/plugins/blog/query-keys.ts +267 -0
  266. package/src/plugins/blog/schemas.ts +39 -0
  267. package/src/plugins/blog/style.css +22 -0
  268. package/src/plugins/blog/types.ts +37 -0
  269. package/src/plugins/blog/utils.ts +144 -0
  270. package/src/plugins/client/index.ts +53 -0
  271. package/src/plugins/index.ts +0 -0
  272. package/src/plugins/utils.ts +35 -0
  273. package/src/types.ts +209 -0
  274. package/dist/plugins/index.cjs +0 -15
  275. package/dist/plugins/index.d.cts +0 -64
  276. package/dist/plugins/index.d.mts +0 -64
  277. package/dist/plugins/index.d.ts +0 -64
  278. package/dist/plugins/index.mjs +0 -11
  279. package/dist/shared/stack.DrUAVfIH.d.cts +0 -17
  280. package/dist/shared/stack.DrUAVfIH.d.mts +0 -17
  281. package/dist/shared/stack.DrUAVfIH.d.ts +0 -17
  282. /package/dist/{shared/stack.CktCg4PJ.cjs → plugins/utils.cjs} +0 -0
@@ -0,0 +1,368 @@
1
+ "use client";
2
+ import { createApiClient } from '@btst/stack/plugins/client';
3
+ import { useInfiniteQuery, useSuspenseInfiniteQuery, useQuery, useSuspenseQuery, useQueryClient, useMutation } from '@tanstack/react-query';
4
+ import { useDebounce } from './use-debounce.mjs';
5
+ import { useRef, useEffect } from 'react';
6
+ import { useInView } from 'react-intersection-observer';
7
+ import { createBlogQueryKeys } from '../../query-keys.mjs';
8
+ import { usePluginOverrides } from '@btst/stack/context';
9
+
10
+ const SHARED_QUERY_CONFIG = {
11
+ retry: false,
12
+ refetchOnWindowFocus: false,
13
+ refetchOnMount: false,
14
+ refetchOnReconnect: false,
15
+ staleTime: 1e3 * 60 * 5,
16
+ // 5 minutes
17
+ gcTime: 1e3 * 60 * 10
18
+ // 10 minutes
19
+ };
20
+ function usePosts(options = {}) {
21
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
22
+ const client = createApiClient({
23
+ baseURL: apiBaseURL,
24
+ basePath: apiBasePath
25
+ });
26
+ const {
27
+ tag,
28
+ tagSlug,
29
+ limit = 10,
30
+ enabled = true,
31
+ query,
32
+ published
33
+ } = options;
34
+ const queries = createBlogQueryKeys(client);
35
+ const queryParams = {
36
+ tag,
37
+ tagSlug,
38
+ limit,
39
+ query,
40
+ published
41
+ };
42
+ const basePosts = queries.posts.list(queryParams);
43
+ const {
44
+ data,
45
+ isLoading,
46
+ error,
47
+ fetchNextPage,
48
+ hasNextPage,
49
+ isFetchingNextPage,
50
+ refetch
51
+ } = useInfiniteQuery({
52
+ ...basePosts,
53
+ ...SHARED_QUERY_CONFIG,
54
+ initialPageParam: 0,
55
+ getNextPageParam: (lastPage, allPages) => {
56
+ const posts2 = lastPage;
57
+ if (posts2.length < limit) return void 0;
58
+ return allPages.length * limit;
59
+ },
60
+ enabled: enabled && !!client
61
+ });
62
+ const posts = data?.pages?.flat() ?? [];
63
+ return {
64
+ posts,
65
+ isLoading,
66
+ error,
67
+ loadMore: fetchNextPage,
68
+ hasMore: !!hasNextPage,
69
+ isLoadingMore: isFetchingNextPage,
70
+ refetch
71
+ };
72
+ }
73
+ function useSuspensePosts(options = {}) {
74
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
75
+ const client = createApiClient({
76
+ baseURL: apiBaseURL,
77
+ basePath: apiBasePath
78
+ });
79
+ const {
80
+ tag,
81
+ tagSlug,
82
+ limit = 10,
83
+ enabled = true,
84
+ query,
85
+ published
86
+ } = options;
87
+ const queries = createBlogQueryKeys(client);
88
+ const queryParams = { tag, tagSlug, limit, query, published };
89
+ const basePosts = queries.posts.list(queryParams);
90
+ const {
91
+ data,
92
+ fetchNextPage,
93
+ hasNextPage,
94
+ isFetchingNextPage,
95
+ refetch,
96
+ error,
97
+ isFetching
98
+ } = useSuspenseInfiniteQuery({
99
+ ...basePosts,
100
+ ...SHARED_QUERY_CONFIG,
101
+ initialPageParam: 0,
102
+ getNextPageParam: (lastPage, allPages) => {
103
+ const posts2 = lastPage;
104
+ if (posts2.length < limit) return void 0;
105
+ return allPages.length * limit;
106
+ }
107
+ });
108
+ if (error && !isFetching) {
109
+ throw error;
110
+ }
111
+ const posts = data.pages?.flat() ?? [];
112
+ return {
113
+ posts,
114
+ loadMore: fetchNextPage,
115
+ hasMore: !!hasNextPage,
116
+ isLoadingMore: isFetchingNextPage,
117
+ refetch
118
+ };
119
+ }
120
+ function usePost(slug) {
121
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
122
+ const client = createApiClient({
123
+ baseURL: apiBaseURL,
124
+ basePath: apiBasePath
125
+ });
126
+ const queries = createBlogQueryKeys(client);
127
+ const basePost = queries.posts.detail(slug ?? "");
128
+ const { data, isLoading, error, refetch } = useQuery({
129
+ ...basePost,
130
+ ...SHARED_QUERY_CONFIG,
131
+ enabled: !!client && !!slug
132
+ });
133
+ return {
134
+ post: data || null,
135
+ isLoading,
136
+ error,
137
+ refetch
138
+ };
139
+ }
140
+ function useSuspensePost(slug) {
141
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
142
+ const client = createApiClient({
143
+ baseURL: apiBaseURL,
144
+ basePath: apiBasePath
145
+ });
146
+ const queries = createBlogQueryKeys(client);
147
+ const basePost = queries.posts.detail(slug);
148
+ const { data, refetch, error, isFetching } = useSuspenseQuery({
149
+ ...basePost,
150
+ ...SHARED_QUERY_CONFIG
151
+ });
152
+ if (error && !isFetching) {
153
+ throw error;
154
+ }
155
+ return { post: data || null, refetch };
156
+ }
157
+ function useTags() {
158
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
159
+ const client = createApiClient({
160
+ baseURL: apiBaseURL,
161
+ basePath: apiBasePath
162
+ });
163
+ const queries = createBlogQueryKeys(client);
164
+ const baseTags = queries.tags.list();
165
+ const { data, isLoading, error, refetch } = useQuery({
166
+ ...baseTags,
167
+ ...SHARED_QUERY_CONFIG,
168
+ enabled: !!client
169
+ });
170
+ return {
171
+ tags: data ?? [],
172
+ isLoading,
173
+ error,
174
+ refetch
175
+ };
176
+ }
177
+ function useSuspenseTags() {
178
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
179
+ const client = createApiClient({
180
+ baseURL: apiBaseURL,
181
+ basePath: apiBasePath
182
+ });
183
+ const queries = createBlogQueryKeys(client);
184
+ const baseTags = queries.tags.list();
185
+ const { data, refetch, error, isFetching } = useSuspenseQuery({
186
+ ...baseTags,
187
+ ...SHARED_QUERY_CONFIG
188
+ });
189
+ if (error && !isFetching) {
190
+ throw error;
191
+ }
192
+ return {
193
+ tags: data ?? [],
194
+ refetch
195
+ };
196
+ }
197
+ function useCreatePost() {
198
+ const { refresh, apiBaseURL, apiBasePath } = usePluginOverrides("blog");
199
+ const client = createApiClient({
200
+ baseURL: apiBaseURL,
201
+ basePath: apiBasePath
202
+ });
203
+ const queryClient = useQueryClient();
204
+ const queries = createBlogQueryKeys(client);
205
+ return useMutation({
206
+ mutationKey: [...queries.posts._def, "create"],
207
+ mutationFn: async (postData) => {
208
+ const response = await client("@post/posts", {
209
+ method: "POST",
210
+ body: postData
211
+ });
212
+ return response.data;
213
+ },
214
+ onSuccess: async (created) => {
215
+ if (created?.slug) {
216
+ queryClient.setQueryData(
217
+ queries.posts.detail(created.slug).queryKey,
218
+ created
219
+ );
220
+ }
221
+ await queryClient.invalidateQueries({
222
+ queryKey: queries.posts.list._def
223
+ });
224
+ await queryClient.invalidateQueries({
225
+ queryKey: queries.drafts.list._def
226
+ });
227
+ if (refresh) {
228
+ await refresh();
229
+ }
230
+ }
231
+ });
232
+ }
233
+ function useUpdatePost() {
234
+ const { refresh, apiBaseURL, apiBasePath } = usePluginOverrides("blog");
235
+ const client = createApiClient({
236
+ baseURL: apiBaseURL,
237
+ basePath: apiBasePath
238
+ });
239
+ const queryClient = useQueryClient();
240
+ const queries = createBlogQueryKeys(client);
241
+ return useMutation({
242
+ mutationKey: [...queries.posts._def, "update"],
243
+ mutationFn: async ({ id, data }) => {
244
+ const response = await client(`@put/posts/:id`, {
245
+ method: "PUT",
246
+ params: { id },
247
+ body: data
248
+ });
249
+ return response.data;
250
+ },
251
+ onSuccess: async (updated) => {
252
+ if (updated?.slug) {
253
+ queryClient.setQueryData(
254
+ queries.posts.detail(updated.slug).queryKey,
255
+ updated
256
+ );
257
+ }
258
+ await queryClient.invalidateQueries({
259
+ queryKey: queries.posts.list._def
260
+ });
261
+ await queryClient.invalidateQueries({
262
+ queryKey: queries.drafts.list._def
263
+ });
264
+ if (refresh) {
265
+ await refresh();
266
+ }
267
+ }
268
+ });
269
+ }
270
+ function usePostSearch({
271
+ query,
272
+ enabled = true,
273
+ debounceMs = 300,
274
+ limit = 10,
275
+ published = true
276
+ }) {
277
+ const debouncedQuery = useDebounce(query, debounceMs);
278
+ const shouldSearch = enabled && (query?.trim().length ?? 0) > 0;
279
+ const lastResultsRef = useRef([]);
280
+ const { posts, isLoading, error, refetch } = usePosts({
281
+ query: debouncedQuery,
282
+ limit,
283
+ enabled: shouldSearch && debouncedQuery.trim() !== "",
284
+ published
285
+ });
286
+ const effectivePosts = shouldSearch ? posts : [];
287
+ useEffect(() => {
288
+ if (!isLoading && posts && posts.length >= 0) {
289
+ lastResultsRef.current = posts;
290
+ }
291
+ }, [posts, isLoading]);
292
+ const isDebouncing = enabled && debounceMs > 0 && debouncedQuery !== query;
293
+ const effectiveLoading = isLoading || isDebouncing;
294
+ const dataToReturn = !shouldSearch ? [] : effectiveLoading ? lastResultsRef.current : effectivePosts;
295
+ return {
296
+ posts: dataToReturn,
297
+ // compatibility alias similar to tanstack useQuery
298
+ data: dataToReturn,
299
+ isLoading: effectiveLoading,
300
+ error,
301
+ refetch,
302
+ isSearching: effectiveLoading,
303
+ searchQuery: debouncedQuery
304
+ };
305
+ }
306
+ function useNextPreviousPosts(createdAt, options = {}) {
307
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
308
+ const client = createApiClient({
309
+ baseURL: apiBaseURL,
310
+ basePath: apiBasePath
311
+ });
312
+ const queries = createBlogQueryKeys(client);
313
+ const { ref, inView } = useInView({
314
+ // start a little early so the data is ready as it scrolls in
315
+ rootMargin: "200px 0px",
316
+ // run once; keep data cached after
317
+ triggerOnce: true
318
+ });
319
+ const dateValue = typeof createdAt === "string" ? new Date(createdAt) : createdAt;
320
+ const baseQuery = queries.posts.nextPrevious(dateValue);
321
+ const { data, isLoading, error, refetch } = useQuery({
322
+ ...baseQuery,
323
+ ...SHARED_QUERY_CONFIG,
324
+ enabled: (options.enabled ?? true) && inView && !!client
325
+ });
326
+ return {
327
+ previousPost: data?.previous ?? null,
328
+ nextPost: data?.next ?? null,
329
+ isLoading,
330
+ error,
331
+ refetch,
332
+ ref,
333
+ inView
334
+ };
335
+ }
336
+ function useRecentPosts(options = {}) {
337
+ const { apiBaseURL, apiBasePath } = usePluginOverrides("blog");
338
+ const client = createApiClient({
339
+ baseURL: apiBaseURL,
340
+ basePath: apiBasePath
341
+ });
342
+ const queries = createBlogQueryKeys(client);
343
+ const { ref, inView } = useInView({
344
+ // start a little early so the data is ready as it scrolls in
345
+ rootMargin: "200px 0px",
346
+ // run once; keep data cached after
347
+ triggerOnce: true
348
+ });
349
+ const baseQuery = queries.posts.recent({
350
+ limit: options.limit ?? 5,
351
+ excludeSlug: options.excludeSlug
352
+ });
353
+ const { data, isLoading, error, refetch } = useQuery({
354
+ ...baseQuery,
355
+ ...SHARED_QUERY_CONFIG,
356
+ enabled: (options.enabled ?? true) && inView && !!client
357
+ });
358
+ return {
359
+ recentPosts: data ?? [],
360
+ isLoading,
361
+ error,
362
+ refetch,
363
+ ref,
364
+ inView
365
+ };
366
+ }
367
+
368
+ export { useCreatePost, useNextPreviousPosts, usePost, usePostSearch, usePosts, useRecentPosts, useSuspensePost, useSuspensePosts, useSuspenseTags, useTags, useUpdatePost };
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const blogHooks = require('./blog-hooks.cjs');
4
+
5
+
6
+
7
+ exports.useCreatePost = blogHooks.useCreatePost;
8
+ exports.useNextPreviousPosts = blogHooks.useNextPreviousPosts;
9
+ exports.usePost = blogHooks.usePost;
10
+ exports.usePostSearch = blogHooks.usePostSearch;
11
+ exports.usePosts = blogHooks.usePosts;
12
+ exports.useRecentPosts = blogHooks.useRecentPosts;
13
+ exports.useSuspensePost = blogHooks.useSuspensePost;
14
+ exports.useSuspensePosts = blogHooks.useSuspensePosts;
15
+ exports.useSuspenseTags = blogHooks.useSuspenseTags;
16
+ exports.useTags = blogHooks.useTags;
17
+ exports.useUpdatePost = blogHooks.useUpdatePost;
@@ -0,0 +1,150 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+ import { S as SerializedPost, c as createPostSchema, u as updatePostSchema, a as SerializedTag } from '../../../../shared/stack.CoPoHVfV.cjs';
3
+ import { z } from 'zod';
4
+
5
+ interface UsePostsOptions {
6
+ tag?: string;
7
+ tagSlug?: string;
8
+ limit?: number;
9
+ enabled?: boolean;
10
+ query?: string;
11
+ published?: boolean;
12
+ slug?: string;
13
+ }
14
+ interface UsePostsResult {
15
+ posts: SerializedPost[];
16
+ isLoading: boolean;
17
+ error: Error | null;
18
+ loadMore: () => void;
19
+ hasMore: boolean;
20
+ isLoadingMore: boolean;
21
+ refetch: () => void;
22
+ }
23
+ interface UsePostSearchOptions {
24
+ query: string;
25
+ enabled?: boolean;
26
+ debounceMs?: number;
27
+ limit?: number;
28
+ published?: boolean;
29
+ }
30
+ interface UsePostSearchResult {
31
+ posts: SerializedPost[];
32
+ data: SerializedPost[];
33
+ isLoading: boolean;
34
+ error: Error | null;
35
+ refetch: () => void;
36
+ isSearching: boolean;
37
+ searchQuery: string;
38
+ }
39
+ interface UsePostResult {
40
+ post: SerializedPost | null;
41
+ isLoading: boolean;
42
+ error: Error | null;
43
+ refetch: () => void;
44
+ }
45
+ type PostCreateInput = z.infer<typeof createPostSchema>;
46
+ type PostUpdateInput = z.infer<typeof updatePostSchema>;
47
+ /**
48
+ * Hook for fetching paginated posts with load more functionality
49
+ */
50
+ declare function usePosts(options?: UsePostsOptions): UsePostsResult;
51
+ /** Suspense variant of usePosts */
52
+ declare function useSuspensePosts(options?: UsePostsOptions): {
53
+ posts: SerializedPost[];
54
+ loadMore: () => Promise<unknown>;
55
+ hasMore: boolean;
56
+ isLoadingMore: boolean;
57
+ refetch: () => Promise<unknown>;
58
+ };
59
+ /**
60
+ * Hook for fetching a single post by slug
61
+ */
62
+ declare function usePost(slug?: string): UsePostResult;
63
+ /** Suspense variant of usePost */
64
+ declare function useSuspensePost(slug: string): {
65
+ post: SerializedPost | null;
66
+ refetch: () => Promise<unknown>;
67
+ };
68
+ /**
69
+ * Hook for fetching all unique tags across posts
70
+ */
71
+ declare function useTags(): {
72
+ tags: SerializedTag[];
73
+ isLoading: boolean;
74
+ error: Error | null;
75
+ refetch: () => void;
76
+ };
77
+ /** Suspense variant of useTags */
78
+ declare function useSuspenseTags(): {
79
+ tags: SerializedTag[];
80
+ refetch: () => Promise<unknown>;
81
+ };
82
+ /** Create a new post */
83
+ declare function useCreatePost(): _tanstack_react_query.UseMutationResult<SerializedPost | null, Error, {
84
+ published: boolean;
85
+ title: string;
86
+ content: string;
87
+ excerpt: string;
88
+ tags: ({
89
+ name: string;
90
+ } | {
91
+ id: string;
92
+ name: string;
93
+ slug: string;
94
+ })[];
95
+ slug?: string | undefined;
96
+ createdAt?: Date | undefined;
97
+ publishedAt?: Date | undefined;
98
+ updatedAt?: Date | undefined;
99
+ image?: string | undefined;
100
+ }, unknown>;
101
+ /** Update an existing post by id */
102
+ declare function useUpdatePost(): _tanstack_react_query.UseMutationResult<SerializedPost | null, Error, {
103
+ id: string;
104
+ data: PostUpdateInput;
105
+ }, unknown>;
106
+ /**
107
+ * Hook for searching posts by a free-text query. Uses `usePosts` under the hood.
108
+ * Debounces the query and preserves last successful results to avoid flicker.
109
+ */
110
+ declare function usePostSearch({ query, enabled, debounceMs, limit, published, }: UsePostSearchOptions): UsePostSearchResult;
111
+ interface UseNextPreviousPostsOptions {
112
+ enabled?: boolean;
113
+ }
114
+ interface UseNextPreviousPostsResult {
115
+ previousPost: SerializedPost | null;
116
+ nextPost: SerializedPost | null;
117
+ isLoading: boolean;
118
+ error: Error | null;
119
+ refetch: () => void;
120
+ }
121
+ /**
122
+ * Hook for fetching previous and next posts relative to a given date
123
+ * Uses useInView to only fetch when the component is in view
124
+ */
125
+ declare function useNextPreviousPosts(createdAt: string | Date, options?: UseNextPreviousPostsOptions): UseNextPreviousPostsResult & {
126
+ ref: (node: Element | null) => void;
127
+ inView: boolean;
128
+ };
129
+ interface UseRecentPostsOptions {
130
+ limit?: number;
131
+ excludeSlug?: string;
132
+ enabled?: boolean;
133
+ }
134
+ interface UseRecentPostsResult {
135
+ recentPosts: SerializedPost[];
136
+ isLoading: boolean;
137
+ error: Error | null;
138
+ refetch: () => void;
139
+ }
140
+ /**
141
+ * Hook for fetching recent posts
142
+ * Uses useInView to only fetch when the component is in view
143
+ */
144
+ declare function useRecentPosts(options?: UseRecentPostsOptions): UseRecentPostsResult & {
145
+ ref: (node: Element | null) => void;
146
+ inView: boolean;
147
+ };
148
+
149
+ export { useCreatePost, useNextPreviousPosts, usePost, usePostSearch, usePosts, useRecentPosts, useSuspensePost, useSuspensePosts, useSuspenseTags, useTags, useUpdatePost };
150
+ export type { PostCreateInput, PostUpdateInput, UseNextPreviousPostsOptions, UseNextPreviousPostsResult, UsePostResult, UsePostSearchOptions, UsePostSearchResult, UsePostsOptions, UsePostsResult, UseRecentPostsOptions, UseRecentPostsResult };
@@ -0,0 +1,150 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+ import { S as SerializedPost, c as createPostSchema, u as updatePostSchema, a as SerializedTag } from '../../../../shared/stack.CoPoHVfV.mjs';
3
+ import { z } from 'zod';
4
+
5
+ interface UsePostsOptions {
6
+ tag?: string;
7
+ tagSlug?: string;
8
+ limit?: number;
9
+ enabled?: boolean;
10
+ query?: string;
11
+ published?: boolean;
12
+ slug?: string;
13
+ }
14
+ interface UsePostsResult {
15
+ posts: SerializedPost[];
16
+ isLoading: boolean;
17
+ error: Error | null;
18
+ loadMore: () => void;
19
+ hasMore: boolean;
20
+ isLoadingMore: boolean;
21
+ refetch: () => void;
22
+ }
23
+ interface UsePostSearchOptions {
24
+ query: string;
25
+ enabled?: boolean;
26
+ debounceMs?: number;
27
+ limit?: number;
28
+ published?: boolean;
29
+ }
30
+ interface UsePostSearchResult {
31
+ posts: SerializedPost[];
32
+ data: SerializedPost[];
33
+ isLoading: boolean;
34
+ error: Error | null;
35
+ refetch: () => void;
36
+ isSearching: boolean;
37
+ searchQuery: string;
38
+ }
39
+ interface UsePostResult {
40
+ post: SerializedPost | null;
41
+ isLoading: boolean;
42
+ error: Error | null;
43
+ refetch: () => void;
44
+ }
45
+ type PostCreateInput = z.infer<typeof createPostSchema>;
46
+ type PostUpdateInput = z.infer<typeof updatePostSchema>;
47
+ /**
48
+ * Hook for fetching paginated posts with load more functionality
49
+ */
50
+ declare function usePosts(options?: UsePostsOptions): UsePostsResult;
51
+ /** Suspense variant of usePosts */
52
+ declare function useSuspensePosts(options?: UsePostsOptions): {
53
+ posts: SerializedPost[];
54
+ loadMore: () => Promise<unknown>;
55
+ hasMore: boolean;
56
+ isLoadingMore: boolean;
57
+ refetch: () => Promise<unknown>;
58
+ };
59
+ /**
60
+ * Hook for fetching a single post by slug
61
+ */
62
+ declare function usePost(slug?: string): UsePostResult;
63
+ /** Suspense variant of usePost */
64
+ declare function useSuspensePost(slug: string): {
65
+ post: SerializedPost | null;
66
+ refetch: () => Promise<unknown>;
67
+ };
68
+ /**
69
+ * Hook for fetching all unique tags across posts
70
+ */
71
+ declare function useTags(): {
72
+ tags: SerializedTag[];
73
+ isLoading: boolean;
74
+ error: Error | null;
75
+ refetch: () => void;
76
+ };
77
+ /** Suspense variant of useTags */
78
+ declare function useSuspenseTags(): {
79
+ tags: SerializedTag[];
80
+ refetch: () => Promise<unknown>;
81
+ };
82
+ /** Create a new post */
83
+ declare function useCreatePost(): _tanstack_react_query.UseMutationResult<SerializedPost | null, Error, {
84
+ published: boolean;
85
+ title: string;
86
+ content: string;
87
+ excerpt: string;
88
+ tags: ({
89
+ name: string;
90
+ } | {
91
+ id: string;
92
+ name: string;
93
+ slug: string;
94
+ })[];
95
+ slug?: string | undefined;
96
+ createdAt?: Date | undefined;
97
+ publishedAt?: Date | undefined;
98
+ updatedAt?: Date | undefined;
99
+ image?: string | undefined;
100
+ }, unknown>;
101
+ /** Update an existing post by id */
102
+ declare function useUpdatePost(): _tanstack_react_query.UseMutationResult<SerializedPost | null, Error, {
103
+ id: string;
104
+ data: PostUpdateInput;
105
+ }, unknown>;
106
+ /**
107
+ * Hook for searching posts by a free-text query. Uses `usePosts` under the hood.
108
+ * Debounces the query and preserves last successful results to avoid flicker.
109
+ */
110
+ declare function usePostSearch({ query, enabled, debounceMs, limit, published, }: UsePostSearchOptions): UsePostSearchResult;
111
+ interface UseNextPreviousPostsOptions {
112
+ enabled?: boolean;
113
+ }
114
+ interface UseNextPreviousPostsResult {
115
+ previousPost: SerializedPost | null;
116
+ nextPost: SerializedPost | null;
117
+ isLoading: boolean;
118
+ error: Error | null;
119
+ refetch: () => void;
120
+ }
121
+ /**
122
+ * Hook for fetching previous and next posts relative to a given date
123
+ * Uses useInView to only fetch when the component is in view
124
+ */
125
+ declare function useNextPreviousPosts(createdAt: string | Date, options?: UseNextPreviousPostsOptions): UseNextPreviousPostsResult & {
126
+ ref: (node: Element | null) => void;
127
+ inView: boolean;
128
+ };
129
+ interface UseRecentPostsOptions {
130
+ limit?: number;
131
+ excludeSlug?: string;
132
+ enabled?: boolean;
133
+ }
134
+ interface UseRecentPostsResult {
135
+ recentPosts: SerializedPost[];
136
+ isLoading: boolean;
137
+ error: Error | null;
138
+ refetch: () => void;
139
+ }
140
+ /**
141
+ * Hook for fetching recent posts
142
+ * Uses useInView to only fetch when the component is in view
143
+ */
144
+ declare function useRecentPosts(options?: UseRecentPostsOptions): UseRecentPostsResult & {
145
+ ref: (node: Element | null) => void;
146
+ inView: boolean;
147
+ };
148
+
149
+ export { useCreatePost, useNextPreviousPosts, usePost, usePostSearch, usePosts, useRecentPosts, useSuspensePost, useSuspensePosts, useSuspenseTags, useTags, useUpdatePost };
150
+ export type { PostCreateInput, PostUpdateInput, UseNextPreviousPostsOptions, UseNextPreviousPostsResult, UsePostResult, UsePostSearchOptions, UsePostSearchResult, UsePostsOptions, UsePostsResult, UseRecentPostsOptions, UseRecentPostsResult };