zudoku 0.3.0-dev.83 → 0.3.0-dev.84

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 (185) hide show
  1. package/cli.js +5 -1
  2. package/dist/app/demo.js +5 -4
  3. package/dist/app/demo.js.map +1 -1
  4. package/dist/app/main.js +3 -1
  5. package/dist/app/main.js.map +1 -1
  6. package/dist/app/standalone.js +5 -4
  7. package/dist/app/standalone.js.map +1 -1
  8. package/dist/config/validators/ResolvedSidebarSchema.d.ts +18 -0
  9. package/dist/config/validators/ResolvedSidebarSchema.js +76 -0
  10. package/dist/config/validators/ResolvedSidebarSchema.js.map +1 -0
  11. package/dist/config/validators/SidebarSchema.d.ts +177 -0
  12. package/dist/config/validators/SidebarSchema.js +71 -0
  13. package/dist/config/validators/SidebarSchema.js.map +1 -0
  14. package/dist/config/validators/validate.d.ts +411 -59
  15. package/dist/config/validators/validate.js +22 -4
  16. package/dist/config/validators/validate.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/lib/components/DevPortal.js +1 -1
  19. package/dist/lib/components/DevPortal.js.map +1 -1
  20. package/dist/lib/components/Header.js.map +1 -1
  21. package/dist/lib/components/Heading.d.ts +1 -1
  22. package/dist/lib/components/Layout.js +2 -2
  23. package/dist/lib/components/Layout.js.map +1 -1
  24. package/dist/lib/components/TopNavigation.js +5 -5
  25. package/dist/lib/components/TopNavigation.js.map +1 -1
  26. package/dist/lib/components/context/DevPortalProvider.d.ts +9 -3
  27. package/dist/lib/components/context/DevPortalProvider.js +11 -23
  28. package/dist/lib/components/context/DevPortalProvider.js.map +1 -1
  29. package/dist/lib/components/context/ThemeContext.d.ts +1 -4
  30. package/dist/lib/components/context/ThemeContext.js +3 -29
  31. package/dist/lib/components/context/ThemeContext.js.map +1 -1
  32. package/dist/lib/components/context/ThemeProvider.d.ts +4 -0
  33. package/dist/lib/components/context/ThemeProvider.js +23 -0
  34. package/dist/lib/components/context/ThemeProvider.js.map +1 -0
  35. package/dist/lib/components/navigation/Sidebar.d.ts +1 -0
  36. package/dist/lib/components/navigation/Sidebar.js +12 -0
  37. package/dist/lib/components/navigation/Sidebar.js.map +1 -0
  38. package/dist/lib/components/navigation/SidebarBadge.d.ts +22 -0
  39. package/dist/lib/components/navigation/SidebarBadge.js +24 -0
  40. package/dist/lib/components/navigation/SidebarBadge.js.map +1 -0
  41. package/dist/lib/components/navigation/SidebarCategory.d.ts +5 -0
  42. package/dist/lib/components/navigation/SidebarCategory.js +33 -0
  43. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -0
  44. package/dist/lib/components/navigation/SidebarItem.d.ts +12 -0
  45. package/dist/lib/components/navigation/SidebarItem.js +42 -0
  46. package/dist/lib/components/navigation/SidebarItem.js.map +1 -0
  47. package/dist/lib/components/navigation/{SideNavigationWrapper.d.ts → SidebarWrapper.d.ts} +1 -1
  48. package/dist/lib/components/navigation/{SideNavigationWrapper.js → SidebarWrapper.js} +2 -2
  49. package/dist/lib/components/navigation/SidebarWrapper.js.map +1 -0
  50. package/dist/lib/components/navigation/utils.d.ts +16 -0
  51. package/dist/lib/components/navigation/utils.js +85 -0
  52. package/dist/lib/components/navigation/utils.js.map +1 -0
  53. package/dist/lib/core/DevPortalContext.d.ts +9 -32
  54. package/dist/lib/core/DevPortalContext.js +8 -5
  55. package/dist/lib/core/DevPortalContext.js.map +1 -1
  56. package/dist/lib/core/plugins.d.ts +6 -8
  57. package/dist/lib/core/plugins.js.map +1 -1
  58. package/dist/lib/plugins/markdown/MdxPage.js +5 -36
  59. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  60. package/dist/lib/plugins/markdown/generateRoutes.js +20 -43
  61. package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
  62. package/dist/lib/plugins/openapi/Sidecar.js +12 -2
  63. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  64. package/dist/lib/plugins/openapi/index.js +14 -11
  65. package/dist/lib/plugins/openapi/index.js.map +1 -1
  66. package/dist/lib/plugins/openapi/interfaces.d.ts +1 -1
  67. package/dist/lib/util/useScrollToAnchor.js +31 -17
  68. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  69. package/dist/vite/plugin-sidebar.d.ts +3 -0
  70. package/dist/vite/plugin-sidebar.js +23 -0
  71. package/dist/vite/plugin-sidebar.js.map +1 -0
  72. package/dist/vite/plugin.js +2 -0
  73. package/dist/vite/plugin.js.map +1 -1
  74. package/lib/{AuthenticationPlugin-XS0DoAhE.js → AuthenticationPlugin-DgwV0hVu.js} +7 -7
  75. package/lib/{AuthenticationPlugin-XS0DoAhE.js.map → AuthenticationPlugin-DgwV0hVu.js.map} +1 -1
  76. package/lib/{CategoryHeading-DCmchnA1.js → CategoryHeading-BWq12Bfa.js} +3 -3
  77. package/lib/{CategoryHeading-DCmchnA1.js.map → CategoryHeading-BWq12Bfa.js.map} +1 -1
  78. package/lib/{Combination-C442XfGG.js → Combination-DkycFHkm.js} +4 -4
  79. package/lib/{Combination-C442XfGG.js.map → Combination-DkycFHkm.js.map} +1 -1
  80. package/lib/{DevPortalProvider-BWeAysxF.js → DevPortalProvider-CTxoCHIT.js} +375 -417
  81. package/lib/DevPortalProvider-CTxoCHIT.js.map +1 -0
  82. package/lib/DeveloperHint-BQSFXH01.js +10 -0
  83. package/lib/{DeveloperHint-DQVwIery.js.map → DeveloperHint-BQSFXH01.js.map} +1 -1
  84. package/lib/{Input-3IEt27jb.js → Input-BclXSY0g.js} +5 -5
  85. package/lib/{Input-3IEt27jb.js.map → Input-BclXSY0g.js.map} +1 -1
  86. package/lib/{Markdown-QsZ-PHET.js → Markdown-B_Gax7at.js} +1136 -1152
  87. package/lib/{Markdown-QsZ-PHET.js.map → Markdown-B_Gax7at.js.map} +1 -1
  88. package/lib/{MdxPage-CA1WmW14.js → MdxPage-Crlr0GmN.js} +67 -81
  89. package/lib/MdxPage-Crlr0GmN.js.map +1 -0
  90. package/lib/{OperationList-CHK_erYP.js → OperationList-nQ0bd8TU.js} +8 -8
  91. package/lib/{OperationList-CHK_erYP.js.map → OperationList-nQ0bd8TU.js.map} +1 -1
  92. package/lib/Route-CNvxEBnR.js +14 -0
  93. package/lib/{Route-D70pGn9n.js.map → Route-CNvxEBnR.js.map} +1 -1
  94. package/lib/{SlotletProvider-B71hNEUL.js → SlotletProvider-CzMAO73_.js} +12 -12
  95. package/lib/{SlotletProvider-B71hNEUL.js.map → SlotletProvider-CzMAO73_.js.map} +1 -1
  96. package/lib/Spinner-fF-Xv-gw.js +274 -0
  97. package/lib/Spinner-fF-Xv-gw.js.map +1 -0
  98. package/lib/index-7kcHaXD6.js +1771 -0
  99. package/lib/index-7kcHaXD6.js.map +1 -0
  100. package/lib/{index-Bl6YeerK.js → index-CgCPw6Jn.js} +1026 -1043
  101. package/lib/index-CgCPw6Jn.js.map +1 -0
  102. package/lib/{index-BH-Ub36F.js → index-DkuZvRNP.js} +4 -4
  103. package/lib/{index-BH-Ub36F.js.map → index-DkuZvRNP.js.map} +1 -1
  104. package/lib/joinPath-VeNuJa7y.js +8 -0
  105. package/lib/joinPath-VeNuJa7y.js.map +1 -0
  106. package/lib/jsx-runtime-B6kdoens.js +635 -0
  107. package/lib/jsx-runtime-B6kdoens.js.map +1 -0
  108. package/lib/{AnchorLink-BZcpTwOs.js → utils-CzT_9Tsn.js} +258 -214
  109. package/lib/utils-CzT_9Tsn.js.map +1 -0
  110. package/lib/zudoku.auth-clerk.js +1 -1
  111. package/lib/zudoku.auth-openid.js +2 -2
  112. package/lib/zudoku.components.js +1229 -1227
  113. package/lib/zudoku.components.js.map +1 -1
  114. package/lib/zudoku.plugin-api-keys.js +19 -19
  115. package/lib/zudoku.plugin-custom-page.js +2 -2
  116. package/lib/zudoku.plugin-markdown.js +21 -38
  117. package/lib/zudoku.plugin-markdown.js.map +1 -1
  118. package/lib/zudoku.plugin-openapi.js +8 -6
  119. package/lib/zudoku.plugin-openapi.js.map +1 -1
  120. package/package.json +4 -1
  121. package/src/app/demo.tsx +5 -4
  122. package/src/app/main.css +2 -2
  123. package/src/app/main.tsx +3 -1
  124. package/src/app/standalone.tsx +5 -4
  125. package/src/lib/components/DevPortal.tsx +1 -1
  126. package/src/lib/components/Header.tsx +2 -2
  127. package/src/lib/components/Layout.tsx +2 -2
  128. package/src/lib/components/TopNavigation.tsx +5 -5
  129. package/src/lib/components/context/DevPortalProvider.ts +11 -28
  130. package/src/lib/components/context/ThemeContext.tsx +3 -41
  131. package/src/lib/components/context/ThemeProvider.tsx +27 -0
  132. package/src/lib/components/navigation/{SideNavigation.tsx → Sidebar.tsx} +7 -7
  133. package/src/lib/components/navigation/SidebarBadge.tsx +40 -0
  134. package/src/lib/components/navigation/SidebarCategory.tsx +105 -0
  135. package/src/lib/components/navigation/SidebarItem.tsx +96 -0
  136. package/src/lib/components/navigation/{SideNavigationWrapper.tsx → SidebarWrapper.tsx} +1 -1
  137. package/src/lib/components/navigation/utils.ts +120 -0
  138. package/src/lib/core/DevPortalContext.ts +12 -44
  139. package/src/lib/core/plugins.ts +6 -13
  140. package/src/lib/plugins/markdown/MdxPage.tsx +14 -50
  141. package/src/lib/plugins/markdown/generateRoutes.tsx +29 -57
  142. package/src/lib/plugins/openapi/Sidecar.tsx +15 -2
  143. package/src/lib/plugins/openapi/index.tsx +17 -23
  144. package/src/lib/plugins/openapi/interfaces.ts +1 -1
  145. package/src/lib/util/useScrollToAnchor.ts +39 -18
  146. package/dist/lib/components/navigation/SideNavigation.d.ts +0 -1
  147. package/dist/lib/components/navigation/SideNavigation.js +0 -12
  148. package/dist/lib/components/navigation/SideNavigation.js.map +0 -1
  149. package/dist/lib/components/navigation/SideNavigationCategory.d.ts +0 -4
  150. package/dist/lib/components/navigation/SideNavigationCategory.js +0 -26
  151. package/dist/lib/components/navigation/SideNavigationCategory.js.map +0 -1
  152. package/dist/lib/components/navigation/SideNavigationItem.d.ts +0 -9
  153. package/dist/lib/components/navigation/SideNavigationItem.js +0 -44
  154. package/dist/lib/components/navigation/SideNavigationItem.js.map +0 -1
  155. package/dist/lib/components/navigation/SideNavigationWrapper.js.map +0 -1
  156. package/dist/lib/components/navigation/useNavigationCollapsibleState.d.ts +0 -9
  157. package/dist/lib/components/navigation/useNavigationCollapsibleState.js +0 -28
  158. package/dist/lib/components/navigation/useNavigationCollapsibleState.js.map +0 -1
  159. package/dist/lib/components/navigation/util.d.ts +0 -8
  160. package/dist/lib/components/navigation/util.js +0 -15
  161. package/dist/lib/components/navigation/util.js.map +0 -1
  162. package/dist/lib/plugins/openapi/MethodBadge.d.ts +0 -13
  163. package/dist/lib/plugins/openapi/MethodBadge.js +0 -26
  164. package/dist/lib/plugins/openapi/MethodBadge.js.map +0 -1
  165. package/dist/lib/util/traverseNavigation.d.ts +0 -6
  166. package/dist/lib/util/traverseNavigation.js +0 -30
  167. package/dist/lib/util/traverseNavigation.js.map +0 -1
  168. package/lib/AnchorLink-BZcpTwOs.js.map +0 -1
  169. package/lib/DevPortalProvider-BWeAysxF.js.map +0 -1
  170. package/lib/DeveloperHint-DQVwIery.js +0 -10
  171. package/lib/MdxPage-CA1WmW14.js.map +0 -1
  172. package/lib/Route-D70pGn9n.js +0 -13
  173. package/lib/Spinner-Coi7ORUV.js +0 -244
  174. package/lib/Spinner-Coi7ORUV.js.map +0 -1
  175. package/lib/index-Bl6YeerK.js.map +0 -1
  176. package/lib/index-Dt-pU7Vu.js +0 -916
  177. package/lib/index-Dt-pU7Vu.js.map +0 -1
  178. package/lib/jsx-runtime-CJBdjYYx.js +0 -1526
  179. package/lib/jsx-runtime-CJBdjYYx.js.map +0 -1
  180. package/src/lib/components/navigation/SideNavigationCategory.tsx +0 -72
  181. package/src/lib/components/navigation/SideNavigationItem.tsx +0 -148
  182. package/src/lib/components/navigation/useNavigationCollapsibleState.ts +0 -42
  183. package/src/lib/components/navigation/util.ts +0 -38
  184. package/src/lib/plugins/openapi/MethodBadge.tsx +0 -36
  185. package/src/lib/util/traverseNavigation.ts +0 -55
@@ -1,19 +1,19 @@
1
- import { a as f, j as e, O as g } from "./jsx-runtime-CJBdjYYx.js";
2
- import { a as p, R as j } from "./SlotletProvider-B71hNEUL.js";
3
- import { u as v, a as u, I as k, S as w, b, c as K, d as N, e as E, f as y } from "./Input-3IEt27jb.js";
4
- import { L as x } from "./index-Dt-pU7Vu.js";
5
- import { u as h, x as A, y as S } from "./DevPortalProvider-BWeAysxF.js";
6
- import { B as l, p as I } from "./Combination-C442XfGG.js";
7
- import { D as P } from "./DeveloperHint-DQVwIery.js";
1
+ import { j as e } from "./jsx-runtime-B6kdoens.js";
2
+ import { a as p, R as f } from "./SlotletProvider-CzMAO73_.js";
3
+ import { u as g, a as u, I as j, S as v, b as k, c as w, d as b, e as K, f as y } from "./Input-BclXSY0g.js";
4
+ import { b as N, L as x, O as E } from "./index-7kcHaXD6.js";
5
+ import { u as h, q as A, t as S } from "./DevPortalProvider-CTxoCHIT.js";
6
+ import { B as l, p as I } from "./Combination-DkycFHkm.js";
7
+ import { D as P } from "./DeveloperHint-BQSFXH01.js";
8
8
  import { useState as D } from "react";
9
- import { c as d, a as C } from "./Markdown-QsZ-PHET.js";
9
+ import { c as d, a as q } from "./Markdown-B_Gax7at.js";
10
10
  /**
11
11
  * @license lucide-react v0.378.0 - ISC
12
12
  *
13
13
  * This source code is licensed under the ISC license.
14
14
  * See the LICENSE file in the root directory of this source tree.
15
15
  */
16
- const R = d("EyeOff", [
16
+ const C = d("EyeOff", [
17
17
  ["path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24", key: "1jxqfv" }],
18
18
  [
19
19
  "path",
@@ -34,7 +34,7 @@ const R = d("EyeOff", [
34
34
  * This source code is licensed under the ISC license.
35
35
  * See the LICENSE file in the root directory of this source tree.
36
36
  */
37
- const q = d("Eye", [
37
+ const R = d("Eye", [
38
38
  ["path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z", key: "rwhkz3" }],
39
39
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
40
40
  ]);
@@ -71,7 +71,7 @@ class z extends Error {
71
71
  }
72
72
  }
73
73
  const F = ({ service: t }) => {
74
- const s = h(), r = f(), n = v({
74
+ const s = h(), r = N(), n = g({
75
75
  defaultValues: {
76
76
  expiresOn: "30"
77
77
  }
@@ -95,16 +95,16 @@ const F = ({ service: t }) => {
95
95
  onSubmit: n.handleSubmit((i) => o.mutate(i)),
96
96
  children: /* @__PURE__ */ e.jsxs("div", { className: "flex gap-2 flex-col", children: [
97
97
  "Note",
98
- /* @__PURE__ */ e.jsx(k, { ...n.register("description") }),
98
+ /* @__PURE__ */ e.jsx(j, { ...n.register("description") }),
99
99
  "Expiration",
100
100
  /* @__PURE__ */ e.jsxs(
101
- w,
101
+ v,
102
102
  {
103
103
  onValueChange: (i) => n.setValue("expiresOn", i),
104
104
  defaultValue: n.getValues("expiresOn"),
105
105
  children: [
106
- /* @__PURE__ */ e.jsx(b, { children: /* @__PURE__ */ e.jsx(K, {}) }),
107
- /* @__PURE__ */ e.jsx(N, { children: /* @__PURE__ */ e.jsxs(E, { children: [
106
+ /* @__PURE__ */ e.jsx(k, { children: /* @__PURE__ */ e.jsx(w, {}) }),
107
+ /* @__PURE__ */ e.jsx(b, { children: /* @__PURE__ */ e.jsxs(K, { children: [
108
108
  [7, 30, 60, 90].map((i) => /* @__PURE__ */ e.jsxs(y, { value: String(i), children: [
109
109
  i,
110
110
  " days"
@@ -127,7 +127,7 @@ const F = ({ service: t }) => {
127
127
  return s.setDate(s.getDate() + t), s.toISOString();
128
128
  }, T = () => {
129
129
  const t = I();
130
- return t.isAuthEnabled && t.isPending ? null : t.isAuthenticated ? /* @__PURE__ */ e.jsx(g, {}) : t.isAuthEnabled ? /* @__PURE__ */ e.jsxs("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: [
130
+ return t.isAuthEnabled && t.isPending ? null : t.isAuthenticated ? /* @__PURE__ */ e.jsx(E, {}) : t.isAuthEnabled ? /* @__PURE__ */ e.jsxs("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: [
131
131
  "Please login first to view this page",
132
132
  /* @__PURE__ */ e.jsx(l, { onClick: () => t.login(), children: "Login" })
133
133
  ] }) : /* @__PURE__ */ e.jsx("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: /* @__PURE__ */ e.jsxs(P, { className: "max-w-[600px]", children: [
@@ -174,7 +174,7 @@ const F = ({ service: t }) => {
174
174
  ] }) : /* @__PURE__ */ e.jsx(
175
175
  "ul",
176
176
  {
177
- className: C(
177
+ className: q(
178
178
  "grid grid-cols-1 rounded border",
179
179
  "lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]"
180
180
  ),
@@ -240,7 +240,7 @@ const F = ({ service: t }) => {
240
240
  variant: "outline",
241
241
  onClick: () => r((n) => !n),
242
242
  size: "icon",
243
- children: s ? /* @__PURE__ */ e.jsx(R, { size: 16 }) : /* @__PURE__ */ e.jsx(q, { size: 16 })
243
+ children: s ? /* @__PURE__ */ e.jsx(C, { size: 16 }) : /* @__PURE__ */ e.jsx(R, { size: 16 })
244
244
  }
245
245
  )
246
246
  ] });
@@ -304,7 +304,7 @@ const F = ({ service: t }) => {
304
304
  getRoutes: () => [
305
305
  {
306
306
  element: /* @__PURE__ */ e.jsx(T, {}),
307
- errorElement: /* @__PURE__ */ e.jsx(j, {}),
307
+ errorElement: /* @__PURE__ */ e.jsx(f, {}),
308
308
  children: [
309
309
  {
310
310
  path: "/settings/api-keys",
@@ -1,5 +1,5 @@
1
- import { j as m } from "./jsx-runtime-CJBdjYYx.js";
2
- import { P as o } from "./Markdown-QsZ-PHET.js";
1
+ import { j as m } from "./jsx-runtime-B6kdoens.js";
2
+ import { P as o } from "./Markdown-B_Gax7at.js";
3
3
  const l = (s) => ({
4
4
  getRoutes: () => s.map(({ path: e, element: t }) => ({
5
5
  path: e,
@@ -1,48 +1,31 @@
1
- import { j as o, N as x } from "./jsx-runtime-CJBdjYYx.js";
2
- import { v as d, z as g, l as h } from "./DevPortalProvider-BWeAysxF.js";
3
- const f = (t, e) => {
4
- const a = Object.entries(t).flatMap(
5
- ([n, m]) => {
6
- const r = n.match(/pages\/(.*).mdx?$/), s = r == null ? void 0 : r.at(1);
7
- if (!s) return [];
8
- const i = s.split("/");
1
+ import { j as m } from "./jsx-runtime-B6kdoens.js";
2
+ const u = (t, e) => Object.entries(t).flatMap(([a, r]) => {
3
+ const n = a.match(/pages\/(.*).mdx?$/), o = n == null ? void 0 : n.at(1);
4
+ if (!o) return [];
5
+ const s = o.split("/");
6
+ return {
7
+ path: s.at(-1) === "index" ? s.slice(0, -1).join("/") : o,
8
+ lazy: async () => {
9
+ const { MdxPage: i } = await import("./MdxPage-Crlr0GmN.js"), { default: p, ...c } = await r();
9
10
  return {
10
- path: i.at(-1) === "index" ? i.slice(0, -1).join("/") : s,
11
- lazy: async () => {
12
- const { MdxPage: u } = await import("./MdxPage-CA1WmW14.js"), { default: c, ...l } = await m();
13
- return {
14
- element: /* @__PURE__ */ o.jsx(
15
- u,
16
- {
17
- mdxComponent: c,
18
- ...l,
19
- defaultOptions: e
20
- }
21
- )
22
- };
23
- }
11
+ element: /* @__PURE__ */ m.jsx(
12
+ i,
13
+ {
14
+ mdxComponent: p,
15
+ ...c,
16
+ defaultOptions: e
17
+ }
18
+ )
24
19
  };
25
20
  }
26
- ), p = Array.from(
27
- new Set(a.map((n) => n.path.split("/").at(0)))
28
- ).map((n) => ({
29
- path: `/${n}`,
30
- element: /* @__PURE__ */ o.jsx(j, {})
31
- }));
32
- return [...a, ...p];
33
- }, j = () => {
34
- const t = d();
35
- return t ? g(t, (e, a) => {
36
- if (!("children" in e || !h(e)))
37
- return /* @__PURE__ */ o.jsx(x, { to: a, replace: !0 });
38
- }) : null;
39
- }, w = ({
21
+ };
22
+ }), g = ({
40
23
  markdownFiles: t,
41
24
  defaultOptions: e
42
25
  }) => ({
43
- getRoutes: () => f(t, e)
26
+ getRoutes: () => u(t, e)
44
27
  });
45
28
  export {
46
- w as markdownPlugin
29
+ g as markdownPlugin
47
30
  };
48
31
  //# 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 { Navigate, type RouteObject } from \"react-router-dom\";\nimport { useTopNavigationItem } from \"../../components/context/DevPortalProvider.js\";\nimport { isPathItem } from \"../../components/navigation/util.js\";\nimport { traverseNavigation } from \"../../util/traverseNavigation.js\";\n\nimport {\n MarkdownPluginDefaultOptions,\n MarkdownPluginOptions,\n} from \"./index.js\";\n\nexport const generateRoutes = (\n markdownFiles: MarkdownPluginOptions[\"markdownFiles\"],\n defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] => {\n const routes = Object.entries(markdownFiles).flatMap(\n ([file, importPromise]) => {\n // @todo we can pass in the folder name and then filter the markdown files based on that path\n const match = file.match(/pages\\/(.*).mdx?$/);\n const path = match?.at(1);\n\n if (!path) return [];\n\n const pathSegments = path.split(\"/\");\n const isIndexFile = pathSegments.at(-1) === \"index\";\n const routePath = isIndexFile\n ? pathSegments.slice(0, -1).join(\"/\")\n : path;\n\n return {\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 } satisfies RouteObject;\n },\n );\n\n const rootRoutes: RouteObject[] = Array.from(\n new Set(routes.map((route) => route.path.split(\"/\").at(0))),\n ).map((dir) => ({\n path: `/${dir}`,\n element: <Redirect />,\n }));\n\n return [...routes, ...rootRoutes];\n};\n\nconst Redirect = () => {\n const navItem = useTopNavigationItem();\n\n if (!navItem) return null;\n\n return traverseNavigation(navItem, (node, fullPath) => {\n if (\"children\" in node || !isPathItem(node)) return;\n return <Navigate to={fullPath} replace />;\n });\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};\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}: MarkdownPluginOptions): DevPortalPlugin => ({\n getRoutes: () => generateRoutes(markdownFiles, defaultOptions),\n});\n"],"names":["generateRoutes","markdownFiles","defaultOptions","routes","file","importPromise","match","path","pathSegments","MdxPage","Component","props","jsx","rootRoutes","route","dir","Redirect","navItem","useTopNavigationItem","traverseNavigation","node","fullPath","isPathItem","Navigate","markdownPlugin"],"mappings":";;AAUa,MAAAA,IAAiB,CAC5BC,GACAC,MACkB;AAClB,QAAMC,IAAS,OAAO,QAAQF,CAAa,EAAE;AAAA,IAC3C,CAAC,CAACG,GAAMC,CAAa,MAAM;AAEnB,YAAAC,IAAQF,EAAK,MAAM,mBAAmB,GACtCG,IAAOD,KAAA,gBAAAA,EAAO,GAAG;AAEnB,UAAA,CAACC,EAAM,QAAO;AAEZ,YAAAC,IAAeD,EAAK,MAAM,GAAG;AAM5B,aAAA;AAAA,QACL,MANkBC,EAAa,GAAG,EAAE,MAAM,UAExCA,EAAa,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAClCD;AAAA,QAIF,MAAM,YAAY;AAChB,gBAAM,EAAE,SAAAE,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAMN;AACxC,iBAAA;AAAA,YACL,SACEO,gBAAAA,EAAA;AAAA,cAACH;AAAA,cAAA;AAAA,gBACC,cAAcC;AAAA,gBACb,GAAGC;AAAA,gBACJ,gBAAAT;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAGN;AAAA,MAAA;AAAA,IAEJ;AAAA,EAAA,GAGIW,IAA4B,MAAM;AAAA,IACtC,IAAI,IAAIV,EAAO,IAAI,CAACW,MAAUA,EAAM,KAAK,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAAA,EAAA,EAC1D,IAAI,CAACC,OAAS;AAAA,IACd,MAAM,IAAIA,CAAG;AAAA,IACb,+BAAUC,GAAS,EAAA;AAAA,EACnB,EAAA;AAEF,SAAO,CAAC,GAAGb,GAAQ,GAAGU,CAAU;AAClC,GAEMG,IAAW,MAAM;AACrB,QAAMC,IAAUC;AAEZ,SAACD,IAEEE,EAAmBF,GAAS,CAACG,GAAMC,MAAa;AACrD,QAAI,gBAAcD,KAAQ,CAACE,EAAWF,CAAI;AAC1C,aAAQR,gBAAAA,EAAAA,IAAAW,GAAA,EAAS,IAAIF,GAAU,SAAO,GAAC,CAAA;AAAA,EAAA,CACxC,IALoB;AAMvB,GCtCaG,IAAiB,CAAC;AAAA,EAC7B,eAAAvB;AAAA,EACA,gBAAAC;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,CAAc;AAC/D;"}
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 defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] =>\n Object.entries(markdownFiles).flatMap(([file, importPromise]) => {\n // @todo we can pass in the folder name and then filter the markdown files based on that path\n const match = file.match(/pages\\/(.*).mdx?$/);\n const path = match?.at(1);\n\n if (!path) return [];\n\n const pathSegments = path.split(\"/\");\n const isIndexFile = pathSegments.at(-1) === \"index\";\n const routePath = isIndexFile ? pathSegments.slice(0, -1).join(\"/\") : path;\n\n return {\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 } 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};\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}: MarkdownPluginOptions): DevPortalPlugin => ({\n getRoutes: () => generateRoutes(markdownFiles, defaultOptions),\n});\n"],"names":["generateRoutes","markdownFiles","defaultOptions","file","importPromise","match","path","pathSegments","MdxPage","Component","props","jsx","markdownPlugin"],"mappings":";AAOO,MAAMA,IAAiB,CAC5BC,GACAC,MAEA,OAAO,QAAQD,CAAa,EAAE,QAAQ,CAAC,CAACE,GAAMC,CAAa,MAAM;AAEzD,QAAAC,IAAQF,EAAK,MAAM,mBAAmB,GACtCG,IAAOD,KAAA,gBAAAA,EAAO,GAAG;AAEnB,MAAA,CAACC,EAAM,QAAO;AAEZ,QAAAC,IAAeD,EAAK,MAAM,GAAG;AAI5B,SAAA;AAAA,IACL,MAJkBC,EAAa,GAAG,EAAE,MAAM,UACZA,EAAa,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAAID;AAAA,IAIpE,MAAM,YAAY;AAChB,YAAM,EAAE,SAAAE,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAMN;AACxC,aAAA;AAAA,QACL,SACEO,gBAAAA,EAAA;AAAA,UAACH;AAAA,UAAA;AAAA,YACC,cAAcC;AAAA,YACb,GAAGC;AAAA,YACJ,gBAAAR;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAGN;AAAA,EAAA;AAEJ,CAAC,GCVUU,IAAiB,CAAC;AAAA,EAC7B,eAAAX;AAAA,EACA,gBAAAC;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,CAAc;AAC/D;"}
@@ -1,12 +1,14 @@
1
- import "./jsx-runtime-CJBdjYYx.js";
2
- import { o as f } from "./index-Bl6YeerK.js";
1
+ import "./jsx-runtime-B6kdoens.js";
2
+ import { o as l } from "./index-CgCPw6Jn.js";
3
3
  import "./urql-DrBfkb92.js";
4
- import "./DevPortalProvider-BWeAysxF.js";
4
+ import "./DevPortalProvider-CTxoCHIT.js";
5
5
  import "zudoku/openapi-worker";
6
- import "./Combination-C442XfGG.js";
7
- import "./Markdown-QsZ-PHET.js";
6
+ import "./Combination-DkycFHkm.js";
7
+ import "./Markdown-B_Gax7at.js";
8
+ import "./joinPath-VeNuJa7y.js";
8
9
  import "./router-BiRCp01d.js";
10
+ import "./index-7kcHaXD6.js";
9
11
  export {
10
- f as openApiPlugin
12
+ l as openApiPlugin
11
13
  };
12
14
  //# 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.3.0-dev.83",
3
+ "version": "0.3.0-dev.84",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -102,9 +102,11 @@
102
102
  "class-variance-authority": "0.7.0",
103
103
  "dotenv": "16.4.5",
104
104
  "express": "4.19.2",
105
+ "glob": "^11.0.0",
105
106
  "graphql": "16.9.0",
106
107
  "graphql-type-json": "0.3.2",
107
108
  "graphql-yoga": "5.2.0",
109
+ "gray-matter": "^4.0.3",
108
110
  "loglevel": "^1.9.1",
109
111
  "lru-cache": "10.2.0",
110
112
  "mdx": "0.3.1",
@@ -170,6 +172,7 @@
170
172
  "react-markdown": "9.0.1",
171
173
  "react-router-dom": "6.25.1",
172
174
  "rollup-plugin-visualizer": "^5.12.0",
175
+ "tsx": "4.16.5",
173
176
  "typescript": "5.5.3"
174
177
  },
175
178
  "peerDependencies": {
package/src/app/demo.tsx CHANGED
@@ -32,14 +32,15 @@ createRoot(document.getElementById("root")!).render(
32
32
  },
33
33
  pageTitle: "Developer Portal",
34
34
  }}
35
- navigation={[
35
+ topNavigation={[
36
36
  {
37
+ id: "demo",
37
38
  label: "API Reference",
38
- path: "/demo",
39
- categories: [],
40
39
  },
41
40
  ]}
42
- plugins={[openApiPlugin({ type: "url", input: apiUrl!, path: "/demo" })]}
41
+ plugins={[
42
+ openApiPlugin({ type: "url", input: apiUrl!, navigationId: "demo" }),
43
+ ]}
43
44
  />
44
45
  </StrictMode>,
45
46
  );
package/src/app/main.css CHANGED
@@ -137,10 +137,10 @@
137
137
  --slide-offset: -0.75rem;
138
138
  @apply overflow-hidden;
139
139
  }
140
- [data-animate="true"] .CollapsibleContent[data-state="open"] {
140
+ .CollapsibleContent[data-state="open"] {
141
141
  animation: slideDown 300ms var(--easing);
142
142
  }
143
- [data-animate="true"] .CollapsibleContent[data-state="closed"] {
143
+ .CollapsibleContent[data-state="closed"] {
144
144
  animation: slideUp 300ms var(--easing);
145
145
  }
146
146
 
package/src/app/main.tsx CHANGED
@@ -4,6 +4,7 @@ import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
4
4
  import { configuredAuthProvider } from "virtual:zudoku-auth";
5
5
  import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
6
6
  import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
7
+ import { configuredSidebar } from "virtual:zudoku-sidebar";
7
8
  import "virtual:zudoku-theme.css";
8
9
  import { DevPortal, Layout, RouterError } from "zudoku/components";
9
10
  import { isNavigationPlugin } from "zudoku/internal";
@@ -35,8 +36,9 @@ export const convertZudokuConfigToOptions = (
35
36
  title: "%s | Developer Portal",
36
37
  ...config.metadata,
37
38
  },
39
+ sidebars: configuredSidebar,
40
+ topNavigation: config.topNavigation,
38
41
  mdx: config.mdx,
39
- navigation: config.navigation ?? [],
40
42
  authentication: configuredAuthProvider,
41
43
  plugins: [
42
44
  ...configuredDocsPlugins,
@@ -38,14 +38,15 @@ createRoot(root).render(
38
38
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
39
39
  pageTitle: pageTitle ?? "Developer Portal",
40
40
  }}
41
- navigation={[
41
+ topNavigation={[
42
42
  {
43
+ id: "demo",
43
44
  label: "API Reference",
44
- path: "/",
45
- categories: [],
46
45
  },
47
46
  ]}
48
- plugins={[openApiPlugin({ type: "url", input: apiUrl!, path: "/" })]}
47
+ plugins={[
48
+ openApiPlugin({ type: "url", input: apiUrl!, navigationId: "/" }),
49
+ ]}
49
50
  />
50
51
  </StrictMode>,
51
52
  );
@@ -28,7 +28,7 @@ import {
28
28
  DEFAULT_COMPONENTS,
29
29
  } from "./context/ComponentsContext.js";
30
30
  import { DevPortalProvider } from "./context/DevPortalProvider.js";
31
- import { ThemeProvider } from "./context/ThemeContext.js";
31
+ import { ThemeProvider } from "./context/ThemeProvider.js";
32
32
  import { ViewportAnchorProvider } from "./context/ViewportAnchorContext.js";
33
33
  import { SlotletProvider } from "./SlotletProvider.js";
34
34
 
@@ -3,7 +3,7 @@ import { memo } from "react";
3
3
 
4
4
  import { Link, useLocation } from "react-router-dom";
5
5
  import { useAuth } from "../authentication/hook.js";
6
- import { isProfileMenuPlugin, NavigationItem } from "../core/plugins.js";
6
+ import { isProfileMenuPlugin, ProfileNavigationItem } from "../core/plugins.js";
7
7
  import { Button } from "../ui/Button.js";
8
8
  import {
9
9
  DropdownMenu,
@@ -22,7 +22,7 @@ import { TopNavigation } from "./TopNavigation.js";
22
22
  import { useDevPortal } from "./context/DevPortalProvider.js";
23
23
  import { useTheme } from "./context/ThemeContext.js";
24
24
 
25
- const RecursiveMenu = ({ item }: { item: NavigationItem }) => {
25
+ const RecursiveMenu = ({ item }: { item: ProfileNavigationItem }) => {
26
26
  return item.children ? (
27
27
  <DropdownMenuSub key={item.label}>
28
28
  <DropdownMenuSubTrigger>{item.label}</DropdownMenuSubTrigger>
@@ -7,7 +7,7 @@ import { useScrollToTop } from "../util/useScrollToTop.js";
7
7
  import { useDevPortal } from "./context/DevPortalProvider.js";
8
8
  import { useViewportAnchor } from "./context/ViewportAnchorContext.js";
9
9
  import { Header } from "./Header.js";
10
- import { SideNavigation } from "./navigation/SideNavigation.js";
10
+ import { Sidebar } from "./navigation/Sidebar.js";
11
11
  import { Slotlet } from "./SlotletProvider.js";
12
12
  import { Spinner } from "./Spinner.js";
13
13
 
@@ -47,7 +47,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
47
47
  </div>
48
48
  }
49
49
  >
50
- <SideNavigation />
50
+ <Sidebar />
51
51
  <main
52
52
  className={cn(
53
53
  "dark:border-white/10 translate-x-0 h-full",
@@ -4,17 +4,17 @@ import { NavLink } from "react-router-dom";
4
4
  import { useDevPortal } from "./context/DevPortalProvider.js";
5
5
 
6
6
  export const TopNavigation = () => {
7
- const { navigation } = useDevPortal();
7
+ const { topNavigation } = useDevPortal();
8
8
 
9
- // Hide tope nav if there is only one item
10
- if (navigation.length <= 1) {
9
+ // Hide top nav if there is only one item
10
+ if (topNavigation.length <= 1) {
11
11
  return null;
12
12
  }
13
13
 
14
14
  return (
15
15
  <nav className="border-b text-sm px-12 h-[--top-nav-height]">
16
16
  <ul className="flex flex-row items-center gap-8">
17
- {navigation.map((item) => (
17
+ {topNavigation.map((item) => (
18
18
  <li key={item.label}>
19
19
  <NavLink
20
20
  className={({ isActive }) =>
@@ -25,7 +25,7 @@ export const TopNavigation = () => {
25
25
  : "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
26
26
  )
27
27
  }
28
- to={item.path}
28
+ to={item.id}
29
29
  >
30
30
  {item.label}
31
31
  </NavLink>
@@ -1,8 +1,7 @@
1
1
  import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
2
2
  import { createContext, useContext } from "react";
3
- import { matchPath, useLocation } from "react-router-dom";
3
+ import { useLocation } from "react-router-dom";
4
4
  import { DevPortalContext } from "../../core/DevPortalContext.js";
5
- import { traverseNavigation } from "../../util/traverseNavigation.js";
6
5
 
7
6
  const DevPortalReactContext = createContext<DevPortalContext | undefined>(
8
7
  undefined,
@@ -29,43 +28,27 @@ export const useApiIdentities = () => {
29
28
  };
30
29
 
31
30
  export const useTopNavigationItem = () => {
32
- const { navigation } = useDevPortal();
31
+ const { topNavigation } = useDevPortal();
33
32
  const location = useLocation();
34
33
 
35
- // The `/` path needs this logic because it would always match:
36
- // Only if a leaf node actually matches the current path it is active
37
- for (const item of navigation) {
38
- const foundNavItem = traverseNavigation(item, (_node, fullPath) => {
39
- if (location.pathname === fullPath) {
40
- return item;
41
- }
42
- });
34
+ const firstPart = location.pathname.split("/").at(1);
35
+ if (!firstPart) return;
43
36
 
44
- if (foundNavItem) {
45
- return foundNavItem;
46
- }
47
- }
48
- if (location.pathname === "/") {
49
- return navigation.find((item) => item.path === "/");
50
- }
51
-
52
- return navigation.find(
53
- (item) =>
54
- item.path !== "/" &&
55
- matchPath({ path: item.path, end: false }, location.pathname),
56
- );
37
+ return topNavigation.find((item) => item.id === firstPart);
57
38
  };
58
39
 
59
40
  export const useNavigation = () => {
60
- const { getNavigation } = useDevPortal();
41
+ const { getPluginNavigation, sidebars } = useDevPortal();
61
42
  const navItem = useTopNavigationItem();
62
-
63
- const path = navItem?.path ?? "";
43
+ const path = navItem?.id;
44
+ const currentSidebar = path ? sidebars[path] ?? [] : [];
64
45
 
65
46
  return useSuspenseQuery({
66
47
  queryFn: async () => {
48
+ const pluginSidebar = path ? await getPluginNavigation(path) : [];
49
+
67
50
  return {
68
- items: [...(navItem?.categories ?? []), ...(await getNavigation(path))],
51
+ items: [...currentSidebar, ...pluginSidebar],
69
52
  currentTopNavItem: navItem,
70
53
  };
71
54
  },
@@ -1,46 +1,8 @@
1
- import {
2
- createContext,
3
- type ReactNode,
4
- useCallback,
5
- useContext,
6
- useEffect,
7
- useState,
8
- } from "react";
1
+ import { createContext, useContext } from "react";
9
2
 
10
- const ThemeContext = createContext<readonly [boolean, () => void]>([
3
+ export const ThemeContext = createContext<readonly [boolean, () => void]>([
11
4
  false,
12
5
  () => {},
13
6
  ]);
14
7
 
15
- export const useTheme = () => {
16
- const context = useContext(ThemeContext);
17
- if (!context) {
18
- throw new Error("useTheme must be used within a ThemeProvider");
19
- }
20
- return context;
21
- };
22
-
23
- export const ThemeProvider = (props: { children: ReactNode }) => {
24
- const [dark, setDark] = useState(false);
25
-
26
- // On mount, read the preferred theme from the persistence
27
- useEffect(() => {
28
- const theme = localStorage.getItem("theme");
29
- const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
30
- const isDark = theme === "dark" || (!theme && prefersDark.matches);
31
-
32
- setDark(isDark);
33
- }, [dark]);
34
-
35
- // To toggle between dark and light modes
36
- const toggle = useCallback(() => {
37
- const toggled = !dark;
38
- document.documentElement.classList.toggle("dark", toggled);
39
- localStorage.setItem("theme", toggled ? "dark" : "light");
40
- setDark(toggled);
41
- }, [dark]);
42
-
43
- const value = [dark, toggle] as const;
44
-
45
- return <ThemeContext.Provider value={value} {...props} />;
46
- };
8
+ export const useTheme = () => useContext(ThemeContext);
@@ -0,0 +1,27 @@
1
+ import { ReactNode, useCallback, useEffect, useState } from "react";
2
+ import { ThemeContext } from "./ThemeContext.js";
3
+
4
+ export const ThemeProvider = (props: { children: ReactNode }) => {
5
+ const [dark, setDark] = useState(false);
6
+
7
+ // On mount, read the preferred theme from the persistence
8
+ useEffect(() => {
9
+ const theme = localStorage.getItem("theme");
10
+ const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
11
+ const isDark = theme === "dark" || (!theme && prefersDark.matches);
12
+
13
+ setDark(isDark);
14
+ }, [dark]);
15
+
16
+ // To toggle between dark and light modes
17
+ const toggle = useCallback(() => {
18
+ const toggled = !dark;
19
+ document.documentElement.classList.toggle("dark", toggled);
20
+ localStorage.setItem("theme", toggled ? "dark" : "light");
21
+ setDark(toggled);
22
+ }, [dark]);
23
+
24
+ const value = [dark, toggle] as const;
25
+
26
+ return <ThemeContext.Provider value={value} {...props} />;
27
+ };
@@ -2,23 +2,23 @@ import { useRef } from "react";
2
2
 
3
3
  import { useNavigation } from "../context/DevPortalProvider.js";
4
4
  import { Slotlet } from "../SlotletProvider.js";
5
- import { SideNavigationCategory } from "./SideNavigationCategory.js";
6
- import { SideNavigationWrapper } from "./SideNavigationWrapper.js";
5
+ import { SidebarItem } from "./SidebarItem.js";
6
+ import { SidebarWrapper } from "./SidebarWrapper.js";
7
7
 
8
- export const SideNavigation = () => {
8
+ export const Sidebar = () => {
9
9
  const navRef = useRef<HTMLDivElement | null>(null);
10
10
  const navigation = useNavigation();
11
11
 
12
12
  return (
13
- <SideNavigationWrapper
13
+ <SidebarWrapper
14
14
  ref={navRef}
15
15
  pushMainContent={navigation.data.items.length > 0}
16
16
  >
17
17
  <Slotlet name="zudoku-before-navigation" />
18
- {navigation.data.items.map((category) => (
19
- <SideNavigationCategory key={category.label} category={category} />
18
+ {navigation.data.items.map((item) => (
19
+ <SidebarItem key={item.label} item={item} />
20
20
  ))}
21
21
  <Slotlet name="zudoku-after-navigation" />
22
- </SideNavigationWrapper>
22
+ </SidebarWrapper>
23
23
  );
24
24
  };
@@ -0,0 +1,40 @@
1
+ import { cn } from "../../util/cn.js";
2
+
3
+ export const TextColorMap = {
4
+ green: "text-green-600",
5
+ blue: "text-sky-600",
6
+ yellow: "text-yellow-600",
7
+ red: "text-red-600",
8
+ purple: "text-purple-600",
9
+ indigo: "text-indigo-600",
10
+ gray: "text-gray-600",
11
+ };
12
+
13
+ export const ColorMap = {
14
+ green: "bg-green-400 dark:bg-green-800",
15
+ blue: "bg-sky-400 dark:bg-sky-800",
16
+ yellow: "bg-yellow-400 dark:bg-yellow-800",
17
+ red: "bg-red-400 dark:bg-red-800",
18
+ purple: "bg-purple-400 dark:bg-purple-600",
19
+ indigo: "bg-indigo-400 dark:bg-indigo-600",
20
+ gray: "bg-gray-400 dark:bg-gray-600",
21
+ };
22
+
23
+ export const SidebarBadge = ({
24
+ color,
25
+ label,
26
+ }: {
27
+ color: keyof typeof ColorMap;
28
+ label: string;
29
+ }) => {
30
+ return (
31
+ <span
32
+ className={cn(
33
+ "mt-0.5 flex items-center duration-200 transition-opacity text-center uppercase font-mono text-[0.65rem] font-bold rounded text-background dark:text-zinc-50 h-4 px-1",
34
+ ColorMap[color],
35
+ )}
36
+ >
37
+ {label}
38
+ </span>
39
+ );
40
+ };