zudoku 0.13.7 → 0.14.1

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 (177) 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 +3 -0
  5. package/dist/app/entry.server.js.map +1 -1
  6. package/dist/app/main.d.ts +1 -0
  7. package/dist/app/main.js +6 -21
  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/validators/InputSidebarSchema.d.ts +2 -2
  14. package/dist/config/validators/SidebarSchema.d.ts +24 -1
  15. package/dist/config/validators/SidebarSchema.js +76 -39
  16. package/dist/config/validators/SidebarSchema.js.map +1 -1
  17. package/dist/config/validators/validate.d.ts +329 -264
  18. package/dist/config/validators/validate.js +11 -10
  19. package/dist/config/validators/validate.js.map +1 -1
  20. package/dist/index.d.ts +4 -1
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/components/Header.js +6 -1
  24. package/dist/lib/components/Header.js.map +1 -1
  25. package/dist/lib/components/Heading.d.ts +1 -1
  26. package/dist/lib/components/SlotletProvider.d.ts +2 -1
  27. package/dist/lib/components/SlotletProvider.js.map +1 -1
  28. package/dist/lib/components/SyntaxHighlight.js +4 -1
  29. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  30. package/dist/lib/components/TopNavigation.js +30 -5
  31. package/dist/lib/components/TopNavigation.js.map +1 -1
  32. package/dist/lib/components/context/ZudokuContext.d.ts +6 -12
  33. package/dist/lib/components/context/ZudokuContext.js +26 -20
  34. package/dist/lib/components/context/ZudokuContext.js.map +1 -1
  35. package/dist/lib/components/navigation/Sidebar.js +3 -3
  36. package/dist/lib/components/navigation/Sidebar.js.map +1 -1
  37. package/dist/lib/components/navigation/SidebarCategory.js +2 -4
  38. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  39. package/dist/lib/components/navigation/SidebarItem.js +1 -3
  40. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  41. package/dist/lib/components/navigation/utils.js +10 -14
  42. package/dist/lib/components/navigation/utils.js.map +1 -1
  43. package/dist/lib/core/DevPortalContext.d.ts +3 -7
  44. package/dist/lib/core/DevPortalContext.js.map +1 -1
  45. package/dist/lib/core/plugins.d.ts +1 -0
  46. package/dist/lib/core/plugins.js.map +1 -1
  47. package/dist/lib/plugins/custom-pages/CustomPage.js +2 -2
  48. package/dist/lib/plugins/markdown/index.d.ts +5 -6
  49. package/dist/lib/plugins/markdown/index.js +31 -3
  50. package/dist/lib/plugins/markdown/index.js.map +1 -1
  51. package/dist/lib/plugins/markdown/resolver.d.ts +38 -0
  52. package/dist/lib/plugins/markdown/resolver.js +75 -0
  53. package/dist/lib/plugins/markdown/resolver.js.map +1 -0
  54. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  55. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  56. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  57. package/dist/lib/plugins/openapi/client/worker.js.map +1 -1
  58. package/dist/lib/plugins/openapi/index.js.map +1 -1
  59. package/dist/lib/ui/Badge.d.ts +1 -1
  60. package/dist/lib/ui/Button.d.ts +1 -1
  61. package/dist/lib/ui/Command.d.ts +80 -0
  62. package/dist/lib/ui/Command.js +31 -0
  63. package/dist/lib/ui/Command.js.map +1 -0
  64. package/dist/lib/util/MdxComponents.js.map +1 -1
  65. package/dist/lib/util/useExposedProps.js +3 -2
  66. package/dist/lib/util/useExposedProps.js.map +1 -1
  67. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  68. package/dist/vite/build.js +7 -2
  69. package/dist/vite/build.js.map +1 -1
  70. package/dist/vite/config.js +11 -6
  71. package/dist/vite/config.js.map +1 -1
  72. package/dist/vite/debug.d.ts +1 -0
  73. package/dist/vite/debug.js +10 -0
  74. package/dist/vite/debug.js.map +1 -0
  75. package/dist/vite/plugin-config-reload.js +0 -2
  76. package/dist/vite/plugin-config-reload.js.map +1 -1
  77. package/dist/vite/plugin-docs.js +37 -26
  78. package/dist/vite/plugin-docs.js.map +1 -1
  79. package/dist/vite/plugin-frontmatter.d.ts +2 -1
  80. package/dist/vite/plugin-frontmatter.js +27 -24
  81. package/dist/vite/plugin-frontmatter.js.map +1 -1
  82. package/dist/vite/plugin-sidebar.js +7 -6
  83. package/dist/vite/plugin-sidebar.js.map +1 -1
  84. package/dist/vite/plugin.js +1 -1
  85. package/dist/vite/plugin.js.map +1 -1
  86. package/dist/vite/prerender.d.ts +5 -1
  87. package/dist/vite/prerender.js +6 -5
  88. package/dist/vite/prerender.js.map +1 -1
  89. package/lib/{utils-B2yoT99j.js → AnchorLink-BbB2q-jx.js} +214 -258
  90. package/lib/AnchorLink-BbB2q-jx.js.map +1 -0
  91. package/lib/{AuthenticationPlugin-Bpdes0cJ.js → AuthenticationPlugin-C9BHGXlE.js} +2 -2
  92. package/lib/{AuthenticationPlugin-Bpdes0cJ.js.map → AuthenticationPlugin-C9BHGXlE.js.map} +1 -1
  93. package/lib/Dialog-k70Qfukb.js +67 -0
  94. package/lib/Dialog-k70Qfukb.js.map +1 -0
  95. package/lib/{Markdown-1BO9EA_X.js → Markdown-BDcCAWwm.js} +18 -16
  96. package/lib/{Markdown-1BO9EA_X.js.map → Markdown-BDcCAWwm.js.map} +1 -1
  97. package/lib/{MdxPage-BEOcOICU.js → MdxPage-DKMH_t0f.js} +14 -13
  98. package/lib/{MdxPage-BEOcOICU.js.map → MdxPage-DKMH_t0f.js.map} +1 -1
  99. package/lib/{OperationList-Cea2Yt8e.js → OperationList-Tj7ubW_t.js} +3 -3
  100. package/lib/OperationList-Tj7ubW_t.js.map +1 -0
  101. package/lib/{Route-BHT-onwf.js → Route-C3DGB6OS.js} +2 -2
  102. package/lib/{Route-BHT-onwf.js.map → Route-C3DGB6OS.js.map} +1 -1
  103. package/lib/{Select-m1aXZGAP.js → Select-Bagt3Bme.js} +3 -3
  104. package/lib/{Select-m1aXZGAP.js.map → Select-Bagt3Bme.js.map} +1 -1
  105. package/lib/{SlotletProvider-CPfsBw39.js → SlotletProvider-Da7eFgd2.js} +3 -3
  106. package/lib/{SlotletProvider-CPfsBw39.js.map → SlotletProvider-Da7eFgd2.js.map} +1 -1
  107. package/lib/{ZudokuContext-D1D8Anlj.js → ZudokuContext-BKXGJTmu.js} +459 -410
  108. package/lib/ZudokuContext-BKXGJTmu.js.map +1 -0
  109. package/lib/__vite-browser-external-BYRIRx8p.js +9 -0
  110. package/lib/__vite-browser-external-BYRIRx8p.js.map +1 -0
  111. package/lib/assets/worker-Bf8vjASY.js.map +1 -1
  112. package/lib/{hook-JSRuxV1P.js → hook-sn0zMTkE.js} +2 -2
  113. package/lib/{hook-JSRuxV1P.js.map → hook-sn0zMTkE.js.map} +1 -1
  114. package/lib/{index-Cj-F-4ME.js → index-AjWCJNGC.js} +1180 -1238
  115. package/lib/index-AjWCJNGC.js.map +1 -0
  116. package/lib/ui/Command.js +550 -0
  117. package/lib/ui/Command.js.map +1 -0
  118. package/lib/useExposedProps-ChOIUaS4.js +9 -0
  119. package/lib/useExposedProps-ChOIUaS4.js.map +1 -0
  120. package/lib/zudoku.auth-clerk.js +1 -1
  121. package/lib/zudoku.auth-openid.js +2 -2
  122. package/lib/zudoku.components.js +467 -451
  123. package/lib/zudoku.components.js.map +1 -1
  124. package/lib/zudoku.plugin-api-keys.js +6 -6
  125. package/lib/zudoku.plugin-custom-pages.js +14 -14
  126. package/lib/zudoku.plugin-custom-pages.js.map +1 -1
  127. package/lib/zudoku.plugin-markdown.js +93 -27
  128. package/lib/zudoku.plugin-markdown.js.map +1 -1
  129. package/lib/zudoku.plugin-openapi.js +5 -6
  130. package/lib/zudoku.plugin-openapi.js.map +1 -1
  131. package/package.json +4 -3
  132. package/src/app/entry.client.tsx +4 -2
  133. package/src/app/entry.server.tsx +4 -0
  134. package/src/app/main.css +4 -0
  135. package/src/app/main.tsx +9 -25
  136. package/src/app/standalone.tsx +1 -1
  137. package/src/lib/components/Header.tsx +17 -2
  138. package/src/lib/components/SlotletProvider.tsx +2 -0
  139. package/src/lib/components/SyntaxHighlight.tsx +5 -1
  140. package/src/lib/components/TopNavigation.tsx +58 -24
  141. package/src/lib/components/context/ZudokuContext.ts +28 -20
  142. package/src/lib/components/navigation/Sidebar.tsx +5 -5
  143. package/src/lib/components/navigation/SidebarCategory.tsx +2 -4
  144. package/src/lib/components/navigation/SidebarItem.tsx +1 -3
  145. package/src/lib/components/navigation/utils.ts +11 -16
  146. package/src/lib/core/DevPortalContext.ts +3 -7
  147. package/src/lib/core/plugins.ts +2 -0
  148. package/src/lib/plugins/custom-pages/CustomPage.tsx +2 -2
  149. package/src/lib/plugins/markdown/index.tsx +49 -12
  150. package/src/lib/plugins/markdown/resolver.ts +92 -0
  151. package/src/lib/plugins/openapi/Endpoint.tsx +2 -2
  152. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +1 -1
  153. package/src/lib/plugins/openapi/Sidecar.tsx +1 -1
  154. package/src/lib/plugins/openapi/client/worker.ts +2 -2
  155. package/src/lib/plugins/openapi/index.tsx +1 -1
  156. package/src/lib/ui/Command.tsx +151 -0
  157. package/src/lib/util/MdxComponents.tsx +0 -1
  158. package/src/lib/util/useExposedProps.tsx +8 -2
  159. package/src/lib/util/useScrollToAnchor.ts +1 -1
  160. package/dist/lib/plugins/markdown/generateRoutes.d.ts +0 -3
  161. package/dist/lib/plugins/markdown/generateRoutes.js +0 -21
  162. package/dist/lib/plugins/markdown/generateRoutes.js.map +0 -1
  163. package/dist/lib/ui/Note.d.ts +0 -8
  164. package/dist/lib/ui/Note.js +0 -23
  165. package/dist/lib/ui/Note.js.map +0 -1
  166. package/lib/OperationList-Cea2Yt8e.js.map +0 -1
  167. package/lib/ZudokuContext-D1D8Anlj.js.map +0 -1
  168. package/lib/index-Cj-F-4ME.js.map +0 -1
  169. package/lib/joinPath-B7kNnUX4.js +0 -8
  170. package/lib/joinPath-B7kNnUX4.js.map +0 -1
  171. package/lib/ui/Note.js +0 -51
  172. package/lib/ui/Note.js.map +0 -1
  173. package/lib/useExposedProps-B9K-9GTc.js +0 -9
  174. package/lib/useExposedProps-B9K-9GTc.js.map +0 -1
  175. package/lib/utils-B2yoT99j.js.map +0 -1
  176. package/src/lib/plugins/markdown/generateRoutes.tsx +0 -38
  177. package/src/lib/ui/Note.tsx +0 -58
@@ -1,13 +1,13 @@
1
1
  import { j as e } from "./jsx-runtime-B6kdoens.js";
2
- import { S as m, R as f } from "./SlotletProvider-CPfsBw39.js";
2
+ import { S as m, R as g } from "./SlotletProvider-Da7eFgd2.js";
3
3
  import { i as c } from "./invariant-Caa8-XvF.js";
4
- import { u as d, S as g, a as j, b as v, c as w, d as b, e as x } from "./Select-m1aXZGAP.js";
4
+ import { u as d, S as f, a as j, b as v, c as w, d as b, e as x } from "./Select-Bagt3Bme.js";
5
5
  import { a as k } from "./index.esm-C5mr_sKO.js";
6
6
  import { a as K, L as u, O as N } from "./index-CRo94sKK.js";
7
- import { u as h, a as I, e as S } from "./ZudokuContext-D1D8Anlj.js";
7
+ import { u as h, d as I, g as S } from "./ZudokuContext-BKXGJTmu.js";
8
8
  import { Button as l } from "./ui/Button.js";
9
9
  import { Input as A } from "./ui/Input.js";
10
- import { u as C } from "./hook-JSRuxV1P.js";
10
+ import { u as C } from "./hook-sn0zMTkE.js";
11
11
  import { D as E } from "./DeveloperHint-DHdLXGHA.js";
12
12
  import { RotateCwIcon as P, TrashIcon as D, EyeOffIcon as R, EyeIcon as q, CheckIcon as O, CopyIcon as z } from "lucide-react";
13
13
  import { useState as p } from "react";
@@ -40,7 +40,7 @@ const F = ({ service: t }) => {
40
40
  /* @__PURE__ */ e.jsx(A, { ...n.register("description") }),
41
41
  "Expiration",
42
42
  /* @__PURE__ */ e.jsxs(
43
- g,
43
+ f,
44
44
  {
45
45
  onValueChange: (a) => n.setValue("expiresOn", a),
46
46
  defaultValue: n.getValues("expiresOn"),
@@ -259,7 +259,7 @@ const F = ({ service: t }) => {
259
259
  getRoutes: () => [
260
260
  {
261
261
  element: /* @__PURE__ */ e.jsx(V, {}),
262
- errorElement: /* @__PURE__ */ e.jsx(f, {}),
262
+ errorElement: /* @__PURE__ */ e.jsx(g, {}),
263
263
  children: [
264
264
  {
265
265
  path: "/settings/api-keys",
@@ -1,22 +1,22 @@
1
- import { j as e } from "./jsx-runtime-B6kdoens.js";
1
+ import { j as o } from "./jsx-runtime-B6kdoens.js";
2
2
  import a from "react";
3
- import { P as n } from "./Markdown-1BO9EA_X.js";
3
+ import { P as n } from "./Markdown-BDcCAWwm.js";
4
4
  import { c } from "./cn-BmFQLtkS.js";
5
- import { u } from "./useExposedProps-B9K-9GTc.js";
6
- const l = ({
7
- element: s,
8
- render: t,
9
- prose: o = !0
5
+ import { u as p } from "./useExposedProps-ChOIUaS4.js";
6
+ const u = ({
7
+ element: t,
8
+ render: s,
9
+ prose: e = !0
10
10
  }) => {
11
- const r = u(), m = t ? a.createElement(t, r) : s;
12
- return /* @__PURE__ */ e.jsx("div", { className: c(o && n, "max-w-full"), children: m });
13
- }, g = (s) => ({
14
- getRoutes: () => s.map(({ path: t, ...o }) => ({
15
- path: t,
16
- element: /* @__PURE__ */ e.jsx(l, { ...o })
11
+ const r = p(), m = s ? a.createElement(s, r) : t;
12
+ return /* @__PURE__ */ o.jsx("div", { className: c(e && n, "max-w-full"), children: m });
13
+ }, d = (t) => ({
14
+ getRoutes: () => t.map(({ path: s, ...e }) => ({
15
+ path: s,
16
+ element: /* @__PURE__ */ o.jsx(u, { ...e })
17
17
  }))
18
18
  });
19
19
  export {
20
- g as customPagesPlugin
20
+ d as customPagesPlugin
21
21
  };
22
22
  //# sourceMappingURL=zudoku.plugin-custom-pages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-custom-pages.js","sources":["../src/lib/plugins/custom-pages/CustomPage.tsx","../src/lib/plugins/custom-pages/index.tsx"],"sourcesContent":["import React from \"react\";\nimport { ProseClasses } from \"../../components/Markdown.js\";\nimport { cn } from \"../../util/cn.js\";\nimport { useExposedProps } from \"../../util/useExposedProps.js\";\nimport type { CustomPageConfig } from \"./index.js\";\n\nexport const CustomPage = ({\n element,\n render,\n prose = true,\n}: Omit<CustomPageConfig, \"path\">) => {\n const slotletProps = useExposedProps();\n const content = render ? React.createElement(render, slotletProps) : element;\n\n return (\n <div className={cn(prose && ProseClasses, \"max-w-full\")}>{content}</div>\n );\n};\n","import { type ComponentType, type ReactNode } from \"react\";\nimport type { RouteObject } from \"react-router-dom\";\nimport { type ExposedComponentProps } from \"../../components/SlotletProvider.js\";\nimport type { DevPortalPlugin, NavigationPlugin } from \"../../core/plugins.js\";\nimport { CustomPage } from \"./CustomPage.js\";\n\nexport type CustomPageConfig = {\n path: string;\n prose?: boolean;\n element?: ReactNode;\n render?: ComponentType<ExposedComponentProps>;\n};\n\nexport const customPagesPlugin = (\n config: CustomPageConfig[],\n): DevPortalPlugin & NavigationPlugin => {\n return {\n getRoutes: (): RouteObject[] =>\n config.map(({ path, ...props }) => ({\n path,\n element: <CustomPage {...props} />,\n })),\n };\n};\n"],"names":["CustomPage","element","render","prose","slotletProps","useExposedProps","content","React","jsx","cn","ProseClasses","customPagesPlugin","config","path","props"],"mappings":";;;;;AAMO,MAAMA,IAAa,CAAC;AAAA,EACzB,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,OAAAC,IAAQ;AACV,MAAsC;AACpC,QAAMC,IAAeC,KACfC,IAAUJ,IAASK,EAAM,cAAcL,GAAQE,CAAY,IAAIH;AAGnE,SAAAO,gBAAAA,MAAC,SAAI,WAAWC,EAAGN,KAASO,GAAc,YAAY,GAAI,UAAQJ,EAAA,CAAA;AAEtE,GCJaK,IAAoB,CAC/BC,OAEO;AAAA,EACL,WAAW,MACTA,EAAO,IAAI,CAAC,EAAE,MAAAC,GAAM,GAAGC,SAAa;AAAA,IAClC,MAAAD;AAAA,IACA,SAASL,gBAAAA,EAAAA,IAACR,GAAY,EAAA,GAAGc,EAAO,CAAA;AAAA,EAAA,EAChC;AAAA;"}
1
+ {"version":3,"file":"zudoku.plugin-custom-pages.js","sources":["../src/lib/plugins/custom-pages/CustomPage.tsx","../src/lib/plugins/custom-pages/index.tsx"],"sourcesContent":["import React from \"react\";\nimport { ProseClasses } from \"../../components/Markdown.js\";\nimport { cn } from \"../../util/cn.js\";\nimport { useExposedProps } from \"../../util/useExposedProps.js\";\nimport type { CustomPageConfig } from \"./index.js\";\n\nexport const CustomPage = ({\n element,\n render,\n prose = true,\n}: Omit<CustomPageConfig, \"path\">) => {\n const exposedProps = useExposedProps();\n const content = render ? React.createElement(render, exposedProps) : element;\n\n return (\n <div className={cn(prose && ProseClasses, \"max-w-full\")}>{content}</div>\n );\n};\n","import { type ComponentType, type ReactNode } from \"react\";\nimport type { RouteObject } from \"react-router-dom\";\nimport { type ExposedComponentProps } from \"../../components/SlotletProvider.js\";\nimport type { DevPortalPlugin, NavigationPlugin } from \"../../core/plugins.js\";\nimport { CustomPage } from \"./CustomPage.js\";\n\nexport type CustomPageConfig = {\n path: string;\n prose?: boolean;\n element?: ReactNode;\n render?: ComponentType<ExposedComponentProps>;\n};\n\nexport const customPagesPlugin = (\n config: CustomPageConfig[],\n): DevPortalPlugin & NavigationPlugin => {\n return {\n getRoutes: (): RouteObject[] =>\n config.map(({ path, ...props }) => ({\n path,\n element: <CustomPage {...props} />,\n })),\n };\n};\n"],"names":["CustomPage","element","render","prose","exposedProps","useExposedProps","content","React","jsx","cn","ProseClasses","customPagesPlugin","config","path","props"],"mappings":";;;;;AAMO,MAAMA,IAAa,CAAC;AAAA,EACzB,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,OAAAC,IAAQ;AACV,MAAsC;AACpC,QAAMC,IAAeC,KACfC,IAAUJ,IAASK,EAAM,cAAcL,GAAQE,CAAY,IAAIH;AAGnE,SAAAO,gBAAAA,MAAC,SAAI,WAAWC,EAAGN,KAASO,GAAc,YAAY,GAAI,UAAQJ,EAAA,CAAA;AAEtE,GCJaK,IAAoB,CAC/BC,OAEO;AAAA,EACL,WAAW,MACTA,EAAO,IAAI,CAAC,EAAE,MAAAC,GAAM,GAAGC,SAAa;AAAA,IAClC,MAAAD;AAAA,IACA,SAASL,gBAAAA,EAAAA,IAACR,GAAY,EAAA,GAAGc,EAAO,CAAA;AAAA,EAAA,EAChC;AAAA;"}
@@ -1,32 +1,98 @@
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-BEOcOICU.js"), { default: m, ...l } = await p();
10
- return {
11
- element: /* @__PURE__ */ u.jsx(
12
- i,
13
- {
14
- mdxComponent: m,
15
- ...l,
16
- defaultOptions: n
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-DKMH_t0f.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
+ };
17
88
  }
18
- )
19
- };
20
- }
21
- } : [];
22
- }), f = ({
23
- markdownFiles: t,
24
- defaultOptions: e,
25
- filesPath: n
26
- }) => ({
27
- getRoutes: () => x(t, n, e)
89
+ };
90
+ t.set(r, h);
91
+ })
92
+ ), [...t.values()];
93
+ }
28
94
  });
29
95
  export {
30
- f as markdownPlugin
96
+ C as markdownPlugin
31
97
  };
32
98
  //# sourceMappingURL=zudoku.plugin-markdown.js.map
@@ -1 +1 @@
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
+ {"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,16 +1,15 @@
1
1
  import "./jsx-runtime-B6kdoens.js";
2
- import { o as u } from "./index-Cj-F-4ME.js";
3
- import "./ZudokuContext-D1D8Anlj.js";
2
+ import { o as s } from "./index-AjWCJNGC.js";
3
+ import "./ZudokuContext-BKXGJTmu.js";
4
4
  import "lucide-react";
5
5
  import "zudoku/openapi-worker";
6
- import "./hook-JSRuxV1P.js";
7
- import "./Markdown-1BO9EA_X.js";
6
+ import "./hook-sn0zMTkE.js";
7
+ import "./Markdown-BDcCAWwm.js";
8
8
  import "./ui/Button.js";
9
- import "./joinPath-B7kNnUX4.js";
10
9
  import "./urql-core-KJnLL26g.js";
11
10
  import "./router-BsfSoK2j.js";
12
11
  import "./index-CRo94sKK.js";
13
12
  export {
14
- u as openApiPlugin
13
+ s as openApiPlugin
15
14
  };
16
15
  //# 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.13.7",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -147,6 +147,7 @@
147
147
  "chokidar": "3.6.0",
148
148
  "class-variance-authority": "0.7.0",
149
149
  "clsx": "2.1.1",
150
+ "cmdk": "1.0.4",
150
151
  "dotenv": "16.4.5",
151
152
  "embla-carousel-react": "8.3.1",
152
153
  "express": "4.21.1",
@@ -167,7 +168,7 @@
167
168
  "posthog-node": "4.2.1",
168
169
  "prism-react-renderer": "2.4.0",
169
170
  "prismjs": "1.29.0",
170
- "react-error-boundary": "4.0.13",
171
+ "react-error-boundary": "4.1.2",
171
172
  "react-hook-form": "7.53.0",
172
173
  "react-is": "18.3.1",
173
174
  "react-markdown": "9.0.1",
@@ -199,7 +200,7 @@
199
200
  "zustand": "5.0.0"
200
201
  },
201
202
  "devDependencies": {
202
- "@types/express": "4.17.21",
203
+ "@types/express": "5.0.0",
203
204
  "@types/har-format": "1.2.15",
204
205
  "@types/json-schema": "7.0.15",
205
206
  "@types/mdx": "2.0.13",
@@ -20,8 +20,10 @@ if (root.childElementCount > 0) {
20
20
  }
21
21
 
22
22
  async function hydrateLazyRoutes(routes: RouteObject[]) {
23
- const path = window.location.pathname.slice(config.basePath?.length ?? 0);
24
- const lazyMatches = matchRoutes(routes, path)?.filter((m) => m.route.lazy);
23
+ const path = window.location.pathname;
24
+ const lazyMatches = matchRoutes(routes, path, config.basePath)?.filter(
25
+ (m) => m.route.lazy,
26
+ );
25
27
 
26
28
  if (lazyMatches?.length) {
27
29
  await Promise.all(
@@ -96,6 +96,10 @@ 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
+
99
103
  response.write(
100
104
  htmlStart.replace(
101
105
  "<!--app-helmet-->",
package/src/app/main.css CHANGED
@@ -103,6 +103,10 @@
103
103
  @apply h-full overscroll-none;
104
104
  }
105
105
 
106
+ details summary {
107
+ @apply cursor-pointer;
108
+ }
109
+
106
110
  #root {
107
111
  @apply min-h-screen w-full;
108
112
  }
package/src/app/main.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { redirect, type RouteObject } from "react-router-dom";
1
+ import { 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";
@@ -10,10 +10,8 @@ import { configuredSidebar } from "virtual:zudoku-sidebar";
10
10
  import "virtual:zudoku-theme.css";
11
11
  import { DevPortal, Layout, RouterError } from "zudoku/components";
12
12
  import type { ZudokuConfig } from "../config/config.js";
13
- import { traverseSidebar } from "../lib/components/navigation/utils.js";
14
13
  import type { ZudokuContextOptions } from "../lib/core/DevPortalContext.js";
15
14
  import { isNavigationPlugin } from "../lib/core/plugins.js";
16
- import { joinPath } from "../lib/util/joinPath.js";
17
15
 
18
16
  export const convertZudokuConfigToOptions = (
19
17
  config: ZudokuConfig,
@@ -67,9 +65,7 @@ export const convertZudokuConfigToOptions = (
67
65
  };
68
66
  };
69
67
 
70
- export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
71
- const options = convertZudokuConfigToOptions(config);
72
-
68
+ export const getRoutesByOptions = (options: ZudokuContextOptions) => {
73
69
  const allPlugins = [
74
70
  ...(options.plugins ? options.plugins : []),
75
71
  ...(options.authentication?.getAuthenticationPlugin
@@ -77,27 +73,8 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
77
73
  : []),
78
74
  ];
79
75
 
80
- const topNavRedirects =
81
- options.topNavigation?.flatMap((topNavItem) => {
82
- if (!options.sidebars?.[topNavItem.id]) return [];
83
-
84
- const first =
85
- topNavItem.default ??
86
- traverseSidebar(options.sidebars[topNavItem.id], (item) => {
87
- if (item.type === "doc") return joinPath(topNavItem.id, item.id);
88
- });
89
-
90
- if (!first) return [];
91
-
92
- return {
93
- path: topNavItem.id,
94
- loader: () => redirect(joinPath(first)),
95
- } satisfies RouteObject;
96
- }) ?? [];
97
-
98
76
  const routes = allPlugins
99
77
  .flatMap((plugin) => (isNavigationPlugin(plugin) ? plugin.getRoutes() : []))
100
- .concat(topNavRedirects)
101
78
  .concat({
102
79
  path: "*",
103
80
  loader: () => {
@@ -105,6 +82,13 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
105
82
  },
106
83
  });
107
84
 
85
+ return routes;
86
+ };
87
+
88
+ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
89
+ const options = convertZudokuConfigToOptions(config);
90
+ const routes = getRoutesByOptions(options);
91
+
108
92
  return [
109
93
  {
110
94
  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
@@ -17,6 +17,7 @@ import {
17
17
  DropdownMenuTrigger,
18
18
  } from "../ui/DropdownMenu.js";
19
19
  import { cn } from "../util/cn.js";
20
+ import { joinPath } from "../util/joinPath.js";
20
21
  import { Banner } from "./Banner.js";
21
22
  import { useTheme } from "./context/ThemeContext.js";
22
23
  import { useZudoku } from "./context/ZudokuContext.js";
@@ -70,14 +71,28 @@ export const Header = memo(function HeaderInner() {
70
71
  {page?.logo && (
71
72
  <>
72
73
  <img
73
- src={page.logo.src.light}
74
+ src={
75
+ /https?:\/\//.test(page.logo.src.light)
76
+ ? page.logo.src.light
77
+ : joinPath(
78
+ import.meta.env.BASE_URL,
79
+ page.logo.src.light,
80
+ )
81
+ }
74
82
  alt={page.logo.alt ?? page.pageTitle}
75
83
  style={{ width: page.logo.width }}
76
84
  className={cn("h-10", isDark && "hidden")}
77
85
  loading="lazy"
78
86
  />
79
87
  <img
80
- src={page.logo.src.dark}
88
+ src={
89
+ /https?:\/\//.test(page.logo.src.dark)
90
+ ? page.logo.src.dark
91
+ : joinPath(
92
+ import.meta.env.BASE_URL,
93
+ page.logo.src.dark,
94
+ )
95
+ }
81
96
  alt={page.logo.alt ?? page.pageTitle}
82
97
  style={{ width: page.logo.width }}
83
98
  className={cn("h-10", !isDark && "hidden")}
@@ -8,6 +8,7 @@ import { isValidElementType } from "react-is";
8
8
  import {
9
9
  type Location,
10
10
  type NavigateFunction,
11
+ type Params,
11
12
  type SetURLSearchParams,
12
13
  } from "react-router-dom";
13
14
  import { useExposedProps } from "../util/useExposedProps.js";
@@ -38,6 +39,7 @@ export type ExposedComponentProps = {
38
39
  navigate: NavigateFunction;
39
40
  searchParams: URLSearchParams;
40
41
  setSearchParams: SetURLSearchParams;
42
+ params: Params;
41
43
  };
42
44
 
43
45
  export const Slotlet = ({ name }: { name: string }) => {
@@ -46,6 +46,10 @@ type SyntaxHighlightProps = {
46
46
  language?: string;
47
47
  } & Omit<HighlightProps, "children" | "language">;
48
48
 
49
+ const remapLang = {
50
+ mdx: "md",
51
+ } as Record<string, string>;
52
+
49
53
  export const SyntaxHighlight = ({
50
54
  copyable = true,
51
55
  language = "plain",
@@ -61,7 +65,7 @@ export const SyntaxHighlight = ({
61
65
  return (
62
66
  <Highlight
63
67
  theme={isDark ? themes.vsDark : themes.github}
64
- language={language}
68
+ language={remapLang[language] ?? language}
65
69
  {...props}
66
70
  >
67
71
  {({ className, style, tokens, getLineProps, getTokenProps }) => (
@@ -1,8 +1,11 @@
1
1
  import { cx } from "class-variance-authority";
2
- import { NavLink } from "react-router-dom";
3
-
2
+ import { Suspense } from "react";
3
+ import { Link } from "react-router-dom";
4
4
  import { useAuth } from "../authentication/hook.js";
5
- import { useZudoku } from "./context/ZudokuContext.js";
5
+ import { TopNavigationItem } from "../../config/validators/validate.js";
6
+ import { joinPath } from "../util/joinPath.js";
7
+ import { useCurrentNavigation, useZudoku } from "./context/ZudokuContext.js";
8
+ import { traverseSidebar } from "./navigation/utils.js";
6
9
 
7
10
  export const isHiddenItem =
8
11
  (isAuthenticated?: boolean) =>
@@ -25,26 +28,57 @@ export const TopNavigation = () => {
25
28
  }
26
29
 
27
30
  return (
28
- <nav className="hidden lg:block border-b text-sm px-12 h-[--top-nav-height]">
29
- <ul className="flex flex-row items-center gap-8">
30
- {topNavigation.filter(isHiddenItem(isAuthenticated)).map((item) => (
31
- <li key={item.label}>
32
- <NavLink
33
- className={({ isActive }) =>
34
- cx(
35
- "block py-3.5 font-medium -mb-px border-b-2",
36
- isActive
37
- ? "border-primary text-foreground"
38
- : "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
39
- )
40
- }
41
- to={item.id}
42
- >
43
- {item.label}
44
- </NavLink>
45
- </li>
46
- ))}
47
- </ul>
48
- </nav>
31
+ <Suspense>
32
+ <nav className="hidden lg:block border-b text-sm px-12 h-[--top-nav-height]">
33
+ <ul className="flex flex-row items-center gap-8">
34
+ {topNavigation.filter(isHiddenItem(isAuthenticated)).map((item) => (
35
+ <li key={item.id}>
36
+ <TopNavItem {...item} />
37
+ </li>
38
+ ))}
39
+ </ul>
40
+ </nav>
41
+ </Suspense>
42
+ );
43
+ };
44
+
45
+ const TopNavItem = ({ id, label, default: defaultLink }: TopNavigationItem) => {
46
+ const { sidebars } = useZudoku();
47
+ const nav = useCurrentNavigation();
48
+ const currentSidebar = sidebars[id];
49
+
50
+ // TODO: This is a bit of a hack to get the first link in the sidebar
51
+ // We should really process this when we load the config so we can validate
52
+ // that the sidebar is actually set. In this case we just fall back to linking
53
+ // to the id if we can't resolve a sidebar.
54
+ const first =
55
+ defaultLink ??
56
+ (currentSidebar
57
+ ? traverseSidebar(currentSidebar, (item) => {
58
+ if (item.type === "doc") return joinPath(item.id);
59
+ })
60
+ : joinPath(id));
61
+
62
+ if (!first) {
63
+ throw new Error(
64
+ `No links found in top navigation for top navigation '${id}'. Check that the sidebar isn't empty or that a default link set.`,
65
+ );
66
+ }
67
+
68
+ // Manually set the active sidebar based on our logic of what is active
69
+ const isActive = nav.data.topNavItem?.id === id;
70
+
71
+ return (
72
+ <Link
73
+ className={cx(
74
+ "block py-3.5 font-medium -mb-px border-b-2",
75
+ isActive
76
+ ? "border-primary text-foreground"
77
+ : "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
78
+ )}
79
+ to={first}
80
+ >
81
+ {label}
82
+ </Link>
49
83
  );
50
84
  };