zudoku 0.63.0 → 0.64.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 (245) hide show
  1. package/client.d.ts +8 -0
  2. package/dist/app/entry.server.js +14 -1
  3. package/dist/app/entry.server.js.map +1 -1
  4. package/dist/config/config.d.ts +3 -1
  5. package/dist/config/validators/BuildSchema.d.ts +5 -4
  6. package/dist/config/validators/BuildSchema.js +5 -2
  7. package/dist/config/validators/BuildSchema.js.map +1 -1
  8. package/dist/config/validators/InputNavigationSchema.d.ts +20 -20
  9. package/dist/config/validators/validate.d.ts +10 -12
  10. package/dist/config/validators/validate.js +8 -8
  11. package/dist/config/validators/validate.js.map +1 -1
  12. package/dist/flat-config.d.ts +6 -1
  13. package/dist/lib/authentication/authentication.d.ts +17 -9
  14. package/dist/lib/authentication/components/OAuthErrorPage.js +1 -1
  15. package/dist/lib/authentication/components/OAuthErrorPage.js.map +1 -1
  16. package/dist/lib/authentication/components/SignIn.js +6 -5
  17. package/dist/lib/authentication/components/SignIn.js.map +1 -1
  18. package/dist/lib/authentication/components/SignOut.js +6 -6
  19. package/dist/lib/authentication/components/SignOut.js.map +1 -1
  20. package/dist/lib/authentication/components/SignUp.js +5 -5
  21. package/dist/lib/authentication/components/SignUp.js.map +1 -1
  22. package/dist/lib/authentication/hook.d.ts +3 -2
  23. package/dist/lib/authentication/hook.js +12 -8
  24. package/dist/lib/authentication/hook.js.map +1 -1
  25. package/dist/lib/authentication/providers/auth0.js +1 -1
  26. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  27. package/dist/lib/authentication/providers/azureb2c.d.ts +4 -4
  28. package/dist/lib/authentication/providers/azureb2c.js +3 -3
  29. package/dist/lib/authentication/providers/azureb2c.js.map +1 -1
  30. package/dist/lib/authentication/providers/clerk.js +2 -2
  31. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  32. package/dist/lib/authentication/providers/openid.d.ts +7 -7
  33. package/dist/lib/authentication/providers/openid.js +5 -3
  34. package/dist/lib/authentication/providers/openid.js.map +1 -1
  35. package/dist/lib/authentication/providers/supabase/SupabaseAuthUI.d.ts +8 -0
  36. package/dist/lib/authentication/providers/supabase/SupabaseAuthUI.js +39 -0
  37. package/dist/lib/authentication/providers/supabase/SupabaseAuthUI.js.map +1 -0
  38. package/dist/lib/authentication/providers/supabase.js +35 -31
  39. package/dist/lib/authentication/providers/supabase.js.map +1 -1
  40. package/dist/lib/authentication/state.d.ts +1 -5
  41. package/dist/lib/authentication/state.js +2 -14
  42. package/dist/lib/authentication/state.js.map +1 -1
  43. package/dist/lib/components/Zudoku.js +3 -3
  44. package/dist/lib/components/index.d.ts +2 -2
  45. package/dist/lib/components/navigation/Toc.js +1 -1
  46. package/dist/lib/components/navigation/Toc.js.map +1 -1
  47. package/dist/lib/core/RouteGuard.d.ts +1 -1
  48. package/dist/lib/core/RouteGuard.js +6 -14
  49. package/dist/lib/core/RouteGuard.js.map +1 -1
  50. package/dist/lib/core/ZudokuContext.d.ts +1 -0
  51. package/dist/lib/core/ZudokuContext.js +2 -0
  52. package/dist/lib/core/ZudokuContext.js.map +1 -1
  53. package/dist/lib/core/__internal.d.ts +1 -1
  54. package/dist/lib/hooks/index.d.ts +2 -2
  55. package/dist/lib/plugins/markdown/MdxPage.d.ts +2 -1
  56. package/dist/lib/plugins/markdown/MdxPage.js +3 -2
  57. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  58. package/dist/lib/plugins/markdown/index.d.ts +1 -0
  59. package/dist/lib/plugins/markdown/index.js +1 -1
  60. package/dist/lib/plugins/markdown/index.js.map +1 -1
  61. package/dist/lib/plugins/openapi/index.js +4 -9
  62. package/dist/lib/plugins/openapi/index.js.map +1 -1
  63. package/dist/lib/plugins/openapi/playground/CollapsibleHeader.js +1 -1
  64. package/dist/lib/plugins/openapi/playground/CollapsibleHeader.js.map +1 -1
  65. package/dist/lib/plugins/openapi/playground/Playground.js +12 -2
  66. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  67. package/dist/lib/plugins/openapi/playground/RequestLoginDialog.d.ts +2 -1
  68. package/dist/lib/plugins/openapi/playground/RequestLoginDialog.js +10 -2
  69. package/dist/lib/plugins/openapi/playground/RequestLoginDialog.js.map +1 -1
  70. package/dist/lib/plugins/openapi/playground/result-panel/Highlight.d.ts +1 -1
  71. package/dist/lib/plugins/openapi/playground/result-panel/ResponseStatusBar.js +1 -1
  72. package/dist/lib/plugins/openapi/playground/result-panel/ResponseStatusBar.js.map +1 -1
  73. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js +23 -21
  74. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js.map +1 -1
  75. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +1 -1
  76. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -1
  77. package/dist/lib/plugins/openapi/playground/useRememberSkipLoginDialog.js +2 -0
  78. package/dist/lib/plugins/openapi/playground/useRememberSkipLoginDialog.js.map +1 -1
  79. package/dist/lib/shiki.d.ts +1 -1
  80. package/dist/lib/shiki.js +13 -2
  81. package/dist/lib/shiki.js.map +1 -1
  82. package/dist/lib/ui/Callout.d.ts +5 -5
  83. package/dist/lib/ui/Callout.js +5 -5
  84. package/dist/lib/ui/Callout.js.map +1 -1
  85. package/dist/lib/ui/EmbeddedCodeBlock.d.ts +3 -1
  86. package/dist/lib/ui/EmbeddedCodeBlock.js +2 -2
  87. package/dist/lib/ui/EmbeddedCodeBlock.js.map +1 -1
  88. package/dist/lib/ui/ReactComponentDoc.d.ts +1 -1
  89. package/dist/lib/ui/ReactComponentDoc.js +2 -2
  90. package/dist/lib/ui/ReactComponentDoc.js.map +1 -1
  91. package/dist/lib/ui/SyntaxHighlight.d.ts +1 -0
  92. package/dist/lib/ui/SyntaxHighlight.js.map +1 -1
  93. package/dist/lib/util/MdxComponents.d.ts +2 -1
  94. package/dist/lib/util/MdxComponents.js +3 -2
  95. package/dist/lib/util/MdxComponents.js.map +1 -1
  96. package/dist/lib/util/syncZustandState.d.ts +5 -0
  97. package/dist/lib/util/syncZustandState.js +14 -0
  98. package/dist/lib/util/syncZustandState.js.map +1 -0
  99. package/dist/vite/api/SchemaManager.d.ts +3 -1
  100. package/dist/vite/api/SchemaManager.js +22 -3
  101. package/dist/vite/api/SchemaManager.js.map +1 -1
  102. package/dist/vite/api/SchemaManager.test.js +2 -2
  103. package/dist/vite/api/SchemaManager.test.js.map +1 -1
  104. package/dist/vite/plugin-api.js +14 -5
  105. package/dist/vite/plugin-api.js.map +1 -1
  106. package/dist/vite/plugin-docs.js +1 -1
  107. package/dist/vite/plugin-docs.js.map +1 -1
  108. package/dist/vite/plugin-markdown-export.js +4 -2
  109. package/dist/vite/plugin-markdown-export.js.map +1 -1
  110. package/dist/vite/plugin-mdx.js +36 -30
  111. package/dist/vite/plugin-mdx.js.map +1 -1
  112. package/lib/{ErrorAlert-VBJ8aHH7.js → ErrorAlert-DE3Sf66a.js} +1711 -1772
  113. package/lib/ErrorAlert-DE3Sf66a.js.map +1 -0
  114. package/lib/{MdxPage-DFRNwSsc.js → MdxPage-DZfeC0QY.js} +81 -80
  115. package/lib/MdxPage-DZfeC0QY.js.map +1 -0
  116. package/lib/{OAuthErrorPage-DJUOdr6Q.js → OAuthErrorPage-BycMozgn.js} +8 -8
  117. package/lib/{OAuthErrorPage-DJUOdr6Q.js.map → OAuthErrorPage-BycMozgn.js.map} +1 -1
  118. package/lib/{OasProvider-D2NYAaBN.js → OasProvider-Bf5zBDBY.js} +3 -3
  119. package/lib/{OasProvider-D2NYAaBN.js.map → OasProvider-Bf5zBDBY.js.map} +1 -1
  120. package/lib/{OperationList-DmXCI4NU.js → OperationList-Cmiw1xm2.js} +10 -10
  121. package/lib/{OperationList-DmXCI4NU.js.map → OperationList-Cmiw1xm2.js.map} +1 -1
  122. package/lib/{Pagination-CT4VUR6u.js → Pagination-CJszmeSA.js} +3 -3
  123. package/lib/{Pagination-CT4VUR6u.js.map → Pagination-CJszmeSA.js.map} +1 -1
  124. package/lib/RouteGuard-DhU3LRr1.js +81 -0
  125. package/lib/RouteGuard-DhU3LRr1.js.map +1 -0
  126. package/lib/{RouterError-fm21cqlj.js → RouterError-VDLnrFqF.js} +5 -5
  127. package/lib/{RouterError-fm21cqlj.js.map → RouterError-VDLnrFqF.js.map} +1 -1
  128. package/lib/{SchemaList-uElsscMN.js → SchemaList-xZSf3IMh.js} +7 -7
  129. package/lib/{SchemaList-uElsscMN.js.map → SchemaList-xZSf3IMh.js.map} +1 -1
  130. package/lib/{SchemaView-CNQ3VAbI.js → SchemaView-tHXTm5oM.js} +3 -3
  131. package/lib/{SchemaView-CNQ3VAbI.js.map → SchemaView-tHXTm5oM.js.map} +1 -1
  132. package/lib/{Select-CPoGZU_V.js → Select-C1DeCqKv.js} +3 -3
  133. package/lib/{Select-CPoGZU_V.js.map → Select-C1DeCqKv.js.map} +1 -1
  134. package/lib/SignUp-6SGx9Yyq.js +50 -0
  135. package/lib/SignUp-6SGx9Yyq.js.map +1 -0
  136. package/lib/{SyntaxHighlight-B0laqAqK.js → SyntaxHighlight-zvlnSnHB.js} +789 -778
  137. package/lib/{SyntaxHighlight-B0laqAqK.js.map → SyntaxHighlight-zvlnSnHB.js.map} +1 -1
  138. package/lib/{Toc-KzXCRqrX.js → Toc-Da9yp7lo.js} +5 -5
  139. package/lib/Toc-Da9yp7lo.js.map +1 -0
  140. package/lib/{ZudokuContext-BXTZApgy.js → ZudokuContext-BUZ5hkWB.js} +33 -31
  141. package/lib/ZudokuContext-BUZ5hkWB.js.map +1 -0
  142. package/lib/{chunk-PVWAREVJ-BO6B-RAk.js → chunk-PVWAREVJ-BMhpCH5D.js} +7 -7
  143. package/lib/{chunk-PVWAREVJ-BO6B-RAk.js.map → chunk-PVWAREVJ-BMhpCH5D.js.map} +1 -1
  144. package/lib/{circular-BWT7_Ahq.js → circular-DvuimBGQ.js} +2 -2
  145. package/lib/{circular-BWT7_Ahq.js.map → circular-DvuimBGQ.js.map} +1 -1
  146. package/lib/{createServer-zhJZSgor.js → createServer-D9UvCoDf.js} +4 -4
  147. package/lib/{createServer-zhJZSgor.js.map → createServer-D9UvCoDf.js.map} +1 -1
  148. package/lib/{errors-XqO6MsfU.js → errors-CuGgh3hf.js} +2 -2
  149. package/lib/{errors-XqO6MsfU.js.map → errors-CuGgh3hf.js.map} +1 -1
  150. package/lib/hook-CMeoxziF.js +40 -0
  151. package/lib/hook-CMeoxziF.js.map +1 -0
  152. package/lib/{index-BPSpOxTK.js → index-B1rmok4X.js} +148 -147
  153. package/lib/index-B1rmok4X.js.map +1 -0
  154. package/lib/{index-D8Btv4uT.js → index-Cr9_YzOZ.js} +826 -780
  155. package/lib/index-Cr9_YzOZ.js.map +1 -0
  156. package/lib/{index-C5L4favO.js → index-rYHsvtTo.js} +2 -2
  157. package/lib/{index-C5L4favO.js.map → index-rYHsvtTo.js.map} +1 -1
  158. package/lib/{mutation-CdGPxHNX.js → mutation-BSU0xu4m.js} +2 -2
  159. package/lib/{mutation-CdGPxHNX.js.map → mutation-BSU0xu4m.js.map} +1 -1
  160. package/lib/ui/Callout.js +18 -18
  161. package/lib/ui/Callout.js.map +1 -1
  162. package/lib/ui/CodeBlock.js +217 -7
  163. package/lib/ui/CodeBlock.js.map +1 -1
  164. package/lib/ui/EmbeddedCodeBlock.js +22 -19
  165. package/lib/ui/EmbeddedCodeBlock.js.map +1 -1
  166. package/lib/ui/ReactComponentDoc.js +13 -13
  167. package/lib/ui/ReactComponentDoc.js.map +1 -1
  168. package/lib/ui/SyntaxHighlight.js +3 -3
  169. package/lib/{useExposedProps-Cd7Yg_uG.js → useExposedProps-U3pmsHaG.js} +2 -2
  170. package/lib/{useExposedProps-Cd7Yg_uG.js.map → useExposedProps-U3pmsHaG.js.map} +1 -1
  171. package/lib/zudoku.__internal.js +7 -7
  172. package/lib/zudoku.auth-auth0.js +13 -13
  173. package/lib/zudoku.auth-auth0.js.map +1 -1
  174. package/lib/zudoku.auth-azureb2c.js +28 -28
  175. package/lib/zudoku.auth-azureb2c.js.map +1 -1
  176. package/lib/zudoku.auth-clerk.js +40 -40
  177. package/lib/zudoku.auth-clerk.js.map +1 -1
  178. package/lib/zudoku.auth-openid.js +53 -56
  179. package/lib/zudoku.auth-openid.js.map +1 -1
  180. package/lib/zudoku.auth-supabase.js +111 -52
  181. package/lib/zudoku.auth-supabase.js.map +1 -1
  182. package/lib/zudoku.components.js +6 -6
  183. package/lib/zudoku.hooks.js +4 -4
  184. package/lib/zudoku.plugin-api-catalog.js +5 -5
  185. package/lib/zudoku.plugin-api-keys.js +99 -99
  186. package/lib/zudoku.plugin-custom-pages.js +1 -1
  187. package/lib/zudoku.plugin-markdown.js +10 -9
  188. package/lib/zudoku.plugin-markdown.js.map +1 -1
  189. package/lib/zudoku.plugin-openapi.js +6 -7
  190. package/lib/zudoku.plugin-openapi.js.map +1 -1
  191. package/lib/zudoku.plugin-redirect.js +1 -1
  192. package/lib/zudoku.plugin-search-pagefind.js +38 -38
  193. package/lib/zudoku.plugin-search-pagefind.js.map +1 -1
  194. package/lib/zudoku.router.js +2 -2
  195. package/package.json +18 -10
  196. package/src/app/entry.server.tsx +16 -6
  197. package/src/app/main.css +61 -9
  198. package/src/lib/authentication/authentication.ts +22 -4
  199. package/src/lib/authentication/components/OAuthErrorPage.tsx +1 -1
  200. package/src/lib/authentication/components/SignIn.tsx +7 -5
  201. package/src/lib/authentication/components/SignOut.tsx +7 -6
  202. package/src/lib/authentication/components/SignUp.tsx +5 -8
  203. package/src/lib/authentication/hook.ts +21 -10
  204. package/src/lib/authentication/providers/auth0.tsx +2 -1
  205. package/src/lib/authentication/providers/azureb2c.tsx +10 -3
  206. package/src/lib/authentication/providers/clerk.tsx +9 -2
  207. package/src/lib/authentication/providers/openid.tsx +20 -15
  208. package/src/lib/authentication/providers/supabase/SupabaseAuthUI.tsx +75 -0
  209. package/src/lib/authentication/providers/supabase.tsx +59 -43
  210. package/src/lib/authentication/state.ts +3 -23
  211. package/src/lib/components/Zudoku.tsx +3 -3
  212. package/src/lib/components/navigation/Toc.tsx +3 -3
  213. package/src/lib/core/RouteGuard.tsx +33 -13
  214. package/src/lib/core/ZudokuContext.ts +3 -0
  215. package/src/lib/plugins/markdown/MdxPage.tsx +4 -1
  216. package/src/lib/plugins/markdown/index.tsx +2 -0
  217. package/src/lib/plugins/openapi/index.tsx +9 -29
  218. package/src/lib/plugins/openapi/playground/CollapsibleHeader.tsx +2 -2
  219. package/src/lib/plugins/openapi/playground/Playground.tsx +13 -2
  220. package/src/lib/plugins/openapi/playground/RequestLoginDialog.tsx +20 -1
  221. package/src/lib/plugins/openapi/playground/result-panel/ResponseStatusBar.tsx +2 -2
  222. package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +102 -58
  223. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +1 -1
  224. package/src/lib/plugins/openapi/playground/useRememberSkipLoginDialog.tsx +3 -0
  225. package/src/lib/shiki.ts +16 -2
  226. package/src/lib/ui/Callout.tsx +10 -5
  227. package/src/lib/ui/EmbeddedCodeBlock.tsx +6 -3
  228. package/src/lib/ui/ReactComponentDoc.tsx +17 -17
  229. package/src/lib/ui/SyntaxHighlight.tsx +6 -1
  230. package/src/lib/util/MdxComponents.tsx +3 -5
  231. package/src/lib/util/syncZustandState.ts +22 -0
  232. package/lib/CodeBlock-CanTUJLl.js +0 -221
  233. package/lib/CodeBlock-CanTUJLl.js.map +0 -1
  234. package/lib/ErrorAlert-VBJ8aHH7.js.map +0 -1
  235. package/lib/MdxPage-DFRNwSsc.js.map +0 -1
  236. package/lib/RouteGuard-Bg0Lu0OU.js +0 -56
  237. package/lib/RouteGuard-Bg0Lu0OU.js.map +0 -1
  238. package/lib/SignUp-BraHuRN_.js +0 -56
  239. package/lib/SignUp-BraHuRN_.js.map +0 -1
  240. package/lib/Toc-KzXCRqrX.js.map +0 -1
  241. package/lib/ZudokuContext-BXTZApgy.js.map +0 -1
  242. package/lib/hook-CAebs2rv.js +0 -31
  243. package/lib/hook-CAebs2rv.js.map +0 -1
  244. package/lib/index-BPSpOxTK.js.map +0 -1
  245. package/lib/index-D8Btv4uT.js.map +0 -1
@@ -27,6 +27,7 @@ import {
27
27
  } from "../../components/navigation/utils.js";
28
28
  import { Pagination } from "../../components/Pagination.js";
29
29
  import { Typography } from "../../components/Typography.js";
30
+ import { joinUrl } from "../../util/joinUrl.js";
30
31
  import type { MdxComponentsType } from "../../util/MdxComponents.js";
31
32
  import { ChatGPTLogo } from "./assets/ChatGPTLogo.js";
32
33
  import { ClaudeLogo } from "./assets/ClaudeLogo.js";
@@ -55,6 +56,7 @@ const MarkdownHeadings = {
55
56
 
56
57
  export const MdxPage = ({
57
58
  mdxComponent: MdxComponent,
59
+ basePath,
58
60
  frontmatter = {},
59
61
  defaultOptions,
60
62
  __filepath,
@@ -62,6 +64,7 @@ export const MdxPage = ({
62
64
  excerpt,
63
65
  }: PropsWithChildren<
64
66
  Omit<MDXImport, "default"> & {
67
+ basePath: string;
65
68
  mdxComponent: MDXImport["default"];
66
69
  defaultOptions?: MarkdownPluginDefaultOptions;
67
70
  }
@@ -101,7 +104,7 @@ export const MdxPage = ({
101
104
  const copyMarkdownConfig =
102
105
  frontmatter.copyPage !== false && defaultOptions?.copyPage !== false;
103
106
 
104
- const markdownUrl = `${location.pathname}.md`;
107
+ const markdownUrl = joinUrl(basePath, `${location.pathname}.md`);
105
108
 
106
109
  const handleCopyMarkdown = async () => {
107
110
  const response = await fetch(markdownUrl);
@@ -5,6 +5,7 @@ import type { ZudokuDocsConfig } from "../../../config/validators/validate.js";
5
5
  import type { ZudokuPlugin } from "../../core/plugins.js";
6
6
 
7
7
  export interface MarkdownPluginOptions extends ZudokuDocsConfig {
8
+ basePath: string;
8
9
  fileImports: Record<string, () => Promise<MDXImport>>;
9
10
  }
10
11
  export type MarkdownPluginDefaultOptions = Pick<
@@ -46,6 +47,7 @@ export const markdownPlugin = (
46
47
  return {
47
48
  element: (
48
49
  <MdxPage
50
+ basePath={options.basePath}
49
51
  mdxComponent={Component}
50
52
  {...props}
51
53
  defaultOptions={options.defaultOptions}
@@ -1,8 +1,7 @@
1
- import { CirclePlayIcon, LogInIcon } from "lucide-react";
2
- import type { ReactNode } from "react";
1
+ import { CirclePlayIcon } from "lucide-react";
2
+ import type { PropsWithChildren } from "react";
3
3
  import { matchPath } from "react-router";
4
4
  import type { NavigationItem } from "../../../config/validators/NavigationSchema.js";
5
- import { useAuth } from "../../authentication/hook.js";
6
5
  import type { ZudokuPlugin } from "../../core/plugins.js";
7
6
  import { Button } from "../../ui/Button.js";
8
7
  import { joinUrl } from "../../util/joinUrl.js";
@@ -71,47 +70,28 @@ export const openApiPlugin = (config: OasPluginConfig): ZudokuPlugin => {
71
70
  },
72
71
  getMdxComponents: () => ({
73
72
  OpenPlaygroundButton: ({
74
- requireAuth,
75
73
  server,
76
- method,
77
- url,
74
+ method = "get",
75
+ url = "/",
78
76
  children,
79
77
  ...props
80
- }: Partial<PlaygroundContentProps> & { children: ReactNode } & Pick<
81
- PlaygroundContentProps,
82
- "server"
83
- > & {
84
- requireAuth: boolean;
85
- }) => {
86
- const auth = useAuth();
87
-
78
+ }: PropsWithChildren<Partial<PlaygroundContentProps>>) => {
88
79
  if (!server) {
89
80
  throw new Error("Server is required");
90
81
  }
91
82
 
92
- if (requireAuth && !auth.isAuthenticated) {
93
- return (
94
- <Button
95
- className="gap-2 items-center"
96
- variant="outline"
97
- onClick={auth.login}
98
- >
99
- Login to open in Playground <LogInIcon size={16} />
100
- </Button>
101
- );
102
- }
103
-
104
83
  return (
105
84
  <PlaygroundDialog
106
- url={url ?? "/"}
107
- method={method ?? "get"}
85
+ url={url}
86
+ method={method}
108
87
  server={server}
109
88
  {...props}
110
89
  >
111
90
  <Button className="gap-2 items-center" variant="outline">
112
91
  {children ?? (
113
92
  <>
114
- Open in Playground <CirclePlayIcon size={16} />
93
+ Open in Playground
94
+ <CirclePlayIcon size={16} />
115
95
  </>
116
96
  )}
117
97
  </Button>
@@ -12,7 +12,7 @@ export const CollapsibleHeaderTrigger = ({
12
12
  return (
13
13
  <div
14
14
  className={cn(
15
- "grid grid-cols-[max-content_1fr_min-content_max-content] items-center gap-4 group bg-muted w-full h-10 ps-4 pe-2 border-b",
15
+ "grid grid-cols-[max-content_1fr_min-content_max-content] items-center gap-2 group bg-muted w-full h-10 ps-4 pe-2 border-b",
16
16
  className,
17
17
  )}
18
18
  >
@@ -24,7 +24,7 @@ export const CollapsibleHeaderTrigger = ({
24
24
  )}
25
25
  >
26
26
  <ChevronUpIcon
27
- className="group-data-[state=open]:rotate-180 transition-transform flex-shrink-0"
27
+ className="group-data-[state=open]:rotate-180 transition-transform shrink-0"
28
28
  size={16}
29
29
  />
30
30
  </CollapsibleTrigger>
@@ -145,6 +145,7 @@ export const Playground = ({
145
145
  const { setRememberedIdentity, getRememberedIdentity } = useIdentityStore();
146
146
  const [, startTransition] = useTransition();
147
147
  const { skipLogin, setSkipLogin } = useRememberSkipLoginDialog();
148
+ const [isLoginDialogDismissed, setIsLoginDialogDismissed] = useState(false);
148
149
  const [showLongRunningWarning, setShowLongRunningWarning] = useState(false);
149
150
  const abortControllerRef = useRef<AbortController | undefined>(undefined);
150
151
  const latestSetRememberedIdentity = useLatest(setRememberedIdentity);
@@ -361,7 +362,7 @@ export const Playground = ({
361
362
  </div>
362
363
  );
363
364
 
364
- const showLogin = requiresLogin && !skipLogin;
365
+ const showLogin = requiresLogin && !skipLogin && !isLoginDialogDismissed;
365
366
  const isBodySupported = ["POST", "PUT", "PATCH", "DELETE"].includes(
366
367
  method.toUpperCase(),
367
368
  );
@@ -397,7 +398,17 @@ export const Playground = ({
397
398
  />
398
399
  <RequestLoginDialog
399
400
  open={showLogin}
400
- setOpen={(open) => setSkipLogin(!open)}
401
+ setOpen={(open) => {
402
+ if (!open) {
403
+ setIsLoginDialogDismissed(true);
404
+ }
405
+ }}
406
+ onSkip={(rememberSkip) => {
407
+ setIsLoginDialogDismissed(true);
408
+ if (rememberSkip) {
409
+ setSkipLogin(true);
410
+ }
411
+ }}
401
412
  onSignUp={onSignUp}
402
413
  onLogin={onLogin}
403
414
  />
@@ -1,4 +1,6 @@
1
+ import { useState } from "react";
1
2
  import { Button } from "zudoku/ui/Button.js";
3
+ import { Checkbox } from "zudoku/ui/Checkbox.js";
2
4
  import {
3
5
  Dialog,
4
6
  DialogContent,
@@ -6,18 +8,28 @@ import {
6
8
  DialogFooter,
7
9
  DialogTitle,
8
10
  } from "zudoku/ui/Dialog.js";
11
+ import { Label } from "zudoku/ui/Label.js";
9
12
 
10
13
  const RequestLoginDialog = ({
11
14
  open,
12
15
  setOpen,
13
16
  onSignUp,
14
17
  onLogin,
18
+ onSkip,
15
19
  }: {
16
20
  open: boolean;
17
21
  onSignUp?: () => void;
18
22
  onLogin?: () => void;
19
23
  setOpen: (open: boolean) => void;
24
+ onSkip?: (rememberSkip: boolean) => void;
20
25
  }) => {
26
+ const [rememberSkip, setRememberSkip] = useState(false);
27
+
28
+ const handleSkip = () => {
29
+ onSkip?.(rememberSkip);
30
+ setOpen(false);
31
+ };
32
+
21
33
  return (
22
34
  <Dialog open={open} onOpenChange={setOpen}>
23
35
  <DialogContent>
@@ -26,8 +38,15 @@ const RequestLoginDialog = ({
26
38
  The Playground is a tool for developers to test and explore our APIs.
27
39
  To use the Playground, you need to login.
28
40
  </DialogDescription>
41
+ <Label className="flex items-center gap-2 font-normal">
42
+ <Checkbox
43
+ checked={rememberSkip}
44
+ onCheckedChange={(checked) => setRememberSkip(checked === true)}
45
+ />
46
+ Don't show this again
47
+ </Label>
29
48
  <DialogFooter className="flex gap-2 sm:justify-between">
30
- <Button type="button" variant="ghost" onClick={() => setOpen(false)}>
49
+ <Button type="button" variant="outline" onClick={handleSkip}>
31
50
  Skip
32
51
  </Button>
33
52
  <div className="flex gap-2">
@@ -84,7 +84,7 @@ export const ResponseStatusBar = ({
84
84
  };
85
85
 
86
86
  return (
87
- <div className="relative flex h-10 text-xs gap-4 px-4 items-center justify-between font-mono border-b">
87
+ <div className="relative shrink-0 flex h-10 text-xs gap-4 px-4 items-center justify-between font-mono border-b">
88
88
  <div className="flex items-center gap-2">
89
89
  <ResponseCodeCircle status={status} /> {status ?? "Sending Request..."}
90
90
  {status ? ` ${statusCodeMap[status]}` : ""}
@@ -104,7 +104,7 @@ export const ResponseStatusBar = ({
104
104
  </div>
105
105
  </div>
106
106
  <div
107
- className="h-full bg-neutral-500/10 absolute left-0 -bottom-0 z-10 transition-all duration-200 ease-in-out"
107
+ className="h-full bg-neutral-500/10 absolute left-0 bottom-0 z-10 transition-all duration-200 ease-in-out"
108
108
  style={{
109
109
  opacity: isFinished ? 0 : 1,
110
110
  width: isFinished ? 0 : `${progress * 100}%`,
@@ -5,7 +5,9 @@ import {
5
5
  DownloadIcon,
6
6
  EyeIcon,
7
7
  EyeOffIcon,
8
+ MinusCircleIcon,
8
9
  PlusCircleIcon,
10
+ SquareCodeIcon,
9
11
  } from "lucide-react";
10
12
  import { useState } from "react";
11
13
  import { Button } from "zudoku/ui/Button.js";
@@ -22,6 +24,7 @@ import {
22
24
  SelectTrigger,
23
25
  SelectValue,
24
26
  } from "zudoku/ui/Select.js";
27
+ import { SyntaxHighlight } from "zudoku/ui/SyntaxHighlight.js";
25
28
  import { cn } from "../../../../util/cn.js";
26
29
  import createVariantComponent from "../../../../util/createVariantComponent.js";
27
30
  import { humanFileSize } from "../../../../util/humanFileSize.js";
@@ -30,7 +33,6 @@ import {
30
33
  CollapsibleHeaderTrigger,
31
34
  } from "../CollapsibleHeader.js";
32
35
  import { convertToTypes } from "./convertToTypes.js";
33
- import { Highlight } from "./Highlight.js";
34
36
 
35
37
  const mimeTypeToLanguage = (mimeType: string) => {
36
38
  const mimeTypeMapping = {
@@ -92,28 +94,35 @@ const Row = createVariantComponent(
92
94
  "grid-cols-subgrid grid border-b col-span-full px-4 py-1.5 font-mono text-xs",
93
95
  );
94
96
 
95
- const RowContent = createVariantComponent("div", "py-1 break-all");
97
+ const RowContent = createVariantComponent("div", "py-1 break-words");
96
98
  const RowValue = ({ value, header }: { value: string; header: string }) => {
97
99
  const secretHeaders = ["authorization", "key", "secret", "token"];
98
100
  const isSecret = secretHeaders.includes(header.toLowerCase());
99
101
  const [revealed, setRevealed] = useState(!isSecret);
100
102
  return (
101
103
  <RowContent
102
- className={cn(isSecret && "cursor-pointer flex group")}
104
+ className={cn(
105
+ "max-h-28 overflow-auto",
106
+ isSecret && "cursor-pointer flex group",
107
+ )}
103
108
  onClick={() => {
104
109
  if (isSecret) {
105
110
  setRevealed((prev) => !prev);
106
111
  }
107
112
  }}
108
113
  >
109
- <SecretText secret={value} previewChars={0} revealed={revealed} />
110
- {isSecret ? (
111
- revealed ? (
112
- <EyeOffIcon size={14} className={cn("hidden group-hover:block")} />
113
- ) : (
114
- <EyeIcon size={14} className={cn("hidden group-hover:block")} />
115
- )
116
- ) : null}
114
+ {!isSecret ? (
115
+ value
116
+ ) : (
117
+ <>
118
+ <SecretText secret={value} previewChars={0} revealed={revealed} />
119
+ {revealed ? (
120
+ <EyeOffIcon size={14} className={cn("hidden group-hover:block")} />
121
+ ) : (
122
+ <EyeIcon size={14} className={cn("hidden group-hover:block")} />
123
+ )}
124
+ </>
125
+ )}
117
126
  </RowContent>
118
127
  );
119
128
  };
@@ -174,13 +183,13 @@ export const ResponseTab = ({
174
183
  <>
175
184
  <Collapsible defaultOpen>
176
185
  <CollapsibleHeaderTrigger>
177
- <CornerDownRightIcon size={16} />
186
+ <CornerDownRightIcon size={14} />
178
187
  <CollapsibleHeader className="col-span-2">
179
- Header Request
188
+ Request Headers
180
189
  </CollapsibleHeader>
181
190
  </CollapsibleHeaderTrigger>
182
191
  <CollapsibleContent>
183
- <div className="grid grid-cols-2 gap-x-6 text-sm">
192
+ <div className="grid grid-cols-[2fr_3fr] gap-x-6 text-sm">
184
193
  {request.headers
185
194
  .slice(0, MAX_HEADERS_TO_SHOW)
186
195
  .map(([key, value]) => (
@@ -189,19 +198,45 @@ export const ResponseTab = ({
189
198
  <RowValue value={value} header={key} />
190
199
  </Row>
191
200
  ))}
201
+ {request.headers.length > MAX_HEADERS_TO_SHOW && (
202
+ <Collapsible className="col-span-full grid-cols-subgrid grid group">
203
+ <CollapsibleTrigger className="data-[state=open]:hidden justify-center col-span-2 text-xs text-muted-foreground hover:text-primary border-b h-8 flex items-center gap-2">
204
+ Show {request.headers.length - MAX_HEADERS_TO_SHOW} more
205
+ headers
206
+ <PlusCircleIcon size={12} className="text-muted-foreground" />
207
+ </CollapsibleTrigger>
208
+ <CollapsibleContent className="col-span-full grid grid-cols-subgrid">
209
+ {request.headers
210
+ .slice(MAX_HEADERS_TO_SHOW)
211
+ .map(([key, value]) => (
212
+ <Row key={key}>
213
+ <RowContent>{key}</RowContent>
214
+ <RowValue value={value} header={key} />
215
+ </Row>
216
+ ))}
217
+ <CollapsibleTrigger className="justify-center col-span-2 text-xs text-muted-foreground hover:text-primary border-b h-8 flex items-center gap-2">
218
+ Hide {request.headers.length - MAX_HEADERS_TO_SHOW} headers
219
+ <MinusCircleIcon
220
+ size={12}
221
+ className="text-muted-foreground"
222
+ />
223
+ </CollapsibleTrigger>
224
+ </CollapsibleContent>
225
+ </Collapsible>
226
+ )}
192
227
  </div>
193
228
  </CollapsibleContent>
194
229
  </Collapsible>
195
230
 
196
231
  <Collapsible defaultOpen>
197
232
  <CollapsibleHeaderTrigger>
198
- <CornerDownLeftIcon size={16} />
233
+ <CornerDownLeftIcon size={14} />
199
234
  <CollapsibleHeader className="col-span-2">
200
- Header Response
235
+ Response Headers
201
236
  </CollapsibleHeader>
202
237
  </CollapsibleHeaderTrigger>
203
238
  <CollapsibleContent>
204
- <div className="grid grid-cols-2 gap-x-6 text-sm">
239
+ <div className="grid grid-cols-[2fr_3fr] gap-x-6 text-sm">
205
240
  {sortedHeaders.slice(0, MAX_HEADERS_TO_SHOW).map(([key, value]) => (
206
241
  <Row key={key}>
207
242
  <RowContent>{key}</RowContent>
@@ -211,10 +246,7 @@ export const ResponseTab = ({
211
246
  {sortedHeaders.length > MAX_HEADERS_TO_SHOW && (
212
247
  <Collapsible className="col-span-full grid-cols-subgrid grid group">
213
248
  <CollapsibleTrigger className="data-[state=open]:hidden justify-center col-span-2 text-xs text-muted-foreground hover:text-primary border-b h-8 flex items-center gap-2">
214
- <span>
215
- Show {sortedHeaders.length - MAX_HEADERS_TO_SHOW} more
216
- headers
217
- </span>
249
+ Show {sortedHeaders.length - MAX_HEADERS_TO_SHOW} more headers
218
250
  <PlusCircleIcon size={12} className="text-muted-foreground" />
219
251
  </CollapsibleTrigger>
220
252
  <CollapsibleContent className="col-span-full grid grid-cols-subgrid">
@@ -226,6 +258,13 @@ export const ResponseTab = ({
226
258
  <RowValue value={value} header={key} />
227
259
  </Row>
228
260
  ))}
261
+ <CollapsibleTrigger className="justify-center col-span-2 text-xs text-muted-foreground hover:text-primary border-b h-8 flex items-center gap-2">
262
+ Hide {sortedHeaders.length - MAX_HEADERS_TO_SHOW} headers
263
+ <MinusCircleIcon
264
+ size={12}
265
+ className="text-muted-foreground"
266
+ />
267
+ </CollapsibleTrigger>
229
268
  </CollapsibleContent>
230
269
  </Collapsible>
231
270
  )}
@@ -233,26 +272,30 @@ export const ResponseTab = ({
233
272
  </CollapsibleContent>
234
273
  </Collapsible>
235
274
 
236
- <div className="flex gap-2 justify-between items-center border-b h-10">
275
+ <div className="flex gap-2 justify-between items-center border-b px-2 flex-0">
276
+ <CollapsibleHeader className="flex items-center gap-2">
277
+ <SquareCodeIcon size={14} />
278
+ Response body
279
+ </CollapsibleHeader>
237
280
  {jsonContent && !isBinary && (
238
- <div className="px-2">
239
- <Select
240
- value={view}
241
- onValueChange={(value) => setView(value as "formatted" | "raw")}
242
- >
243
- <SelectTrigger className="min-w-32 border-none h-8">
244
- <SelectValue placeholder="View" />
245
- </SelectTrigger>
246
- <SelectContent>
247
- <SelectItem value="formatted">Formatted</SelectItem>
248
- <SelectItem value="raw">Raw</SelectItem>
249
- <SelectItem value="types">Types</SelectItem>
250
- </SelectContent>
251
- </Select>
252
- </div>
281
+ <Select
282
+ value={view}
283
+ onValueChange={(value) =>
284
+ setView(value as "formatted" | "raw" | "types")
285
+ }
286
+ >
287
+ <SelectTrigger className="max-w-32 border-0 bg-transparent">
288
+ <SelectValue placeholder="View" />
289
+ </SelectTrigger>
290
+ <SelectContent>
291
+ <SelectItem value="formatted">Formatted</SelectItem>
292
+ <SelectItem value="raw">Raw</SelectItem>
293
+ <SelectItem value="types">Types</SelectItem>
294
+ </SelectContent>
295
+ </Select>
253
296
  )}
254
297
  </div>
255
- <div>
298
+ <div className="flex-1">
256
299
  {isBinary ? (
257
300
  <div className="p-4 text-center">
258
301
  <div className="flex flex-col items-center gap-4">
@@ -272,26 +315,27 @@ export const ResponseTab = ({
272
315
  </div>
273
316
  </div>
274
317
  ) : (
275
- <div className="overflow-auto max-w-full p-4 text-xs max-h-[calc(83.333vh-180px)]">
276
- <Highlight
277
- language={
278
- view === "types"
279
- ? "typescript"
280
- : view === "raw"
281
- ? jsonContent
282
- ? "plain"
283
- : detectedLanguage
284
- : "json"
285
- }
286
- code={
287
- (view === "raw"
288
- ? body
289
- : view === "types"
290
- ? types.data?.lines.join("\n")
291
- : beautifiedBody) ?? ""
292
- }
293
- />
294
- </div>
318
+ <SyntaxHighlight
319
+ className="text-xs flex-1"
320
+ embedded
321
+ fullHeight
322
+ language={
323
+ view === "types"
324
+ ? "typescript"
325
+ : view === "raw"
326
+ ? jsonContent
327
+ ? "plain"
328
+ : detectedLanguage
329
+ : "json"
330
+ }
331
+ code={
332
+ (view === "raw"
333
+ ? body
334
+ : view === "types"
335
+ ? types.data?.lines.join("\n")
336
+ : beautifiedBody) ?? ""
337
+ }
338
+ />
295
339
  )}
296
340
  </div>
297
341
  </>
@@ -25,7 +25,7 @@ export const ResultPanel = ({
25
25
  tip?: React.ReactNode;
26
26
  }) => {
27
27
  return (
28
- <div className="overflow-y-auto h-[80vh] bg-muted/50">
28
+ <div className="flex flex-col overflow-y-auto h-[80vh] bg-muted/50">
29
29
  {(queryMutation.isPending || queryMutation.data) && (
30
30
  <ResponseStatusBar
31
31
  status={queryMutation.data?.status}
@@ -1,5 +1,6 @@
1
1
  import { create } from "zustand";
2
2
  import { createJSONStorage, persist } from "zustand/middleware";
3
+ import { syncZustandState } from "../../../util/syncZustandState.js";
3
4
 
4
5
  type RememberSkipLoginState = {
5
6
  skipLogin: boolean;
@@ -18,3 +19,5 @@ export const useRememberSkipLoginDialog = create<RememberSkipLoginState>()(
18
19
  },
19
20
  ),
20
21
  );
22
+
23
+ syncZustandState(useRememberSkipLoginDialog);
package/src/lib/shiki.ts CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  } from "@shikijs/transformers";
8
8
  import type { Root } from "hast";
9
9
  import { toJsxRuntime } from "hast-util-to-jsx-runtime";
10
- import { Fragment, type JSX } from "react";
10
+ import { createElement, Fragment } from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
12
12
  import type {
13
13
  BundledLanguage,
@@ -21,6 +21,9 @@ import type { Pluggable } from "unified";
21
21
  import { visit } from "unist-util-visit";
22
22
  import { cn } from "./util/cn.js";
23
23
 
24
+ export const HIGHLIGHT_CODE_BLOCK_CLASS =
25
+ "overflow-x-auto scrollbar not-inline";
26
+
24
27
  const engine = createJavaScriptRegexEngine({ forgiving: true });
25
28
  export const highlighter = await createHighlighterCore({
26
29
  engine,
@@ -143,5 +146,16 @@ export const highlight = (
143
146
  themes,
144
147
  });
145
148
 
146
- return toJsxRuntime(value, { Fragment, jsx, jsxs }) as JSX.Element;
149
+ return toJsxRuntime(value, {
150
+ Fragment,
151
+ jsx,
152
+ jsxs,
153
+ components: {
154
+ code: (props) =>
155
+ createElement("code", {
156
+ ...props,
157
+ className: cn(props.className, HIGHLIGHT_CODE_BLOCK_CLASS),
158
+ }),
159
+ },
160
+ });
147
161
  };
@@ -14,7 +14,8 @@ const stylesMap = {
14
14
  bg: "bg-gray-100 dark:bg-zinc-800/50",
15
15
  iconColor: "text-gray-600 dark:text-zinc-300",
16
16
  titleColor: "text-gray-600 dark:text-zinc-300",
17
- textColor: "text-gray-600 dark:text-zinc-300",
17
+ textColor:
18
+ "text-gray-600 dark:text-zinc-300 [&_a]:hover:text-gray-700 [&_a]:dark:hover:text-zinc-400",
18
19
  Icon: InfoIcon as LucideIcon,
19
20
  },
20
21
  tip: {
@@ -22,7 +23,8 @@ const stylesMap = {
22
23
  bg: "bg-green-200/25 dark:bg-green-950/70",
23
24
  iconColor: "text-green-600 dark:text-green-200",
24
25
  titleColor: "text-green-700 dark:text-green-200",
25
- textColor: "text-green-600 dark:text-green-50",
26
+ textColor:
27
+ "text-green-600 dark:text-green-50 [&_a]:hover:text-green-700 [&_a]:dark:hover:text-green-300",
26
28
  Icon: LightbulbIcon as LucideIcon,
27
29
  },
28
30
  info: {
@@ -30,7 +32,8 @@ const stylesMap = {
30
32
  bg: "bg-blue-50 dark:bg-blue-950/40",
31
33
  iconColor: "text-blue-400 dark:text-blue-200",
32
34
  titleColor: "text-blue-700 dark:text-blue-200",
33
- textColor: "text-blue-600 dark:text-blue-100",
35
+ textColor:
36
+ "text-blue-600 dark:text-blue-100 [&_a]:hover:text-blue-800 [&_a]:dark:hover:text-blue-300",
34
37
  Icon: InfoIcon as LucideIcon,
35
38
  },
36
39
  caution: {
@@ -38,7 +41,8 @@ const stylesMap = {
38
41
  bg: "bg-yellow-100/60 dark:bg-yellow-400/10",
39
42
  iconColor: "text-yellow-500 dark:text-yellow-300",
40
43
  titleColor: "text-yellow-600 dark:text-yellow-300",
41
- textColor: "text-yellow-700 dark:text-yellow-200",
44
+ textColor:
45
+ "text-yellow-700 dark:text-yellow-200 [&_a]:hover:text-yellow-800 [&_a]:dark:hover:text-yellow-300",
42
46
  Icon: AlertTriangleIcon as LucideIcon,
43
47
  },
44
48
  danger: {
@@ -46,7 +50,8 @@ const stylesMap = {
46
50
  bg: "bg-rose-50 dark:bg-rose-950/40",
47
51
  iconColor: "text-rose-400 dark:text-rose-300",
48
52
  titleColor: "text-rose-800 dark:text-rose-300",
49
- textColor: "text-rose-700 dark:text-rose-100",
53
+ textColor:
54
+ "text-rose-700 dark:text-rose-100 [&_a]:hover:text-rose-800 [&_a]:dark:hover:text-rose-300",
50
55
  Icon: ShieldAlertIcon as LucideIcon,
51
56
  },
52
57
  } as const;
@@ -19,13 +19,14 @@ export type CodeBlockProps = {
19
19
 
20
20
  export const EmbeddedCodeBlock = ({
21
21
  children,
22
+ fullHeight,
22
23
  language,
23
24
  showCopy = "hover",
24
25
  showCopyText,
25
26
  showLanguageIndicator = true,
26
27
  showLineNumbers,
27
28
  ...props
28
- }: CodeBlockProps) => {
29
+ }: CodeBlockProps & { fullHeight?: boolean }) => {
29
30
  const [isCopied, setIsCopied] = useState(false);
30
31
  const ref = useRef<HTMLDivElement>(null);
31
32
 
@@ -36,11 +37,13 @@ export const EmbeddedCodeBlock = ({
36
37
  className={cn(
37
38
  "code-block-wrapper relative group bg-muted/50",
38
39
  showLineNumbers && "line-numbers",
40
+ fullHeight && "h-full",
39
41
  )}
40
42
  >
41
43
  <div
42
44
  className={cn(
43
- "code-block text-sm not-prose scrollbar overflow-x-auto [&>pre]:p-2",
45
+ "code-block text-sm not-prose scrollbar [&>pre]:overflow-x-auto [&>pre]:p-2",
46
+ fullHeight && "h-full [&>pre]:h-full",
44
47
  props.className,
45
48
  )}
46
49
  ref={ref}
@@ -50,7 +53,7 @@ export const EmbeddedCodeBlock = ({
50
53
  {showLanguageIndicator && (
51
54
  <span
52
55
  className={cn(
53
- "absolute top-1.5 end-3 !text-[11px] font-mono text-muted-foreground transition group-hover:opacity-0",
56
+ "absolute top-1.5 end-3 text-[11px]! font-mono text-muted-foreground transition group-hover:opacity-0",
54
57
  showCopy === "always" && "hidden",
55
58
  )}
56
59
  >