zudoku 0.18.8 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/main.js +2 -1
- package/dist/app/main.js.map +1 -1
- package/dist/cli/common/outdated.js +2 -1
- package/dist/cli/common/outdated.js.map +1 -1
- package/dist/config/common.d.ts +8 -0
- package/dist/config/common.js +2 -0
- package/dist/config/common.js.map +1 -0
- package/dist/config/config.d.ts +3 -2
- package/dist/config/loader.d.ts +5 -0
- package/dist/config/loader.js +110 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/validators/common.d.ts +4651 -0
- package/dist/config/validators/common.js +269 -0
- package/dist/config/validators/common.js.map +1 -0
- package/dist/config/validators/validate.d.ts +669 -533
- package/dist/config/validators/validate.js +9 -234
- package/dist/config/validators/validate.js.map +1 -1
- package/dist/lib/authentication/providers/openid.js +7 -2
- package/dist/lib/authentication/providers/openid.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/TopNavigation.d.ts +1 -1
- package/dist/lib/components/navigation/SidebarCategory.d.ts +1 -2
- package/dist/lib/components/navigation/SidebarCategory.js +3 -4
- package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
- package/dist/lib/components/navigation/SidebarItem.d.ts +1 -3
- package/dist/lib/components/navigation/SidebarItem.js +4 -9
- package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
- package/dist/lib/components/navigation/SidebarWrapper.js +1 -1
- package/dist/lib/components/navigation/SidebarWrapper.js.map +1 -1
- package/dist/lib/core/ZudokuContext.d.ts +1 -1
- package/dist/lib/oas/graphql/index.js +0 -1
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/plugins/api-catalog/Catalog.d.ts +6 -0
- package/dist/lib/plugins/api-catalog/Catalog.js +29 -0
- package/dist/lib/plugins/api-catalog/Catalog.js.map +1 -0
- package/dist/lib/plugins/api-catalog/index.d.ts +23 -0
- package/dist/lib/plugins/api-catalog/index.js +15 -0
- package/dist/lib/plugins/api-catalog/index.js.map +1 -0
- package/dist/lib/plugins/markdown/index.d.ts +1 -1
- package/dist/lib/plugins/markdown/resolver.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.js +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
- package/dist/lib/plugins/redirect/index.d.ts +1 -1
- package/dist/lib/ui/Command.d.ts +1 -1
- package/dist/lib/util/MdxComponents.d.ts +2 -3
- package/dist/lib/util/MdxComponents.js.map +1 -1
- package/dist/vite/build.js +4 -1
- package/dist/vite/build.js.map +1 -1
- package/dist/vite/config.d.ts +1 -3
- package/dist/vite/config.js +2 -4
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/dev-server.js.map +1 -1
- package/dist/vite/output.d.ts +1 -1
- package/dist/vite/output.js.map +1 -1
- package/dist/vite/plugin-api.js +44 -1
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-component.js +1 -0
- package/dist/vite/plugin-component.js.map +1 -1
- package/dist/vite/plugin-config-reload.d.ts +1 -2
- package/dist/vite/plugin-config-reload.js.map +1 -1
- package/dist/vite/plugin.d.ts +1 -2
- package/dist/vite/plugin.js.map +1 -1
- package/dist/vite/prerender.d.ts +2 -1
- package/dist/vite/prerender.js +2 -2
- package/dist/vite/prerender.js.map +1 -1
- package/dist/vite/sitemap.d.ts +1 -1
- package/dist/zuplo/env.d.ts +6 -0
- package/dist/zuplo/env.js +9 -0
- package/dist/zuplo/env.js.map +1 -0
- package/dist/zuplo/with-zuplo.d.ts +2 -2
- package/dist/zuplo/with-zuplo.js.map +1 -1
- package/lib/Markdown-ievDDhFT.js.map +1 -1
- package/lib/{OperationList-DzE32oyS.js → OperationList-DT5Fu9bC.js} +2 -2
- package/lib/{OperationList-DzE32oyS.js.map → OperationList-DT5Fu9bC.js.map} +1 -1
- package/lib/assets/{worker-CyxLedqF.js → worker-C_2va8B8.js} +1 -2
- package/lib/assets/{worker-CyxLedqF.js.map → worker-C_2va8B8.js.map} +1 -1
- package/lib/{createServer-DTiCfoql.js → createServer-BCAHdrpE.js} +1 -2
- package/lib/{createServer-DTiCfoql.js.map → createServer-BCAHdrpE.js.map} +1 -1
- package/lib/{index-NNCc1BSK.js → index-CBctPUfP.js} +4 -3
- package/lib/index-CBctPUfP.js.map +1 -0
- package/lib/zudoku.auth-openid.js +42 -37
- package/lib/zudoku.auth-openid.js.map +1 -1
- package/lib/zudoku.components.js +259 -271
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.openapi-worker.js +1 -1
- package/lib/zudoku.plugin-api-catalog.js +121 -0
- package/lib/zudoku.plugin-api-catalog.js.map +1 -0
- package/lib/zudoku.plugin-markdown.js.map +1 -1
- package/lib/zudoku.plugin-openapi.js +1 -1
- package/lib/zudoku.plugin-redirect.js.map +1 -1
- package/package.json +6 -2
- package/src/app/main.tsx +5 -1
- package/src/lib/authentication/providers/openid.tsx +7 -2
- package/src/lib/components/TopNavigation.tsx +1 -1
- package/src/lib/components/navigation/SidebarCategory.tsx +7 -9
- package/src/lib/components/navigation/SidebarItem.tsx +3 -16
- package/src/lib/components/navigation/SidebarWrapper.tsx +1 -1
- package/src/lib/core/ZudokuContext.ts +1 -1
- package/src/lib/oas/graphql/index.ts +0 -1
- package/src/lib/plugins/api-catalog/Catalog.tsx +124 -0
- package/src/lib/plugins/api-catalog/index.tsx +50 -0
- package/src/lib/plugins/markdown/index.tsx +1 -1
- package/src/lib/plugins/markdown/resolver.ts +2 -4
- package/src/lib/plugins/openapi/playground/PathParams.tsx +1 -0
- package/src/lib/plugins/redirect/index.tsx +1 -1
- package/src/lib/util/MdxComponents.tsx +2 -5
- package/lib/index-NNCc1BSK.js.map +0 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { j as e } from "./jsx-runtime-B6kdoens.js";
|
|
2
|
+
import { s as n } from "./index-LNp6rxyU.js";
|
|
3
|
+
import { Fragment as x } from "react";
|
|
4
|
+
import { Head as f, Link as h } from "./zudoku.components.js";
|
|
5
|
+
import { M as u } from "./Markdown-ievDDhFT.js";
|
|
6
|
+
import { u as j } from "./useExposedProps-CTPtylCV.js";
|
|
7
|
+
const b = ({
|
|
8
|
+
items: l,
|
|
9
|
+
categories: i,
|
|
10
|
+
label: o = "API Library"
|
|
11
|
+
}) => {
|
|
12
|
+
const { searchParams: c, setSearchParams: m } = j(), t = c.get("category");
|
|
13
|
+
return /* @__PURE__ */ e.jsxs("section", { className: "pt-[--padding-content-top] pb-[--padding-content-bottom]", children: [
|
|
14
|
+
/* @__PURE__ */ e.jsx(f, { children: /* @__PURE__ */ e.jsx("title", { children: o }) }),
|
|
15
|
+
/* @__PURE__ */ e.jsxs("div", { className: "grid grid-cols-12 gap-12", children: [
|
|
16
|
+
/* @__PURE__ */ e.jsx("div", { className: "flex flex-col gap-4 col-span-3 px-4 not-prose sticky top-48", children: /* @__PURE__ */ e.jsx("div", { className: "justify-between", children: i.map((s, a) => /* @__PURE__ */ e.jsxs(x, { children: [
|
|
17
|
+
/* @__PURE__ */ e.jsxs("div", { className: "flex justify-between mb-2.5", children: [
|
|
18
|
+
/* @__PURE__ */ e.jsx("span", { className: "font-medium text-sm", children: s.label }),
|
|
19
|
+
a === 0 && t && /* @__PURE__ */ e.jsx(
|
|
20
|
+
"button",
|
|
21
|
+
{
|
|
22
|
+
type: "button",
|
|
23
|
+
className: "text-end text-sm mr-8 text-foreground/60 hover:text-foreground",
|
|
24
|
+
onClick: () => m({}),
|
|
25
|
+
children: "Clear"
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
] }),
|
|
29
|
+
/* @__PURE__ */ e.jsx("ul", { className: "space-y-1 [&>li]:py-2", children: Array.from(
|
|
30
|
+
new Set(
|
|
31
|
+
s.tags.map((r) => ({
|
|
32
|
+
tag: r,
|
|
33
|
+
count: l.filter(
|
|
34
|
+
(d) => d.categories.find((p) => p.tags.includes(r))
|
|
35
|
+
).length
|
|
36
|
+
})).map(({ tag: r, count: d }) => /* @__PURE__ */ e.jsxs(
|
|
37
|
+
"li",
|
|
38
|
+
{
|
|
39
|
+
className: `flex px-4 rounded-lg -translate-x-4 justify-between text-sm cursor-pointer hover:text-primary transition ${n(r) === t ? "font-medium bg-border/30 rounded" : ""}`,
|
|
40
|
+
onClick: () => m({
|
|
41
|
+
category: n(s.label + " " + r)
|
|
42
|
+
}),
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ e.jsx("span", { children: r }),
|
|
45
|
+
/* @__PURE__ */ e.jsx(
|
|
46
|
+
"span",
|
|
47
|
+
{
|
|
48
|
+
className: `flex items-center justify-center border rounded-md w-8 text-xs font-semibold ${n(r) === t ? "bg-primary border-primary text-primary-foreground" : ""}`,
|
|
49
|
+
children: d
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
n(s.label + " " + r)
|
|
55
|
+
))
|
|
56
|
+
)
|
|
57
|
+
) })
|
|
58
|
+
] }, s.label)) }) }),
|
|
59
|
+
/* @__PURE__ */ e.jsxs("div", { className: "col-span-9", children: [
|
|
60
|
+
/* @__PURE__ */ e.jsx("h3", { className: "mt-0 text-2xl font-bold mb-4", children: o }),
|
|
61
|
+
/* @__PURE__ */ e.jsx("div", { className: "grid grid-cols-2 gap-4", children: l.filter(
|
|
62
|
+
(s) => !t || s.categories.find(
|
|
63
|
+
(a) => a.tags.find(
|
|
64
|
+
(r) => n(a.label + " " + r) === t
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
).map((s, a) => /* @__PURE__ */ e.jsx(
|
|
68
|
+
h,
|
|
69
|
+
{
|
|
70
|
+
to: {
|
|
71
|
+
pathname: `/${s.path}`,
|
|
72
|
+
search: t ? `category=${t}` : ""
|
|
73
|
+
},
|
|
74
|
+
className: "no-underline hover:!text-foreground",
|
|
75
|
+
children: /* @__PURE__ */ e.jsxs(
|
|
76
|
+
"div",
|
|
77
|
+
{
|
|
78
|
+
className: "border h-full rounded p-4 flex flex-col gap-2 cursor-pointer hover:bg-border/20 font-normal",
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ e.jsx("span", { className: "font-semibold", children: s.label }),
|
|
81
|
+
/* @__PURE__ */ e.jsx(
|
|
82
|
+
u,
|
|
83
|
+
{
|
|
84
|
+
className: "text-sm whitespace-pre-wrap mb-6 line-clamp-2",
|
|
85
|
+
content: s.description
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
a
|
|
91
|
+
)
|
|
92
|
+
},
|
|
93
|
+
s.path
|
|
94
|
+
)) })
|
|
95
|
+
] })
|
|
96
|
+
] })
|
|
97
|
+
] });
|
|
98
|
+
}, k = ({
|
|
99
|
+
navigationId: l,
|
|
100
|
+
items: i,
|
|
101
|
+
label: o,
|
|
102
|
+
categories: c
|
|
103
|
+
}) => ({
|
|
104
|
+
getRoutes: () => [
|
|
105
|
+
{
|
|
106
|
+
path: l,
|
|
107
|
+
element: /* @__PURE__ */ e.jsx(
|
|
108
|
+
b,
|
|
109
|
+
{
|
|
110
|
+
label: o,
|
|
111
|
+
items: i,
|
|
112
|
+
categories: c ?? []
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
export {
|
|
119
|
+
k as apiCatalogPlugin
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=zudoku.plugin-api-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zudoku.plugin-api-catalog.js","sources":["../src/lib/plugins/api-catalog/Catalog.tsx","../src/lib/plugins/api-catalog/index.tsx"],"sourcesContent":["import slugify from \"@sindresorhus/slugify\";\nimport { Fragment } from \"react\";\nimport { Head, Link } from \"zudoku/components\";\nimport { Markdown } from \"../../components/Markdown.js\";\nimport { useExposedProps } from \"../../util/useExposedProps.js\";\nimport type { ApiCatalogItem, CatalogCategory } from \"./index.js\";\n\nexport const Catalog = ({\n items,\n categories,\n label = \"API Library\",\n}: {\n label: string;\n items: ApiCatalogItem[];\n categories: CatalogCategory[];\n}) => {\n const { searchParams, setSearchParams } = useExposedProps();\n const activeCategory = searchParams.get(\"category\");\n return (\n <section className=\"pt-[--padding-content-top] pb-[--padding-content-bottom]\">\n <Head>\n <title>{label}</title>\n </Head>\n <div className=\"grid grid-cols-12 gap-12\">\n <div className=\"flex flex-col gap-4 col-span-3 px-4 not-prose sticky top-48\">\n <div className=\"justify-between\">\n {categories.map((category, idx) => (\n <Fragment key={category.label}>\n <div className=\"flex justify-between mb-2.5\">\n <span className=\"font-medium text-sm\">{category.label}</span>\n {idx === 0 && activeCategory && (\n <button\n type=\"button\"\n className=\"text-end text-sm mr-8 text-foreground/60 hover:text-foreground\"\n onClick={() => setSearchParams({})}\n >\n Clear\n </button>\n )}\n </div>\n <ul className=\"space-y-1 [&>li]:py-2\">\n {Array.from(\n new Set(\n category.tags\n .map((tag) => ({\n tag,\n count: items.filter((api) =>\n api.categories.find((c) => c.tags.includes(tag)),\n ).length,\n }))\n .map(({ tag, count }) => (\n <li\n key={slugify(category.label + \" \" + tag)}\n className={`flex px-4 rounded-lg -translate-x-4 justify-between text-sm cursor-pointer hover:text-primary transition ${\n slugify(tag) === activeCategory\n ? \"font-medium bg-border/30 rounded\"\n : \"\"\n }`}\n onClick={() =>\n setSearchParams({\n category: slugify(category.label + \" \" + tag),\n })\n }\n >\n <span>{tag}</span>\n <span\n className={`flex items-center justify-center border rounded-md w-8 text-xs font-semibold ${\n slugify(tag) === activeCategory\n ? \"bg-primary border-primary text-primary-foreground\"\n : \"\"\n }`}\n >\n {count}\n </span>\n </li>\n )),\n ),\n )}\n </ul>\n </Fragment>\n ))}\n </div>\n </div>\n <div className=\"col-span-9\">\n <h3 className=\"mt-0 text-2xl font-bold mb-4\">{label}</h3>\n\n <div className=\"grid grid-cols-2 gap-4\">\n {items\n .filter(\n (api) =>\n !activeCategory ||\n api.categories.find((c) =>\n c.tags.find(\n (t) => slugify(c.label + \" \" + t) === activeCategory,\n ),\n ),\n )\n .map((api, i) => (\n <Link\n to={{\n pathname: `/${api.path}`,\n search: activeCategory ? `category=${activeCategory}` : \"\",\n }}\n className=\"no-underline hover:!text-foreground\"\n key={api.path}\n >\n <div\n className=\"border h-full rounded p-4 flex flex-col gap-2 cursor-pointer hover:bg-border/20 font-normal\"\n key={i}\n >\n <span className=\"font-semibold\">{api.label}</span>\n <Markdown\n className=\"text-sm whitespace-pre-wrap mb-6 line-clamp-2\"\n content={api.description}\n />\n </div>\n </Link>\n ))}\n </div>\n </div>\n </div>\n </section>\n );\n};\n","import type { ZudokuPlugin } from \"../../core/plugins.js\";\nimport { Catalog } from \"./Catalog.js\";\n\nexport type ApiCatalogItem = {\n path: string;\n label: string;\n description: string;\n categories: CatalogCategory[];\n};\n\nexport type CatalogCategory = {\n label: string;\n tags: string[];\n};\n\nexport type ApiCatalogPluginOptions = {\n navigationId: string;\n label: string;\n categories?: CatalogCategory[];\n items: ApiCatalogItem[];\n};\n\nexport const apiCatalogPlugin = ({\n navigationId,\n items,\n label,\n categories,\n}: {\n navigationId: string;\n label: string;\n categories?: CatalogCategory[];\n items: ApiCatalogItem[];\n}): ZudokuPlugin => {\n return {\n getRoutes: () => {\n return [\n {\n path: navigationId,\n element: (\n <Catalog\n label={label}\n items={items}\n categories={categories ?? []}\n />\n ),\n },\n ];\n },\n };\n};\n"],"names":["Catalog","items","categories","label","searchParams","setSearchParams","useExposedProps","activeCategory","jsxs","jsx","Head","category","idx","Fragment","tag","api","c","count","slugify","t","i","Link","Markdown","apiCatalogPlugin","navigationId"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zudoku.plugin-markdown.js","sources":["../src/lib/plugins/markdown/resolver.ts","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport {\
|
|
1
|
+
{"version":3,"file":"zudoku.plugin-markdown.js","sources":["../src/lib/plugins/markdown/resolver.ts","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { ZudokuDocsConfig } from \"../../../config/validators/common.js\";\nimport { ZudokuConfig } from \"../../../config/validators/validate.js\";\n\nconst DEFAULT_DOCS_FILES = \"/pages/**/*.{md,mdx}\";\n\n// TODO: This should be dynamic based on the glob selector\nconst SUPPORTED_EXTENSIONS = [\".md\", \".mdx\"];\n\n/**\n * Utilities for resolving markdown file paths and routes\n */\nexport class DocResolver {\n constructor(private config: ZudokuConfig) {}\n\n fileMap = new Map<string, string>();\n\n /**\n * Gets the default docs config from the zudoku config\n */\n getDocsConfigs() {\n const docsConfigs: ZudokuDocsConfig[] = this.config.docs\n ? Array.isArray(this.config.docs)\n ? this.config.docs\n : [this.config.docs]\n : [{ files: DEFAULT_DOCS_FILES }];\n\n return docsConfigs;\n }\n\n /**\n * Resolves the first matching file system path for a given docId\n * @param docId - The docId to resolve\n * @returns\n */\n resolveFilePath(docId: string) {\n const docsConfigs = this.getDocsConfigs();\n let fsPath: string | undefined;\n\n docsConfigs.forEach(({ files: fileGlob }) => {\n if (fsPath) {\n return;\n }\n const rootDir = DocResolver.getRootDir(fileGlob);\n for (const ext of SUPPORTED_EXTENSIONS) {\n if (fsPath) {\n return;\n }\n const checkPath = path.join(rootDir, `${docId}${ext}`);\n if (fs.existsSync(checkPath)) {\n fsPath = checkPath;\n }\n }\n });\n\n return fsPath;\n }\n\n /**\n * Gets the root directory from a files glob\n */\n private static getRootDir(filesGlob: string) {\n let rootDir = filesGlob.split(\"**\")[0];\n if (!rootDir) {\n throw new Error(\"Invalid files glob. Must have '**' in the path.\");\n }\n rootDir = rootDir.replace(\"/**\", \"/\");\n return rootDir;\n }\n\n /**\n * Resolves the route path for a given file system path\n * @param options - The options to resolve the route path\n * @returns The string route path\n */\n static resolveRoutePath({\n filesGlob,\n fsPath,\n }: {\n filesGlob: string;\n fsPath: string;\n }) {\n const rootDir = this.getRootDir(filesGlob);\n const re = new RegExp(`^${rootDir}(.*).mdx?`);\n const match = fsPath.match(re);\n const routePath = match?.at(1);\n return routePath;\n }\n}\n","import type { Toc } from \"@stefanprobst/rehype-extract-toc\";\nimport type { MDXProps } from \"mdx/types.js\";\nimport { RouteObject } from \"react-router-dom\";\nimport { ZudokuDocsConfig } from \"../../../config/validators/common.js\";\nimport type { ZudokuPlugin } from \"../../core/plugins.js\";\nimport { DocResolver } from \"./resolver.js\";\n\nexport interface MarkdownPluginOptions extends ZudokuDocsConfig {\n fileImports: Record<string, () => Promise<MDXImport>>;\n}\nexport type MarkdownPluginDefaultOptions = Pick<\n Frontmatter,\n \"toc\" | \"disablePager\"\n>;\n\nexport type Frontmatter = {\n title?: string;\n description?: string;\n category?: string;\n toc?: boolean;\n disablePager?: boolean;\n};\n\nexport type MDXImport = {\n tableOfContents: Toc;\n frontmatter: Frontmatter;\n excerpt?: string;\n default: (props: MDXProps) => JSX.Element;\n};\n\nexport const markdownPlugin = (\n options: MarkdownPluginOptions[],\n): ZudokuPlugin => ({\n getRoutes: () => {\n const routeMap = new Map<string, RouteObject>();\n options.forEach(({ fileImports, files, defaultOptions }) =>\n Object.entries(fileImports).flatMap(([file, importPromise]) => {\n const routePath = DocResolver.resolveRoutePath({\n filesGlob: files,\n fsPath: file,\n });\n\n if (!routePath) return [];\n\n if (routeMap.has(routePath)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Duplicate route path found for ${routePath}. Skipping file at '${file}'.`,\n );\n return [];\n }\n\n const route: RouteObject = {\n path: routePath,\n lazy: async () => {\n const { MdxPage } = await import(\"./MdxPage.js\");\n const { default: Component, ...props } = await importPromise();\n return {\n element: (\n <MdxPage\n file={file}\n mdxComponent={Component}\n {...props}\n defaultOptions={defaultOptions}\n />\n ),\n };\n },\n };\n routeMap.set(routePath, route);\n }),\n );\n return [...routeMap.values()];\n },\n});\n"],"names":["DEFAULT_DOCS_FILES","SUPPORTED_EXTENSIONS","DocResolver","config","__publicField","docId","docsConfigs","fsPath","fileGlob","rootDir","ext","checkPath","path","fs","filesGlob","re","match","markdownPlugin","options","routeMap","fileImports","files","defaultOptions","file","importPromise","routePath","route","MdxPage","Component","props","jsx"],"mappings":";;;;;AAKA,MAAMA,IAAqB,wBAGrBC,IAAuB,CAAC,OAAO,MAAM;AAKpC,MAAMC,EAAY;AAAA,EACvB,YAAoBC,GAAsB;AAE1C,IAAAC,EAAA,qCAAc;AAFM,SAAA,SAAAD;AAAA,EAAuB;AAAA;AAAA;AAAA;AAAA,EAO3C,iBAAiB;AAOR,WANiC,KAAK,OAAO,OAChD,MAAM,QAAQ,KAAK,OAAO,IAAI,IAC5B,KAAK,OAAO,OACZ,CAAC,KAAK,OAAO,IAAI,IACnB,CAAC,EAAE,OAAOH,EAAA,CAAoB;AAAA,EAGpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgBK,GAAe;AACvB,UAAAC,IAAc,KAAK;AACrB,QAAAC;AAEJ,WAAAD,EAAY,QAAQ,CAAC,EAAE,OAAOE,QAAe;AAC3C,UAAID;AACF;AAEI,YAAAE,IAAUP,EAAY,WAAWM,CAAQ;AAC/C,iBAAWE,KAAOT,GAAsB;AACtC,YAAIM;AACF;AAEI,cAAAI,IAAYC,EAAK,KAAKH,GAAS,GAAGJ,CAAK,GAAGK,CAAG,EAAE;AACjD,QAAAG,EAAG,WAAWF,CAAS,MAChBJ,IAAAI;AAAA,MAEb;AAAA,IAAA,CACD,GAEMJ;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe,WAAWO,GAAmB;AAC3C,QAAIL,IAAUK,EAAU,MAAM,IAAI,EAAE,CAAC;AACrC,QAAI,CAACL;AACG,YAAA,IAAI,MAAM,iDAAiD;AAEzD,WAAAA,IAAAA,EAAQ,QAAQ,OAAO,GAAG,GAC7BA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,iBAAiB;AAAA,IACtB,WAAAK;AAAA,IACA,QAAAP;AAAA,EAAA,GAIC;AACK,UAAAE,IAAU,KAAK,WAAWK,CAAS,GACnCC,IAAK,IAAI,OAAO,IAAIN,CAAO,WAAW,GACtCO,IAAQT,EAAO,MAAMQ,CAAE;AAEtB,WADWC,KAAA,gBAAAA,EAAO,GAAG;AAAA,EAE9B;AACF;AC3Da,MAAAC,IAAiB,CAC5BC,OACkB;AAAA,EAClB,WAAW,MAAM;AACT,UAAAC,wBAAe;AACb,WAAAD,EAAA;AAAA,MAAQ,CAAC,EAAE,aAAAE,GAAa,OAAAC,GAAO,gBAAAC,QACrC,OAAO,QAAQF,CAAW,EAAE,QAAQ,CAAC,CAACG,GAAMC,CAAa,MAAM;AACvD,cAAAC,IAAYvB,EAAY,iBAAiB;AAAA,UAC7C,WAAWmB;AAAA,UACX,QAAQE;AAAA,QAAA,CACT;AAEG,YAAA,CAACE,EAAW,QAAO;AAEnB,YAAAN,EAAS,IAAIM,CAAS;AAEhB,yBAAA;AAAA,YACN,kCAAkCA,CAAS,uBAAuBF,CAAI;AAAA,UAAA,GAEjE;AAGT,cAAMG,IAAqB;AAAA,UACzB,MAAMD;AAAA,UACN,MAAM,YAAY;AAChB,kBAAM,EAAE,SAAAE,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAML;AACxC,mBAAA;AAAA,cACL,SACEM,gBAAAA,EAAA;AAAA,gBAACH;AAAA,gBAAA;AAAA,kBACC,MAAAJ;AAAA,kBACA,cAAcK;AAAA,kBACb,GAAGC;AAAA,kBACJ,gBAAAP;AAAA,gBAAA;AAAA,cACF;AAAA,YAAA;AAAA,UAGN;AAAA,QAAA;AAEO,QAAAH,EAAA,IAAIM,GAAWC,CAAK;AAAA,MAAA,CAC9B;AAAA,IAAA,GAEI,CAAC,GAAGP,EAAS,OAAA,CAAQ;AAAA,EAC9B;AACF;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zudoku.plugin-redirect.js","sources":["../src/lib/plugins/redirect/index.tsx"],"sourcesContent":["import { redirect } from \"react-router-dom\";\nimport { ZudokuRedirect } from \"../../../config/validators/
|
|
1
|
+
{"version":3,"file":"zudoku.plugin-redirect.js","sources":["../src/lib/plugins/redirect/index.tsx"],"sourcesContent":["import { redirect } from \"react-router-dom\";\nimport { ZudokuRedirect } from \"../../../config/validators/common.js\";\nimport type { ZudokuPlugin } from \"../../core/plugins.js\";\n\nexport const redirectPlugin = (options: {\n redirects: ZudokuRedirect[];\n}): ZudokuPlugin => {\n return {\n getRoutes: () =>\n options.redirects.map(({ from, to }) => ({\n path: from,\n loader: () => redirect(to, 301),\n })),\n };\n};\n"],"names":["redirectPlugin","options","from","to","redirect"],"mappings":";AAIa,MAAAA,IAAiB,CAACC,OAGtB;AAAA,EACL,WAAW,MACTA,EAAQ,UAAU,IAAI,CAAC,EAAE,MAAAC,GAAM,IAAAC,SAAU;AAAA,IACvC,MAAMD;AAAA,IACN,QAAQ,MAAME,EAASD,GAAI,GAAG;AAAA,EAAA,EAC9B;AAAA;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://zudoku.dev",
|
|
6
6
|
"repository": {
|
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
"import": "./lib/zudoku.plugin-api-keys.js",
|
|
55
55
|
"types": "./dist/lib/plugins/api-keys/index.d.ts"
|
|
56
56
|
},
|
|
57
|
+
"./plugins/api-catalog": {
|
|
58
|
+
"import": "./lib/zudoku.plugin-api-catalog.js",
|
|
59
|
+
"types": "./dist/lib/plugins/api-catalog/index.d.ts"
|
|
60
|
+
},
|
|
57
61
|
"./plugins/markdown": {
|
|
58
62
|
"import": "./lib/zudoku.plugin-markdown.js",
|
|
59
63
|
"types": "./dist/lib/plugins/markdown/index.d.ts"
|
|
@@ -149,7 +153,6 @@
|
|
|
149
153
|
"@types/react": "18.3.11",
|
|
150
154
|
"@types/react-dom": "18.3.1",
|
|
151
155
|
"@vitejs/plugin-react": "4.3.4",
|
|
152
|
-
"@zudoku/config": "0.18.8",
|
|
153
156
|
"@zudoku/httpsnippet": "10.0.9",
|
|
154
157
|
"@zudoku/react-helmet-async": "2.0.4",
|
|
155
158
|
"autoprefixer": "10.4.20",
|
|
@@ -200,6 +203,7 @@
|
|
|
200
203
|
"strip-ansi": "7.1.0",
|
|
201
204
|
"tailwind-merge": "2.5.4",
|
|
202
205
|
"tailwindcss": "3.4.13",
|
|
206
|
+
"tsx": "^4.19.2",
|
|
203
207
|
"ulidx": "2.4.1",
|
|
204
208
|
"unist-util-visit": "5.0.0",
|
|
205
209
|
"urql": "4.1.0",
|
package/src/app/main.tsx
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type RouteObject } from "react-router-dom";
|
|
2
2
|
import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
configuredApiCatalogPlugins,
|
|
5
|
+
configuredApiPlugins,
|
|
6
|
+
} from "virtual:zudoku-api-plugins";
|
|
4
7
|
import { configuredAuthProvider } from "virtual:zudoku-auth";
|
|
5
8
|
import { configuredCustomPagesPlugin } from "virtual:zudoku-custom-pages-plugin";
|
|
6
9
|
import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
|
|
@@ -57,6 +60,7 @@ export const convertZudokuConfigToOptions = (
|
|
|
57
60
|
...(configuredRedirectPlugin ? [configuredRedirectPlugin] : []),
|
|
58
61
|
...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
|
|
59
62
|
...(configuredCustomPagesPlugin ? [configuredCustomPagesPlugin] : []),
|
|
63
|
+
...configuredApiCatalogPlugins,
|
|
60
64
|
...(configuredAuthProvider?.getAuthenticationPlugin
|
|
61
65
|
? [configuredAuthProvider.getAuthenticationPlugin()]
|
|
62
66
|
: []),
|
|
@@ -203,9 +203,14 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
203
203
|
}
|
|
204
204
|
const tokenState = providerData as TokenState;
|
|
205
205
|
|
|
206
|
-
if (tokenState.expiresOn < new Date()) {
|
|
206
|
+
if (new Date(tokenState.expiresOn) < new Date()) {
|
|
207
207
|
if (!tokenState.refreshToken) {
|
|
208
|
-
|
|
208
|
+
useAuthState.setState({
|
|
209
|
+
isAuthenticated: false,
|
|
210
|
+
isPending: false,
|
|
211
|
+
profile: null,
|
|
212
|
+
providerData: null,
|
|
213
|
+
});
|
|
209
214
|
return "";
|
|
210
215
|
}
|
|
211
216
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cx } from "class-variance-authority";
|
|
2
2
|
import { Suspense } from "react";
|
|
3
3
|
import { NavLink, useNavigation } from "react-router-dom";
|
|
4
|
-
import { TopNavigationItem } from "../../config/validators/
|
|
4
|
+
import { TopNavigationItem } from "../../config/validators/common.js";
|
|
5
5
|
import { useAuth } from "../authentication/hook.js";
|
|
6
6
|
import { ZudokuError } from "../util/invariant.js";
|
|
7
7
|
import { joinPath } from "../util/joinPath.js";
|
|
@@ -10,11 +10,9 @@ import { useIsCategoryOpen } from "./utils.js";
|
|
|
10
10
|
|
|
11
11
|
export const SidebarCategory = ({
|
|
12
12
|
category,
|
|
13
|
-
level,
|
|
14
13
|
onRequestClose,
|
|
15
14
|
}: {
|
|
16
15
|
category: SidebarItemCategory;
|
|
17
|
-
level: number;
|
|
18
16
|
onRequestClose?: () => void;
|
|
19
17
|
}) => {
|
|
20
18
|
const isCategoryOpen = useIsCategoryOpen(category);
|
|
@@ -67,7 +65,6 @@ export const SidebarCategory = ({
|
|
|
67
65
|
onClick={() => setHasInteracted(true)}
|
|
68
66
|
className={navigationListItem({
|
|
69
67
|
isActive: false,
|
|
70
|
-
isTopLevel: level === 0,
|
|
71
68
|
className: [
|
|
72
69
|
"text-start",
|
|
73
70
|
isCollapsible
|
|
@@ -79,10 +76,7 @@ export const SidebarCategory = ({
|
|
|
79
76
|
{category.icon && (
|
|
80
77
|
<category.icon
|
|
81
78
|
size={16}
|
|
82
|
-
className={cn(
|
|
83
|
-
"align-[-0.125em] -translate-x-1",
|
|
84
|
-
isActive && "text-primary",
|
|
85
|
-
)}
|
|
79
|
+
className={cn("align-[-0.125em] ", isActive && "text-primary")}
|
|
86
80
|
/>
|
|
87
81
|
)}
|
|
88
82
|
{category.link?.type === "doc" ? (
|
|
@@ -118,9 +112,14 @@ export const SidebarCategory = ({
|
|
|
118
112
|
className={cn(
|
|
119
113
|
// CollapsibleContent class is used to animate and it should only be applied when the user has triggered the toggle
|
|
120
114
|
hasInteracted && "CollapsibleContent",
|
|
115
|
+
"ms-6 my-1",
|
|
121
116
|
)}
|
|
122
117
|
>
|
|
123
|
-
<ul
|
|
118
|
+
<ul
|
|
119
|
+
className={
|
|
120
|
+
"relative after:absolute after:-left-[--padding-nav-item] after:translate-x-[1.5px] after:top-0 after:bottom-0 after:w-px after:bg-border"
|
|
121
|
+
}
|
|
122
|
+
>
|
|
124
123
|
{category.items.map((item) => (
|
|
125
124
|
<SidebarItem
|
|
126
125
|
key={
|
|
@@ -129,7 +128,6 @@ export const SidebarCategory = ({
|
|
|
129
128
|
item.label
|
|
130
129
|
}
|
|
131
130
|
onRequestClose={onRequestClose}
|
|
132
|
-
level={level + 1}
|
|
133
131
|
item={item}
|
|
134
132
|
/>
|
|
135
133
|
))}
|
|
@@ -13,10 +13,6 @@ export const navigationListItem = cva(
|
|
|
13
13
|
"flex items-center gap-2 px-[--padding-nav-item] py-1.5 rounded-lg hover:bg-accent transition-colors duration-300",
|
|
14
14
|
{
|
|
15
15
|
variants: {
|
|
16
|
-
isTopLevel: {
|
|
17
|
-
true: "font-medium -mx-[--padding-nav-item]",
|
|
18
|
-
false: "-mr-[--padding-nav-item] ml-[--padding-nav-item]",
|
|
19
|
-
},
|
|
20
16
|
isActive: {
|
|
21
17
|
true: "text-primary font-medium",
|
|
22
18
|
false: "text-foreground/80",
|
|
@@ -36,11 +32,9 @@ export const DATA_ANCHOR_ATTR = "data-anchor";
|
|
|
36
32
|
|
|
37
33
|
export const SidebarItem = ({
|
|
38
34
|
item,
|
|
39
|
-
level = 0,
|
|
40
35
|
onRequestClose,
|
|
41
36
|
}: {
|
|
42
37
|
item: SidebarItemType;
|
|
43
|
-
level?: number;
|
|
44
38
|
onRequestClose?: () => void;
|
|
45
39
|
}) => {
|
|
46
40
|
const { activeAnchor } = useViewportAnchor();
|
|
@@ -49,18 +43,12 @@ export const SidebarItem = ({
|
|
|
49
43
|
switch (item.type) {
|
|
50
44
|
case "category":
|
|
51
45
|
return (
|
|
52
|
-
<SidebarCategory
|
|
53
|
-
category={item}
|
|
54
|
-
level={level}
|
|
55
|
-
onRequestClose={onRequestClose}
|
|
56
|
-
/>
|
|
46
|
+
<SidebarCategory category={item} onRequestClose={onRequestClose} />
|
|
57
47
|
);
|
|
58
48
|
case "doc":
|
|
59
49
|
return (
|
|
60
50
|
<NavLink
|
|
61
|
-
className={({ isActive }) =>
|
|
62
|
-
navigationListItem({ isActive, isTopLevel: level === 0 })
|
|
63
|
-
}
|
|
51
|
+
className={({ isActive }) => navigationListItem({ isActive })}
|
|
64
52
|
to={joinPath(item.id)}
|
|
65
53
|
onClick={onRequestClose}
|
|
66
54
|
>
|
|
@@ -84,7 +72,6 @@ export const SidebarItem = ({
|
|
|
84
72
|
{...{ [DATA_ANCHOR_ATTR]: item.href.slice(1) }}
|
|
85
73
|
className={navigationListItem({
|
|
86
74
|
isActive: item.href.slice(1) === activeAnchor,
|
|
87
|
-
isTopLevel: level === 0,
|
|
88
75
|
className: item.badge?.placement !== "start" && "justify-between",
|
|
89
76
|
})}
|
|
90
77
|
onClick={onRequestClose}
|
|
@@ -120,7 +107,7 @@ export const SidebarItem = ({
|
|
|
120
107
|
</NavLink>
|
|
121
108
|
) : (
|
|
122
109
|
<a
|
|
123
|
-
className={navigationListItem(
|
|
110
|
+
className={navigationListItem()}
|
|
124
111
|
href={item.href}
|
|
125
112
|
target="_blank"
|
|
126
113
|
rel="noopener noreferrer"
|
|
@@ -13,7 +13,7 @@ export const SidebarWrapper = forwardRef<
|
|
|
13
13
|
data-navigation={String(pushMainContent)}
|
|
14
14
|
className={cn(
|
|
15
15
|
"scrollbar peer hidden lg:flex flex-col fixed text-sm overflow-y-auto shrink-0",
|
|
16
|
-
"
|
|
16
|
+
"-mx-[--padding-nav-item] pb-20 mt-[--padding-content-top]",
|
|
17
17
|
"w-[--side-nav-width] h-[calc(100%-var(--header-height))] scroll-pt-2 gap-2",
|
|
18
18
|
className,
|
|
19
19
|
)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
+
import { TopNavigationItem } from "../../config/validators/common.js";
|
|
2
3
|
import type { SidebarConfig } from "../../config/validators/SidebarSchema.js";
|
|
3
|
-
import { TopNavigationItem } from "../../config/validators/validate.js";
|
|
4
4
|
import { type AuthenticationProvider } from "../authentication/authentication.js";
|
|
5
5
|
import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
|
|
6
6
|
import { Slotlets } from "../components/SlotletProvider.js";
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import slugify from "@sindresorhus/slugify";
|
|
2
|
+
import { Fragment } from "react";
|
|
3
|
+
import { Head, Link } from "zudoku/components";
|
|
4
|
+
import { Markdown } from "../../components/Markdown.js";
|
|
5
|
+
import { useExposedProps } from "../../util/useExposedProps.js";
|
|
6
|
+
import type { ApiCatalogItem, CatalogCategory } from "./index.js";
|
|
7
|
+
|
|
8
|
+
export const Catalog = ({
|
|
9
|
+
items,
|
|
10
|
+
categories,
|
|
11
|
+
label = "API Library",
|
|
12
|
+
}: {
|
|
13
|
+
label: string;
|
|
14
|
+
items: ApiCatalogItem[];
|
|
15
|
+
categories: CatalogCategory[];
|
|
16
|
+
}) => {
|
|
17
|
+
const { searchParams, setSearchParams } = useExposedProps();
|
|
18
|
+
const activeCategory = searchParams.get("category");
|
|
19
|
+
return (
|
|
20
|
+
<section className="pt-[--padding-content-top] pb-[--padding-content-bottom]">
|
|
21
|
+
<Head>
|
|
22
|
+
<title>{label}</title>
|
|
23
|
+
</Head>
|
|
24
|
+
<div className="grid grid-cols-12 gap-12">
|
|
25
|
+
<div className="flex flex-col gap-4 col-span-3 px-4 not-prose sticky top-48">
|
|
26
|
+
<div className="justify-between">
|
|
27
|
+
{categories.map((category, idx) => (
|
|
28
|
+
<Fragment key={category.label}>
|
|
29
|
+
<div className="flex justify-between mb-2.5">
|
|
30
|
+
<span className="font-medium text-sm">{category.label}</span>
|
|
31
|
+
{idx === 0 && activeCategory && (
|
|
32
|
+
<button
|
|
33
|
+
type="button"
|
|
34
|
+
className="text-end text-sm mr-8 text-foreground/60 hover:text-foreground"
|
|
35
|
+
onClick={() => setSearchParams({})}
|
|
36
|
+
>
|
|
37
|
+
Clear
|
|
38
|
+
</button>
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
41
|
+
<ul className="space-y-1 [&>li]:py-2">
|
|
42
|
+
{Array.from(
|
|
43
|
+
new Set(
|
|
44
|
+
category.tags
|
|
45
|
+
.map((tag) => ({
|
|
46
|
+
tag,
|
|
47
|
+
count: items.filter((api) =>
|
|
48
|
+
api.categories.find((c) => c.tags.includes(tag)),
|
|
49
|
+
).length,
|
|
50
|
+
}))
|
|
51
|
+
.map(({ tag, count }) => (
|
|
52
|
+
<li
|
|
53
|
+
key={slugify(category.label + " " + tag)}
|
|
54
|
+
className={`flex px-4 rounded-lg -translate-x-4 justify-between text-sm cursor-pointer hover:text-primary transition ${
|
|
55
|
+
slugify(tag) === activeCategory
|
|
56
|
+
? "font-medium bg-border/30 rounded"
|
|
57
|
+
: ""
|
|
58
|
+
}`}
|
|
59
|
+
onClick={() =>
|
|
60
|
+
setSearchParams({
|
|
61
|
+
category: slugify(category.label + " " + tag),
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
>
|
|
65
|
+
<span>{tag}</span>
|
|
66
|
+
<span
|
|
67
|
+
className={`flex items-center justify-center border rounded-md w-8 text-xs font-semibold ${
|
|
68
|
+
slugify(tag) === activeCategory
|
|
69
|
+
? "bg-primary border-primary text-primary-foreground"
|
|
70
|
+
: ""
|
|
71
|
+
}`}
|
|
72
|
+
>
|
|
73
|
+
{count}
|
|
74
|
+
</span>
|
|
75
|
+
</li>
|
|
76
|
+
)),
|
|
77
|
+
),
|
|
78
|
+
)}
|
|
79
|
+
</ul>
|
|
80
|
+
</Fragment>
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="col-span-9">
|
|
85
|
+
<h3 className="mt-0 text-2xl font-bold mb-4">{label}</h3>
|
|
86
|
+
|
|
87
|
+
<div className="grid grid-cols-2 gap-4">
|
|
88
|
+
{items
|
|
89
|
+
.filter(
|
|
90
|
+
(api) =>
|
|
91
|
+
!activeCategory ||
|
|
92
|
+
api.categories.find((c) =>
|
|
93
|
+
c.tags.find(
|
|
94
|
+
(t) => slugify(c.label + " " + t) === activeCategory,
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
.map((api, i) => (
|
|
99
|
+
<Link
|
|
100
|
+
to={{
|
|
101
|
+
pathname: `/${api.path}`,
|
|
102
|
+
search: activeCategory ? `category=${activeCategory}` : "",
|
|
103
|
+
}}
|
|
104
|
+
className="no-underline hover:!text-foreground"
|
|
105
|
+
key={api.path}
|
|
106
|
+
>
|
|
107
|
+
<div
|
|
108
|
+
className="border h-full rounded p-4 flex flex-col gap-2 cursor-pointer hover:bg-border/20 font-normal"
|
|
109
|
+
key={i}
|
|
110
|
+
>
|
|
111
|
+
<span className="font-semibold">{api.label}</span>
|
|
112
|
+
<Markdown
|
|
113
|
+
className="text-sm whitespace-pre-wrap mb-6 line-clamp-2"
|
|
114
|
+
content={api.description}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</Link>
|
|
118
|
+
))}
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</section>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ZudokuPlugin } from "../../core/plugins.js";
|
|
2
|
+
import { Catalog } from "./Catalog.js";
|
|
3
|
+
|
|
4
|
+
export type ApiCatalogItem = {
|
|
5
|
+
path: string;
|
|
6
|
+
label: string;
|
|
7
|
+
description: string;
|
|
8
|
+
categories: CatalogCategory[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CatalogCategory = {
|
|
12
|
+
label: string;
|
|
13
|
+
tags: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type ApiCatalogPluginOptions = {
|
|
17
|
+
navigationId: string;
|
|
18
|
+
label: string;
|
|
19
|
+
categories?: CatalogCategory[];
|
|
20
|
+
items: ApiCatalogItem[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const apiCatalogPlugin = ({
|
|
24
|
+
navigationId,
|
|
25
|
+
items,
|
|
26
|
+
label,
|
|
27
|
+
categories,
|
|
28
|
+
}: {
|
|
29
|
+
navigationId: string;
|
|
30
|
+
label: string;
|
|
31
|
+
categories?: CatalogCategory[];
|
|
32
|
+
items: ApiCatalogItem[];
|
|
33
|
+
}): ZudokuPlugin => {
|
|
34
|
+
return {
|
|
35
|
+
getRoutes: () => {
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
path: navigationId,
|
|
39
|
+
element: (
|
|
40
|
+
<Catalog
|
|
41
|
+
label={label}
|
|
42
|
+
items={items}
|
|
43
|
+
categories={categories ?? []}
|
|
44
|
+
/>
|
|
45
|
+
),
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Toc } from "@stefanprobst/rehype-extract-toc";
|
|
2
2
|
import type { MDXProps } from "mdx/types.js";
|
|
3
3
|
import { RouteObject } from "react-router-dom";
|
|
4
|
-
import { ZudokuDocsConfig } from "../../../config/validators/
|
|
4
|
+
import { ZudokuDocsConfig } from "../../../config/validators/common.js";
|
|
5
5
|
import type { ZudokuPlugin } from "../../core/plugins.js";
|
|
6
6
|
import { DocResolver } from "./resolver.js";
|
|
7
7
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
ZudokuDocsConfig,
|
|
6
|
-
} from "../../../config/validators/validate.js";
|
|
3
|
+
import { ZudokuDocsConfig } from "../../../config/validators/common.js";
|
|
4
|
+
import { ZudokuConfig } from "../../../config/validators/validate.js";
|
|
7
5
|
|
|
8
6
|
const DEFAULT_DOCS_FILES = "/pages/**/*.{md,mdx}";
|
|
9
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { redirect } from "react-router-dom";
|
|
2
|
-
import { ZudokuRedirect } from "../../../config/validators/
|
|
2
|
+
import { ZudokuRedirect } from "../../../config/validators/common.js";
|
|
3
3
|
import type { ZudokuPlugin } from "../../core/plugins.js";
|
|
4
4
|
|
|
5
5
|
export const redirectPlugin = (options: {
|