zudoku 0.0.0-eb5886a → 0.0.0-f114fe8

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 (131) hide show
  1. package/cli.js +2 -2
  2. package/dist/app/entry.client.js +2 -2
  3. package/dist/app/entry.client.js.map +1 -1
  4. package/dist/app/entry.server.js +0 -3
  5. package/dist/app/entry.server.js.map +1 -1
  6. package/dist/app/main.d.ts +0 -1
  7. package/dist/app/main.js +21 -6
  8. package/dist/app/main.js.map +1 -1
  9. package/dist/app/standalone.js.map +1 -1
  10. package/dist/cli/common/machine-id/lib.js.map +1 -1
  11. package/dist/cli/common/outdated.js.map +1 -1
  12. package/dist/cli/common/utils/box.js.map +1 -1
  13. package/dist/config/config.d.ts +1 -1
  14. package/dist/config/validators/SidebarSchema.d.ts +1 -1
  15. package/dist/config/validators/SidebarSchema.js +9 -5
  16. package/dist/config/validators/SidebarSchema.js.map +1 -1
  17. package/dist/config/validators/validate.d.ts +48 -62
  18. package/dist/config/validators/validate.js +5 -6
  19. package/dist/config/validators/validate.js.map +1 -1
  20. package/dist/index.d.ts +0 -3
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/components/Header.js +1 -5
  24. package/dist/lib/components/Header.js.map +1 -1
  25. package/dist/lib/components/TopNavigation.js +4 -28
  26. package/dist/lib/components/TopNavigation.js.map +1 -1
  27. package/dist/lib/components/context/ZudokuContext.d.ts +12 -5
  28. package/dist/lib/components/context/ZudokuContext.js +20 -26
  29. package/dist/lib/components/context/ZudokuContext.js.map +1 -1
  30. package/dist/lib/components/index.d.ts +1 -1
  31. package/dist/lib/components/navigation/Sidebar.js +3 -3
  32. package/dist/lib/components/navigation/Sidebar.js.map +1 -1
  33. package/dist/lib/components/navigation/SidebarCategory.js +3 -1
  34. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  35. package/dist/lib/components/navigation/SidebarItem.js +3 -1
  36. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  37. package/dist/lib/components/navigation/utils.js +14 -10
  38. package/dist/lib/components/navigation/utils.js.map +1 -1
  39. package/dist/lib/core/DevPortalContext.d.ts +6 -3
  40. package/dist/lib/core/DevPortalContext.js.map +1 -1
  41. package/dist/lib/core/plugins.d.ts +0 -1
  42. package/dist/lib/core/plugins.js.map +1 -1
  43. package/dist/lib/plugins/markdown/generateRoutes.d.ts +3 -0
  44. package/dist/lib/plugins/markdown/generateRoutes.js +21 -0
  45. package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -0
  46. package/dist/lib/plugins/markdown/index.d.ts +6 -5
  47. package/dist/lib/plugins/markdown/index.js +3 -31
  48. package/dist/lib/plugins/markdown/index.js.map +1 -1
  49. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  50. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  51. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  52. package/dist/lib/plugins/openapi/client/worker.js.map +1 -1
  53. package/dist/lib/plugins/openapi/index.js.map +1 -1
  54. package/dist/lib/ui/Button.d.ts +1 -1
  55. package/dist/lib/util/MdxComponents.d.ts +1 -1
  56. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  57. package/dist/vite/plugin-config-reload.js.map +1 -1
  58. package/dist/vite/plugin-docs.js +13 -19
  59. package/dist/vite/plugin-docs.js.map +1 -1
  60. package/dist/vite/plugin-sidebar.js +2 -5
  61. package/dist/vite/plugin-sidebar.js.map +1 -1
  62. package/lib/{AuthenticationPlugin-BFO0iXPa.js → AuthenticationPlugin-Bx9FK124.js} +2 -2
  63. package/lib/{AuthenticationPlugin-BFO0iXPa.js.map → AuthenticationPlugin-Bx9FK124.js.map} +1 -1
  64. package/lib/{Input-B2qMWklW.js → Input-CtVUl3eT.js} +3 -3
  65. package/lib/{Input-B2qMWklW.js.map → Input-CtVUl3eT.js.map} +1 -1
  66. package/lib/{MdxPage-aE7f-Uli.js → MdxPage-BqBWsXZ1.js} +24 -25
  67. package/lib/{MdxPage-aE7f-Uli.js.map → MdxPage-BqBWsXZ1.js.map} +1 -1
  68. package/lib/{OperationList-BcfWM4ir.js → OperationList-CYrmxPa8.js} +4 -4
  69. package/lib/OperationList-CYrmxPa8.js.map +1 -0
  70. package/lib/{Route-DzTbXYJ8.js → Route-Q5mqNQrv.js} +2 -2
  71. package/lib/{Route-DzTbXYJ8.js.map → Route-Q5mqNQrv.js.map} +1 -1
  72. package/lib/{SidebarBadge-1Mv5r_Vo.js → SidebarBadge-Dx7jtnoA.js} +2 -2
  73. package/lib/{SidebarBadge-1Mv5r_Vo.js.map → SidebarBadge-Dx7jtnoA.js.map} +1 -1
  74. package/lib/ZudokuContext-cr-pTRY1.js +1084 -0
  75. package/lib/ZudokuContext-cr-pTRY1.js.map +1 -0
  76. package/lib/assets/worker-Bcj4NA2p.js.map +1 -1
  77. package/lib/{index-DrrYONSc.js → index-BlJ2rj99.js} +419 -416
  78. package/lib/index-BlJ2rj99.js.map +1 -0
  79. package/lib/{index-Bwy2Len1.js → index-BngPzhKn.js} +3 -3
  80. package/lib/{index-Bwy2Len1.js.map → index-BngPzhKn.js.map} +1 -1
  81. package/lib/{index-DtahPCcC.js → index-Dolisrci.js} +2 -2
  82. package/lib/{index-DtahPCcC.js.map → index-Dolisrci.js.map} +1 -1
  83. package/lib/joinPath-B7kNnUX4.js +8 -0
  84. package/lib/joinPath-B7kNnUX4.js.map +1 -0
  85. package/lib/{AnchorLink-CnXSVkGB.js → utils-ByIc_KIM.js} +275 -231
  86. package/lib/utils-ByIc_KIM.js.map +1 -0
  87. package/lib/zudoku.auth-clerk.js +1 -1
  88. package/lib/zudoku.auth-openid.js +1 -1
  89. package/lib/zudoku.components.js +735 -745
  90. package/lib/zudoku.components.js.map +1 -1
  91. package/lib/zudoku.plugin-api-keys.js +3 -3
  92. package/lib/zudoku.plugin-markdown.js +27 -93
  93. package/lib/zudoku.plugin-markdown.js.map +1 -1
  94. package/lib/zudoku.plugin-openapi.js +5 -4
  95. package/lib/zudoku.plugin-openapi.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/app/entry.client.tsx +2 -4
  98. package/src/app/entry.server.tsx +0 -4
  99. package/src/app/main.tsx +25 -9
  100. package/src/app/standalone.tsx +1 -1
  101. package/src/lib/components/Header.tsx +2 -10
  102. package/src/lib/components/TopNavigation.tsx +15 -47
  103. package/src/lib/components/context/ZudokuContext.ts +20 -34
  104. package/src/lib/components/navigation/Sidebar.tsx +5 -5
  105. package/src/lib/components/navigation/SidebarCategory.tsx +3 -1
  106. package/src/lib/components/navigation/SidebarItem.tsx +3 -1
  107. package/src/lib/components/navigation/utils.ts +16 -11
  108. package/src/lib/core/DevPortalContext.ts +2 -3
  109. package/src/lib/core/plugins.ts +0 -2
  110. package/src/lib/plugins/markdown/generateRoutes.tsx +38 -0
  111. package/src/lib/plugins/markdown/index.tsx +12 -49
  112. package/src/lib/plugins/openapi/Endpoint.tsx +2 -2
  113. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +1 -1
  114. package/src/lib/plugins/openapi/Sidecar.tsx +1 -1
  115. package/src/lib/plugins/openapi/client/worker.ts +2 -2
  116. package/src/lib/plugins/openapi/index.tsx +1 -1
  117. package/src/lib/util/useScrollToAnchor.ts +1 -1
  118. package/dist/lib/plugins/markdown/resolver.d.ts +0 -38
  119. package/dist/lib/plugins/markdown/resolver.js +0 -75
  120. package/dist/lib/plugins/markdown/resolver.js.map +0 -1
  121. package/dist/vite/debug.d.ts +0 -1
  122. package/dist/vite/debug.js +0 -10
  123. package/dist/vite/debug.js.map +0 -1
  124. package/lib/AnchorLink-CnXSVkGB.js.map +0 -1
  125. package/lib/OperationList-BcfWM4ir.js.map +0 -1
  126. package/lib/ZudokuContext-CSrx4lfi.js +0 -1134
  127. package/lib/ZudokuContext-CSrx4lfi.js.map +0 -1
  128. package/lib/__vite-browser-external-BYRIRx8p.js +0 -9
  129. package/lib/__vite-browser-external-BYRIRx8p.js.map +0 -1
  130. package/lib/index-DrrYONSc.js.map +0 -1
  131. package/src/lib/plugins/markdown/resolver.ts +0 -92
@@ -1,9 +1,9 @@
1
1
  import { j as e } from "./jsx-runtime-B6kdoens.js";
2
2
  import { S as x, R as f } from "./SlotletProvider-D3UD5Go3.js";
3
- import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-B2qMWklW.js";
3
+ import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-CtVUl3eT.js";
4
4
  import { a as N, L as u, O as I } from "./index-BG0g4WW0.js";
5
- import { b as h, c as E, d as S } from "./ZudokuContext-CSrx4lfi.js";
6
- import { B as l, m as A } from "./index-DtahPCcC.js";
5
+ import { u as h, a as E, b as S } from "./ZudokuContext-cr-pTRY1.js";
6
+ import { B as l, m as A } from "./index-Dolisrci.js";
7
7
  import { D as C } from "./DeveloperHint-YeWHKvyr.js";
8
8
  import { RotateCwIcon as P, TrashIcon as D, EyeOffIcon as R, EyeIcon as q, CheckIcon as O, CopyIcon as z } from "lucide-react";
9
9
  import { useState as p } from "react";
@@ -1,98 +1,32 @@
1
- var d = Object.defineProperty;
2
- var m = (n, t, o) => t in n ? d(n, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : n[t] = o;
3
- var f = (n, t, o) => m(n, typeof t != "symbol" ? t + "" : t, o);
4
- import { j as P } from "./jsx-runtime-B6kdoens.js";
5
- import { f as u } from "./__vite-browser-external-BYRIRx8p.js";
6
- const x = "/pages/**/*.{md,mdx}", D = [".md", ".mdx"];
7
- class c {
8
- constructor(t) {
9
- f(this, "fileMap", /* @__PURE__ */ new Map());
10
- this.config = t;
11
- }
12
- /**
13
- * Gets the default docs config from the zudoku config
14
- */
15
- getDocsConfigs() {
16
- return this.config.docs ? Array.isArray(this.config.docs) ? this.config.docs : [this.config.docs] : [{ files: x }];
17
- }
18
- /**
19
- * Resolves the first matching file system path for a given docId
20
- * @param docId - The docId to resolve
21
- * @returns
22
- */
23
- resolveFilePath(t) {
24
- const o = this.getDocsConfigs();
25
- let s;
26
- return o.forEach(({ files: i }) => {
27
- if (s)
28
- return;
29
- const e = c.getRootDir(i);
30
- for (const a of D) {
31
- if (s)
32
- return;
33
- const r = u.join(e, `${t}${a}`);
34
- u.existsSync(r) && (s = r);
35
- }
36
- }), s;
37
- }
38
- /**
39
- * Gets the root directory from a files glob
40
- */
41
- static getRootDir(t) {
42
- let o = t.split("**")[0];
43
- if (!o)
44
- throw new Error("Invalid files glob. Must have '**' in the path.");
45
- return o = o.replace("/**", "/"), o;
46
- }
47
- /**
48
- * Resolves the route path for a given file system path
49
- * @param options - The options to resolve the route path
50
- * @returns The string route path
51
- */
52
- static resolveRoutePath({
53
- filesGlob: t,
54
- fsPath: o
55
- }) {
56
- const s = this.getRootDir(t), i = new RegExp(`^${s}(.*).mdx?`), e = o.match(i);
57
- return e == null ? void 0 : e.at(1);
58
- }
59
- }
60
- const C = (n) => ({
61
- getRoutes: () => {
62
- const t = /* @__PURE__ */ new Map();
63
- return n.forEach(
64
- ({ fileImports: o, files: s, defaultOptions: i }) => Object.entries(o).flatMap(([e, a]) => {
65
- const r = c.resolveRoutePath({
66
- filesGlob: s,
67
- fsPath: e
68
- });
69
- if (!r) return [];
70
- if (t.has(r))
71
- return console.warn(
72
- `Duplicate route path found for ${r}. Skipping file at '${e}'.`
73
- ), [];
74
- const h = {
75
- path: r,
76
- lazy: async () => {
77
- const { MdxPage: l } = await import("./MdxPage-aE7f-Uli.js"), { default: p, ...g } = await a();
78
- return {
79
- element: /* @__PURE__ */ P.jsx(
80
- l,
81
- {
82
- mdxComponent: p,
83
- ...g,
84
- defaultOptions: i
85
- }
86
- )
87
- };
1
+ import { j as u } from "./jsx-runtime-B6kdoens.js";
2
+ const x = (t, e, n) => Object.entries(t).flatMap(([a, p]) => {
3
+ let o = e.split("**")[0];
4
+ o = o.replace("/**", "/");
5
+ const c = new RegExp(`^${o}(.*).mdx?`), r = a.match(c), s = r == null ? void 0 : r.at(1);
6
+ return s ? {
7
+ path: s,
8
+ lazy: async () => {
9
+ const { MdxPage: i } = await import("./MdxPage-BqBWsXZ1.js"), { default: m, ...l } = await p();
10
+ return {
11
+ element: /* @__PURE__ */ u.jsx(
12
+ i,
13
+ {
14
+ mdxComponent: m,
15
+ ...l,
16
+ defaultOptions: n
88
17
  }
89
- };
90
- t.set(r, h);
91
- })
92
- ), [...t.values()];
93
- }
18
+ )
19
+ };
20
+ }
21
+ } : [];
22
+ }), f = ({
23
+ markdownFiles: t,
24
+ defaultOptions: e,
25
+ filesPath: n
26
+ }) => ({
27
+ getRoutes: () => x(t, n, e)
94
28
  });
95
29
  export {
96
- C as markdownPlugin
30
+ f as markdownPlugin
97
31
  };
98
32
  //# sourceMappingURL=zudoku.plugin-markdown.js.map
@@ -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 { DevPortalPlugin } 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 default: (props: MDXProps) => JSX.Element;\n};\n\nexport const markdownPlugin = (\n options: MarkdownPluginOptions[],\n): DevPortalPlugin => ({\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 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;AC9Da,MAAAC,IAAiB,CAC5BC,OACqB;AAAA,EACrB,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,cAAcC;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/generateRoutes.tsx","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import { type RouteObject } from \"react-router-dom\";\n\nimport {\n MarkdownPluginDefaultOptions,\n MarkdownPluginOptions,\n} from \"./index.js\";\n\nexport const generateRoutes = (\n markdownFiles: MarkdownPluginOptions[\"markdownFiles\"],\n filesPath: string,\n defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] =>\n Object.entries(markdownFiles).flatMap(([file, importPromise]) => {\n let rootDir = filesPath.split(\"**\")[0];\n rootDir = rootDir.replace(\"/**\", \"/\");\n const re = new RegExp(`^${rootDir}(.*).mdx?`);\n const match = file.match(re);\n const fsPath = match?.at(1);\n\n if (!fsPath) return [];\n\n return {\n path: fsPath,\n lazy: async () => {\n const { MdxPage } = await import(\"./MdxPage.js\");\n const { default: Component, ...props } = await importPromise();\n return {\n element: (\n <MdxPage\n mdxComponent={Component}\n {...props}\n defaultOptions={defaultOptions}\n />\n ),\n };\n },\n } satisfies RouteObject;\n });\n","import type { Toc } from \"@stefanprobst/rehype-extract-toc\";\nimport type { MDXProps } from \"mdx/types.js\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\nimport { generateRoutes } from \"./generateRoutes.js\";\n\nexport type MarkdownPluginOptions = {\n markdownFiles: Record<string, () => Promise<MDXImport>>;\n defaultOptions?: MarkdownPluginDefaultOptions;\n filesPath: string;\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 default: (props: MDXProps) => JSX.Element;\n};\n\nexport const markdownPlugin = ({\n markdownFiles,\n defaultOptions,\n filesPath,\n}: MarkdownPluginOptions): DevPortalPlugin => ({\n getRoutes: () => generateRoutes(markdownFiles, filesPath, defaultOptions),\n});\n"],"names":["generateRoutes","markdownFiles","filesPath","defaultOptions","file","importPromise","rootDir","re","match","fsPath","MdxPage","Component","props","jsx","markdownPlugin"],"mappings":";AAOO,MAAMA,IAAiB,CAC5BC,GACAC,GACAC,MAEA,OAAO,QAAQF,CAAa,EAAE,QAAQ,CAAC,CAACG,GAAMC,CAAa,MAAM;AAC/D,MAAIC,IAAUJ,EAAU,MAAM,IAAI,EAAE,CAAC;AAC3B,EAAAI,IAAAA,EAAQ,QAAQ,OAAO,GAAG;AACpC,QAAMC,IAAK,IAAI,OAAO,IAAID,CAAO,WAAW,GACtCE,IAAQJ,EAAK,MAAMG,CAAE,GACrBE,IAASD,KAAA,gBAAAA,EAAO,GAAG;AAErB,SAACC,IAEE;AAAA,IACL,MAAMA;AAAA,IACN,MAAM,YAAY;AAChB,YAAM,EAAE,SAAAC,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAMP;AACxC,aAAA;AAAA,QACL,SACEQ,gBAAAA,EAAA;AAAA,UAACH;AAAA,UAAA;AAAA,YACC,cAAcC;AAAA,YACb,GAAGC;AAAA,YACJ,gBAAAT;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAGN;AAAA,EAAA,IAhBkB;AAkBtB,CAAC,GCRUW,IAAiB,CAAC;AAAA,EAC7B,eAAAb;AAAA,EACA,gBAAAE;AAAA,EACA,WAAAD;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,GAAWC,CAAc;AAC1E;"}
@@ -1,15 +1,16 @@
1
1
  import "./jsx-runtime-B6kdoens.js";
2
- import { o as s } from "./index-DrrYONSc.js";
2
+ import { o as u } from "./index-BlJ2rj99.js";
3
3
  import "./urql-YhcsXYy8.js";
4
- import "./ZudokuContext-CSrx4lfi.js";
4
+ import "./ZudokuContext-cr-pTRY1.js";
5
5
  import "lucide-react";
6
6
  import "zudoku/openapi-worker";
7
- import "./index-DtahPCcC.js";
7
+ import "./index-Dolisrci.js";
8
8
  import "./ErrorPage-CsZAN_za.js";
9
9
  import "./Markdown-DapSf3wG.js";
10
+ import "./joinPath-B7kNnUX4.js";
10
11
  import "./router-D2p7Olpn.js";
11
12
  import "./index-BG0g4WW0.js";
12
13
  export {
13
- s as openApiPlugin
14
+ u as openApiPlugin
14
15
  };
15
16
  //# sourceMappingURL=zudoku.plugin-openapi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
1
+ {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.0.0-eb5886a",
3
+ "version": "0.0.0-f114fe8",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -20,10 +20,8 @@ if (root.childElementCount > 0) {
20
20
  }
21
21
 
22
22
  async function hydrateLazyRoutes(routes: RouteObject[]) {
23
- const path = window.location.pathname;
24
- const lazyMatches = matchRoutes(routes, path, config.basePath)?.filter(
25
- (m) => m.route.lazy,
26
- );
23
+ const path = window.location.pathname.slice(config.basePath?.length ?? 0);
24
+ const lazyMatches = matchRoutes(routes, path)?.filter((m) => m.route.lazy);
27
25
 
28
26
  if (lazyMatches?.length) {
29
27
  await Promise.all(
@@ -96,10 +96,6 @@ export const render = async ({
96
96
 
97
97
  const [htmlStart, htmlEnd] = template.split("<!--app-html-->");
98
98
 
99
- if (!htmlStart) {
100
- throw new Error("No <!--app-html--> found in template");
101
- }
102
-
103
99
  response.write(
104
100
  htmlStart.replace(
105
101
  "<!--app-helmet-->",
package/src/app/main.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { type RouteObject } from "react-router-dom";
1
+ import { redirect, type RouteObject } from "react-router-dom";
2
2
  import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
3
3
  import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
4
4
  import { configuredAuthProvider } from "virtual:zudoku-auth";
@@ -11,7 +11,9 @@ import { isNavigationPlugin } from "zudoku/internal";
11
11
  import { customPagePlugin } from "zudoku/plugins/custom-page";
12
12
  import { inkeepSearchPlugin } from "zudoku/plugins/search-inkeep";
13
13
  import type { ZudokuConfig } from "../config/config.js";
14
+ import { traverseSidebar } from "../lib/components/navigation/utils.js";
14
15
  import type { ZudokuContextOptions } from "../lib/core/DevPortalContext.js";
16
+ import { joinPath } from "../lib/util/joinPath.js";
15
17
 
16
18
  export const convertZudokuConfigToOptions = (
17
19
  config: ZudokuConfig,
@@ -67,7 +69,9 @@ export const convertZudokuConfigToOptions = (
67
69
  };
68
70
  };
69
71
 
70
- export const getRoutesByOptions = (options: ZudokuContextOptions) => {
72
+ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
73
+ const options = convertZudokuConfigToOptions(config);
74
+
71
75
  const allPlugins = [
72
76
  ...(options.plugins ? options.plugins : []),
73
77
  ...(options.authentication?.getAuthenticationPlugin
@@ -75,8 +79,27 @@ export const getRoutesByOptions = (options: ZudokuContextOptions) => {
75
79
  : []),
76
80
  ];
77
81
 
82
+ const topNavRedirects =
83
+ options.topNavigation?.flatMap((topNavItem) => {
84
+ if (!options.sidebars?.[topNavItem.id]) return [];
85
+
86
+ const first =
87
+ topNavItem.default ??
88
+ traverseSidebar(options.sidebars[topNavItem.id], (item) => {
89
+ if (item.type === "doc") return joinPath(topNavItem.id, item.id);
90
+ });
91
+
92
+ if (!first) return [];
93
+
94
+ return {
95
+ path: topNavItem.id,
96
+ loader: () => redirect(joinPath(first)),
97
+ } satisfies RouteObject;
98
+ }) ?? [];
99
+
78
100
  const routes = allPlugins
79
101
  .flatMap((plugin) => (isNavigationPlugin(plugin) ? plugin.getRoutes() : []))
102
+ .concat(topNavRedirects)
80
103
  .concat({
81
104
  path: "*",
82
105
  loader: () => {
@@ -84,13 +107,6 @@ export const getRoutesByOptions = (options: ZudokuContextOptions) => {
84
107
  },
85
108
  });
86
109
 
87
- return routes;
88
- };
89
-
90
- export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
91
- const options = convertZudokuConfigToOptions(config);
92
- const routes = getRoutesByOptions(options);
93
-
94
110
  return [
95
111
  {
96
112
  element: (
@@ -16,7 +16,7 @@ if (!root) {
16
16
  themeToggle();
17
17
 
18
18
  const apiUrl = root.getAttribute("data-api-url");
19
- const pageTitle = document.getElementsByTagName("title")[0]!.innerText;
19
+ const pageTitle = document.getElementsByTagName("title")[0].innerText;
20
20
  const logoUrl = root.getAttribute("data-logo-url");
21
21
 
22
22
  // IMPORTANT: This component must not contain tailwind classes
@@ -70,22 +70,14 @@ export const Header = memo(function HeaderInner() {
70
70
  {page?.logo && (
71
71
  <>
72
72
  <img
73
- src={
74
- /https?:\/\//.test(page.logo.src.light)
75
- ? page.logo.src.light
76
- : import.meta.env.BASE_URL + page.logo.src.light
77
- }
73
+ src={page.logo.src.light}
78
74
  alt={page.logo.alt ?? page.pageTitle}
79
75
  style={{ width: page.logo.width }}
80
76
  className={cn("h-10", isDark && "hidden")}
81
77
  loading="lazy"
82
78
  />
83
79
  <img
84
- src={
85
- /https?:\/\//.test(page.logo.src.dark)
86
- ? page.logo.src.dark
87
- : import.meta.env.BASE_URL + page.logo.src.dark
88
- }
80
+ src={page.logo.src.dark}
89
81
  alt={page.logo.alt ?? page.pageTitle}
90
82
  style={{ width: page.logo.width }}
91
83
  className={cn("h-10", !isDark && "hidden")}
@@ -1,10 +1,7 @@
1
1
  import { cx } from "class-variance-authority";
2
2
  import { NavLink } from "react-router-dom";
3
3
 
4
- import { TopNavigationItem } from "../../config/validators/validate.js";
5
- import { joinPath } from "../util/joinPath.js";
6
- import { useCurrentNavigation, useZudoku } from "./context/ZudokuContext.js";
7
- import { traverseSidebar } from "./navigation/utils.js";
4
+ import { useZudoku } from "./context/ZudokuContext.js";
8
5
 
9
6
  export const TopNavigation = () => {
10
7
  const { topNavigation } = useZudoku();
@@ -18,52 +15,23 @@ export const TopNavigation = () => {
18
15
  <nav className="hidden lg:block border-b text-sm px-12 h-[--top-nav-height]">
19
16
  <ul className="flex flex-row items-center gap-8">
20
17
  {topNavigation.map((item) => (
21
- <li key={item.id}>
22
- <TopNavItem {...item} />
18
+ <li key={item.label}>
19
+ <NavLink
20
+ className={({ isActive }) =>
21
+ cx(
22
+ "block py-3.5 font-medium -mb-px border-b-2",
23
+ isActive
24
+ ? "border-primary text-foreground"
25
+ : "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
26
+ )
27
+ }
28
+ to={item.id}
29
+ >
30
+ {item.label}
31
+ </NavLink>
23
32
  </li>
24
33
  ))}
25
34
  </ul>
26
35
  </nav>
27
36
  );
28
37
  };
29
-
30
- const TopNavItem = ({ id, label, default: defaultLink }: TopNavigationItem) => {
31
- const { sidebars } = useZudoku();
32
- const nav = useCurrentNavigation();
33
- const currentSidebar = sidebars[id];
34
-
35
- // TODO: This is a bit of a hack to get the first link in the sidebar
36
- // We should really process this when we load the config so we can validate
37
- // that the sidebar is actually set. In this case we just fall back to linking
38
- // to the id if we can't resolve a sidebar.
39
- const first =
40
- defaultLink ??
41
- (currentSidebar
42
- ? traverseSidebar(currentSidebar, (item) => {
43
- if (item.type === "doc") return joinPath(item.id);
44
- })
45
- : joinPath(id));
46
-
47
- if (!first) {
48
- throw new Error(
49
- `No links found in top navigation for top navigation '${id}'. Check that the sidebar isn't empty or that a default link set.`,
50
- );
51
- }
52
-
53
- // Manually set the active sidebar based on our logic of what is active
54
- const isActive = nav.data.topNavItem?.id === id;
55
-
56
- return (
57
- <NavLink
58
- className={cx(
59
- "block py-3.5 font-medium -mb-px border-b-2",
60
- isActive
61
- ? "border-primary text-foreground"
62
- : "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
63
- )}
64
- to={first}
65
- >
66
- {label}
67
- </NavLink>
68
- );
69
- };
@@ -1,11 +1,7 @@
1
1
  import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
2
2
  import { createContext, useContext } from "react";
3
3
  import { useLocation } from "react-router-dom";
4
- import { SidebarItem } from "../../../config/validators/SidebarSchema.js";
5
- import { TopNavigationItem } from "../../../config/validators/validate.js";
6
4
  import { DevPortalContext } from "../../core/DevPortalContext.js";
7
- import { joinPath } from "../../util/joinPath.js";
8
- import { traverseSidebar } from "../navigation/utils.js";
9
5
 
10
6
  export const ZudokuReactContext = createContext<DevPortalContext | undefined>(
11
7
  undefined,
@@ -29,44 +25,34 @@ export const useApiIdentities = () => {
29
25
  });
30
26
  };
31
27
 
32
- export const useCurrentNavigation = () => {
33
- const { getPluginSidebar, sidebars, topNavigation } = useZudoku();
28
+ export const useTopNavigationItem = () => {
29
+ const { topNavigation } = useZudoku();
34
30
  const location = useLocation();
35
31
 
36
- const currentSidebarItem = Object.entries(sidebars).find(([, sidebar]) => {
37
- return traverseSidebar(sidebar, (item) => {
38
- const itemId =
39
- item.type === "doc"
40
- ? joinPath(item.id)
41
- : item.type === "category" && item.link
42
- ? joinPath(item.link.id)
43
- : undefined;
32
+ const firstPart = location.pathname.split("/").at(1);
33
+ if (!firstPart) return;
44
34
 
45
- if (itemId === location.pathname) {
46
- return item;
47
- }
48
- });
49
- });
50
- const currentTopNavItem = topNavigation.find(
51
- (t) => t.id === currentSidebarItem?.[0],
52
- );
35
+ return topNavigation.find((item) => item.id === firstPart);
36
+ };
37
+
38
+ export const useNavigation = () => {
39
+ const { getPluginSidebar, sidebars } = useZudoku();
40
+ const navItem = useTopNavigationItem();
41
+ const path = navItem?.id;
42
+ const currentSidebar = path ? (sidebars[path] ?? []) : [];
43
+ const location = useLocation();
53
44
 
54
45
  return useSuspenseQuery({
55
46
  queryFn: async () => {
56
- const pluginSidebar = await getPluginSidebar(location.pathname);
47
+ const pluginSidebar = path
48
+ ? await getPluginSidebar(path)
49
+ : await getPluginSidebar(location.pathname);
57
50
 
58
- const result: {
59
- sidebar: SidebarItem[];
60
- topNavItem: TopNavigationItem | undefined;
61
- } = {
62
- sidebar: [
63
- ...(currentSidebarItem ? currentSidebarItem[1] : []),
64
- ...pluginSidebar,
65
- ],
66
- topNavItem: currentTopNavItem,
51
+ return {
52
+ items: [...currentSidebar, ...pluginSidebar],
53
+ currentTopNavItem: navItem,
67
54
  };
68
- return result;
69
55
  },
70
- queryKey: ["navigation", location.pathname],
56
+ queryKey: ["navigation", path],
71
57
  });
72
58
  };
@@ -2,23 +2,23 @@ import { useRef } from "react";
2
2
 
3
3
  import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
4
4
  import { DrawerContent, DrawerTitle } from "../../ui/Drawer.js";
5
- import { useCurrentNavigation } from "../context/ZudokuContext.js";
5
+ import { useNavigation } from "../context/ZudokuContext.js";
6
6
  import { Slotlet } from "../SlotletProvider.js";
7
7
  import { SidebarItem } from "./SidebarItem.js";
8
8
  import { SidebarWrapper } from "./SidebarWrapper.js";
9
9
 
10
10
  export const Sidebar = () => {
11
11
  const navRef = useRef<HTMLDivElement | null>(null);
12
- const navigation = useCurrentNavigation();
12
+ const navigation = useNavigation();
13
13
 
14
14
  return (
15
15
  <>
16
16
  <SidebarWrapper
17
17
  ref={navRef}
18
- pushMainContent={navigation.data.sidebar.length > 0}
18
+ pushMainContent={navigation.data.items.length > 0}
19
19
  >
20
20
  <Slotlet name="zudoku-before-navigation" />
21
- {navigation.data.sidebar.map((item) => (
21
+ {navigation.data.items.map((item) => (
22
22
  <SidebarItem key={item.label} item={item} />
23
23
  ))}
24
24
  <Slotlet name="zudoku-after-navigation" />
@@ -30,7 +30,7 @@ export const Sidebar = () => {
30
30
  <VisuallyHidden>
31
31
  <DrawerTitle>Sidebar</DrawerTitle>
32
32
  </VisuallyHidden>
33
- {navigation.data.sidebar.map((item) => (
33
+ {navigation.data.items.map((item) => (
34
34
  <SidebarItem key={item.label} item={item} />
35
35
  ))}
36
36
  </DrawerContent>
@@ -5,6 +5,7 @@ import { NavLink } from "react-router-dom";
5
5
  import type { SidebarItemCategory } from "../../../config/validators/SidebarSchema.js";
6
6
  import { cn } from "../../util/cn.js";
7
7
  import { joinPath } from "../../util/joinPath.js";
8
+ import { useTopNavigationItem } from "../context/ZudokuContext.js";
8
9
  import { navigationListItem, SidebarItem } from "./SidebarItem.js";
9
10
  import { useIsCategoryOpen } from "./utils.js";
10
11
 
@@ -15,6 +16,7 @@ export const SidebarCategory = ({
15
16
  category: SidebarItemCategory;
16
17
  level: number;
17
18
  }) => {
19
+ const topNavItem = useTopNavigationItem();
18
20
  const isCategoryOpen = useIsCategoryOpen(category);
19
21
  const [hasInteracted, setHasInteracted] = useState(false);
20
22
 
@@ -77,7 +79,7 @@ export const SidebarCategory = ({
77
79
  )}
78
80
  {category.link?.type === "doc" ? (
79
81
  <NavLink
80
- to={joinPath(category.link.id)}
82
+ to={joinPath(topNavItem?.id, category.link.id)}
81
83
  className="flex-1"
82
84
  onClick={() => setHasInteracted(true)}
83
85
  >
@@ -7,6 +7,7 @@ import { cn } from "../../util/cn.js";
7
7
  import { joinPath } from "../../util/joinPath.js";
8
8
  import { AnchorLink } from "../AnchorLink.js";
9
9
  import { useViewportAnchor } from "../context/ViewportAnchorContext.js";
10
+ import { useTopNavigationItem } from "../context/ZudokuContext.js";
10
11
  import { SidebarBadge } from "./SidebarBadge.js";
11
12
  import { SidebarCategory } from "./SidebarCategory.js";
12
13
 
@@ -39,6 +40,7 @@ export const SidebarItem = ({
39
40
  basePath?: string;
40
41
  level?: number;
41
42
  }) => {
43
+ const topNavItem = useTopNavigationItem();
42
44
  const { activeAnchor } = useViewportAnchor();
43
45
  const [searchParams] = useSearchParams();
44
46
 
@@ -51,7 +53,7 @@ export const SidebarItem = ({
51
53
  className={({ isActive }) =>
52
54
  navigationListItem({ isActive, isTopLevel: level === 0 })
53
55
  }
54
- to={joinPath(item.id)}
56
+ to={joinPath(topNavItem?.id, item.id)}
55
57
  >
56
58
  {item.icon && <item.icon size={16} className="align-[-0.125em]" />}
57
59
  {item.badge ? (