@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.
- package/README.md +156 -709
- package/dist/api/index.cjs +2 -1
- package/dist/api/index.d.cts +4 -3
- package/dist/api/index.d.mts +4 -3
- package/dist/api/index.d.ts +4 -3
- package/dist/api/index.mjs +1 -1
- package/dist/client/components/compose.cjs +68 -0
- package/dist/client/components/compose.mjs +65 -0
- package/dist/client/components/error-boundary.cjs +24 -0
- package/dist/client/components/error-boundary.mjs +22 -0
- package/dist/client/components/index.cjs +10 -0
- package/dist/client/components/index.d.cts +52 -0
- package/dist/client/components/index.d.mts +52 -0
- package/dist/client/components/index.d.ts +52 -0
- package/dist/client/components/index.mjs +2 -0
- package/dist/client/index.cjs +24 -5
- package/dist/client/index.d.cts +125 -8
- package/dist/client/index.d.mts +125 -8
- package/dist/client/index.d.ts +125 -8
- package/dist/client/index.mjs +21 -4
- package/dist/client/meta-utils.cjs +162 -0
- package/dist/client/meta-utils.mjs +160 -0
- package/dist/client/path-utils.cjs +15 -0
- package/dist/client/path-utils.mjs +13 -0
- package/dist/client/sitemap-utils.cjs +14 -0
- package/dist/client/sitemap-utils.mjs +12 -0
- package/dist/context/index.cjs +6 -63
- package/dist/context/index.d.cts +21 -24
- package/dist/context/index.d.mts +21 -24
- package/dist/context/index.d.ts +21 -24
- package/dist/context/index.mjs +1 -61
- package/dist/context/provider.cjs +51 -0
- package/dist/context/provider.mjs +46 -0
- package/dist/index.cjs +2 -3
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +1 -2
- package/dist/plugins/api/index.cjs +13 -0
- package/dist/plugins/api/index.d.cts +40 -0
- package/dist/plugins/api/index.d.mts +40 -0
- package/dist/plugins/api/index.d.ts +40 -0
- package/dist/plugins/api/index.mjs +8 -0
- package/dist/plugins/blog/api/index.cjs +11 -0
- package/dist/plugins/blog/api/index.d.cts +7 -0
- package/dist/plugins/blog/api/index.d.mts +7 -0
- package/dist/plugins/blog/api/index.d.ts +7 -0
- package/dist/plugins/blog/api/index.mjs +2 -0
- package/dist/plugins/blog/api/plugin.cjs +569 -0
- package/dist/plugins/blog/api/plugin.mjs +565 -0
- package/dist/plugins/blog/client/components/forms/image-field.cjs +133 -0
- package/dist/plugins/blog/client/components/forms/image-field.mjs +131 -0
- package/dist/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
- package/dist/plugins/blog/client/components/forms/markdown-editor.cjs +106 -0
- package/dist/plugins/blog/client/components/forms/markdown-editor.mjs +104 -0
- package/dist/plugins/blog/client/components/forms/post-forms.cjs +401 -0
- package/dist/plugins/blog/client/components/forms/post-forms.mjs +398 -0
- package/dist/plugins/blog/client/components/forms/tags-multiselect.cjs +71 -0
- package/dist/plugins/blog/client/components/forms/tags-multiselect.mjs +65 -0
- package/dist/plugins/blog/client/components/index.cjs +17 -0
- package/dist/plugins/blog/client/components/index.d.cts +22 -0
- package/dist/plugins/blog/client/components/index.d.mts +22 -0
- package/dist/plugins/blog/client/components/index.d.ts +22 -0
- package/dist/plugins/blog/client/components/index.mjs +12 -0
- package/dist/plugins/blog/client/components/loading/form-page-skeleton.cjs +62 -0
- package/dist/plugins/blog/client/components/loading/form-page-skeleton.mjs +60 -0
- package/dist/plugins/blog/client/components/loading/index.cjs +20 -0
- package/dist/plugins/blog/client/components/loading/index.mjs +16 -0
- package/dist/plugins/blog/client/components/loading/list-page-skeleton.cjs +26 -0
- package/dist/plugins/blog/client/components/loading/list-page-skeleton.mjs +24 -0
- package/dist/plugins/blog/client/components/loading/page-header-skeleton.cjs +13 -0
- package/dist/plugins/blog/client/components/loading/page-header-skeleton.mjs +11 -0
- package/dist/plugins/blog/client/components/loading/post-card-skeleton.cjs +22 -0
- package/dist/plugins/blog/client/components/loading/post-card-skeleton.mjs +20 -0
- package/dist/plugins/blog/client/components/loading/post-page-skeleton.cjs +56 -0
- package/dist/plugins/blog/client/components/loading/post-page-skeleton.mjs +54 -0
- package/dist/plugins/blog/client/components/pages/404-page.cjs +19 -0
- package/dist/plugins/blog/client/components/pages/404-page.mjs +17 -0
- package/dist/plugins/blog/client/components/pages/edit-post-page.cjs +41 -0
- package/dist/plugins/blog/client/components/pages/edit-post-page.internal.cjs +57 -0
- package/dist/plugins/blog/client/components/pages/edit-post-page.internal.mjs +55 -0
- package/dist/plugins/blog/client/components/pages/edit-post-page.mjs +39 -0
- package/dist/plugins/blog/client/components/pages/home-page.cjs +41 -0
- package/dist/plugins/blog/client/components/pages/home-page.internal.cjs +61 -0
- package/dist/plugins/blog/client/components/pages/home-page.internal.mjs +59 -0
- package/dist/plugins/blog/client/components/pages/home-page.mjs +39 -0
- package/dist/plugins/blog/client/components/pages/new-post-page.cjs +37 -0
- package/dist/plugins/blog/client/components/pages/new-post-page.internal.cjs +53 -0
- package/dist/plugins/blog/client/components/pages/new-post-page.internal.mjs +51 -0
- package/dist/plugins/blog/client/components/pages/new-post-page.mjs +35 -0
- package/dist/plugins/blog/client/components/pages/post-page.cjs +39 -0
- package/dist/plugins/blog/client/components/pages/post-page.internal.cjs +101 -0
- package/dist/plugins/blog/client/components/pages/post-page.internal.mjs +99 -0
- package/dist/plugins/blog/client/components/pages/post-page.mjs +37 -0
- package/dist/plugins/blog/client/components/pages/tag-page.cjs +39 -0
- package/dist/plugins/blog/client/components/pages/tag-page.internal.cjs +61 -0
- package/dist/plugins/blog/client/components/pages/tag-page.internal.mjs +59 -0
- package/dist/plugins/blog/client/components/pages/tag-page.mjs +37 -0
- package/dist/plugins/blog/client/components/shared/better-blog-attribution.cjs +24 -0
- package/dist/plugins/blog/client/components/shared/better-blog-attribution.mjs +22 -0
- package/dist/plugins/blog/client/components/shared/default-error.cjs +18 -0
- package/dist/plugins/blog/client/components/shared/default-error.mjs +16 -0
- package/dist/plugins/blog/client/components/shared/defaults.cjs +13 -0
- package/dist/plugins/blog/client/components/shared/defaults.mjs +10 -0
- package/dist/plugins/blog/client/components/shared/empty-list.cjs +21 -0
- package/dist/plugins/blog/client/components/shared/empty-list.mjs +19 -0
- package/dist/plugins/blog/client/components/shared/error-placeholder.cjs +24 -0
- package/dist/plugins/blog/client/components/shared/error-placeholder.mjs +22 -0
- package/dist/plugins/blog/client/components/shared/highlight-text.cjs +53 -0
- package/dist/plugins/blog/client/components/shared/highlight-text.mjs +51 -0
- package/dist/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
- package/dist/plugins/blog/client/components/shared/markdown-content.cjs +324 -0
- package/dist/plugins/blog/client/components/shared/markdown-content.mjs +315 -0
- package/dist/plugins/blog/client/components/shared/on-this-page.cjs +161 -0
- package/dist/plugins/blog/client/components/shared/on-this-page.mjs +158 -0
- package/dist/plugins/blog/client/components/shared/page-header.cjs +40 -0
- package/dist/plugins/blog/client/components/shared/page-header.mjs +38 -0
- package/dist/plugins/blog/client/components/shared/page-layout.cjs +24 -0
- package/dist/plugins/blog/client/components/shared/page-layout.mjs +22 -0
- package/dist/plugins/blog/client/components/shared/page-wrapper.cjs +23 -0
- package/dist/plugins/blog/client/components/shared/page-wrapper.mjs +21 -0
- package/dist/plugins/blog/client/components/shared/post-card.cjs +279 -0
- package/dist/plugins/blog/client/components/shared/post-card.mjs +277 -0
- package/dist/plugins/blog/client/components/shared/post-navigation.cjs +74 -0
- package/dist/plugins/blog/client/components/shared/post-navigation.mjs +72 -0
- package/dist/plugins/blog/client/components/shared/posts-list.cjs +48 -0
- package/dist/plugins/blog/client/components/shared/posts-list.mjs +46 -0
- package/dist/plugins/blog/client/components/shared/recent-posts-carousel.cjs +59 -0
- package/dist/plugins/blog/client/components/shared/recent-posts-carousel.mjs +57 -0
- package/dist/plugins/blog/client/components/shared/search-input.cjs +136 -0
- package/dist/plugins/blog/client/components/shared/search-input.mjs +117 -0
- package/dist/plugins/blog/client/components/shared/search-modal.cjs +135 -0
- package/dist/plugins/blog/client/components/shared/search-modal.mjs +116 -0
- package/dist/plugins/blog/client/components/shared/tags-list.cjs +22 -0
- package/dist/plugins/blog/client/components/shared/tags-list.mjs +20 -0
- package/dist/plugins/blog/client/components/shared/use-route-lifecycle.cjs +50 -0
- package/dist/plugins/blog/client/components/shared/use-route-lifecycle.mjs +48 -0
- package/dist/plugins/blog/client/hooks/blog-hooks.cjs +380 -0
- package/dist/plugins/blog/client/hooks/blog-hooks.mjs +368 -0
- package/dist/plugins/blog/client/hooks/index.cjs +17 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +150 -0
- package/dist/plugins/blog/client/hooks/index.d.mts +150 -0
- package/dist/plugins/blog/client/hooks/index.d.ts +150 -0
- package/dist/plugins/blog/client/hooks/index.mjs +1 -0
- package/dist/plugins/blog/client/hooks/use-debounce.cjs +16 -0
- package/dist/plugins/blog/client/hooks/use-debounce.mjs +14 -0
- package/dist/plugins/blog/client/index.cjs +7 -0
- package/dist/plugins/blog/client/index.d.cts +414 -0
- package/dist/plugins/blog/client/index.d.mts +414 -0
- package/dist/plugins/blog/client/index.d.ts +414 -0
- package/dist/plugins/blog/client/index.mjs +1 -0
- package/dist/plugins/blog/client/localization/blog-card.cjs +7 -0
- package/dist/plugins/blog/client/localization/blog-card.mjs +5 -0
- package/dist/plugins/blog/client/localization/blog-common.cjs +10 -0
- package/dist/plugins/blog/client/localization/blog-common.mjs +8 -0
- package/dist/plugins/blog/client/localization/blog-forms.cjs +40 -0
- package/dist/plugins/blog/client/localization/blog-forms.mjs +38 -0
- package/dist/plugins/blog/client/localization/blog-list.cjs +18 -0
- package/dist/plugins/blog/client/localization/blog-list.mjs +16 -0
- package/dist/plugins/blog/client/localization/blog-post.cjs +13 -0
- package/dist/plugins/blog/client/localization/blog-post.mjs +11 -0
- package/dist/plugins/blog/client/localization/index.cjs +17 -0
- package/dist/plugins/blog/client/localization/index.mjs +15 -0
- package/dist/plugins/blog/client/plugin.cjs +462 -0
- package/dist/plugins/blog/client/plugin.mjs +460 -0
- package/dist/plugins/blog/client.css +3 -0
- package/dist/plugins/blog/db.cjs +90 -0
- package/dist/plugins/blog/db.mjs +88 -0
- package/dist/plugins/blog/query-keys.cjs +181 -0
- package/dist/plugins/blog/query-keys.d.cts +530 -0
- package/dist/plugins/blog/query-keys.d.mts +530 -0
- package/dist/plugins/blog/query-keys.d.ts +530 -0
- package/dist/plugins/blog/query-keys.mjs +179 -0
- package/dist/plugins/blog/schemas.cjs +39 -0
- package/dist/plugins/blog/schemas.mjs +35 -0
- package/dist/plugins/blog/style.css +22 -0
- package/dist/plugins/blog/utils.cjs +97 -0
- package/dist/plugins/blog/utils.mjs +87 -0
- package/dist/plugins/client/index.cjs +15 -0
- package/dist/plugins/client/index.d.cts +57 -0
- package/dist/plugins/client/index.d.mts +57 -0
- package/dist/plugins/client/index.d.ts +57 -0
- package/dist/plugins/client/index.mjs +9 -0
- package/dist/{shared/stack.3OUyGp_E.mjs → plugins/utils.mjs} +1 -1
- package/dist/shared/{stack.DORw_1ps.d.cts → stack.ByOugz9d.d.cts} +17 -1
- package/dist/shared/{stack.DORw_1ps.d.mts → stack.ByOugz9d.d.mts} +17 -1
- package/dist/shared/{stack.DORw_1ps.d.ts → stack.ByOugz9d.d.ts} +17 -1
- package/dist/shared/stack.CoPoHVfV.d.cts +76 -0
- package/dist/shared/stack.CoPoHVfV.d.mts +76 -0
- package/dist/shared/stack.CoPoHVfV.d.ts +76 -0
- package/package.json +102 -14
- package/src/__tests__/plugins.test.tsx +539 -0
- package/src/__tests__/sitemap.test.ts +60 -0
- package/src/api/index.ts +75 -0
- package/src/client/components/compose.tsx +116 -0
- package/src/client/components/error-boundary.tsx +30 -0
- package/src/client/components/index.tsx +2 -0
- package/src/client/index.ts +109 -0
- package/src/client/meta-utils.ts +228 -0
- package/src/client/path-utils.ts +38 -0
- package/src/client/sitemap-utils.ts +46 -0
- package/src/context/index.ts +1 -0
- package/src/context/provider.tsx +157 -0
- package/src/index.ts +1 -0
- package/src/plugins/api/index.ts +50 -0
- package/src/plugins/blog/api/index.ts +2 -0
- package/src/plugins/blog/api/plugin.ts +759 -0
- package/src/plugins/blog/client/components/forms/image-field.tsx +165 -0
- package/src/plugins/blog/client/components/forms/markdown-editor-styles.css +30 -0
- package/src/plugins/blog/client/components/forms/markdown-editor.tsx +136 -0
- package/src/plugins/blog/client/components/forms/post-forms.tsx +531 -0
- package/src/plugins/blog/client/components/forms/tags-multiselect.tsx +79 -0
- package/src/plugins/blog/client/components/index.tsx +11 -0
- package/src/plugins/blog/client/components/loading/form-page-skeleton.tsx +75 -0
- package/src/plugins/blog/client/components/loading/index.tsx +27 -0
- package/src/plugins/blog/client/components/loading/list-page-skeleton.tsx +38 -0
- package/src/plugins/blog/client/components/loading/page-header-skeleton.tsx +10 -0
- package/src/plugins/blog/client/components/loading/post-card-skeleton.tsx +30 -0
- package/src/plugins/blog/client/components/loading/post-page-skeleton.tsx +75 -0
- package/src/plugins/blog/client/components/pages/404-page.tsx +23 -0
- package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +60 -0
- package/src/plugins/blog/client/components/pages/edit-post-page.tsx +40 -0
- package/src/plugins/blog/client/components/pages/home-page.internal.tsx +71 -0
- package/src/plugins/blog/client/components/pages/home-page.tsx +42 -0
- package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +59 -0
- package/src/plugins/blog/client/components/pages/new-post-page.tsx +36 -0
- package/src/plugins/blog/client/components/pages/post-page.internal.tsx +142 -0
- package/src/plugins/blog/client/components/pages/post-page.tsx +38 -0
- package/src/plugins/blog/client/components/pages/tag-page.internal.tsx +74 -0
- package/src/plugins/blog/client/components/pages/tag-page.tsx +38 -0
- package/src/plugins/blog/client/components/shared/better-blog-attribution.tsx +19 -0
- package/src/plugins/blog/client/components/shared/default-error.tsx +20 -0
- package/src/plugins/blog/client/components/shared/defaults.tsx +9 -0
- package/src/plugins/blog/client/components/shared/empty-list.tsx +25 -0
- package/src/plugins/blog/client/components/shared/error-placeholder.tsx +20 -0
- package/src/plugins/blog/client/components/shared/highlight-text.tsx +80 -0
- package/src/plugins/blog/client/components/shared/markdown-content-styles.css +328 -0
- package/src/plugins/blog/client/components/shared/markdown-content.tsx +448 -0
- package/src/plugins/blog/client/components/shared/on-this-page.tsx +234 -0
- package/src/plugins/blog/client/components/shared/page-header.tsx +35 -0
- package/src/plugins/blog/client/components/shared/page-layout.tsx +23 -0
- package/src/plugins/blog/client/components/shared/page-wrapper.tsx +32 -0
- package/src/plugins/blog/client/components/shared/post-card.tsx +308 -0
- package/src/plugins/blog/client/components/shared/post-navigation.tsx +98 -0
- package/src/plugins/blog/client/components/shared/posts-list.tsx +67 -0
- package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +79 -0
- package/src/plugins/blog/client/components/shared/search-input.tsx +146 -0
- package/src/plugins/blog/client/components/shared/search-modal.tsx +162 -0
- package/src/plugins/blog/client/components/shared/tags-list.tsx +34 -0
- package/src/plugins/blog/client/components/shared/use-route-lifecycle.tsx +68 -0
- package/src/plugins/blog/client/hooks/blog-hooks.tsx +623 -0
- package/src/plugins/blog/client/hooks/index.tsx +1 -0
- package/src/plugins/blog/client/hooks/use-debounce.ts +43 -0
- package/src/plugins/blog/client/index.ts +9 -0
- package/src/plugins/blog/client/localization/blog-card.ts +3 -0
- package/src/plugins/blog/client/localization/blog-common.ts +7 -0
- package/src/plugins/blog/client/localization/blog-forms.ts +45 -0
- package/src/plugins/blog/client/localization/blog-list.ts +14 -0
- package/src/plugins/blog/client/localization/blog-post.ts +9 -0
- package/src/plugins/blog/client/localization/index.ts +15 -0
- package/src/plugins/blog/client/overrides.ts +123 -0
- package/src/plugins/blog/client/plugin.tsx +672 -0
- package/src/plugins/blog/client.css +3 -0
- package/src/plugins/blog/db.ts +90 -0
- package/src/plugins/blog/query-keys.ts +267 -0
- package/src/plugins/blog/schemas.ts +39 -0
- package/src/plugins/blog/style.css +22 -0
- package/src/plugins/blog/types.ts +37 -0
- package/src/plugins/blog/utils.ts +144 -0
- package/src/plugins/client/index.ts +53 -0
- package/src/plugins/index.ts +0 -0
- package/src/plugins/utils.ts +35 -0
- package/src/types.ts +209 -0
- package/dist/plugins/index.cjs +0 -15
- package/dist/plugins/index.d.cts +0 -64
- package/dist/plugins/index.d.mts +0 -64
- package/dist/plugins/index.d.ts +0 -64
- package/dist/plugins/index.mjs +0 -11
- package/dist/shared/stack.DrUAVfIH.d.cts +0 -17
- package/dist/shared/stack.DrUAVfIH.d.mts +0 -17
- package/dist/shared/stack.DrUAVfIH.d.ts +0 -17
- /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 };
|