zudoku 0.37.1 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/dist/app/main.js +2 -0
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/app/tailwind.js +14 -0
  4. package/dist/app/tailwind.js.map +1 -1
  5. package/dist/config/validators/common.d.ts +287 -18
  6. package/dist/config/validators/common.js +2 -0
  7. package/dist/config/validators/common.js.map +1 -1
  8. package/dist/config/validators/validate.d.ts +107 -7
  9. package/dist/lib/authentication/authentication.d.ts +1 -0
  10. package/dist/lib/authentication/providers/clerk.js +19 -0
  11. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  12. package/dist/lib/authentication/providers/openid.d.ts +1 -0
  13. package/dist/lib/authentication/providers/openid.js +5 -0
  14. package/dist/lib/authentication/providers/openid.js.map +1 -1
  15. package/dist/lib/authentication/providers/supabase.js +5 -0
  16. package/dist/lib/authentication/providers/supabase.js.map +1 -1
  17. package/dist/lib/authentication/state.d.ts +0 -26
  18. package/dist/lib/authentication/state.js +1 -16
  19. package/dist/lib/authentication/state.js.map +1 -1
  20. package/dist/lib/components/Heading.d.ts +1 -1
  21. package/dist/lib/components/Layout.js +5 -10
  22. package/dist/lib/components/Layout.js.map +1 -1
  23. package/dist/lib/components/Main.js +3 -1
  24. package/dist/lib/components/Main.js.map +1 -1
  25. package/dist/lib/components/Pagination.d.ts +10 -0
  26. package/dist/lib/components/Pagination.js +10 -0
  27. package/dist/lib/components/Pagination.js.map +1 -0
  28. package/dist/lib/components/TopNavigation.js +18 -2
  29. package/dist/lib/components/TopNavigation.js.map +1 -1
  30. package/dist/lib/components/navigation/SidebarItem.d.ts +1 -0
  31. package/dist/lib/components/navigation/SidebarItem.js +7 -3
  32. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  33. package/dist/lib/{plugins/markdown → components/navigation}/Toc.js +5 -7
  34. package/dist/lib/components/navigation/Toc.js.map +1 -0
  35. package/dist/lib/core/ZudokuContext.d.ts +7 -0
  36. package/dist/lib/core/ZudokuContext.js +8 -3
  37. package/dist/lib/core/ZudokuContext.js.map +1 -1
  38. package/dist/lib/core/plugins.d.ts +1 -1
  39. package/dist/lib/oas/graphql/index.d.ts +2 -1
  40. package/dist/lib/oas/graphql/index.js +74 -14
  41. package/dist/lib/oas/graphql/index.js.map +1 -1
  42. package/dist/lib/oas/parser/dereference/index.js +2 -0
  43. package/dist/lib/oas/parser/dereference/index.js.map +1 -1
  44. package/dist/lib/oas/parser/index.d.ts +5 -3
  45. package/dist/lib/oas/parser/index.js +0 -22
  46. package/dist/lib/oas/parser/index.js.map +1 -1
  47. package/dist/lib/plugins/api-catalog/index.js +19 -17
  48. package/dist/lib/plugins/api-catalog/index.js.map +1 -1
  49. package/dist/lib/plugins/markdown/MdxPage.js +3 -9
  50. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  51. package/dist/lib/plugins/openapi/ColorizedParam.js +1 -1
  52. package/dist/lib/plugins/openapi/ColorizedParam.js.map +1 -1
  53. package/dist/lib/plugins/openapi/Endpoint.js +1 -1
  54. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  55. package/dist/lib/plugins/openapi/OperationList.d.ts +1 -1
  56. package/dist/lib/plugins/openapi/OperationList.js +29 -9
  57. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  58. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  59. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  60. package/dist/lib/plugins/openapi/ParameterListItem.js +2 -1
  61. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  62. package/dist/lib/plugins/openapi/SchemaList.d.ts +1 -0
  63. package/dist/lib/plugins/openapi/SchemaList.js +52 -0
  64. package/dist/lib/plugins/openapi/SchemaList.js.map +1 -0
  65. package/dist/lib/plugins/openapi/Sidecar.js +29 -5
  66. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  67. package/dist/lib/plugins/openapi/client/GraphQLClient.d.ts +1 -1
  68. package/dist/lib/plugins/openapi/client/GraphQLClient.js +1 -1
  69. package/dist/lib/plugins/openapi/client/GraphQLClient.js.map +1 -1
  70. package/dist/lib/plugins/openapi/client/useCreateQuery.d.ts +6 -2
  71. package/dist/lib/plugins/openapi/client/useCreateQuery.js +5 -5
  72. package/dist/lib/plugins/openapi/client/useCreateQuery.js.map +1 -1
  73. package/dist/lib/plugins/openapi/components/EnumValues.js +1 -1
  74. package/dist/lib/plugins/openapi/components/EnumValues.js.map +1 -1
  75. package/dist/lib/plugins/openapi/graphql/gql.d.ts +6 -2
  76. package/dist/lib/plugins/openapi/graphql/gql.js +3 -2
  77. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  78. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +67 -11
  79. package/dist/lib/plugins/openapi/graphql/graphql.js +34 -5
  80. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  81. package/dist/lib/plugins/openapi/index.js +12 -0
  82. package/dist/lib/plugins/openapi/index.js.map +1 -1
  83. package/dist/lib/plugins/openapi/interfaces.d.ts +26 -0
  84. package/dist/lib/plugins/openapi/playground/Playground.js +1 -1
  85. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  86. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +2 -2
  87. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -1
  88. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.d.ts +1 -2
  89. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js +2 -2
  90. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js.map +1 -1
  91. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.d.ts +0 -1
  92. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js +1 -1
  93. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js.map +1 -1
  94. package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.d.ts +4 -0
  95. package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.js +12 -0
  96. package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.js.map +1 -0
  97. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.d.ts +2 -4
  98. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js +12 -9
  99. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -1
  100. package/dist/lib/plugins/openapi/schema/SchemaView.d.ts +1 -2
  101. package/dist/lib/plugins/openapi/schema/SchemaView.js +30 -52
  102. package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
  103. package/dist/lib/plugins/openapi/schema/utils.d.ts +1 -0
  104. package/dist/lib/plugins/openapi/schema/utils.js +3 -1
  105. package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
  106. package/dist/lib/plugins/openapi/state.d.ts +25 -0
  107. package/dist/lib/plugins/openapi/state.js +18 -0
  108. package/dist/lib/plugins/openapi/state.js.map +1 -0
  109. package/dist/lib/plugins/openapi/util/getRoutes.js +9 -3
  110. package/dist/lib/plugins/openapi/util/getRoutes.js.map +1 -1
  111. package/dist/lib/plugins/search-pagefind/PagefindSearch.js +13 -4
  112. package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -1
  113. package/dist/lib/plugins/search-pagefind/ResultList.js +19 -12
  114. package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -1
  115. package/dist/lib/plugins/search-pagefind/get-results.d.ts +8 -1
  116. package/dist/lib/plugins/search-pagefind/get-results.js +9 -4
  117. package/dist/lib/plugins/search-pagefind/get-results.js.map +1 -1
  118. package/dist/lib/util/traverse.d.ts +2 -8
  119. package/dist/lib/util/traverse.js.map +1 -1
  120. package/dist/lib/util/types.d.ts +7 -0
  121. package/dist/lib/util/types.js +2 -0
  122. package/dist/lib/util/types.js.map +1 -0
  123. package/dist/lib/util/useOnScreen.d.ts +3 -2
  124. package/dist/lib/util/useOnScreen.js +3 -3
  125. package/dist/lib/util/useOnScreen.js.map +1 -1
  126. package/dist/lib/util/useScrollToAnchor.js +18 -12
  127. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  128. package/dist/vite/api/schema-codegen.js +2 -2
  129. package/dist/vite/api/schema-codegen.js.map +1 -1
  130. package/dist/vite/api/schema-codegen.test.js +5 -0
  131. package/dist/vite/api/schema-codegen.test.js.map +1 -1
  132. package/dist/vite/plugin-api.js +12 -8
  133. package/dist/vite/plugin-api.js.map +1 -1
  134. package/lib/{AuthenticationPlugin-Cij2tPWa.js → AuthenticationPlugin-foqdvvkf.js} +3 -3
  135. package/lib/{AuthenticationPlugin-Cij2tPWa.js.map → AuthenticationPlugin-foqdvvkf.js.map} +1 -1
  136. package/lib/{Callout-B2vsR09t.js → Callout-D5frCCJ0.js} +2 -2
  137. package/lib/{Callout-B2vsR09t.js.map → Callout-D5frCCJ0.js.map} +1 -1
  138. package/lib/{Dialog-sbgekbjb.js → Dialog-Dv6WG8RN.js} +5 -5
  139. package/lib/{Dialog-sbgekbjb.js.map → Dialog-Dv6WG8RN.js.map} +1 -1
  140. package/lib/{Markdown-DT5Rrq8_.js → Markdown-aF5FdsNi.js} +1945 -1937
  141. package/lib/{Markdown-DT5Rrq8_.js.map → Markdown-aF5FdsNi.js.map} +1 -1
  142. package/lib/MdxPage-ZW1StNhp.js +83 -0
  143. package/lib/MdxPage-ZW1StNhp.js.map +1 -0
  144. package/lib/{OasProvider-DdEBf2qS.js → OasProvider-Cld9RAMQ.js} +4 -4
  145. package/lib/{OasProvider-DdEBf2qS.js.map → OasProvider-Cld9RAMQ.js.map} +1 -1
  146. package/lib/OperationList-D-OfzJm6.js +5065 -0
  147. package/lib/OperationList-D-OfzJm6.js.map +1 -0
  148. package/lib/Pagination-CYB3nVYx.js +46 -0
  149. package/lib/Pagination-CYB3nVYx.js.map +1 -0
  150. package/lib/SchemaList-Ci1WxRh0.js +148 -0
  151. package/lib/SchemaList-Ci1WxRh0.js.map +1 -0
  152. package/lib/SchemaView-Brn-YxHY.js +345 -0
  153. package/lib/SchemaView-Brn-YxHY.js.map +1 -0
  154. package/lib/{Select-z1Lwl0-J.js → Select-DVFRKf1R.js} +8 -8
  155. package/lib/{Select-z1Lwl0-J.js.map → Select-DVFRKf1R.js.map} +1 -1
  156. package/lib/{SlotletProvider-D8OBnr77.js → SlotletProvider-DXvc0aY6.js} +4 -4
  157. package/lib/{SlotletProvider-D8OBnr77.js.map → SlotletProvider-DXvc0aY6.js.map} +1 -1
  158. package/lib/Toc-YBsgI72s.js +92 -0
  159. package/lib/Toc-YBsgI72s.js.map +1 -0
  160. package/lib/{chunk-HA7DTUK3-ZGg2W6yV.js → chunk-HA7DTUK3-C4gP41vD.js} +5 -5
  161. package/lib/{chunk-HA7DTUK3-ZGg2W6yV.js.map → chunk-HA7DTUK3-C4gP41vD.js.map} +1 -1
  162. package/lib/{createServer-DjgKDpGV.js → createServer-mMau3eV_.js} +1732 -1664
  163. package/lib/{createServer-DjgKDpGV.js.map → createServer-mMau3eV_.js.map} +1 -1
  164. package/lib/hook-CqpVYDqN.js +1483 -0
  165. package/lib/hook-CqpVYDqN.js.map +1 -0
  166. package/lib/index-Bt7MKhZq.js +2514 -0
  167. package/lib/index-Bt7MKhZq.js.map +1 -0
  168. package/lib/{index-DdQSV2RF.js → index-CjPMxpOV.js} +809 -750
  169. package/lib/index-CjPMxpOV.js.map +1 -0
  170. package/lib/{mutation-_Z5C2wFZ.js → mutation-8LjrN7uz.js} +2 -2
  171. package/lib/{mutation-_Z5C2wFZ.js.map → mutation-8LjrN7uz.js.map} +1 -1
  172. package/lib/post-processors/traverse.js.map +1 -1
  173. package/lib/ui/Command.js +1 -1
  174. package/lib/{useExposedProps-BslIn-FE.js → useExposedProps-B9qXJedG.js} +2 -2
  175. package/lib/{useExposedProps-BslIn-FE.js.map → useExposedProps-B9qXJedG.js.map} +1 -1
  176. package/lib/zudoku.auth-auth0.js +1 -1
  177. package/lib/zudoku.auth-clerk.js +59 -41
  178. package/lib/zudoku.auth-clerk.js.map +1 -1
  179. package/lib/zudoku.auth-openid.js +76 -73
  180. package/lib/zudoku.auth-openid.js.map +1 -1
  181. package/lib/zudoku.components.js +31 -1440
  182. package/lib/zudoku.components.js.map +1 -1
  183. package/lib/zudoku.hooks.js +1 -1
  184. package/lib/zudoku.plugin-api-catalog.js +81 -79
  185. package/lib/zudoku.plugin-api-catalog.js.map +1 -1
  186. package/lib/zudoku.plugin-api-keys.js +15 -16
  187. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  188. package/lib/zudoku.plugin-custom-pages.js +2 -2
  189. package/lib/zudoku.plugin-markdown.js +1 -1
  190. package/lib/zudoku.plugin-openapi.js +5 -6
  191. package/lib/zudoku.plugin-openapi.js.map +1 -1
  192. package/lib/zudoku.plugin-redirect.js +1 -1
  193. package/lib/zudoku.plugin-search-pagefind.js +133 -98
  194. package/lib/zudoku.plugin-search-pagefind.js.map +1 -1
  195. package/lib/zudoku.plugins.js.map +1 -1
  196. package/package.json +4 -3
  197. package/src/app/main.tsx +2 -0
  198. package/src/app/tailwind.ts +14 -0
  199. package/src/lib/authentication/authentication.ts +2 -0
  200. package/src/lib/authentication/providers/clerk.tsx +20 -0
  201. package/src/lib/authentication/providers/openid.tsx +6 -0
  202. package/src/lib/authentication/providers/supabase.tsx +6 -0
  203. package/src/lib/authentication/state.ts +1 -35
  204. package/src/lib/components/Layout.tsx +17 -17
  205. package/src/lib/components/Main.tsx +3 -1
  206. package/src/lib/components/Pagination.tsx +47 -0
  207. package/src/lib/components/TopNavigation.tsx +29 -2
  208. package/src/lib/components/navigation/SidebarItem.tsx +10 -4
  209. package/src/lib/{plugins/markdown → components/navigation}/Toc.tsx +5 -14
  210. package/src/lib/core/ZudokuContext.ts +13 -6
  211. package/src/lib/core/plugins.ts +1 -1
  212. package/src/lib/oas/graphql/index.ts +118 -45
  213. package/src/lib/oas/parser/dereference/index.ts +2 -0
  214. package/src/lib/oas/parser/index.ts +7 -29
  215. package/src/lib/plugins/api-catalog/index.tsx +40 -35
  216. package/src/lib/plugins/markdown/MdxPage.tsx +6 -43
  217. package/src/lib/plugins/openapi/ColorizedParam.tsx +1 -1
  218. package/src/lib/plugins/openapi/Endpoint.tsx +1 -1
  219. package/src/lib/plugins/openapi/OperationList.tsx +37 -16
  220. package/src/lib/plugins/openapi/OperationListItem.tsx +7 -2
  221. package/src/lib/plugins/openapi/ParameterListItem.tsx +2 -0
  222. package/src/lib/plugins/openapi/SchemaList.tsx +151 -0
  223. package/src/lib/plugins/openapi/Sidecar.tsx +36 -7
  224. package/src/lib/plugins/openapi/client/GraphQLClient.tsx +1 -1
  225. package/src/lib/plugins/openapi/client/useCreateQuery.ts +12 -5
  226. package/src/lib/plugins/openapi/components/EnumValues.tsx +1 -1
  227. package/src/lib/plugins/openapi/graphql/gql.ts +15 -6
  228. package/src/lib/plugins/openapi/graphql/graphql.ts +104 -15
  229. package/src/lib/plugins/openapi/index.tsx +13 -0
  230. package/src/lib/plugins/openapi/interfaces.ts +29 -0
  231. package/src/lib/plugins/openapi/playground/Playground.tsx +1 -1
  232. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +2 -1
  233. package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.tsx +1 -8
  234. package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.tsx +1 -2
  235. package/src/lib/plugins/openapi/schema/SchemaExampleAndDefault.tsx +36 -0
  236. package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +20 -21
  237. package/src/lib/plugins/openapi/schema/SchemaView.tsx +69 -141
  238. package/src/lib/plugins/openapi/schema/utils.ts +7 -1
  239. package/src/lib/plugins/openapi/state.ts +36 -0
  240. package/src/lib/plugins/openapi/util/getRoutes.tsx +9 -6
  241. package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +26 -4
  242. package/src/lib/plugins/search-pagefind/ResultList.tsx +59 -47
  243. package/src/lib/plugins/search-pagefind/get-results.tsx +31 -10
  244. package/src/lib/util/traverse.ts +2 -6
  245. package/src/lib/util/types.ts +7 -0
  246. package/src/lib/util/useOnScreen.ts +6 -4
  247. package/src/lib/util/useScrollToAnchor.ts +20 -12
  248. package/dist/lib/plugins/markdown/Toc.js.map +0 -1
  249. package/lib/MdxPage-D2rD1vC4.js +0 -200
  250. package/lib/MdxPage-D2rD1vC4.js.map +0 -1
  251. package/lib/OperationList-DT4-gm_S.js +0 -5363
  252. package/lib/OperationList-DT4-gm_S.js.map +0 -1
  253. package/lib/hook-DzQC8PzJ.js +0 -355
  254. package/lib/hook-DzQC8PzJ.js.map +0 -1
  255. package/lib/index-DdQSV2RF.js.map +0 -1
  256. package/lib/index.esm-CltAN0Tf.js +0 -711
  257. package/lib/index.esm-CltAN0Tf.js.map +0 -1
  258. package/lib/joinUrl-BjDooT-T.js +0 -1154
  259. package/lib/joinUrl-BjDooT-T.js.map +0 -1
  260. /package/dist/lib/{plugins/markdown → components/navigation}/Toc.d.ts +0 -0
@@ -1,6 +1,7 @@
1
1
  import * as Collapsible from "@radix-ui/react-collapsible";
2
2
  import { MinusIcon, PlusIcon, RefreshCcwDotIcon } from "lucide-react";
3
3
  import { useCallback, useState } from "react";
4
+ import { InlineCode } from "../../../components/InlineCode.js";
4
5
  import { Markdown, ProseClasses } from "../../../components/Markdown.js";
5
6
  import type { SchemaObject } from "../../../oas/parser/index.js";
6
7
  import { Button } from "../../../ui/Button.js";
@@ -10,6 +11,7 @@ import { EnumValues } from "../components/EnumValues.js";
10
11
  import { SelectOnClick } from "../components/SelectOnClick.js";
11
12
  import { ParamInfos } from "../ParamInfos.js";
12
13
  import { LogicalGroup } from "./LogicalGroup/LogicalGroup.js";
14
+ import { SchemaExampleAndDefault } from "./SchemaExampleAndDefault.js";
13
15
  import { SchemaView } from "./SchemaView.js";
14
16
  import {
15
17
  hasLogicalGroupings,
@@ -18,13 +20,7 @@ import {
18
20
  LogicalSchemaTypeMap,
19
21
  } from "./utils.js";
20
22
 
21
- export const SchemaLogicalGroup = ({
22
- schema,
23
- level,
24
- }: {
25
- schema: SchemaObject;
26
- level: number;
27
- }) => {
23
+ export const SchemaLogicalGroup = ({ schema }: { schema: SchemaObject }) => {
28
24
  const [isOpen, setIsOpen] = useState(true);
29
25
  const toggleOpen = useCallback(() => setIsOpen((prev) => !prev), []);
30
26
 
@@ -37,31 +33,31 @@ export const SchemaLogicalGroup = ({
37
33
  type={type}
38
34
  isOpen={isOpen}
39
35
  toggleOpen={toggleOpen}
40
- level={level}
41
36
  />
42
37
  );
43
38
  }
44
39
  };
45
40
 
46
41
  const RecursiveIndicator = () => (
47
- <div className="flex items-center gap-1.5 italic text-xs text-muted-foreground font-mono bg-muted px-2 py-0.5 rounded-md">
42
+ <InlineCode
43
+ className="inline-flex items-center gap-1.5 italic text-xs translate-y-0.5"
44
+ selectOnClick={false}
45
+ >
48
46
  <RefreshCcwDotIcon size={13} />
49
47
  <span>circular</span>
50
- </div>
48
+ </InlineCode>
51
49
  );
52
50
 
53
51
  export const SchemaPropertyItem = ({
54
52
  name,
55
53
  schema,
56
54
  group,
57
- level,
58
55
  defaultOpen = false,
59
56
  showCollapseButton = true,
60
57
  }: {
61
58
  name: string;
62
59
  schema: SchemaObject;
63
60
  group: "required" | "optional" | "deprecated";
64
- level: number;
65
61
  defaultOpen?: boolean;
66
62
  showCollapseButton?: boolean;
67
63
  }) => {
@@ -73,9 +69,12 @@ export const SchemaPropertyItem = ({
73
69
  <div className="flex flex-col gap-2.5 justify-between text-sm">
74
70
  <div className="space-x-2">
75
71
  <code>{name}</code>
76
- <ParamInfos schema={schema} />
77
- <RecursiveIndicator />
72
+ <ParamInfos
73
+ schema={schema}
74
+ extraItems={[<RecursiveIndicator key="circular-ref" />]}
75
+ />
78
76
  </div>
77
+ <SchemaExampleAndDefault schema={schema} />
79
78
  </div>
80
79
  </li>
81
80
  );
@@ -94,11 +93,11 @@ export const SchemaPropertyItem = ({
94
93
  group !== "optional" && (
95
94
  <span className="text-primary">required</span>
96
95
  ),
96
+ schema.type === "array" &&
97
+ "items" in schema &&
98
+ isCircularRef(schema.items) && <RecursiveIndicator />,
97
99
  ]}
98
100
  />
99
- {schema.type === "array" &&
100
- "items" in schema &&
101
- isCircularRef(schema.items) && <RecursiveIndicator />}
102
101
  </div>
103
102
  {schema.description && (
104
103
  <Markdown
@@ -110,7 +109,7 @@ export const SchemaPropertyItem = ({
110
109
  <EnumValues values={schema.items.enum} />
111
110
  )}
112
111
  {schema.enum && <EnumValues values={schema.enum} />}
113
-
112
+ <SchemaExampleAndDefault schema={schema} />
114
113
  {(hasLogicalGroupings(schema) || isComplexType(schema)) && (
115
114
  <Collapsible.Root
116
115
  defaultOpen={defaultOpen}
@@ -128,15 +127,15 @@ export const SchemaPropertyItem = ({
128
127
  <Collapsible.Content>
129
128
  <div className="mt-2">
130
129
  {hasLogicalGroupings(schema) ? (
131
- <SchemaLogicalGroup schema={schema} level={level + 1} />
130
+ <SchemaLogicalGroup schema={schema} />
132
131
  ) : schema.type === "object" ? (
133
- <SchemaView schema={schema} level={level + 1} />
132
+ <SchemaView schema={schema} />
134
133
  ) : (
135
134
  schema.type === "array" &&
136
135
  "items" in schema &&
137
136
  typeof schema.items === "object" &&
138
137
  !isCircularRef(schema.items) && (
139
- <SchemaView schema={schema.items} level={level + 1} />
138
+ <SchemaView schema={schema.items} />
140
139
  )
141
140
  )}
142
141
  </div>
@@ -5,11 +5,12 @@ import { cn } from "../../../util/cn.js";
5
5
  import { groupBy } from "../../../util/groupBy.js";
6
6
  import { EnumValues } from "../components/EnumValues.js";
7
7
  import { ParamInfos } from "../ParamInfos.js";
8
+ import { SchemaExampleAndDefault } from "./SchemaExampleAndDefault.js";
8
9
  import {
9
10
  SchemaLogicalGroup,
10
11
  SchemaPropertyItem,
11
12
  } from "./SchemaPropertyItem.js";
12
- import { hasLogicalGroupings } from "./utils.js";
13
+ import { hasLogicalGroupings, isBasicType } from "./utils.js";
13
14
 
14
15
  const renderMarkdown = (content?: string) =>
15
16
  content && (
@@ -19,166 +20,93 @@ const renderMarkdown = (content?: string) =>
19
20
  />
20
21
  );
21
22
 
23
+ const renderBasicSchema = (schema: SchemaObject) => (
24
+ <Card className="p-4 space-y-2">
25
+ <span className="text-sm text-muted-foreground">
26
+ <ParamInfos schema={schema} />
27
+ </span>
28
+ {schema.enum && <EnumValues values={schema.enum} />}
29
+ {renderMarkdown(schema.description)}
30
+ <SchemaExampleAndDefault schema={schema} />
31
+ </Card>
32
+ );
33
+
22
34
  export const SchemaView = ({
23
35
  schema,
24
- level = 0,
25
36
  defaultOpen = false,
26
37
  }: {
27
38
  schema?: SchemaObject | null;
28
- level?: number;
29
39
  defaultOpen?: boolean;
30
40
  }) => {
31
41
  if (!schema || Object.keys(schema).length === 0) {
32
42
  return (
33
43
  <Card className="p-4">
34
44
  <span className="text-sm text-muted-foreground italic">
35
- No response specified
45
+ No schema specified
36
46
  </span>
37
47
  </Card>
38
48
  );
39
49
  }
40
50
 
41
- const renderSchema = (schema: SchemaObject, level: number) => {
42
- if (hasLogicalGroupings(schema)) {
43
- return <SchemaLogicalGroup schema={schema} level={level} />;
44
- }
45
-
46
- if (Array.isArray(schema.type)) {
47
- return (
48
- <Card className="p-4 space-y-2">
49
- <span className="text-sm text-muted-foreground">
50
- <ParamInfos schema={schema} />
51
- </span>
52
- {schema.enum && <EnumValues values={schema.enum} />}
53
- {renderMarkdown(schema.description)}
54
- </Card>
55
- );
56
- }
57
-
58
- if (schema.type === "array" && typeof schema.items === "object") {
59
- const itemsSchema = schema.items as SchemaObject;
60
-
61
- if (itemsSchema.enum) {
62
- return (
63
- <Card className="p-4">
64
- <span className="text-sm text-muted-foreground">
65
- <ParamInfos schema={schema} />
66
- </span>
67
- <EnumValues values={itemsSchema.enum} />
68
- {renderMarkdown(schema.description)}
69
- </Card>
70
- );
71
- }
72
-
73
- if (
74
- typeof itemsSchema.type === "string" &&
75
- ["string", "number", "boolean", "integer"].includes(itemsSchema.type)
76
- ) {
77
- return (
78
- <Card className="p-4">
79
- <span className="text-sm text-muted-foreground">
80
- <ParamInfos schema={schema} />
81
- </span>
82
- {renderMarkdown(schema.description)}
83
- </Card>
84
- );
85
- } else if (itemsSchema.type === "object") {
86
- return (
87
- <Card className="flex flex-col gap-2 bg-border/30 p-4">
88
- <span className="text-sm text-muted-foreground">object[]</span>
89
- {renderSchema(itemsSchema, level + 1)}
90
- </Card>
91
- );
92
- } else {
93
- return renderSchema(itemsSchema, level + 1);
94
- }
95
- }
96
-
97
- if (
98
- schema.type === "object" &&
99
- (!schema.properties || Object.keys(schema.properties).length === 0)
100
- ) {
101
- return (
102
- <Card className="p-4 flex gap-2 items-baseline">
103
- {"name" in schema && <>{schema.name as string}</>}
104
- <span className="text-sm text-muted-foreground">
105
- <ParamInfos schema={schema} />
106
- </span>
107
- {renderMarkdown(schema.description)}
108
- </Card>
109
- );
110
- }
111
-
112
- if (schema.properties) {
113
- const groupedProperties = groupBy(
114
- Object.entries(schema.properties),
115
- ([propertyName, property]) => {
116
- return property.deprecated
117
- ? "deprecated"
118
- : schema.required?.includes(propertyName)
119
- ? "required"
120
- : "optional";
121
- },
122
- );
51
+ if (hasLogicalGroupings(schema)) {
52
+ return <SchemaLogicalGroup schema={schema} />;
53
+ }
123
54
 
124
- const groupNames = ["required", "optional", "deprecated"] as const;
55
+ if (isBasicType(schema.type)) {
56
+ return renderBasicSchema(schema);
57
+ }
125
58
 
126
- return (
127
- <Card className="divide-y overflow-hidden">
128
- {groupNames.map(
129
- (group) =>
130
- groupedProperties[group] && (
131
- <ul key={group} className="divide-y">
132
- {groupedProperties[group].map(([name, schema]) => (
133
- <SchemaPropertyItem
134
- key={name}
135
- name={name}
136
- schema={schema}
137
- group={group}
138
- level={level}
139
- defaultOpen={defaultOpen}
140
- />
141
- ))}
142
- </ul>
143
- ),
144
- )}
145
- </Card>
146
- );
147
- }
59
+ if (schema.type === "array" && typeof schema.items === "object") {
60
+ return renderBasicSchema(schema.items as SchemaObject);
61
+ }
148
62
 
149
- if (
150
- typeof schema.type === "string" &&
151
- ["string", "number", "boolean", "integer", "null"].includes(schema.type)
152
- ) {
153
- return (
154
- <Card className="p-4 space-y-2">
155
- <span className="text-sm text-muted-foreground">
156
- <ParamInfos schema={schema} />
157
- </span>
158
- {schema.enum && <EnumValues values={schema.enum} />}
159
- {renderMarkdown(schema.description)}
160
- </Card>
161
- );
162
- }
63
+ if (schema.type === "object") {
64
+ const groupedProperties = groupBy(
65
+ Object.entries(schema.properties ?? {}),
66
+ ([propertyName, property]) => {
67
+ return property.deprecated
68
+ ? "deprecated"
69
+ : schema.required?.includes(propertyName)
70
+ ? "required"
71
+ : "optional";
72
+ },
73
+ );
74
+ const groupNames = ["required", "optional", "deprecated"] as const;
163
75
 
164
- if (schema.additionalProperties) {
165
- return (
166
- <Card className="my-2">
167
- <CardHeader>
168
- <CardTitle>Additional Properties:</CardTitle>
169
- </CardHeader>
170
- <CardContent>
171
- {renderSchema(
172
- schema.additionalProperties as SchemaObject,
173
- level + 1,
174
- )}
175
- </CardContent>
176
- </Card>
177
- );
178
- }
76
+ return (
77
+ <Card className="divide-y overflow-hidden">
78
+ {groupNames.map(
79
+ (group) =>
80
+ groupedProperties[group] && (
81
+ <ul key={group} className="divide-y">
82
+ {groupedProperties[group].map(([name, schema]) => (
83
+ <SchemaPropertyItem
84
+ key={name}
85
+ name={name}
86
+ schema={schema}
87
+ group={group}
88
+ defaultOpen={defaultOpen}
89
+ />
90
+ ))}
91
+ </ul>
92
+ ),
93
+ )}
94
+ </Card>
95
+ );
96
+ }
179
97
 
180
- return null;
181
- };
98
+ if (schema.additionalProperties) {
99
+ return (
100
+ <Card className="my-2">
101
+ <CardHeader>
102
+ <CardTitle>Additional Properties:</CardTitle>
103
+ </CardHeader>
104
+ <CardContent>
105
+ <SchemaView schema={schema.additionalProperties as SchemaObject} />
106
+ </CardContent>
107
+ </Card>
108
+ );
109
+ }
182
110
 
183
- return renderSchema(schema, level);
111
+ return null;
184
112
  };
@@ -1,8 +1,14 @@
1
1
  import { CIRCULAR_REF } from "../../../oas/graphql/circular.js";
2
2
  import type { SchemaObject } from "../../../oas/parser/index.js";
3
3
 
4
+ export const isBasicType = (
5
+ type: unknown,
6
+ ): type is "string" | "number" | "boolean" | "integer" | "null" =>
7
+ typeof type === "string" &&
8
+ ["string", "number", "boolean", "integer", "null"].includes(type);
9
+
4
10
  export const isComplexType = (value: SchemaObject) =>
5
- value.type === "object" ||
11
+ (value.type === "object" && Object.keys(value.properties ?? {}).length > 0) ||
6
12
  (value.type === "array" &&
7
13
  typeof value.items === "object" &&
8
14
  (!value.items.type || value.items.type === "object"));
@@ -0,0 +1,36 @@
1
+ import { useMemo } from "react";
2
+ import { create } from "zustand";
3
+ import { persist } from "zustand/middleware";
4
+
5
+ interface SelectedServerState {
6
+ selectedServer?: string;
7
+ setSelectedServer: (newServer: string) => void;
8
+ }
9
+
10
+ export const useSelectedServerStore = create<SelectedServerState>()(
11
+ persist(
12
+ (set) => ({
13
+ selectedServer: undefined,
14
+ setSelectedServer: (newServer: string) =>
15
+ set({ selectedServer: newServer }),
16
+ }),
17
+ { name: "zudoku-selected-server" },
18
+ ),
19
+ );
20
+
21
+ /**
22
+ * Simple wrapper for `useSelectedServerStore` to fall back to first of the provided servers
23
+ */
24
+ export const useSelectedServer = (servers: Array<{ url: string }>) => {
25
+ const { selectedServer, setSelectedServer } = useSelectedServerStore();
26
+
27
+ const finalSelectedServer = useMemo(
28
+ () =>
29
+ selectedServer && servers.some((s) => s.url === selectedServer)
30
+ ? selectedServer
31
+ : (servers.at(0)?.url ?? ""),
32
+ [selectedServer, servers],
33
+ );
34
+
35
+ return { selectedServer: finalSelectedServer, setSelectedServer };
36
+ };
@@ -1,4 +1,3 @@
1
- import slugify from "@sindresorhus/slugify";
2
1
  import { redirect, type RouteObject } from "react-router";
3
2
  import { joinUrl } from "../../../util/joinUrl.js";
4
3
  import type { GraphQLClient } from "../client/GraphQLClient.js";
@@ -53,10 +52,7 @@ const createVersionRoutes = (
53
52
  versionPath: string,
54
53
  tagPages: string[],
55
54
  ): RouteObject[] => {
56
- const firstTagRoute = joinUrl(
57
- versionPath,
58
- tagPages[0] ? slugify(tagPages[0]) : UNTAGGED_PATH,
59
- );
55
+ const firstTagRoute = joinUrl(versionPath, tagPages.at(0) ?? UNTAGGED_PATH);
60
56
 
61
57
  return [
62
58
  // Redirect to first tag on the index route
@@ -64,7 +60,7 @@ const createVersionRoutes = (
64
60
  // Create routes for each tag
65
61
  ...tagPages.map((tag) =>
66
62
  createRoute({
67
- path: joinUrl(versionPath, slugify(tag)),
63
+ path: joinUrl(versionPath, tag),
68
64
  tag,
69
65
  }),
70
66
  ),
@@ -73,6 +69,13 @@ const createVersionRoutes = (
73
69
  path: joinUrl(versionPath, UNTAGGED_PATH),
74
70
  untagged: true,
75
71
  }),
72
+ {
73
+ path: joinUrl(versionPath, "~schemas"),
74
+ lazy: async () => {
75
+ const { SchemaList } = await import("../SchemaList.js");
76
+ return { element: <SchemaList /> };
77
+ },
78
+ },
76
79
  ];
77
80
  };
78
81
 
@@ -1,6 +1,7 @@
1
1
  import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
2
2
  import { keepPreviousData, useQuery } from "@tanstack/react-query";
3
- import { useState } from "react";
3
+ import { useRef, useState } from "react";
4
+ import { Button } from "zudoku/ui/Button.js";
4
5
  import { Callout } from "zudoku/ui/Callout.js";
5
6
  import {
6
7
  CommandDialog,
@@ -8,6 +9,8 @@ import {
8
9
  CommandInput,
9
10
  } from "zudoku/ui/Command.js";
10
11
  import { DialogTitle } from "zudoku/ui/Dialog.js";
12
+ import { useAuthState } from "../../authentication/state.js";
13
+ import { useZudoku } from "../../components/context/ZudokuContext.js";
11
14
  import { joinUrl } from "../../util/joinUrl.js";
12
15
  import { getResults } from "./get-results.js";
13
16
  import type { PagefindOptions } from "./index.js";
@@ -55,7 +58,7 @@ const usePagefind = (options: PagefindOptions) => {
55
58
  enabled: typeof window !== "undefined",
56
59
  });
57
60
 
58
- if (result.isError) {
61
+ if (result.isError && result.error.message !== "NOT_BUILT_YET") {
59
62
  // eslint-disable-next-line no-console
60
63
  console.error(result.error);
61
64
  }
@@ -74,13 +77,16 @@ export const PagefindSearch = ({
74
77
  }) => {
75
78
  const { pagefind, error, isError } = usePagefind(options);
76
79
  const [searchTerm, setSearchTerm] = useState("");
80
+ const auth = useAuthState();
81
+ const context = useZudoku();
82
+ const inputRef = useRef<HTMLInputElement>(null);
77
83
 
78
84
  const { data: searchResults } = useQuery({
79
85
  queryKey: ["pagefind-search", searchTerm],
80
86
  queryFn: async () => {
81
87
  const search = await pagefind?.search(searchTerm);
82
88
  if (!search) return [];
83
- return getResults(search, options);
89
+ return getResults({ search, options, auth, context });
84
90
  },
85
91
  placeholderData: keepPreviousData,
86
92
  enabled: !!pagefind && !!searchTerm,
@@ -97,13 +103,29 @@ export const PagefindSearch = ({
97
103
  <DialogTitle>Search</DialogTitle>
98
104
  </VisuallyHidden>
99
105
  <CommandInput
106
+ ref={inputRef}
100
107
  placeholder="Search..."
101
108
  value={searchTerm}
102
109
  onValueChange={setSearchTerm}
103
110
  disabled={isError}
104
111
  />
105
112
  <CommandEmpty>
106
- {searchTerm ? "No results found." : "Start typing to search"}
113
+ {searchTerm ? (
114
+ <div className="flex flex-col items-center">
115
+ No results found.
116
+ <Button
117
+ variant="link"
118
+ onClick={() => {
119
+ setSearchTerm("");
120
+ inputRef.current?.focus();
121
+ }}
122
+ >
123
+ Clear search
124
+ </Button>
125
+ </div>
126
+ ) : (
127
+ "Start typing to search"
128
+ )}
107
129
  </CommandEmpty>
108
130
  {isError ? (
109
131
  <div className="p-4 text-sm">
@@ -1,5 +1,5 @@
1
- import { FileTextIcon } from "lucide-react";
2
- import { useCallback } from "react";
1
+ import { BracketsIcon, FileTextIcon } from "lucide-react";
2
+ import { useCallback, useLayoutEffect, useRef } from "react";
3
3
  import { Link, useNavigate } from "react-router";
4
4
  import { CommandGroup, CommandItem, CommandList } from "zudoku/ui/Command.js";
5
5
  import {
@@ -35,6 +35,7 @@ export const ResultList = ({
35
35
  maxSubResults?: number;
36
36
  }) => {
37
37
  const navigate = useNavigate();
38
+ const commandListRef = useRef<HTMLDivElement | null>(null);
38
39
 
39
40
  const cleanResultUrl = useCallback(
40
41
  (url: string) => {
@@ -46,59 +47,70 @@ export const ResultList = ({
46
47
  [basePath],
47
48
  );
48
49
 
50
+ useLayoutEffect(() => {
51
+ requestIdleCallback(() => {
52
+ commandListRef.current?.scrollTo({ top: 0 });
53
+ });
54
+ }, [searchTerm]);
55
+
49
56
  return (
50
- <CommandList className="max-h-[450px]">
57
+ <CommandList className="max-h-[450px]" ref={commandListRef}>
51
58
  {searchTerm && searchResults.length > 0 && (
52
59
  <CommandGroup
53
60
  className="text-sm text-muted-foreground"
54
61
  heading={`${searchResults.length} results for "${searchTerm}"`}
55
62
  />
56
63
  )}
57
- {searchResults.map((result) => (
58
- <CommandGroup
59
- key={[result.meta.title ?? result.excerpt, result.url].join("-")}
60
- >
61
- <CommandItem
62
- asChild
63
- value={`${result.meta.title}-${result.url}`}
64
- className={hoverClassname}
65
- onSelect={() => {
66
- void navigate(cleanResultUrl(result.url));
67
- onClose();
68
- }}
64
+ {searchTerm &&
65
+ searchResults.map((result) => (
66
+ <CommandGroup
67
+ key={[result.meta.title ?? result.excerpt, result.url].join("-")}
69
68
  >
70
- <Link to={cleanResultUrl(result.url)}>
71
- <FileTextIcon size={20} className="text-muted-foreground" />
72
- {result.meta.title}
73
- </Link>
74
- </CommandItem>
75
- {result.sub_results
76
- .sort(sortSubResults)
77
- .slice(0, maxSubResults)
78
- .map((subResult) => (
79
- <CommandItem
80
- asChild
81
- key={`${result.meta.title}-${subResult.url}`}
82
- value={`${result.meta.title}-${subResult.url}`}
83
- className={hoverClassname}
84
- onSelect={() => {
85
- void navigate(cleanResultUrl(subResult.url));
86
- onClose();
87
- }}
88
- >
89
- <Link to={cleanResultUrl(subResult.url)} onClick={onClose}>
90
- <div className="flex flex-col items-start gap-2 ms-2.5 ps-5 border-l border-muted-foreground/50">
91
- <span className="font-bold">{subResult.title}</span>
92
- <span
93
- className="text-[13px] [&_mark]:bg-primary [&_mark]:text-primary-foreground"
94
- dangerouslySetInnerHTML={{ __html: subResult.excerpt }}
95
- />
96
- </div>
97
- </Link>
98
- </CommandItem>
99
- ))}
100
- </CommandGroup>
101
- ))}
69
+ <CommandItem
70
+ asChild
71
+ value={`${result.meta.title}-${result.url}`}
72
+ className={hoverClassname}
73
+ onSelect={() => {
74
+ void navigate(cleanResultUrl(result.url));
75
+ onClose();
76
+ }}
77
+ >
78
+ <Link to={cleanResultUrl(result.url)}>
79
+ {result.meta.section === "openapi" ? (
80
+ <BracketsIcon />
81
+ ) : (
82
+ <FileTextIcon />
83
+ )}
84
+ {result.meta.title}
85
+ </Link>
86
+ </CommandItem>
87
+ {result.sub_results
88
+ .sort(sortSubResults)
89
+ .slice(0, maxSubResults)
90
+ .map((subResult) => (
91
+ <CommandItem
92
+ asChild
93
+ key={`sub-${result.meta.title}-${subResult.url}`}
94
+ value={`sub-${result.meta.title}-${subResult.url}`}
95
+ className={hoverClassname}
96
+ onSelect={() => {
97
+ void navigate(cleanResultUrl(subResult.url));
98
+ onClose();
99
+ }}
100
+ >
101
+ <Link to={cleanResultUrl(subResult.url)} onClick={onClose}>
102
+ <div className="flex flex-col items-start gap-2 ms-2.5 ps-5 border-l border-muted-foreground/50">
103
+ <span className="font-bold">{subResult.title}</span>
104
+ <span
105
+ className="text-[13px] [&_mark]:bg-primary [&_mark]:text-primary-foreground"
106
+ dangerouslySetInnerHTML={{ __html: subResult.excerpt }}
107
+ />
108
+ </div>
109
+ </Link>
110
+ </CommandItem>
111
+ ))}
112
+ </CommandGroup>
113
+ ))}
102
114
  </CommandList>
103
115
  );
104
116
  };