zudoku 0.33.1 → 0.33.2-local.4
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/dist/config/validators/common.d.ts +226 -8
- package/dist/config/validators/common.js +26 -8
- package/dist/config/validators/common.js.map +1 -1
- package/dist/config/validators/validate.d.ts +89 -2
- package/dist/lib/authentication/hook.d.ts +1 -0
- package/dist/lib/authentication/hook.js +11 -1
- package/dist/lib/authentication/hook.js.map +1 -1
- package/dist/lib/authentication/providers/clerk.js +6 -6
- package/dist/lib/authentication/providers/clerk.js.map +1 -1
- package/dist/lib/components/Banner.js +1 -1
- package/dist/lib/components/Banner.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/Layout.js +1 -1
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/index.d.ts +1 -0
- package/dist/lib/core/RouteGuard.js +2 -1
- package/dist/lib/core/RouteGuard.js.map +1 -1
- package/dist/lib/plugins/api-catalog/Catalog.d.ts +3 -1
- package/dist/lib/plugins/api-catalog/Catalog.js +7 -4
- package/dist/lib/plugins/api-catalog/Catalog.js.map +1 -1
- package/dist/lib/plugins/api-catalog/index.js +1 -1
- package/dist/lib/plugins/api-catalog/index.js.map +1 -1
- package/dist/lib/plugins/markdown/MdxPage.js +1 -1
- package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.d.ts +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +2 -1
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +2 -1
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterList.d.ts +2 -1
- package/dist/lib/plugins/openapi/ParameterList.js +3 -2
- package/dist/lib/plugins/openapi/ParameterList.js.map +1 -1
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +3 -1
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.d.ts +3 -2
- package/dist/lib/plugins/openapi/playground/PathParams.js +3 -2
- package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +4 -1
- package/dist/lib/plugins/openapi/playground/Playground.js +10 -7
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/search-pagefind/PagefindSearch.d.ts +6 -0
- package/dist/lib/plugins/search-pagefind/PagefindSearch.js +66 -0
- package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/ResultList.d.ts +8 -0
- package/dist/lib/plugins/search-pagefind/ResultList.js +31 -0
- package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/get-results.d.ts +3 -0
- package/dist/lib/plugins/search-pagefind/get-results.js +37 -0
- package/dist/lib/plugins/search-pagefind/get-results.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/index.d.ts +8 -0
- package/dist/lib/plugins/search-pagefind/index.js +9 -0
- package/dist/lib/plugins/search-pagefind/index.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/types.d.ts +85 -0
- package/dist/lib/plugins/search-pagefind/types.js +2 -0
- package/dist/lib/plugins/search-pagefind/types.js.map +1 -0
- package/dist/lib/ui/Command.d.ts +7 -1
- package/dist/lib/ui/Command.js +2 -2
- package/dist/lib/ui/Command.js.map +1 -1
- package/dist/lib/util/useScrollToAnchor.js +6 -8
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/build.js +4 -0
- package/dist/vite/build.js.map +1 -1
- package/dist/vite/config.js +7 -2
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/dev-server.js +8 -0
- package/dist/vite/dev-server.js.map +1 -1
- package/dist/vite/pagefind.d.ts +4 -0
- package/dist/vite/pagefind.js +15 -0
- package/dist/vite/pagefind.js.map +1 -0
- package/dist/vite/plugin-component.js +4 -0
- package/dist/vite/plugin-component.js.map +1 -1
- package/dist/vite/plugin-search.js +4 -0
- package/dist/vite/plugin-search.js.map +1 -1
- package/dist/vite/prerender/prerender.js +1 -1
- package/dist/vite/prerender/prerender.js.map +1 -1
- package/dist/vite/sitemap.js +2 -1
- package/dist/vite/sitemap.js.map +1 -1
- package/lib/{AuthenticationPlugin-CiO1FM6Q.js → AuthenticationPlugin-BCYuduZ9.js} +3 -3
- package/lib/{AuthenticationPlugin-CiO1FM6Q.js.map → AuthenticationPlugin-BCYuduZ9.js.map} +1 -1
- package/lib/Command-CrTA1FX0.js +140 -0
- package/lib/Command-CrTA1FX0.js.map +1 -0
- package/lib/{Dialog-DIKGQxQc.js → Dialog-mi6BrnrM.js} +3 -3
- package/lib/{Dialog-DIKGQxQc.js.map → Dialog-mi6BrnrM.js.map} +1 -1
- package/lib/{Markdown-DePfm7oQ.js → Markdown-DofXBcqg.js} +2 -2
- package/lib/{Markdown-DePfm7oQ.js.map → Markdown-DofXBcqg.js.map} +1 -1
- package/lib/MdxPage-KJcNWIgt.js +200 -0
- package/lib/MdxPage-KJcNWIgt.js.map +1 -0
- package/lib/{OasProvider-SzD9mHJc.js → OasProvider-HcqBeC4H.js} +4 -4
- package/lib/{OasProvider-SzD9mHJc.js.map → OasProvider-HcqBeC4H.js.map} +1 -1
- package/lib/{OperationList-DDs9NblY.js → OperationList-C3wnbFxp.js} +1857 -1816
- package/lib/OperationList-C3wnbFxp.js.map +1 -0
- package/lib/{Select-Dqtcn53H.js → Select-Co6MuS4j.js} +36 -36
- package/lib/{Select-Dqtcn53H.js.map → Select-Co6MuS4j.js.map} +1 -1
- package/lib/{SlotletProvider-DdtIOUi6.js → SlotletProvider-CYFNHuok.js} +4 -4
- package/lib/{SlotletProvider-DdtIOUi6.js.map → SlotletProvider-CYFNHuok.js.map} +1 -1
- package/lib/{chunk-IR6S3I6Y-D_3UmFIn.js → chunk-IR6S3I6Y-CRDBmIgK.js} +3 -3
- package/lib/{chunk-IR6S3I6Y-D_3UmFIn.js.map → chunk-IR6S3I6Y-CRDBmIgK.js.map} +1 -1
- package/lib/hook-LTe5qHSc.js +347 -0
- package/lib/hook-LTe5qHSc.js.map +1 -0
- package/lib/{index-CibzSNks.js → index-CtkRMvMw.js} +698 -746
- package/lib/index-CtkRMvMw.js.map +1 -0
- package/lib/index-vn5bsvmU.js +1399 -0
- package/lib/index-vn5bsvmU.js.map +1 -0
- package/lib/{mutation-EclmI0is.js → mutation-B81DztCT.js} +2 -2
- package/lib/{mutation-EclmI0is.js.map → mutation-B81DztCT.js.map} +1 -1
- package/lib/ui/Command.js +96 -70
- package/lib/ui/Command.js.map +1 -1
- package/lib/{useExposedProps-RIvey2Oy.js → useExposedProps-D76yras4.js} +2 -2
- package/lib/{useExposedProps-RIvey2Oy.js.map → useExposedProps-D76yras4.js.map} +1 -1
- package/lib/useQuery-CQUwWR9i.js +1137 -0
- package/lib/useQuery-CQUwWR9i.js.map +1 -0
- package/lib/useScrollToAnchor-DKyrbZoy.js +977 -0
- package/lib/useScrollToAnchor-DKyrbZoy.js.map +1 -0
- package/lib/zudoku.auth-auth0.js +1 -1
- package/lib/zudoku.auth-clerk.js +29 -29
- package/lib/zudoku.auth-clerk.js.map +1 -1
- package/lib/zudoku.auth-openid.js +3 -3
- package/lib/zudoku.components.js +32 -1393
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.hooks.js +1 -1
- package/lib/zudoku.plugin-api-catalog.js +87 -71
- package/lib/zudoku.plugin-api-catalog.js.map +1 -1
- package/lib/zudoku.plugin-api-keys.js +16 -15
- package/lib/zudoku.plugin-api-keys.js.map +1 -1
- package/lib/zudoku.plugin-custom-pages.js +2 -2
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +3 -3
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/lib/zudoku.plugin-search-pagefind.js +274 -0
- package/lib/zudoku.plugin-search-pagefind.js.map +1 -0
- package/package.json +8 -3
- package/src/lib/authentication/hook.ts +12 -1
- package/src/lib/authentication/providers/clerk.tsx +10 -6
- package/src/lib/components/Banner.tsx +1 -0
- package/src/lib/components/Heading.tsx +1 -1
- package/src/lib/components/Layout.tsx +1 -0
- package/src/lib/core/RouteGuard.tsx +2 -1
- package/src/lib/plugins/api-catalog/Catalog.tsx +23 -7
- package/src/lib/plugins/api-catalog/index.tsx +1 -0
- package/src/lib/plugins/markdown/MdxPage.tsx +5 -1
- package/src/lib/plugins/openapi/OperationList.tsx +15 -3
- package/src/lib/plugins/openapi/OperationListItem.tsx +8 -0
- package/src/lib/plugins/openapi/ParameterList.tsx +4 -0
- package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +7 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +1 -0
- package/src/lib/plugins/openapi/playground/PathParams.tsx +8 -2
- package/src/lib/plugins/openapi/playground/Playground.tsx +61 -5
- package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +135 -0
- package/src/lib/plugins/search-pagefind/ResultList.tsx +104 -0
- package/src/lib/plugins/search-pagefind/get-results.tsx +54 -0
- package/src/lib/plugins/search-pagefind/index.tsx +21 -0
- package/src/lib/plugins/search-pagefind/types.ts +118 -0
- package/src/lib/ui/Command.tsx +25 -3
- package/src/lib/util/useScrollToAnchor.ts +8 -8
- package/README.md +0 -121
- package/lib/MdxPage-DZTt9ld7.js +0 -193
- package/lib/MdxPage-DZTt9ld7.js.map +0 -1
- package/lib/OperationList-DDs9NblY.js.map +0 -1
- package/lib/hook-CN__aZIt.js +0 -1464
- package/lib/hook-CN__aZIt.js.map +0 -1
- package/lib/index-CibzSNks.js.map +0 -1
- package/lib/index.esm-CQHE3GEU.js +0 -691
- package/lib/index.esm-CQHE3GEU.js.map +0 -1
- package/lib/objectEntries-yMIkr2mI.js +0 -5
- package/lib/objectEntries-yMIkr2mI.js.map +0 -1
- package/lib/useScrollToAnchor-C7ilRSts.js +0 -290
- package/lib/useScrollToAnchor-C7ilRSts.js.map +0 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { FileTextIcon } from "lucide-react";
|
|
2
|
+
import { useCallback } from "react";
|
|
3
|
+
import { Link, useNavigate } from "react-router";
|
|
4
|
+
import { CommandGroup, CommandItem, CommandList } from "zudoku/ui/Command.js";
|
|
5
|
+
import {
|
|
6
|
+
type PagefindSearchFragment,
|
|
7
|
+
type PagefindSubResult,
|
|
8
|
+
} from "./types.js";
|
|
9
|
+
|
|
10
|
+
const sortSubResults = (a: PagefindSubResult, b: PagefindSubResult) => {
|
|
11
|
+
const aScore = a.weighted_locations.reduce(
|
|
12
|
+
(sum, loc) => sum + loc.balanced_score,
|
|
13
|
+
0,
|
|
14
|
+
);
|
|
15
|
+
const bScore = b.weighted_locations.reduce(
|
|
16
|
+
(sum, loc) => sum + loc.balanced_score,
|
|
17
|
+
0,
|
|
18
|
+
);
|
|
19
|
+
return bScore - aScore;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const hoverClassname = `cursor-pointer border border-transparent data-[selected=true]:border-border`;
|
|
23
|
+
|
|
24
|
+
export const ResultList = ({
|
|
25
|
+
basePath,
|
|
26
|
+
searchResults,
|
|
27
|
+
searchTerm,
|
|
28
|
+
onClose,
|
|
29
|
+
maxSubResults = 4,
|
|
30
|
+
}: {
|
|
31
|
+
basePath?: string;
|
|
32
|
+
searchResults: PagefindSearchFragment[];
|
|
33
|
+
searchTerm: string;
|
|
34
|
+
onClose: () => void;
|
|
35
|
+
maxSubResults?: number;
|
|
36
|
+
}) => {
|
|
37
|
+
const navigate = useNavigate();
|
|
38
|
+
|
|
39
|
+
const cleanResultUrl = useCallback(
|
|
40
|
+
(url: string) => {
|
|
41
|
+
const clean = url.replace(".html", "");
|
|
42
|
+
return basePath && clean.startsWith(basePath)
|
|
43
|
+
? clean.slice(basePath.length)
|
|
44
|
+
: clean;
|
|
45
|
+
},
|
|
46
|
+
[basePath],
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<CommandList className="max-h-[450px]">
|
|
51
|
+
{searchTerm && searchResults.length > 0 && (
|
|
52
|
+
<CommandGroup
|
|
53
|
+
className="text-sm text-muted-foreground"
|
|
54
|
+
heading={`${searchResults.length} results for "${searchTerm}"`}
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
{searchResults.map((result) => (
|
|
58
|
+
<CommandGroup
|
|
59
|
+
key={[result.meta.title ?? result.excerpt, result.url].join("-")}
|
|
60
|
+
>
|
|
61
|
+
<CommandItem
|
|
62
|
+
asChild
|
|
63
|
+
value={`${result.meta.title}-${result.url}`}
|
|
64
|
+
className={hoverClassname}
|
|
65
|
+
onSelect={() => {
|
|
66
|
+
void navigate(cleanResultUrl(result.url));
|
|
67
|
+
onClose();
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<Link to={cleanResultUrl(result.url)}>
|
|
71
|
+
<FileTextIcon size={20} className="text-muted-foreground" />
|
|
72
|
+
{result.meta.title}
|
|
73
|
+
</Link>
|
|
74
|
+
</CommandItem>
|
|
75
|
+
{result.sub_results
|
|
76
|
+
.sort(sortSubResults)
|
|
77
|
+
.slice(0, maxSubResults)
|
|
78
|
+
.map((subResult) => (
|
|
79
|
+
<CommandItem
|
|
80
|
+
asChild
|
|
81
|
+
key={`${result.meta.title}-${subResult.url}`}
|
|
82
|
+
value={`${result.meta.title}-${subResult.url}`}
|
|
83
|
+
className={hoverClassname}
|
|
84
|
+
onSelect={() => {
|
|
85
|
+
void navigate(cleanResultUrl(subResult.url));
|
|
86
|
+
onClose();
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<Link to={cleanResultUrl(subResult.url)} onClick={onClose}>
|
|
90
|
+
<div className="flex flex-col items-start gap-2 ms-2.5 ps-5 border-l border-muted-foreground/50">
|
|
91
|
+
<span className="font-bold">{subResult.title}</span>
|
|
92
|
+
<span
|
|
93
|
+
className="text-[13px] [&_mark]:bg-primary [&_mark]:text-primary-foreground"
|
|
94
|
+
dangerouslySetInnerHTML={{ __html: subResult.excerpt }}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
</Link>
|
|
98
|
+
</CommandItem>
|
|
99
|
+
))}
|
|
100
|
+
</CommandGroup>
|
|
101
|
+
))}
|
|
102
|
+
</CommandList>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { PagefindOptions } from "./index.js";
|
|
2
|
+
import type { PagefindSearchFragment, PagefindSearchResults } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export const getResults = async (
|
|
5
|
+
search: PagefindSearchResults,
|
|
6
|
+
options: PagefindOptions,
|
|
7
|
+
) => {
|
|
8
|
+
const maxResults = options.maxResults ?? 10;
|
|
9
|
+
const transformFn = options.transformResults ?? (() => true);
|
|
10
|
+
|
|
11
|
+
const transformedResults: PagefindSearchFragment[] = [];
|
|
12
|
+
|
|
13
|
+
const generator = searchResultGenerator(search, transformFn);
|
|
14
|
+
|
|
15
|
+
for await (const result of generator) {
|
|
16
|
+
transformedResults.push(result);
|
|
17
|
+
if (transformedResults.length >= maxResults) break;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return transformedResults;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async function* searchResultGenerator(
|
|
24
|
+
search: PagefindSearchResults,
|
|
25
|
+
transformFn: NonNullable<PagefindOptions["transformResults"]>,
|
|
26
|
+
) {
|
|
27
|
+
const batchSize = 5;
|
|
28
|
+
let processedCount = 0;
|
|
29
|
+
|
|
30
|
+
while (processedCount < search.results.length) {
|
|
31
|
+
const batch = search.results.slice(
|
|
32
|
+
processedCount,
|
|
33
|
+
processedCount + batchSize,
|
|
34
|
+
);
|
|
35
|
+
processedCount += batch.length;
|
|
36
|
+
|
|
37
|
+
const batchData = await Promise.all(batch.map((result) => result.data()));
|
|
38
|
+
|
|
39
|
+
for (const result of batchData) {
|
|
40
|
+
const transformed = transformFn(result);
|
|
41
|
+
|
|
42
|
+
if (transformed === false) {
|
|
43
|
+
// Skip this result
|
|
44
|
+
continue;
|
|
45
|
+
} else if (transformed === true || transformed == null) {
|
|
46
|
+
// Keep the original result
|
|
47
|
+
yield result;
|
|
48
|
+
} else {
|
|
49
|
+
// Return the transformed result
|
|
50
|
+
yield transformed;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ZudokuConfig } from "../../../config/validators/validate.js";
|
|
2
|
+
import { ClientOnly } from "../../components/ClientOnly.js";
|
|
3
|
+
import type { ZudokuPlugin } from "../../core/plugins.js";
|
|
4
|
+
import { PagefindSearch } from "./PagefindSearch.js";
|
|
5
|
+
|
|
6
|
+
export type PagefindOptions = Extract<
|
|
7
|
+
ZudokuConfig["search"],
|
|
8
|
+
{ type: "pagefind" }
|
|
9
|
+
> & { basePath?: string };
|
|
10
|
+
|
|
11
|
+
export const pagefindSearchPlugin = (
|
|
12
|
+
options: PagefindOptions,
|
|
13
|
+
): ZudokuPlugin => {
|
|
14
|
+
return {
|
|
15
|
+
renderSearch: ({ isOpen, onClose }) => (
|
|
16
|
+
<ClientOnly>
|
|
17
|
+
<PagefindSearch isOpen={isOpen} onClose={onClose} options={options} />
|
|
18
|
+
</ClientOnly>
|
|
19
|
+
),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
interface PagefindIndexOptions {
|
|
2
|
+
basePath?: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
excerptLength?: number;
|
|
5
|
+
indexWeight?: number;
|
|
6
|
+
mergeFilter?: Record<string, unknown>;
|
|
7
|
+
highlightParam?: string;
|
|
8
|
+
language?: string;
|
|
9
|
+
primary?: boolean;
|
|
10
|
+
ranking?: PagefindRankingWeights;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface PagefindRankingWeights {
|
|
14
|
+
termSimilarity?: number;
|
|
15
|
+
pageLength?: number;
|
|
16
|
+
termSaturation?: number;
|
|
17
|
+
termFrequency?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface PagefindSearchOptions {
|
|
21
|
+
preload?: boolean;
|
|
22
|
+
verbose?: boolean;
|
|
23
|
+
filters?: Record<string, unknown>;
|
|
24
|
+
sort?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type PagefindFilterCounts = Record<string, Record<string, number>> & {};
|
|
28
|
+
|
|
29
|
+
interface PagefindSearchResults {
|
|
30
|
+
results: PagefindSearchResult[];
|
|
31
|
+
unfilteredResultCount: number;
|
|
32
|
+
filters: PagefindFilterCounts;
|
|
33
|
+
totalFilters: PagefindFilterCounts;
|
|
34
|
+
timings: {
|
|
35
|
+
preload: number;
|
|
36
|
+
search: number;
|
|
37
|
+
total: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface PagefindSearchResult {
|
|
42
|
+
id: string;
|
|
43
|
+
score: number;
|
|
44
|
+
words: number[];
|
|
45
|
+
data: () => Promise<PagefindSearchFragment>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface PagefindSearchFragment {
|
|
49
|
+
url: string;
|
|
50
|
+
raw_url?: string;
|
|
51
|
+
content: string;
|
|
52
|
+
raw_content?: string;
|
|
53
|
+
excerpt: string;
|
|
54
|
+
sub_results: PagefindSubResult[];
|
|
55
|
+
word_count: number;
|
|
56
|
+
locations: number[];
|
|
57
|
+
weighted_locations: PagefindWordLocation[];
|
|
58
|
+
filters: Record<string, string[]>;
|
|
59
|
+
meta: Record<string, string>;
|
|
60
|
+
anchors: PagefindSearchAnchor[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface PagefindSubResult {
|
|
64
|
+
title: string;
|
|
65
|
+
url: string;
|
|
66
|
+
locations: number[];
|
|
67
|
+
weighted_locations: PagefindWordLocation[];
|
|
68
|
+
excerpt: string;
|
|
69
|
+
anchor?: PagefindSearchAnchor;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface PagefindWordLocation {
|
|
73
|
+
weight: number;
|
|
74
|
+
balanced_score: number;
|
|
75
|
+
location: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface PagefindSearchAnchor {
|
|
79
|
+
element: string;
|
|
80
|
+
id: string;
|
|
81
|
+
text?: string;
|
|
82
|
+
location: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface Pagefind {
|
|
86
|
+
debouncedSearch: (
|
|
87
|
+
query: string,
|
|
88
|
+
options?: PagefindSearchOptions,
|
|
89
|
+
duration?: number,
|
|
90
|
+
) => Promise<PagefindSearchResults>;
|
|
91
|
+
destroy: () => Promise<void>;
|
|
92
|
+
filters: () => Promise<PagefindFilterCounts>;
|
|
93
|
+
init: () => Promise<void>;
|
|
94
|
+
mergeIndex: (
|
|
95
|
+
indexPath: string,
|
|
96
|
+
options?: Record<string, unknown>,
|
|
97
|
+
) => Promise<void>;
|
|
98
|
+
options: (options: PagefindIndexOptions) => Promise<void>;
|
|
99
|
+
preload: (term: string, options?: PagefindIndexOptions) => Promise<void>;
|
|
100
|
+
search: (
|
|
101
|
+
term: string,
|
|
102
|
+
options?: PagefindSearchOptions,
|
|
103
|
+
) => Promise<PagefindSearchResults>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type {
|
|
107
|
+
Pagefind,
|
|
108
|
+
PagefindFilterCounts,
|
|
109
|
+
PagefindIndexOptions,
|
|
110
|
+
PagefindRankingWeights,
|
|
111
|
+
PagefindSearchAnchor,
|
|
112
|
+
PagefindSearchFragment,
|
|
113
|
+
PagefindSearchOptions,
|
|
114
|
+
PagefindSearchResult,
|
|
115
|
+
PagefindSearchResults,
|
|
116
|
+
PagefindSubResult,
|
|
117
|
+
PagefindWordLocation,
|
|
118
|
+
};
|
package/src/lib/ui/Command.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { type DialogProps } from "@radix-ui/react-dialog";
|
|
|
2
2
|
import { Command as CommandPrimitive } from "cmdk";
|
|
3
3
|
import { Search } from "lucide-react";
|
|
4
4
|
import * as React from "react";
|
|
5
|
+
import { ComponentPropsWithoutRef } from "react";
|
|
5
6
|
import { Dialog, DialogContent } from "zudoku/ui/Dialog.js";
|
|
6
7
|
import { cn } from "../util/cn.js";
|
|
7
8
|
|
|
@@ -20,11 +21,32 @@ const Command = React.forwardRef<
|
|
|
20
21
|
));
|
|
21
22
|
Command.displayName = CommandPrimitive.displayName;
|
|
22
23
|
|
|
23
|
-
const CommandDialog = ({
|
|
24
|
+
const CommandDialog = ({
|
|
25
|
+
children,
|
|
26
|
+
command,
|
|
27
|
+
content,
|
|
28
|
+
...props
|
|
29
|
+
}: DialogProps & {
|
|
30
|
+
command?: ComponentPropsWithoutRef<typeof CommandPrimitive>;
|
|
31
|
+
content?: ComponentPropsWithoutRef<typeof DialogContent>;
|
|
32
|
+
}) => {
|
|
24
33
|
return (
|
|
25
34
|
<Dialog {...props}>
|
|
26
|
-
<DialogContent
|
|
27
|
-
|
|
35
|
+
<DialogContent
|
|
36
|
+
{...content}
|
|
37
|
+
className={cn(
|
|
38
|
+
"overflow-hidden p-0 shadow-lg top-[15vh] translate-y-[0%]",
|
|
39
|
+
content?.className,
|
|
40
|
+
)}
|
|
41
|
+
aria-describedby={undefined}
|
|
42
|
+
>
|
|
43
|
+
<Command
|
|
44
|
+
{...command}
|
|
45
|
+
className={cn(
|
|
46
|
+
"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5",
|
|
47
|
+
command?.className,
|
|
48
|
+
)}
|
|
49
|
+
>
|
|
28
50
|
{children}
|
|
29
51
|
</Command>
|
|
30
52
|
</DialogContent>
|
|
@@ -9,21 +9,21 @@ export const useScrollToHash = () => {
|
|
|
9
9
|
|
|
10
10
|
const scrollToHash = useCallback(
|
|
11
11
|
(hash: string) => {
|
|
12
|
-
const cleanHash = hash
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.at(0)!;
|
|
12
|
+
const cleanHash = hash.replace(/^#/, "");
|
|
13
|
+
|
|
14
|
+
// Operation list items might have subdivisions that the sidebar doesn't show.
|
|
15
|
+
// The subdivisions are separated by a slash so we need to remove everything before the slash to get the sidebar correct item.
|
|
16
|
+
const linkHash = cleanHash.split("/").at(0)!;
|
|
18
17
|
const element = document.getElementById(decodeURIComponent(cleanHash));
|
|
18
|
+
|
|
19
19
|
const link = document.querySelector(
|
|
20
|
-
`[${DATA_ANCHOR_ATTR}="${
|
|
20
|
+
`[${DATA_ANCHOR_ATTR}="${linkHash}"]`,
|
|
21
21
|
);
|
|
22
22
|
|
|
23
23
|
if (element) {
|
|
24
24
|
element.scrollIntoView();
|
|
25
25
|
scrollIntoViewIfNeeded(link);
|
|
26
|
-
requestIdleCallback(() => setActiveAnchor(
|
|
26
|
+
requestIdleCallback(() => setActiveAnchor(linkHash));
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
|
package/README.md
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
<div align=center>
|
|
2
|
-
|
|
3
|
-
<a href="https://zudoku.dev" alt="Zudoku">
|
|
4
|
-
<img src="./assets/github-hero.png" width=630 alt="Zudoku Docs & Developer Portal">
|
|
5
|
-
</a>
|
|
6
|
-
|
|
7
|
-
[](https://github.com/zuplo/zudoku/license.md) [](https://www.npmjs.com/package/zudoku) [](https://www.npmjs.com/package/create-zudoku-app) [](https://zuplo.com)
|
|
8
|
-
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
# Zudoku
|
|
12
|
-
|
|
13
|
-
API documentation should always be free.
|
|
14
|
-
|
|
15
|
-
<a href="#-installation"><strong>Installation</strong></a> · <a href="https://zudoku.dev/docs/app-quickstart"><strong>Docs</strong></a> · <a href="#-examples"><strong>Examples</strong></a> · <a href="#-contributing--community"><strong>Contributing</strong></a> · <a href="#-motivation"><strong>Motivation</strong></a>
|
|
16
|
-
|
|
17
|
-
## Introduction
|
|
18
|
-
|
|
19
|
-
**Zudoku** (pronounced "zoo-doh-koo") is an open-source, highly customizable API documentation framework for building quality developer experiences around OpenAPI and, soon, GraphQL documents.
|
|
20
|
-
|
|
21
|
-
Because great API documentation frameworks should be:
|
|
22
|
-
|
|
23
|
-
🌍 Free & Open Source<br /> ✅ OpenAPI powered<br /> 🔩 Extensible with Plugins<br /> ⚡ Easy to setup & blazing fast to work with<br /> 🔧 Easy to maintain
|
|
24
|
-
|
|
25
|
-
## 🤩 Try it, right now!
|
|
26
|
-
|
|
27
|
-
You can test Zudoku with your own OpenAPI document at [zudoku.dev](https://zudoku.dev?utm_source=github&utm_medium=web&utm_content=link&ref=github) and see how good your documentation can look!
|
|
28
|
-
|
|
29
|
-
## ✨ Features
|
|
30
|
-
|
|
31
|
-
- 🚀 Generate documentation from a single or multiple [OpenAPI](https://swagger.io/specification/) schema
|
|
32
|
-
- 📄 Create [MDX pages](https://mdxjs.com/) for anything you want to document
|
|
33
|
-
- 🔐 Integrate your users with authentication via OpenID or OAuth2
|
|
34
|
-
- 🧪 Let users test their API calls using the Integrated Playground (includes authentication!)
|
|
35
|
-
- 🌑 Dark mode (of course!)
|
|
36
|
-
|
|
37
|
-
Zudoku is quick to implement, easy to configure and is highly composable with sensible defaults.
|
|
38
|
-
|
|
39
|
-
## ⚙️ Installation
|
|
40
|
-
|
|
41
|
-
You can use the CLI to generate a new project or use it standalone via CDN as a React component.
|
|
42
|
-
|
|
43
|
-
### ⚡️ Quick start
|
|
44
|
-
|
|
45
|
-
Fire up your new API docs using the command line generator:
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
npm create zudoku-app@latest
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 📦 Standalone via CDN
|
|
52
|
-
|
|
53
|
-
Add the package and styles to your `<head>` and pass the URL for your API schema to the `data-api-url` property, as shown here:
|
|
54
|
-
|
|
55
|
-
```html
|
|
56
|
-
<!doctype html>
|
|
57
|
-
<html>
|
|
58
|
-
<head>
|
|
59
|
-
<title>Zudoku Demo</title>
|
|
60
|
-
<meta charset="UTF-8" />
|
|
61
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
62
|
-
|
|
63
|
-
<link rel="icon" type="image/svg+xml" href="https://cdn.zudoku.dev/logos/favicon.svg" />
|
|
64
|
-
<script type="module" src="https://cdn.zudoku.dev/latest/main.js" crossorigin></script>
|
|
65
|
-
<link rel="stylesheet" href="https://cdn.zudoku.dev/latest/style.css" crossorigin />
|
|
66
|
-
</head>
|
|
67
|
-
<body>
|
|
68
|
-
<div data-api-url="https://api.example.com/openapi.json"></div>
|
|
69
|
-
</body>
|
|
70
|
-
</html>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 🧱 Getting started templates
|
|
74
|
-
|
|
75
|
-
To get started with some of the features Zudoku offers you can use one of these [example templates](https://github.com/zuplo/zudoku/tree/main/examples):
|
|
76
|
-
|
|
77
|
-
| Template | What it does |
|
|
78
|
-
| --------------------------------------------------------------------------------------- | ----------------------------------------------------- |
|
|
79
|
-
| [many-apis](https://github.com/zuplo/zudoku/tree/main/examples/many-apis) | Using more than one OpenAPI document with Zudoku |
|
|
80
|
-
| [with-auth0](https://github.com/zuplo/zudoku/tree/main/examples/with-auth0) | Authenticate users in docs with the Auth0 plugin |
|
|
81
|
-
| [with-config](https://github.com/zuplo/zudoku/tree/main/examples/with-config) | Barebones config, ready for you to setup how you like |
|
|
82
|
-
| [with-vite-config](https://github.com/zuplo/zudoku/tree/main/examples/with-vite-config) | Use Zudoku with your Vite config (Advanced) |
|
|
83
|
-
|
|
84
|
-
## 🎓 Examples
|
|
85
|
-
|
|
86
|
-
- [Rick & Morty API](https://zudoku.dev/demo?api-url=https://rickandmorty.zuplo.io/openapi.json)
|
|
87
|
-
- [Pet Store API](https://zudoku.dev/demo?api-url=https://zudoku.dev/petstore.oas.json)
|
|
88
|
-
- [Zuplo API Documentation](https://docs-zudoku.pages.dev/)
|
|
89
|
-
|
|
90
|
-
### Zudoku use cases
|
|
91
|
-
|
|
92
|
-
Zudoku is a flexible and highly customizable framework that can be used to create many things, including:
|
|
93
|
-
|
|
94
|
-
- Standalone documentation websites
|
|
95
|
-
- OpenAPI powered API references
|
|
96
|
-
- A developer portal with documentation, fully functional API reference for testing and authentication support for your user accounts.
|
|
97
|
-
- Internal documentation
|
|
98
|
-
|
|
99
|
-
## 🔧 Contributing & Community
|
|
100
|
-
|
|
101
|
-
For details on how to contribute to Zudoku, see the [contributing guide](CONTRIBUTING.md).
|
|
102
|
-
|
|
103
|
-
## Changelog
|
|
104
|
-
|
|
105
|
-
Details of the latest updates to Zudoku can be found in the [changelog](CHANGELOG.md).
|
|
106
|
-
|
|
107
|
-
## 🎯 Motivation
|
|
108
|
-
|
|
109
|
-
At Zuplo, we couldn’t find an open-source solution that met our high standards for both trustworthiness and programmability, so we decided to create our own. And since no one chooses Zuplo solely because of our documentation, we felt great about open-sourcing this tool and making it easy for anyone to self-host.
|
|
110
|
-
|
|
111
|
-
We hope that if you use it, you’ll think fondly of Zuplo, and one day, when you’re looking for a gateway or API management product, you’ll consider us as a vendor to evaluate.
|
|
112
|
-
|
|
113
|
-
Zudoku will always be open-source. It will always be free.
|
|
114
|
-
|
|
115
|
-
## License
|
|
116
|
-
|
|
117
|
-
Zudoku is licensed under MIT. See the full [license](LICENSE.md).
|
|
118
|
-
|
|
119
|
-
<a href="https://twitter.com/zuplo">
|
|
120
|
-
<img alt="X (formerly Twitter) Follow" src="https://img.shields.io/twitter/follow/zuplo">
|
|
121
|
-
</a>
|