zudoku 0.18.8 → 0.19.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/config/validators/validate.d.ts +370 -0
- package/dist/config/validators/validate.js +12 -0
- 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/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/openapi/playground/PathParams.js +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.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/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.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-openapi.js +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/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/openapi/playground/PathParams.tsx +1 -0
- 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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.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,7 @@
|
|
|
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.
|
|
156
|
+
"@zudoku/config": "0.19.0",
|
|
153
157
|
"@zudoku/httpsnippet": "10.0.9",
|
|
154
158
|
"@zudoku/react-helmet-async": "2.0.4",
|
|
155
159
|
"autoprefixer": "10.4.20",
|
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
|
|
|
@@ -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
|
+
};
|