zudoku 0.0.0-f3786a4 → 0.0.0-f3f6db5

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 (209) hide show
  1. package/dist/app/main.js +1 -2
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/config/validators/InputSidebarSchema.d.ts +2 -2
  4. package/dist/lib/components/PathRenderer.d.ts +11 -0
  5. package/dist/lib/components/PathRenderer.js +25 -0
  6. package/dist/lib/components/PathRenderer.js.map +1 -0
  7. package/dist/lib/components/ThemeSwitch.js +4 -4
  8. package/dist/lib/components/ThemeSwitch.js.map +1 -1
  9. package/dist/lib/components/index.d.ts +1 -0
  10. package/dist/lib/components/index.js +4 -2
  11. package/dist/lib/components/index.js.map +1 -1
  12. package/dist/lib/components/navigation/SidebarCategory.js +17 -15
  13. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  14. package/dist/lib/oas/graphql/circular.js +17 -6
  15. package/dist/lib/oas/graphql/circular.js.map +1 -1
  16. package/dist/lib/oas/graphql/index.d.ts +1 -0
  17. package/dist/lib/oas/graphql/index.js +41 -23
  18. package/dist/lib/oas/graphql/index.js.map +1 -1
  19. package/dist/lib/plugins/openapi/ColorizedParam.js +3 -1
  20. package/dist/lib/plugins/openapi/ColorizedParam.js.map +1 -1
  21. package/dist/lib/plugins/openapi/Endpoint.js +2 -2
  22. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  23. package/dist/lib/plugins/openapi/{Route.d.ts → OpenApiRoute.d.ts} +2 -1
  24. package/dist/lib/plugins/openapi/{Route.js → OpenApiRoute.js} +3 -4
  25. package/dist/lib/plugins/openapi/OpenApiRoute.js.map +1 -0
  26. package/dist/lib/plugins/openapi/OperationList.d.ts +4 -1
  27. package/dist/lib/plugins/openapi/OperationList.js +20 -14
  28. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  29. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  30. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  31. package/dist/lib/plugins/openapi/ParameterListItem.js +2 -2
  32. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  33. package/dist/lib/plugins/openapi/RequestBodySidecarBox.d.ts +1 -1
  34. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +2 -0
  35. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  36. package/dist/lib/plugins/openapi/Sidecar.js +6 -11
  37. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  38. package/dist/lib/plugins/openapi/SidecarExamples.js +17 -14
  39. package/dist/lib/plugins/openapi/SidecarExamples.js.map +1 -1
  40. package/dist/lib/plugins/openapi/graphql/gql.d.ts +6 -2
  41. package/dist/lib/plugins/openapi/graphql/gql.js +3 -2
  42. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  43. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +47 -26
  44. package/dist/lib/plugins/openapi/graphql/graphql.js +20 -16
  45. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  46. package/dist/lib/plugins/openapi/index.js +97 -54
  47. package/dist/lib/plugins/openapi/index.js.map +1 -1
  48. package/dist/lib/plugins/openapi/interfaces.d.ts +1 -0
  49. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js +5 -5
  50. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js.map +1 -1
  51. package/dist/lib/plugins/openapi/playground/Headers.js +17 -16
  52. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  53. package/dist/lib/plugins/openapi/playground/ParamsGrid.d.ts +5 -0
  54. package/dist/lib/plugins/openapi/playground/ParamsGrid.js +4 -0
  55. package/dist/lib/plugins/openapi/playground/ParamsGrid.js.map +1 -0
  56. package/dist/lib/plugins/openapi/playground/PathParams.js +4 -12
  57. package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
  58. package/dist/lib/plugins/openapi/playground/Playground.d.ts +13 -0
  59. package/dist/lib/plugins/openapi/playground/Playground.js +25 -45
  60. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  61. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
  62. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
  63. package/dist/lib/plugins/openapi/playground/QueryParams.js +4 -3
  64. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  65. package/dist/lib/plugins/openapi/playground/SubmitButton.d.ts +7 -0
  66. package/dist/lib/plugins/openapi/playground/SubmitButton.js +22 -0
  67. package/dist/lib/plugins/openapi/playground/SubmitButton.js.map +1 -0
  68. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.d.ts +7 -0
  69. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js +11 -0
  70. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js.map +1 -0
  71. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.d.ts +8 -0
  72. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js +95 -0
  73. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js.map +1 -0
  74. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.d.ts +7 -0
  75. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +16 -0
  76. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -0
  77. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.d.ts +10 -0
  78. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js +32 -0
  79. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js.map +1 -0
  80. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.d.ts +1 -0
  81. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js +56 -0
  82. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js.map +1 -0
  83. package/dist/lib/plugins/openapi/schema/{SchemaComponents.js → SchemaPropertyItem.js} +10 -8
  84. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -0
  85. package/dist/lib/plugins/openapi/schema/SchemaView.js +1 -1
  86. package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
  87. package/dist/lib/plugins/openapi/schema/utils.d.ts +1 -0
  88. package/dist/lib/plugins/openapi/schema/utils.js +2 -0
  89. package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
  90. package/dist/lib/ui/Command.js +1 -1
  91. package/dist/lib/ui/Command.js.map +1 -1
  92. package/dist/lib/ui/Select.js +2 -2
  93. package/dist/lib/ui/Select.js.map +1 -1
  94. package/dist/lib/util/joinUrl.js +1 -1
  95. package/dist/lib/util/joinUrl.js.map +1 -1
  96. package/dist/lib/util/joinUrl.test.d.ts +1 -0
  97. package/dist/lib/util/joinUrl.test.js +43 -0
  98. package/dist/lib/util/joinUrl.test.js.map +1 -0
  99. package/dist/vite/plugin-api.js +9 -1
  100. package/dist/vite/plugin-api.js.map +1 -1
  101. package/dist/vite/prerender.js +0 -1
  102. package/dist/vite/prerender.js.map +1 -1
  103. package/lib/{AuthenticationPlugin-CvwlQWjV.js → AuthenticationPlugin-Du8cLBSr.js} +2 -2
  104. package/lib/{AuthenticationPlugin-CvwlQWjV.js.map → AuthenticationPlugin-Du8cLBSr.js.map} +1 -1
  105. package/lib/{Markdown-B8o9Qz4q.js → Markdown-Cyrx_JrO.js} +8 -9
  106. package/lib/{Markdown-B8o9Qz4q.js.map → Markdown-Cyrx_JrO.js.map} +1 -1
  107. package/lib/{MdxPage-DiWukCrZ.js → MdxPage-BuG8Tuwc.js} +5 -5
  108. package/lib/{MdxPage-DiWukCrZ.js.map → MdxPage-BuG8Tuwc.js.map} +1 -1
  109. package/lib/OpenApiRoute-UrC_t0e5.js +36 -0
  110. package/lib/OpenApiRoute-UrC_t0e5.js.map +1 -0
  111. package/lib/{OperationList-CyNwMHMV.js → OperationList-CDt1xdc4.js} +1925 -1902
  112. package/lib/OperationList-CDt1xdc4.js.map +1 -0
  113. package/lib/{Select-4kIgJ1bc.js → Select-CnCZ4WhS.js} +61 -61
  114. package/lib/Select-CnCZ4WhS.js.map +1 -0
  115. package/lib/{SlotletProvider-CtIp8rP3.js → SlotletProvider-mQiPDQIH.js} +2 -2
  116. package/lib/{SlotletProvider-CtIp8rP3.js.map → SlotletProvider-mQiPDQIH.js.map} +1 -1
  117. package/lib/{SyntaxHighlight-C1w1QPdY.js → SyntaxHighlight-B0L4SC_N.js} +11 -5
  118. package/lib/SyntaxHighlight-B0L4SC_N.js.map +1 -0
  119. package/lib/{ZudokuContext-Bp2uQx1d.js → ZudokuContext-BTUJPpQl.js} +36 -35
  120. package/lib/{ZudokuContext-Bp2uQx1d.js.map → ZudokuContext-BTUJPpQl.js.map} +1 -1
  121. package/lib/{circular-Dgpd6AN-.js → circular-DxaIIlWD.js} +251 -239
  122. package/lib/{circular-Dgpd6AN-.js.map → circular-DxaIIlWD.js.map} +1 -1
  123. package/lib/{createServer-BV0tHzLK.js → createServer-CjNktZzL.js} +821 -808
  124. package/lib/{createServer-BV0tHzLK.js.map → createServer-CjNktZzL.js.map} +1 -1
  125. package/lib/{hook-BDmay56y.js → hook-FT3SJLe_.js} +2 -2
  126. package/lib/{hook-BDmay56y.js.map → hook-FT3SJLe_.js.map} +1 -1
  127. package/lib/{index-LNp6rxyU.js → index-CjJS0l4l.js} +2 -2
  128. package/lib/{index-LNp6rxyU.js.map → index-CjJS0l4l.js.map} +1 -1
  129. package/lib/index-Eb1oiHbM.js +1997 -0
  130. package/lib/index-Eb1oiHbM.js.map +1 -0
  131. package/lib/{joinUrl-BTy9bvoK.js → joinUrl-nLx9pD-Z.js} +2 -2
  132. package/lib/joinUrl-nLx9pD-Z.js.map +1 -0
  133. package/lib/ui/Command.js +27 -27
  134. package/lib/ui/Command.js.map +1 -1
  135. package/lib/ui/Select.js +2 -2
  136. package/lib/ui/Select.js.map +1 -1
  137. package/lib/{useScrollToAnchor-S-NbG5Za.js → useScrollToAnchor-BZsGmBng.js} +86 -90
  138. package/lib/useScrollToAnchor-BZsGmBng.js.map +1 -0
  139. package/lib/zudoku.auth-clerk.js +1 -1
  140. package/lib/zudoku.auth-openid.js +3 -3
  141. package/lib/zudoku.components.js +364 -348
  142. package/lib/zudoku.components.js.map +1 -1
  143. package/lib/zudoku.plugin-api-catalog.js +3 -3
  144. package/lib/zudoku.plugin-api-keys.js +4 -4
  145. package/lib/zudoku.plugin-custom-pages.js +1 -1
  146. package/lib/zudoku.plugin-markdown.js +1 -1
  147. package/lib/zudoku.plugin-openapi.js +6 -5
  148. package/lib/zudoku.plugin-openapi.js.map +1 -1
  149. package/package.json +1 -1
  150. package/src/app/main.tsx +1 -2
  151. package/src/lib/components/PathRenderer.tsx +59 -0
  152. package/src/lib/components/ThemeSwitch.tsx +15 -14
  153. package/src/lib/components/index.ts +7 -5
  154. package/src/lib/components/navigation/SidebarCategory.tsx +44 -41
  155. package/src/lib/oas/graphql/circular.ts +27 -6
  156. package/src/lib/oas/graphql/index.ts +63 -35
  157. package/src/lib/plugins/openapi/ColorizedParam.tsx +3 -3
  158. package/src/lib/plugins/openapi/Endpoint.tsx +2 -2
  159. package/src/lib/plugins/openapi/{Route.tsx → OpenApiRoute.tsx} +3 -3
  160. package/src/lib/plugins/openapi/OperationList.tsx +34 -12
  161. package/src/lib/plugins/openapi/OperationListItem.tsx +6 -1
  162. package/src/lib/plugins/openapi/ParameterListItem.tsx +2 -1
  163. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +2 -0
  164. package/src/lib/plugins/openapi/Sidecar.tsx +18 -27
  165. package/src/lib/plugins/openapi/SidecarExamples.tsx +24 -24
  166. package/src/lib/plugins/openapi/graphql/gql.ts +12 -4
  167. package/src/lib/plugins/openapi/graphql/graphql.ts +66 -43
  168. package/src/lib/plugins/openapi/index.tsx +125 -67
  169. package/src/lib/plugins/openapi/interfaces.ts +1 -0
  170. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +30 -27
  171. package/src/lib/plugins/openapi/playground/Headers.tsx +65 -65
  172. package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +8 -0
  173. package/src/lib/plugins/openapi/playground/PathParams.tsx +34 -74
  174. package/src/lib/plugins/openapi/playground/Playground.tsx +86 -148
  175. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +1 -1
  176. package/src/lib/plugins/openapi/playground/QueryParams.tsx +46 -45
  177. package/src/lib/plugins/openapi/playground/SubmitButton.tsx +75 -0
  178. package/src/lib/plugins/openapi/playground/result-panel/RequestTab.tsx +73 -0
  179. package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +210 -0
  180. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +101 -0
  181. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.test.ts +64 -0
  182. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.ts +36 -0
  183. package/src/lib/plugins/openapi/schema/{SchemaComponents.tsx → SchemaPropertyItem.tsx} +10 -6
  184. package/src/lib/plugins/openapi/schema/SchemaView.tsx +4 -1
  185. package/src/lib/plugins/openapi/schema/utils.ts +4 -0
  186. package/src/lib/ui/Command.tsx +1 -1
  187. package/src/lib/ui/Select.tsx +1 -1
  188. package/src/lib/util/joinUrl.test.ts +62 -0
  189. package/src/lib/util/joinUrl.ts +1 -1
  190. package/dist/lib/plugins/openapi/Route.js.map +0 -1
  191. package/dist/lib/plugins/openapi/playground/ResponseTab.d.ts +0 -4
  192. package/dist/lib/plugins/openapi/playground/ResponseTab.js +0 -42
  193. package/dist/lib/plugins/openapi/playground/ResponseTab.js.map +0 -1
  194. package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +0 -1
  195. package/lib/OperationList-CyNwMHMV.js.map +0 -1
  196. package/lib/Route-DH64hIrR.js +0 -35
  197. package/lib/Route-DH64hIrR.js.map +0 -1
  198. package/lib/Select-4kIgJ1bc.js.map +0 -1
  199. package/lib/StaggeredRender-DgsamH_G.js +0 -17
  200. package/lib/StaggeredRender-DgsamH_G.js.map +0 -1
  201. package/lib/SyntaxHighlight-C1w1QPdY.js.map +0 -1
  202. package/lib/index-Bn6Lc9tq.js +0 -9
  203. package/lib/index-Bn6Lc9tq.js.map +0 -1
  204. package/lib/index-BtNudmKQ.js +0 -1744
  205. package/lib/index-BtNudmKQ.js.map +0 -1
  206. package/lib/joinUrl-BTy9bvoK.js.map +0 -1
  207. package/lib/useScrollToAnchor-S-NbG5Za.js.map +0 -1
  208. package/src/lib/plugins/openapi/playground/ResponseTab.tsx +0 -76
  209. /package/dist/lib/plugins/openapi/schema/{SchemaComponents.d.ts → SchemaPropertyItem.d.ts} +0 -0
@@ -1,15 +1,15 @@
1
- import { matchPath } from "react-router";
2
- import { type ZudokuPlugin } from "../../core/plugins.js";
3
- import { graphql } from "./graphql/index.js";
4
-
1
+ import slugify from "@sindresorhus/slugify";
5
2
  import { CirclePlayIcon, LogInIcon } from "lucide-react";
3
+ import { matchPath, redirect, RouteObject } from "react-router";
6
4
  import type { SidebarItem } from "../../../config/validators/SidebarSchema.js";
7
5
  import { useAuth } from "../../authentication/hook.js";
8
6
  import { ColorMap } from "../../components/navigation/SidebarBadge.js";
7
+ import { type ZudokuPlugin } from "../../core/plugins.js";
9
8
  import type { SchemaImports } from "../../oas/graphql/index.js";
10
9
  import { Button } from "../../ui/Button.js";
11
- import { joinPath } from "../../util/joinPath.js";
10
+ import { joinUrl } from "../../util/joinUrl.js";
12
11
  import { GraphQLClient } from "./client/GraphQLClient.js";
12
+ import { graphql } from "./graphql/index.js";
13
13
  import { OasPluginConfig } from "./interfaces.js";
14
14
  import type { PlaygroundContentProps } from "./playground/Playground.js";
15
15
  import { PlaygroundDialog } from "./playground/PlaygroundDialog.js";
@@ -19,17 +19,27 @@ const GetCategoriesQuery = graphql(`
19
19
  schema(input: $input, type: $type) {
20
20
  url
21
21
  tags {
22
- __typename
23
22
  name
24
- operations {
25
- __typename
26
- slug
27
- deprecated
28
- method
29
- summary
30
- operationId
31
- path
32
- }
23
+ }
24
+ }
25
+ }
26
+ `);
27
+
28
+ const GetOperationsQuery = graphql(`
29
+ query GetOperations(
30
+ $input: JSON!
31
+ $type: SchemaType!
32
+ $tag: String
33
+ $untagged: Boolean
34
+ ) {
35
+ schema(input: $input, type: $type) {
36
+ operations(tag: $tag, untagged: $untagged) {
37
+ slug
38
+ deprecated
39
+ method
40
+ summary
41
+ operationId
42
+ path
33
43
  }
34
44
  }
35
45
  }
@@ -49,9 +59,10 @@ const MethodColorMap: Record<string, keyof typeof ColorMap> = {
49
59
 
50
60
  export type OpenApiPluginOptions = OasPluginConfig & InternalOasPluginConfig;
51
61
 
52
- export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
53
- const basePath = joinPath(config.navigationId ?? "/reference");
62
+ const UNTAGGED_PATH = "~endpoints";
54
63
 
64
+ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
65
+ const basePath = joinUrl(config.navigationId ?? "/reference");
55
66
  const versions = config.type === "file" ? Object.keys(config.input) : [];
56
67
 
57
68
  const client = new GraphQLClient(config);
@@ -122,41 +133,60 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
122
133
  }
123
134
 
124
135
  try {
125
- const version =
126
- versions.find((v) => path === joinPath(basePath, v)) ??
127
- Object.keys(config.input).at(0);
136
+ const urlVersion = versions.find((v) =>
137
+ path.startsWith(joinUrl(basePath, v)),
138
+ );
139
+ const version = urlVersion ?? Object.keys(config.input).at(0);
128
140
 
129
141
  const data = await client.fetch(GetCategoriesQuery, {
130
142
  type: config.type,
131
143
  input: config.type === "file" ? config.input[version!] : config.input,
132
- version,
133
144
  });
134
145
 
135
- const categories = data.schema.tags
136
- .filter((tag) => tag.operations.length > 0)
137
- .map<SidebarItem>((tag) => ({
138
- type: "category",
139
- label: tag.name || "Other endpoints",
140
- collapsible: true,
141
- collapsed: false,
142
- items: tag.operations.map((operation) => ({
143
- type: "link",
144
- label: operation.summary ?? operation.path,
145
- href: `#${operation.slug}`,
146
- badge: {
147
- label: operation.method,
148
- color: MethodColorMap[operation.method.toLowerCase()]!,
149
- invert: true,
150
- },
151
- })),
152
- }));
146
+ const tag = config.tagPages?.find(
147
+ (tag) => path.split("/").at(-1) === slugify(tag),
148
+ );
153
149
 
154
- categories.unshift({
155
- type: "link",
156
- label: "Overview",
157
- href: "#description",
150
+ const operationsData = await client.fetch(GetOperationsQuery, {
151
+ type: config.type,
152
+ input: config.type === "file" ? config.input[version!] : config.input,
153
+ tag,
154
+ untagged: tag === undefined,
158
155
  });
159
156
 
157
+ const items = operationsData.schema.operations.map((operation) => ({
158
+ type: "link" as const,
159
+ label: operation.summary ?? operation.path,
160
+ href: `#${operation.slug}`,
161
+ badge: {
162
+ label: operation.method,
163
+ color: MethodColorMap[operation.method.toLowerCase()]!,
164
+ invert: true,
165
+ } as const,
166
+ }));
167
+
168
+ const categories = data.schema.tags
169
+ // .filter((tag) => tag.operations.length > 0)
170
+ .map<SidebarItem>((tag) => {
171
+ const categoryLink = joinUrl(
172
+ basePath,
173
+ urlVersion,
174
+ tag.name ? slugify(tag.name) : UNTAGGED_PATH,
175
+ );
176
+ return {
177
+ type: "category",
178
+ label: tag.name || "Other endpoints",
179
+ link: {
180
+ type: "doc" as const,
181
+ id: categoryLink,
182
+ label: tag.name!,
183
+ },
184
+ collapsible: false,
185
+ collapsed: true,
186
+ items: path === categoryLink ? items : [],
187
+ };
188
+ });
189
+
160
190
  return categories;
161
191
  } catch {
162
192
  return [];
@@ -165,31 +195,59 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
165
195
  getRoutes: () => {
166
196
  const versionsInPath = [null, ...versions];
167
197
 
168
- return versionsInPath.map((version) => ({
169
- path: basePath + (version ? `/${version}` : ""),
170
- async lazy() {
171
- const { OpenApiRoute } = await import("./Route.js");
172
- return {
173
- element: (
174
- <OpenApiRoute
175
- basePath={basePath}
176
- versions={versions}
177
- client={client}
178
- config={config}
179
- />
180
- ),
181
- };
182
- },
183
- children: [
184
- {
185
- index: true,
186
- async lazy() {
187
- const { OperationList } = await import("./OperationList.js");
188
- return { element: <OperationList /> };
189
- },
190
- },
191
- ],
198
+ const tagPages = (config.tagPages ?? []).map((tag) => ({
199
+ tag,
200
+ path: slugify(tag),
192
201
  }));
202
+
203
+ return versionsInPath.map((version) => {
204
+ const versionPath = joinUrl(basePath, version ? `/${version}` : "");
205
+
206
+ return {
207
+ path: versionPath,
208
+ async lazy() {
209
+ const { OpenApiRoute } = await import("./OpenApiRoute.js");
210
+ return {
211
+ element: (
212
+ <OpenApiRoute
213
+ version={version ?? undefined}
214
+ basePath={basePath}
215
+ versions={versions}
216
+ client={client}
217
+ config={config}
218
+ />
219
+ ),
220
+ };
221
+ },
222
+ children: [
223
+ {
224
+ index: true,
225
+ loader: () =>
226
+ redirect(
227
+ joinUrl(versionPath, tagPages.at(0)?.path ?? UNTAGGED_PATH),
228
+ ),
229
+ },
230
+ {
231
+ path: joinUrl(versionPath, UNTAGGED_PATH),
232
+ async lazy() {
233
+ const { OperationList } = await import("./OperationList.js");
234
+ return { element: <OperationList untagged={true} /> };
235
+ },
236
+ },
237
+ ...tagPages.map<RouteObject>((tag) => {
238
+ return {
239
+ path: joinUrl(versionPath, tag.path),
240
+ async lazy() {
241
+ const { OperationList } = await import("./OperationList.js");
242
+ return {
243
+ element: <OperationList tag={tag.tag} />,
244
+ };
245
+ },
246
+ };
247
+ }),
248
+ ],
249
+ };
250
+ });
193
251
  },
194
252
  };
195
253
  };
@@ -20,6 +20,7 @@ export type OasPluginConfig = {
20
20
  server?: string;
21
21
  navigationId?: string;
22
22
  skipPreload?: boolean;
23
+ tagPages?: Array<string>;
23
24
  } & OasPluginConfigOptions &
24
25
  OasSource;
25
26
 
@@ -18,33 +18,36 @@ const ExamplesDropdown = ({
18
18
  onSelect: (example: Example) => void;
19
19
  }) => {
20
20
  return (
21
- <DropdownMenu>
22
- <DropdownMenuTrigger asChild>
23
- <Button variant="outline">Use Example</Button>
24
- </DropdownMenuTrigger>
25
- <DropdownMenuContent className="w-56">
26
- {examples.map((example) => {
27
- return (
28
- <div key={example.mediaType}>
29
- <DropdownMenuLabel>{example.mediaType}</DropdownMenuLabel>
30
- <DropdownMenuSeparator />
31
- <DropdownMenuGroup>
32
- {example.examples?.map((example) => {
33
- return (
34
- <DropdownMenuItem
35
- key={example.name}
36
- onSelect={() => onSelect(example)}
37
- >
38
- {example.name}
39
- </DropdownMenuItem>
40
- );
41
- })}
42
- </DropdownMenuGroup>
43
- </div>
44
- );
45
- })}
46
- </DropdownMenuContent>
47
- </DropdownMenu>
21
+ <div className="flex flex-col gap-2 mt-2 items-end">
22
+ <DropdownMenu>
23
+ <DropdownMenuTrigger asChild>
24
+ <Button variant="outline">Use Example</Button>
25
+ </DropdownMenuTrigger>
26
+ <DropdownMenuContent className="w-56">
27
+ {examples.map((example) => {
28
+ return (
29
+ <div key={example.mediaType}>
30
+ <DropdownMenuLabel>{example.mediaType}</DropdownMenuLabel>
31
+ <DropdownMenuSeparator />
32
+ <DropdownMenuGroup>
33
+ {example.examples?.map((example) => {
34
+ return (
35
+ <DropdownMenuItem
36
+ key={example.name}
37
+ onSelect={() => onSelect(example)}
38
+ className="line-clamp-1"
39
+ >
40
+ {example.summary ?? example.name}
41
+ </DropdownMenuItem>
42
+ );
43
+ })}
44
+ </DropdownMenuGroup>
45
+ </div>
46
+ );
47
+ })}
48
+ </DropdownMenuContent>
49
+ </DropdownMenu>
50
+ </div>
48
51
  );
49
52
  };
50
53
 
@@ -12,6 +12,7 @@ import { Checkbox } from "zudoku/ui/Checkbox.js";
12
12
  import { Autocomplete } from "../../../components/Autocomplete.js";
13
13
  import { Button } from "../../../ui/Button.js";
14
14
  import { Input } from "../../../ui/Input.js";
15
+ import ParamsGrid from "./ParamsGrid.js";
15
16
  import { type PlaygroundForm } from "./Playground.js";
16
17
 
17
18
  const headerOptions = Object.freeze([
@@ -77,56 +78,55 @@ export const Headers = ({
77
78
 
78
79
  return (
79
80
  <div className="flex flex-col gap-2">
80
- <Card className="flex flex-col gap-2 overflow-hidden">
81
- <table className="w-full">
82
- <tbody>
83
- {fields.map((header, i) => (
84
- <tr
85
- key={header.id}
86
- className="group has-[:focus]:bg-muted/50 hover:bg-muted/50"
87
- >
88
- <td className="flex gap-2 items-center pl-3">
89
- <Controller
90
- control={control}
91
- name={`headers.${i}.active`}
92
- render={({ field }) => (
93
- <Checkbox
94
- variant="outline"
95
- id={`headers.${i}.active`}
96
- checked={field.value}
97
- onCheckedChange={(checked) => {
98
- field.onChange(checked);
99
- }}
100
- />
101
- )}
102
- />
103
- <Controller
104
- control={control}
105
- name={`headers.${i}.name`}
106
- render={({ field }) => (
107
- <Autocomplete
108
- {...field}
109
- placeholder="Name"
110
- className="border-0 shadow-none bg-transparent text-xs font-mono"
111
- options={headerOptions}
112
- onEnterPress={() => handleHeaderEnter(i)}
113
- onChange={(e) => {
114
- field.onChange(e);
115
- setValue(`headers.${i}.active`, true);
116
- }}
117
- ref={(el) => {
118
- nameRefs.current[i] = el;
119
- }}
120
- />
121
- )}
122
- />
123
- </td>
124
- <td>
125
- <div className="flex items-center gap-2">
81
+ <Card className="overflow-hidden">
82
+ <ParamsGrid>
83
+ {fields.map((header, i) => (
84
+ <div key={i} className="group grid col-span-full grid-cols-subgrid">
85
+ <div className="flex items-center gap-2 ">
86
+ <Controller
87
+ control={control}
88
+ name={`headers.${i}.active`}
89
+ render={({ field }) => (
90
+ <Checkbox
91
+ variant="outline"
92
+ id={`headers.${i}.active`}
93
+ checked={field.value}
94
+ onCheckedChange={(checked) => {
95
+ field.onChange(checked);
96
+ }}
97
+ />
98
+ )}
99
+ />
100
+ <Controller
101
+ control={control}
102
+ name={`headers.${i}.name`}
103
+ render={({ field }) => (
104
+ <Autocomplete
105
+ {...field}
106
+ placeholder="Name"
107
+ className="border-0 shadow-none bg-transparent text-xs font-mono"
108
+ options={headerOptions}
109
+ onEnterPress={() => handleHeaderEnter(i)}
110
+ onChange={(e) => {
111
+ field.onChange(e);
112
+ setValue(`headers.${i}.active`, true);
113
+ }}
114
+ ref={(el) => {
115
+ nameRefs.current[i] = el;
116
+ }}
117
+ />
118
+ )}
119
+ />
120
+ </div>
121
+ <div className="flex items-center gap-2">
122
+ <Controller
123
+ control={control}
124
+ name={`headers.${i}.value`}
125
+ render={({ field }) => (
126
126
  <Input
127
127
  placeholder="Value"
128
- className="w-full border-0 shadow-none text-xs font-mono"
129
- {...register(`headers.${i}.value`)}
128
+ className="w-full border-0 shadow-none text-xs font-mono focus-visible:ring-0"
129
+ {...field}
130
130
  ref={(el) => {
131
131
  valueRefs.current[i] = el;
132
132
  }}
@@ -137,23 +137,23 @@ export const Headers = ({
137
137
  }}
138
138
  autoComplete="off"
139
139
  />
140
- <Button
141
- size="icon"
142
- variant="ghost"
143
- className="text-muted-foreground opacity-0 group-hover:opacity-100"
144
- onClick={() => {
145
- remove(i);
146
- }}
147
- type="button"
148
- >
149
- <XIcon size={16} />
150
- </Button>
151
- </div>
152
- </td>
153
- </tr>
154
- ))}
155
- </tbody>
156
- </table>
140
+ )}
141
+ />
142
+ <Button
143
+ size="icon"
144
+ variant="ghost"
145
+ className="text-muted-foreground opacity-0 group-hover:opacity-100 rounded-full w-8 h-7"
146
+ onClick={() => {
147
+ remove(i);
148
+ }}
149
+ type="button"
150
+ >
151
+ <XIcon size={16} />
152
+ </Button>
153
+ </div>
154
+ </div>
155
+ ))}
156
+ </ParamsGrid>
157
157
  </Card>
158
158
  <div className="text-end">
159
159
  <Button
@@ -0,0 +1,8 @@
1
+ import createVariantComponent from "../../../util/createVariantComponent.js";
2
+
3
+ const ParamsGrid = createVariantComponent(
4
+ "div",
5
+ "hover:bg-accent/40 grid grid-cols-[2fr_3fr] gap-2 items-center px-3",
6
+ );
7
+
8
+ export default ParamsGrid;
@@ -1,31 +1,10 @@
1
- import { EraserIcon } from "lucide-react";
2
1
  import { Control, Controller, useFieldArray } from "react-hook-form";
3
2
  import { Card } from "zudoku/ui/Card.js";
4
- import { Button } from "../../../ui/Button.js";
5
3
  import { Input } from "../../../ui/Input.js";
6
- import { cn } from "../../../util/cn.js";
7
- import { ColorizedParam, useParamColor } from "../ColorizedParam.js";
4
+ import { ColorizedParam } from "../ColorizedParam.js";
5
+ import ParamsGrid from "./ParamsGrid.js";
8
6
  import type { PlaygroundForm } from "./Playground.js";
9
7
 
10
- const PathParamLabel = ({ name }: { name: string }) => {
11
- const color = useParamColor(name);
12
-
13
- return (
14
- <div className="flex items-center">
15
- <div
16
- className="w-2 h-2 rounded-full"
17
- style={{ backgroundColor: `hsl(${color})` }}
18
- />
19
-
20
- <ColorizedParam
21
- slug={name}
22
- name={name}
23
- className="font-mono text-xs m-2 px-1"
24
- />
25
- </div>
26
- );
27
- };
28
-
29
8
  export const PathParams = ({
30
9
  control,
31
10
  }: {
@@ -38,59 +17,40 @@ export const PathParams = ({
38
17
 
39
18
  return (
40
19
  <Card className="rounded-lg">
41
- <table className="w-full">
42
- <tbody>
43
- {fields.map((part, i) => (
44
- <tr key={part.id} className="hover:bg-accent/40">
45
- <td className="w-5/12">
46
- <Controller
47
- control={control}
48
- name={`pathParams.${i}.value`}
49
- render={() => <PathParamLabel name={part.name} />}
50
- />
51
- </td>
52
- <td className="w-7/12">
53
- <div className="flex justify-between items-center">
54
- <Controller
55
- control={control}
56
- name={`pathParams.${i}.value`}
57
- render={({ field }) => (
58
- <Input
59
- {...field}
60
- required
61
- placeholder="Enter value"
62
- className="w-full border-0 shadow-none text-xs font-mono hover:bg-accent"
63
- />
64
- )}
65
- />
66
- <Controller
67
- control={control}
68
- name={`pathParams.${i}.value`}
69
- render={({ field }) => (
70
- <Button
71
- size="icon"
72
- type="button"
73
- variant="ghost"
74
- aria-label="Clear value"
75
- className={cn(
76
- "ms-2 mr-1",
77
- field.value.length === 0
78
- ? "opacity-0 pointer-events-none"
79
- : "opacity-100",
80
- )}
81
- title="Clear value"
82
- onClick={() => field.onChange("")}
83
- >
84
- <EraserIcon size={16} />
85
- </Button>
86
- )}
20
+ <ParamsGrid>
21
+ {fields.map((part, i) => (
22
+ <>
23
+ <Controller
24
+ control={control}
25
+ name={`pathParams.${i}.name`}
26
+ render={() => (
27
+ <div>
28
+ <ColorizedParam
29
+ slug={part.name}
30
+ name={part.name}
31
+ className="font-mono text-xs px-2"
87
32
  />
88
33
  </div>
89
- </td>
90
- </tr>
91
- ))}
92
- </tbody>
93
- </table>
34
+ )}
35
+ />
36
+
37
+ <div className="flex justify-between items-center">
38
+ <Controller
39
+ control={control}
40
+ name={`pathParams.${i}.value`}
41
+ render={({ field }) => (
42
+ <Input
43
+ {...field}
44
+ required
45
+ placeholder="Enter value"
46
+ className="w-full border-0 shadow-none text-xs font-mono hover:bg-accent"
47
+ />
48
+ )}
49
+ />
50
+ </div>
51
+ </>
52
+ ))}
53
+ </ParamsGrid>
94
54
  </Card>
95
55
  );
96
56
  };