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.
Files changed (107) hide show
  1. package/dist/app/main.js +2 -1
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/cli/common/outdated.js +2 -1
  4. package/dist/cli/common/outdated.js.map +1 -1
  5. package/dist/config/common.d.ts +8 -0
  6. package/dist/config/common.js +2 -0
  7. package/dist/config/common.js.map +1 -0
  8. package/dist/config/config.d.ts +3 -2
  9. package/dist/config/loader.d.ts +5 -0
  10. package/dist/config/loader.js +110 -0
  11. package/dist/config/loader.js.map +1 -0
  12. package/dist/config/validators/common.d.ts +4651 -0
  13. package/dist/config/validators/common.js +269 -0
  14. package/dist/config/validators/common.js.map +1 -0
  15. package/dist/config/validators/validate.d.ts +669 -533
  16. package/dist/config/validators/validate.js +9 -234
  17. package/dist/config/validators/validate.js.map +1 -1
  18. package/dist/lib/authentication/providers/openid.js +7 -2
  19. package/dist/lib/authentication/providers/openid.js.map +1 -1
  20. package/dist/lib/components/Heading.d.ts +1 -1
  21. package/dist/lib/components/TopNavigation.d.ts +1 -1
  22. package/dist/lib/components/navigation/SidebarCategory.d.ts +1 -2
  23. package/dist/lib/components/navigation/SidebarCategory.js +3 -4
  24. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  25. package/dist/lib/components/navigation/SidebarItem.d.ts +1 -3
  26. package/dist/lib/components/navigation/SidebarItem.js +4 -9
  27. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  28. package/dist/lib/components/navigation/SidebarWrapper.js +1 -1
  29. package/dist/lib/components/navigation/SidebarWrapper.js.map +1 -1
  30. package/dist/lib/core/ZudokuContext.d.ts +1 -1
  31. package/dist/lib/oas/graphql/index.js +0 -1
  32. package/dist/lib/oas/graphql/index.js.map +1 -1
  33. package/dist/lib/plugins/api-catalog/Catalog.d.ts +6 -0
  34. package/dist/lib/plugins/api-catalog/Catalog.js +29 -0
  35. package/dist/lib/plugins/api-catalog/Catalog.js.map +1 -0
  36. package/dist/lib/plugins/api-catalog/index.d.ts +23 -0
  37. package/dist/lib/plugins/api-catalog/index.js +15 -0
  38. package/dist/lib/plugins/api-catalog/index.js.map +1 -0
  39. package/dist/lib/plugins/markdown/index.d.ts +1 -1
  40. package/dist/lib/plugins/markdown/resolver.js.map +1 -1
  41. package/dist/lib/plugins/openapi/playground/PathParams.js +1 -1
  42. package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
  43. package/dist/lib/plugins/redirect/index.d.ts +1 -1
  44. package/dist/lib/ui/Command.d.ts +1 -1
  45. package/dist/lib/util/MdxComponents.d.ts +2 -3
  46. package/dist/lib/util/MdxComponents.js.map +1 -1
  47. package/dist/vite/build.js +4 -1
  48. package/dist/vite/build.js.map +1 -1
  49. package/dist/vite/config.d.ts +1 -3
  50. package/dist/vite/config.js +2 -4
  51. package/dist/vite/config.js.map +1 -1
  52. package/dist/vite/dev-server.js.map +1 -1
  53. package/dist/vite/output.d.ts +1 -1
  54. package/dist/vite/output.js.map +1 -1
  55. package/dist/vite/plugin-api.js +44 -1
  56. package/dist/vite/plugin-api.js.map +1 -1
  57. package/dist/vite/plugin-component.js +1 -0
  58. package/dist/vite/plugin-component.js.map +1 -1
  59. package/dist/vite/plugin-config-reload.d.ts +1 -2
  60. package/dist/vite/plugin-config-reload.js.map +1 -1
  61. package/dist/vite/plugin.d.ts +1 -2
  62. package/dist/vite/plugin.js.map +1 -1
  63. package/dist/vite/prerender.d.ts +2 -1
  64. package/dist/vite/prerender.js +2 -2
  65. package/dist/vite/prerender.js.map +1 -1
  66. package/dist/vite/sitemap.d.ts +1 -1
  67. package/dist/zuplo/env.d.ts +6 -0
  68. package/dist/zuplo/env.js +9 -0
  69. package/dist/zuplo/env.js.map +1 -0
  70. package/dist/zuplo/with-zuplo.d.ts +2 -2
  71. package/dist/zuplo/with-zuplo.js.map +1 -1
  72. package/lib/Markdown-ievDDhFT.js.map +1 -1
  73. package/lib/{OperationList-DzE32oyS.js → OperationList-DT5Fu9bC.js} +2 -2
  74. package/lib/{OperationList-DzE32oyS.js.map → OperationList-DT5Fu9bC.js.map} +1 -1
  75. package/lib/assets/{worker-CyxLedqF.js → worker-C_2va8B8.js} +1 -2
  76. package/lib/assets/{worker-CyxLedqF.js.map → worker-C_2va8B8.js.map} +1 -1
  77. package/lib/{createServer-DTiCfoql.js → createServer-BCAHdrpE.js} +1 -2
  78. package/lib/{createServer-DTiCfoql.js.map → createServer-BCAHdrpE.js.map} +1 -1
  79. package/lib/{index-NNCc1BSK.js → index-CBctPUfP.js} +4 -3
  80. package/lib/index-CBctPUfP.js.map +1 -0
  81. package/lib/zudoku.auth-openid.js +42 -37
  82. package/lib/zudoku.auth-openid.js.map +1 -1
  83. package/lib/zudoku.components.js +259 -271
  84. package/lib/zudoku.components.js.map +1 -1
  85. package/lib/zudoku.openapi-worker.js +1 -1
  86. package/lib/zudoku.plugin-api-catalog.js +121 -0
  87. package/lib/zudoku.plugin-api-catalog.js.map +1 -0
  88. package/lib/zudoku.plugin-markdown.js.map +1 -1
  89. package/lib/zudoku.plugin-openapi.js +1 -1
  90. package/lib/zudoku.plugin-redirect.js.map +1 -1
  91. package/package.json +6 -2
  92. package/src/app/main.tsx +5 -1
  93. package/src/lib/authentication/providers/openid.tsx +7 -2
  94. package/src/lib/components/TopNavigation.tsx +1 -1
  95. package/src/lib/components/navigation/SidebarCategory.tsx +7 -9
  96. package/src/lib/components/navigation/SidebarItem.tsx +3 -16
  97. package/src/lib/components/navigation/SidebarWrapper.tsx +1 -1
  98. package/src/lib/core/ZudokuContext.ts +1 -1
  99. package/src/lib/oas/graphql/index.ts +0 -1
  100. package/src/lib/plugins/api-catalog/Catalog.tsx +124 -0
  101. package/src/lib/plugins/api-catalog/index.tsx +50 -0
  102. package/src/lib/plugins/markdown/index.tsx +1 -1
  103. package/src/lib/plugins/markdown/resolver.ts +2 -4
  104. package/src/lib/plugins/openapi/playground/PathParams.tsx +1 -0
  105. package/src/lib/plugins/redirect/index.tsx +1 -1
  106. package/src/lib/util/MdxComponents.tsx +2 -5
  107. package/lib/index-NNCc1BSK.js.map +0 -1
@@ -2,7 +2,7 @@ const o = () => {
2
2
  const r = new SharedWorker(
3
3
  new URL(
4
4
  /* @vite-ignore */
5
- "./assets/worker-CyxLedqF.js",
5
+ "./assets/worker-C_2va8B8.js",
6
6
  import.meta.url
7
7
  ),
8
8
  { type: "module" }
@@ -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 {\n ZudokuConfig,\n ZudokuDocsConfig,\n} 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/validate.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":";;;;;AAOA,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;AC7Da,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
+ {"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,5 +1,5 @@
1
1
  import "./jsx-runtime-B6kdoens.js";
2
- import { o as a } from "./index-NNCc1BSK.js";
2
+ import { o as a } from "./index-CBctPUfP.js";
3
3
  import "./utils-DcpDOncX.js";
4
4
  import "lucide-react";
5
5
  import "./hook-hEqe7fPB.js";
@@ -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/validate.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;"}
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.18.8",
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 { configuredApiPlugins } from "virtual:zudoku-api-plugins";
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
- await this.signIn();
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/validate.js";
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 className="mt-1 border-l ms-0.5">
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({ isTopLevel: level === 0 })}
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
- "px-[--padding-nav-item] -mx-[--padding-nav-item] pb-20 mt-[--padding-content-top]",
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";
@@ -443,7 +443,6 @@ const SchemaSource = builder.enumType("SchemaType", {
443
443
 
444
444
  builder.queryType({
445
445
  fields: (t) => ({
446
- // https://tan-cow-main-bce8a06.d2.zuplo.dev/openapi
447
446
  schema: t.field({
448
447
  type: Schema,
449
448
  args: {
@@ -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/validate.js";
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
- ZudokuConfig,
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
 
@@ -50,6 +50,7 @@ export const PathParams = ({
50
50
  render={({ field }) => (
51
51
  <Input
52
52
  {...field}
53
+ required
53
54
  placeholder="Enter value"
54
55
  className="border-0 shadow-none ring-0 font-mono text-xs"
55
56
  />
@@ -1,5 +1,5 @@
1
1
  import { redirect } from "react-router-dom";
2
- import { ZudokuRedirect } from "../../../config/validators/validate.js";
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: {