zudoku 0.33.0 → 0.33.2-local.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/config/validators/common.d.ts +226 -8
  2. package/dist/config/validators/common.js +26 -8
  3. package/dist/config/validators/common.js.map +1 -1
  4. package/dist/config/validators/validate.d.ts +89 -2
  5. package/dist/lib/authentication/hook.d.ts +1 -0
  6. package/dist/lib/authentication/hook.js +11 -1
  7. package/dist/lib/authentication/hook.js.map +1 -1
  8. package/dist/lib/authentication/providers/clerk.js +6 -6
  9. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  10. package/dist/lib/authentication/state.js +8 -2
  11. package/dist/lib/authentication/state.js.map +1 -1
  12. package/dist/lib/components/Banner.js +1 -1
  13. package/dist/lib/components/Banner.js.map +1 -1
  14. package/dist/lib/components/Heading.d.ts +1 -1
  15. package/dist/lib/components/Layout.js +1 -1
  16. package/dist/lib/components/Layout.js.map +1 -1
  17. package/dist/lib/components/index.d.ts +2 -1
  18. package/dist/lib/core/RouteGuard.d.ts +1 -1
  19. package/dist/lib/core/RouteGuard.js +24 -18
  20. package/dist/lib/core/RouteGuard.js.map +1 -1
  21. package/dist/lib/plugins/api-catalog/Catalog.d.ts +3 -1
  22. package/dist/lib/plugins/api-catalog/Catalog.js +7 -4
  23. package/dist/lib/plugins/api-catalog/Catalog.js.map +1 -1
  24. package/dist/lib/plugins/api-catalog/index.js +1 -1
  25. package/dist/lib/plugins/api-catalog/index.js.map +1 -1
  26. package/dist/lib/plugins/markdown/MdxPage.js +1 -1
  27. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  28. package/dist/lib/plugins/openapi/OperationList.d.ts +1 -1
  29. package/dist/lib/plugins/openapi/OperationList.js +2 -1
  30. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  31. package/dist/lib/plugins/openapi/OperationListItem.js +2 -1
  32. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  33. package/dist/lib/plugins/openapi/ParameterList.d.ts +2 -1
  34. package/dist/lib/plugins/openapi/ParameterList.js +3 -2
  35. package/dist/lib/plugins/openapi/ParameterList.js.map +1 -1
  36. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +3 -1
  37. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
  38. package/dist/lib/plugins/openapi/Sidecar.js +1 -1
  39. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  40. package/dist/lib/plugins/openapi/playground/PathParams.d.ts +3 -2
  41. package/dist/lib/plugins/openapi/playground/PathParams.js +3 -2
  42. package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
  43. package/dist/lib/plugins/openapi/playground/Playground.d.ts +4 -1
  44. package/dist/lib/plugins/openapi/playground/Playground.js +10 -7
  45. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  46. package/dist/lib/plugins/search-pagefind/PagefindSearch.d.ts +6 -0
  47. package/dist/lib/plugins/search-pagefind/PagefindSearch.js +66 -0
  48. package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -0
  49. package/dist/lib/plugins/search-pagefind/ResultList.d.ts +8 -0
  50. package/dist/lib/plugins/search-pagefind/ResultList.js +31 -0
  51. package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -0
  52. package/dist/lib/plugins/search-pagefind/get-results.d.ts +3 -0
  53. package/dist/lib/plugins/search-pagefind/get-results.js +37 -0
  54. package/dist/lib/plugins/search-pagefind/get-results.js.map +1 -0
  55. package/dist/lib/plugins/search-pagefind/index.d.ts +8 -0
  56. package/dist/lib/plugins/search-pagefind/index.js +9 -0
  57. package/dist/lib/plugins/search-pagefind/index.js.map +1 -0
  58. package/dist/lib/plugins/search-pagefind/types.d.ts +85 -0
  59. package/dist/lib/plugins/search-pagefind/types.js +2 -0
  60. package/dist/lib/plugins/search-pagefind/types.js.map +1 -0
  61. package/dist/lib/ui/Command.d.ts +7 -1
  62. package/dist/lib/ui/Command.js +2 -2
  63. package/dist/lib/ui/Command.js.map +1 -1
  64. package/dist/lib/util/useScrollToAnchor.js +6 -8
  65. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  66. package/dist/vite/build.js +4 -0
  67. package/dist/vite/build.js.map +1 -1
  68. package/dist/vite/config.js +7 -2
  69. package/dist/vite/config.js.map +1 -1
  70. package/dist/vite/dev-server.js +8 -0
  71. package/dist/vite/dev-server.js.map +1 -1
  72. package/dist/vite/pagefind.d.ts +4 -0
  73. package/dist/vite/pagefind.js +15 -0
  74. package/dist/vite/pagefind.js.map +1 -0
  75. package/dist/vite/plugin-component.js +4 -0
  76. package/dist/vite/plugin-component.js.map +1 -1
  77. package/dist/vite/plugin-search.js +4 -0
  78. package/dist/vite/plugin-search.js.map +1 -1
  79. package/dist/vite/prerender/prerender.js +1 -1
  80. package/dist/vite/prerender/prerender.js.map +1 -1
  81. package/dist/vite/sitemap.js +2 -1
  82. package/dist/vite/sitemap.js.map +1 -1
  83. package/lib/{AuthenticationPlugin-_gUMnGxb.js → AuthenticationPlugin-BCYuduZ9.js} +3 -3
  84. package/lib/{AuthenticationPlugin-_gUMnGxb.js.map → AuthenticationPlugin-BCYuduZ9.js.map} +1 -1
  85. package/lib/Command-CrTA1FX0.js +140 -0
  86. package/lib/Command-CrTA1FX0.js.map +1 -0
  87. package/lib/Dialog-mi6BrnrM.js +83 -0
  88. package/lib/Dialog-mi6BrnrM.js.map +1 -0
  89. package/lib/{Markdown-DePfm7oQ.js → Markdown-DofXBcqg.js} +2 -2
  90. package/lib/{Markdown-DePfm7oQ.js.map → Markdown-DofXBcqg.js.map} +1 -1
  91. package/lib/MdxPage-KJcNWIgt.js +200 -0
  92. package/lib/MdxPage-KJcNWIgt.js.map +1 -0
  93. package/lib/{OasProvider-Bvu4dDpX.js → OasProvider-HcqBeC4H.js} +4 -4
  94. package/lib/{OasProvider-Bvu4dDpX.js.map → OasProvider-HcqBeC4H.js.map} +1 -1
  95. package/lib/{OperationList-DWnNbwVg.js → OperationList-C3wnbFxp.js} +1857 -1816
  96. package/lib/OperationList-C3wnbFxp.js.map +1 -0
  97. package/lib/{Select-BmoX1iTH.js → Select-Co6MuS4j.js} +36 -36
  98. package/lib/{Select-BmoX1iTH.js.map → Select-Co6MuS4j.js.map} +1 -1
  99. package/lib/{SlotletProvider-DdtIOUi6.js → SlotletProvider-CYFNHuok.js} +4 -4
  100. package/lib/{SlotletProvider-DdtIOUi6.js.map → SlotletProvider-CYFNHuok.js.map} +1 -1
  101. package/lib/{chunk-IR6S3I6Y-D_3UmFIn.js → chunk-IR6S3I6Y-CRDBmIgK.js} +3 -3
  102. package/lib/{chunk-IR6S3I6Y-D_3UmFIn.js.map → chunk-IR6S3I6Y-CRDBmIgK.js.map} +1 -1
  103. package/lib/hook-LTe5qHSc.js +347 -0
  104. package/lib/hook-LTe5qHSc.js.map +1 -0
  105. package/lib/{index-DVBlM15k.js → index-CtkRMvMw.js} +696 -743
  106. package/lib/index-CtkRMvMw.js.map +1 -0
  107. package/lib/index-gQD2h1wX.js +447 -0
  108. package/lib/index-gQD2h1wX.js.map +1 -0
  109. package/lib/index-vn5bsvmU.js +1399 -0
  110. package/lib/index-vn5bsvmU.js.map +1 -0
  111. package/lib/{mutation-DTunCQKB.js → mutation-B81DztCT.js} +2 -2
  112. package/lib/{mutation-DTunCQKB.js.map → mutation-B81DztCT.js.map} +1 -1
  113. package/lib/ui/Command.js +105 -78
  114. package/lib/ui/Command.js.map +1 -1
  115. package/lib/{useExposedProps-RIvey2Oy.js → useExposedProps-D76yras4.js} +2 -2
  116. package/lib/{useExposedProps-RIvey2Oy.js.map → useExposedProps-D76yras4.js.map} +1 -1
  117. package/lib/useQuery-CQUwWR9i.js +1137 -0
  118. package/lib/useQuery-CQUwWR9i.js.map +1 -0
  119. package/lib/useScrollToAnchor-DKyrbZoy.js +977 -0
  120. package/lib/useScrollToAnchor-DKyrbZoy.js.map +1 -0
  121. package/lib/zudoku.auth-auth0.js +1 -1
  122. package/lib/zudoku.auth-clerk.js +29 -29
  123. package/lib/zudoku.auth-clerk.js.map +1 -1
  124. package/lib/zudoku.auth-openid.js +3 -3
  125. package/lib/zudoku.components.js +32 -1382
  126. package/lib/zudoku.components.js.map +1 -1
  127. package/lib/zudoku.hooks.js +1 -1
  128. package/lib/zudoku.plugin-api-catalog.js +87 -71
  129. package/lib/zudoku.plugin-api-catalog.js.map +1 -1
  130. package/lib/zudoku.plugin-api-keys.js +16 -15
  131. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  132. package/lib/zudoku.plugin-custom-pages.js +2 -2
  133. package/lib/zudoku.plugin-markdown.js +1 -1
  134. package/lib/zudoku.plugin-openapi.js +3 -3
  135. package/lib/zudoku.plugin-redirect.js +1 -1
  136. package/lib/zudoku.plugin-search-pagefind.js +274 -0
  137. package/lib/zudoku.plugin-search-pagefind.js.map +1 -0
  138. package/package.json +8 -3
  139. package/src/lib/authentication/hook.ts +12 -1
  140. package/src/lib/authentication/providers/clerk.tsx +10 -6
  141. package/src/lib/authentication/state.ts +8 -2
  142. package/src/lib/components/Banner.tsx +1 -0
  143. package/src/lib/components/Heading.tsx +1 -1
  144. package/src/lib/components/Layout.tsx +1 -0
  145. package/src/lib/core/RouteGuard.tsx +44 -18
  146. package/src/lib/plugins/api-catalog/Catalog.tsx +23 -7
  147. package/src/lib/plugins/api-catalog/index.tsx +1 -0
  148. package/src/lib/plugins/markdown/MdxPage.tsx +5 -1
  149. package/src/lib/plugins/openapi/OperationList.tsx +15 -3
  150. package/src/lib/plugins/openapi/OperationListItem.tsx +8 -0
  151. package/src/lib/plugins/openapi/ParameterList.tsx +4 -0
  152. package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +7 -0
  153. package/src/lib/plugins/openapi/Sidecar.tsx +2 -1
  154. package/src/lib/plugins/openapi/playground/PathParams.tsx +8 -2
  155. package/src/lib/plugins/openapi/playground/Playground.tsx +61 -5
  156. package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +135 -0
  157. package/src/lib/plugins/search-pagefind/ResultList.tsx +104 -0
  158. package/src/lib/plugins/search-pagefind/get-results.tsx +54 -0
  159. package/src/lib/plugins/search-pagefind/index.tsx +21 -0
  160. package/src/lib/plugins/search-pagefind/types.ts +118 -0
  161. package/src/lib/ui/Command.tsx +25 -3
  162. package/src/lib/util/useScrollToAnchor.ts +8 -8
  163. package/README.md +0 -121
  164. package/lib/MdxPage-DM9mE-G-.js +0 -193
  165. package/lib/MdxPage-DM9mE-G-.js.map +0 -1
  166. package/lib/OperationList-DWnNbwVg.js.map +0 -1
  167. package/lib/hook-4_6pQSo4.js +0 -1460
  168. package/lib/hook-4_6pQSo4.js.map +0 -1
  169. package/lib/index-DVBlM15k.js.map +0 -1
  170. package/lib/index-Du5aNddU.js +0 -509
  171. package/lib/index-Du5aNddU.js.map +0 -1
  172. package/lib/index.esm-CQHE3GEU.js +0 -691
  173. package/lib/index.esm-CQHE3GEU.js.map +0 -1
  174. package/lib/objectEntries-yMIkr2mI.js +0 -5
  175. package/lib/objectEntries-yMIkr2mI.js.map +0 -1
  176. package/lib/useScrollToAnchor-BW8y_cwU.js +0 -290
  177. package/lib/useScrollToAnchor-BW8y_cwU.js.map +0 -1
@@ -15,7 +15,9 @@ export const useAuth = () => {
15
15
  throw new Error("Authentication is not enabled.");
16
16
  }
17
17
  // TODO: Should handle errors/state
18
- await authentication.signIn();
18
+ await authentication.signIn({
19
+ redirectTo: window.location.href,
20
+ });
19
21
  },
20
22
 
21
23
  logout: async () => {
@@ -28,5 +30,14 @@ export const useAuth = () => {
28
30
  // Redirect to home
29
31
  window.location.href = "/";
30
32
  },
33
+
34
+ signup: async () => {
35
+ if (!isAuthEnabled) {
36
+ throw new Error("Authentication is not enabled.");
37
+ }
38
+ await authentication.signUp({
39
+ redirectTo: window.location.href,
40
+ });
41
+ },
31
42
  };
32
43
  };
@@ -106,18 +106,22 @@ const clerkAuth: AuthenticationProviderInitializer<
106
106
  providerData: null,
107
107
  });
108
108
  },
109
- signIn: async () => {
109
+ signIn: async ({ redirectTo }: { redirectTo?: string }) => {
110
110
  await ensureLoaded;
111
111
  await clerkApi?.redirectToSignIn({
112
- signInForceRedirectUrl: window.location.origin + redirectToAfterSignIn,
113
- signUpForceRedirectUrl: window.location.origin + redirectToAfterSignUp,
112
+ signInForceRedirectUrl:
113
+ redirectTo ?? window.location.origin + redirectToAfterSignIn,
114
+ signUpForceRedirectUrl:
115
+ redirectTo ?? window.location.origin + redirectToAfterSignUp,
114
116
  });
115
117
  },
116
- signUp: async () => {
118
+ signUp: async ({ redirectTo }: { redirectTo?: string }) => {
117
119
  await ensureLoaded;
118
120
  await clerkApi?.redirectToSignUp({
119
- signInForceRedirectUrl: window.location.origin + redirectToAfterSignIn,
120
- signUpForceRedirectUrl: window.location.origin + redirectToAfterSignUp,
121
+ signInForceRedirectUrl:
122
+ redirectTo ?? window.location.origin + redirectToAfterSignIn,
123
+ signUpForceRedirectUrl:
124
+ redirectTo ?? window.location.origin + redirectToAfterSignUp,
121
125
  });
122
126
  },
123
127
  getAuthenticationPlugin() {
@@ -38,14 +38,20 @@ export const useAuthState = create<AuthState>()(
38
38
  persist(
39
39
  (state) => ({
40
40
  isAuthenticated: false,
41
- isPending: false,
41
+ isPending: true,
42
42
  profile: null,
43
43
  providerData: null,
44
44
  }),
45
45
  {
46
+ merge: (persistedState, currentState) => {
47
+ return {
48
+ ...currentState,
49
+ isPending: false,
50
+ ...(typeof persistedState === "object" ? persistedState : {}),
51
+ };
52
+ },
46
53
  name: "auth-state",
47
54
  storage: createJSONStorage(() => localStorage),
48
- // partialize: (s) => ({ state: s }),
49
55
  },
50
56
  ),
51
57
  );
@@ -34,6 +34,7 @@ export const Banner = () => {
34
34
  "relative text-primary-foreground text-sm font-medium px-4 py-2 flex gap-2 items-center",
35
35
  mappedColor,
36
36
  )}
37
+ data-pagefind-ignore="all"
37
38
  style={style}
38
39
  >
39
40
  <div className="w-full">{page.banner.message}</div>
@@ -38,7 +38,7 @@ const getComponent = (level: number) => {
38
38
  }
39
39
  };
40
40
 
41
- export type HeadingProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
41
+ export type HeadingProps = React.HTMLAttributes<HTMLHeadingElement> &
42
42
  VariantProps<typeof heading> & {
43
43
  children: ReactNode;
44
44
  className?: string;
@@ -89,6 +89,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
89
89
  </DrawerTrigger>
90
90
  </div>
91
91
  <main
92
+ data-pagefind-body
92
93
  className={cn(
93
94
  "h-full dark:border-white/10 translate-x-0",
94
95
  "lg:overflow-visible",
@@ -1,5 +1,12 @@
1
- import { useEffect } from "react";
2
- import { matchPath, Outlet, useLocation } from "react-router";
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { matchPath, Outlet, useLocation, useNavigate } from "react-router";
3
+ import {
4
+ Dialog,
5
+ DialogContent,
6
+ DialogDescription,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ } from "zudoku/ui/Dialog.js";
3
10
  import { useAuth } from "../authentication/hook.js";
4
11
  import { useZudoku } from "../components/context/ZudokuContext.js";
5
12
  import { ZudokuError } from "../util/invariant.js";
@@ -8,6 +15,7 @@ import { useLatest } from "../util/useLatest.js";
8
15
  export const RouteGuard = () => {
9
16
  const auth = useAuth();
10
17
  const zudoku = useZudoku();
18
+ const navigate = useNavigate();
11
19
  const location = useLocation();
12
20
  const latestPath = useLatest(location.pathname);
13
21
 
@@ -15,24 +23,42 @@ export const RouteGuard = () => {
15
23
  matchPath({ path, end: true }, location.pathname),
16
24
  );
17
25
 
18
- useEffect(() => {
19
- if (!isProtected || auth.isPending || auth.isAuthenticated) {
20
- return;
21
- }
22
-
23
- void zudoku.authentication?.signIn({
24
- redirectTo: latestPath.current,
25
- });
26
- }, [
27
- isProtected,
28
- auth.isPending,
29
- auth.isAuthenticated,
30
- zudoku.authentication,
31
- latestPath,
32
- ]);
26
+ useQuery({
27
+ queryKey: ["login-redirect"],
28
+ queryFn: async () => {
29
+ await new Promise((resolve) => setTimeout(resolve, 1200));
30
+ await zudoku.authentication?.signIn({
31
+ redirectTo: latestPath.current,
32
+ });
33
+ return true;
34
+ },
35
+ enabled:
36
+ typeof window !== "undefined" &&
37
+ isProtected &&
38
+ !auth.isPending &&
39
+ !auth.isAuthenticated,
40
+ });
33
41
 
34
42
  if (isProtected && !auth.isAuthenticated) {
35
- return null;
43
+ return (
44
+ <Dialog
45
+ open={true}
46
+ onOpenChange={(open) => {
47
+ if (!open) {
48
+ void navigate(-1);
49
+ }
50
+ }}
51
+ >
52
+ <DialogContent>
53
+ <DialogHeader>
54
+ <DialogTitle>Logging you in...</DialogTitle>
55
+ </DialogHeader>
56
+ <DialogDescription>
57
+ Please wait while we log you in.
58
+ </DialogDescription>
59
+ </DialogContent>
60
+ </Dialog>
61
+ );
36
62
  }
37
63
 
38
64
  if (isProtected && !auth.isAuthEnabled) {
@@ -1,6 +1,7 @@
1
1
  import { useSuspenseQuery } from "@tanstack/react-query";
2
+ import { Helmet } from "@zudoku/react-helmet-async";
2
3
  import { useMatch } from "react-router";
3
- import { Head, Link } from "zudoku/components";
4
+ import { Link } from "zudoku/components";
4
5
  import { useAuthState } from "../../authentication/state.js";
5
6
  import { Heading } from "../../components/Heading.js";
6
7
  import { Markdown } from "../../components/Markdown.js";
@@ -11,7 +12,10 @@ export const Catalog = ({
11
12
  items,
12
13
  filterCatalogItems = (items) => items,
13
14
  label = "API Library",
14
- }: Omit<ApiCatalogPluginOptions, "navigationId">) => {
15
+ categoryLabel,
16
+ }: Omit<ApiCatalogPluginOptions, "navigationId"> & {
17
+ categoryLabel?: string;
18
+ }) => {
15
19
  const auth = useAuthState();
16
20
  const match = useMatch({ path: "/catalog/:category" });
17
21
  const activeCategory = match?.params.category;
@@ -21,13 +25,25 @@ export const Catalog = ({
21
25
  queryKey: ["catalogItems", auth],
22
26
  });
23
27
 
28
+ // Only index the overview page, ignore the rest
29
+ const dataSet = activeCategory ? { "data-pagefind-ignore": "all" } : {};
30
+
24
31
  return (
25
- <section className="pt-[--padding-content-top] pb-[--padding-content-bottom]">
26
- <Head>
27
- <title>{label}</title>
28
- </Head>
32
+ <section
33
+ className="pt-[--padding-content-top] pb-[--padding-content-bottom]"
34
+ {...dataSet}
35
+ >
36
+ <Helmet>
37
+ <title>
38
+ {categoryLabel ? `${categoryLabel} - ` : ""}
39
+ {label}
40
+ </title>
41
+ </Helmet>
29
42
  <div className="grid gap-4">
30
- <Heading level={2}>{label}</Heading>
43
+ <Heading level={2}>
44
+ {label}
45
+ {categoryLabel && ` - ${categoryLabel}`}
46
+ </Heading>
31
47
 
32
48
  <div className="grid grid-cols-2 gap-4">
33
49
  {catalogItems.data
@@ -98,6 +98,7 @@ export const apiCatalogPlugin = ({
98
98
  element: (
99
99
  <Catalog
100
100
  label={label}
101
+ categoryLabel={tag}
101
102
  items={items}
102
103
  filterCatalogItems={filterCatalogItems}
103
104
  categories={categories}
@@ -90,7 +90,11 @@ export const MdxPage = ({
90
90
  }, [file]);
91
91
 
92
92
  return (
93
- <div className="xl:grid grid-cols-[--sidecar-grid-cols] gap-8 justify-between">
93
+ <div
94
+ className="xl:grid grid-cols-[--sidecar-grid-cols] gap-8 justify-between"
95
+ data-pagefind-filter="section:markdown"
96
+ data-pagefind-meta="section:markdown"
97
+ >
94
98
  <Helmet>
95
99
  <title>{pageTitle}</title>
96
100
  {excerpt && <meta name="description" content={excerpt} />}
@@ -1,4 +1,4 @@
1
- import { ResultOf } from "@graphql-typed-document-node/core";
1
+ import { type ResultOf } from "@graphql-typed-document-node/core";
2
2
  import { useSuspenseQuery } from "@tanstack/react-query";
3
3
  import { Helmet } from "@zudoku/react-helmet-async";
4
4
  import { useNavigate } from "react-router";
@@ -152,8 +152,14 @@ export const OperationList = ({
152
152
  ? sanitizeMarkdownForMetatag(description)
153
153
  : undefined;
154
154
 
155
+ const showVersions = Object.entries(versions).length > 1;
156
+
155
157
  return (
156
- <div className="pt-[--padding-content-top]">
158
+ <div
159
+ className="pt-[--padding-content-top]"
160
+ data-pagefind-filter="section:openapi"
161
+ data-pagefind-meta="section:openapi"
162
+ >
157
163
  <Helmet>
158
164
  <title>{title}</title>
159
165
  {metaDescription && (
@@ -168,10 +174,16 @@ export const OperationList = ({
168
174
  <CategoryHeading>Overview</CategoryHeading>
169
175
  <Heading level={1} id="description" registerSidebarAnchor>
170
176
  {title}
177
+ {showVersions && (
178
+ <span className="text-xl text-muted-foreground">
179
+ {" "}
180
+ ({version})
181
+ </span>
182
+ )}
171
183
  </Heading>
172
184
  </div>
173
185
  <div>
174
- {Object.entries(versions).length > 1 && (
186
+ {showVersions && (
175
187
  <Select
176
188
  onValueChange={(version) => navigate(versions[version]!)}
177
189
  defaultValue={version}
@@ -1,3 +1,4 @@
1
+ import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
1
2
  import { useRef, useState } from "react";
2
3
  import { Heading } from "../../components/Heading.js";
3
4
  import { Markdown, ProseClasses } from "../../components/Markdown.js";
@@ -84,6 +85,7 @@ export const OperationListItem = ({
84
85
  groupedParameters[group]?.length ? (
85
86
  <ParameterList
86
87
  key={group}
88
+ summary={operation.summary ?? undefined}
87
89
  id={operation.slug}
88
90
  parameters={groupedParameters[group]}
89
91
  group={group}
@@ -101,6 +103,9 @@ export const OperationListItem = ({
101
103
  className="capitalize"
102
104
  id={`${operation.slug}/request-body`}
103
105
  >
106
+ {operation.summary && (
107
+ <VisuallyHidden>{operation.summary} &rsaquo; </VisuallyHidden>
108
+ )}
104
109
  Request Body
105
110
  </Heading>
106
111
  <SchemaView schema={schema} />
@@ -113,6 +118,9 @@ export const OperationListItem = ({
113
118
  className="capitalize mt-8 pt-8 border-t"
114
119
  id={`${operation.slug}/responses`}
115
120
  >
121
+ {operation.summary && (
122
+ <VisuallyHidden>{operation.summary} &rsaquo; </VisuallyHidden>
123
+ )}
116
124
  Responses
117
125
  </Heading>
118
126
  <Tabs
@@ -1,3 +1,4 @@
1
+ import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
1
2
  import { Heading } from "../../components/Heading.js";
2
3
  import { Card } from "../../ui/Card.js";
3
4
  import type { ParameterGroup } from "./OperationListItem.js";
@@ -7,16 +8,19 @@ import {
7
8
  } from "./ParameterListItem.js";
8
9
 
9
10
  export const ParameterList = ({
11
+ summary,
10
12
  group,
11
13
  parameters,
12
14
  id,
13
15
  }: {
16
+ summary?: string;
14
17
  group: ParameterGroup;
15
18
  parameters: ParameterListItemResult[];
16
19
  id: string;
17
20
  }) => (
18
21
  <>
19
22
  <Heading level={3} id={`${id}/${group}-parameters`} className="capitalize">
23
+ {summary && <VisuallyHidden>{summary} &rsaquo; </VisuallyHidden>}
20
24
  {group === "header" ? "Headers" : `${group} Parameters`}
21
25
  </Heading>
22
26
  <Card>
@@ -1,3 +1,4 @@
1
+ import { useAuth } from "zudoku/components";
1
2
  import type { OperationListItemResult } from "./OperationList.js";
2
3
  import { PlaygroundDialog } from "./playground/PlaygroundDialog.js";
3
4
  import { Content } from "./SidecarExamples.js";
@@ -13,6 +14,9 @@ export const PlaygroundDialogWrapper = ({
13
14
  operation: OperationListItemResult;
14
15
  examples?: Content;
15
16
  }) => {
17
+ const { isAuthEnabled, login, signup, isPending, isAuthenticated } =
18
+ useAuth();
19
+
16
20
  const headers = operation.parameters
17
21
  ?.filter((p) => p.in === "header")
18
22
  .sort((a, b) => (a.required && !b.required ? -1 : 1))
@@ -49,6 +53,9 @@ export const PlaygroundDialogWrapper = ({
49
53
  queryParams={queryParams}
50
54
  pathParams={pathParams}
51
55
  examples={examples}
56
+ requiresLogin={isAuthEnabled && !isAuthenticated && !isPending}
57
+ onLogin={() => login()}
58
+ onSignUp={() => signup()}
52
59
  />
53
60
  );
54
61
  };
@@ -175,10 +175,11 @@ export const Sidecar = ({
175
175
  <aside
176
176
  ref={ref}
177
177
  className="flex flex-col overflow-hidden sticky top-[--scroll-padding] gap-4"
178
+ data-pagefind-ignore="all"
178
179
  >
179
180
  <SidecarBox.Root>
180
181
  <SidecarBox.Head className="flex justify-between items-center flex-nowrap py-2.5 gap-2 text-xs">
181
- <span className="font-mono break-words">
182
+ <span className="font-mono break-words leading-6">
182
183
  <span className={cn("font-semibold", methodTextColor)}>
183
184
  {operation.method.toLocaleUpperCase()}
184
185
  </span>
@@ -1,4 +1,4 @@
1
- import { Control, Controller, useFieldArray } from "react-hook-form";
1
+ import { type Control, Controller, useFieldArray } from "react-hook-form";
2
2
  import { Card } from "zudoku/ui/Card.js";
3
3
  import { Input } from "../../../ui/Input.js";
4
4
  import { ColorizedParam } from "../ColorizedParam.js";
@@ -7,18 +7,24 @@ import type { PlaygroundForm } from "./Playground.js";
7
7
 
8
8
  export const PathParams = ({
9
9
  control,
10
+ url,
10
11
  }: {
11
12
  control: Control<PlaygroundForm>;
13
+ url: string;
12
14
  }) => {
13
15
  const { fields } = useFieldArray<PlaygroundForm, "pathParams">({
14
16
  control,
15
17
  name: "pathParams",
16
18
  });
17
19
 
20
+ const sortedFields = [...fields].sort(
21
+ (a, b) => url.indexOf(`{${a.name}}`) - url.indexOf(`{${b.name}}`),
22
+ );
23
+
18
24
  return (
19
25
  <Card className="rounded-lg">
20
26
  <ParamsGrid>
21
- {fields.map((field, i) => (
27
+ {sortedFields.map((field, i) => (
22
28
  <ParamsGridItem key={field.id}>
23
29
  <Controller
24
30
  control={control}
@@ -1,10 +1,11 @@
1
1
  import { useMutation } from "@tanstack/react-query";
2
2
  import { InfoIcon } from "lucide-react";
3
- import { Fragment, useEffect, useRef, useTransition } from "react";
3
+ import { Fragment, useEffect, useRef, useState, useTransition } from "react";
4
4
  import { FormProvider, useForm } from "react-hook-form";
5
5
  import { Alert, AlertDescription, AlertTitle } from "zudoku/ui/Alert.js";
6
6
  import { PathRenderer } from "../../../components/PathRenderer.js";
7
7
 
8
+ import { Button } from "zudoku/ui/Button.js";
8
9
  import { Label } from "zudoku/ui/Label.js";
9
10
  import { RadioGroup, RadioGroupItem } from "zudoku/ui/RadioGroup.js";
10
11
  import {
@@ -97,6 +98,9 @@ export type PlaygroundContentProps = {
97
98
  pathParams?: PathParam[];
98
99
  defaultBody?: string;
99
100
  examples?: Content;
101
+ requiresLogin?: boolean;
102
+ onLogin?: () => void;
103
+ onSignUp?: () => void;
100
104
  };
101
105
 
102
106
  export const Playground = ({
@@ -109,11 +113,15 @@ export const Playground = ({
109
113
  pathParams = [],
110
114
  defaultBody = "",
111
115
  examples,
116
+ requiresLogin = false,
117
+ onLogin,
118
+ onSignUp,
112
119
  }: PlaygroundContentProps) => {
113
120
  const { selectedServer, setSelectedServer } = useSelectedServer(
114
121
  servers.map((url) => ({ url })),
115
122
  );
116
123
  const [, startTransition] = useTransition();
124
+ const [skipLogin, setSkipLogin] = useState(false);
117
125
  const { register, control, handleSubmit, watch, setValue, ...form } =
118
126
  useForm<PlaygroundForm>({
119
127
  defaultValues: {
@@ -262,7 +270,7 @@ export const Playground = ({
262
270
  ));
263
271
 
264
272
  const serverSelect = (
265
- <div className="inline-block opacity-50 hover:opacity-100 transition">
273
+ <div className="inline-block opacity-50 hover:opacity-100 transition translate-y-[4px]">
266
274
  {server ? (
267
275
  <span>{server.replace(/^https?:\/\//, "")}</span>
268
276
  ) : (
@@ -290,6 +298,8 @@ export const Playground = ({
290
298
  </div>
291
299
  );
292
300
 
301
+ const showLogin = requiresLogin && !skipLogin;
302
+
293
303
  return (
294
304
  <FormProvider
295
305
  {...{ register, control, handleSubmit, watch, setValue, ...form }}
@@ -297,15 +307,61 @@ export const Playground = ({
297
307
  <form
298
308
  onSubmit={handleSubmit((data) => queryMutation.mutateAsync(data))}
299
309
  ref={formRef}
310
+ className="relative"
300
311
  >
301
- <div className="grid grid-cols-2 text-sm h-full">
312
+ {showLogin && (
313
+ <div className="absolute top-1/2 right-1/2 -translate-y-1/2 translate-x-1/2 z-50 max-w-md">
314
+ <Alert>
315
+ <AlertTitle className="mb-2">
316
+ Welcome to the Playground!
317
+ </AlertTitle>
318
+ <AlertDescription className="flex flex-col gap-2">
319
+ <div className="mb-2">
320
+ The Playground is a tool for developers to test and explore
321
+ our APIs. To use the Playground, you need to login.
322
+ </div>
323
+ <div className="flex gap-2 justify-between">
324
+ <Button
325
+ type="button"
326
+ variant="ghost"
327
+ onClick={() => setSkipLogin(true)}
328
+ >
329
+ Skip
330
+ </Button>
331
+ <div className="flex gap-2">
332
+ {onSignUp && (
333
+ <Button
334
+ type="button"
335
+ variant="outline"
336
+ onClick={onSignUp}
337
+ >
338
+ Sign Up
339
+ </Button>
340
+ )}
341
+ {onLogin && (
342
+ <Button type="button" variant="default" onClick={onLogin}>
343
+ Login
344
+ </Button>
345
+ )}
346
+ </div>
347
+ </div>
348
+ </AlertDescription>
349
+ </Alert>
350
+ </div>
351
+ )}
352
+ <div
353
+ className={cn(
354
+ "grid grid-cols-2 text-sm h-full",
355
+ showLogin && "opacity-30 pointer-events-none",
356
+ )}
357
+ >
302
358
  <div className="flex flex-col gap-4 p-4 after:bg-muted-foreground/20 relative after:absolute after:w-px after:inset-0 after:left-auto">
303
359
  <div className="flex gap-2 items-stretch">
304
360
  <div className="flex flex-1 items-center w-full border rounded-md">
305
361
  <div className="border-r p-2 bg-muted rounded-l-md self-stretch font-semibold font-mono flex items-center">
306
362
  {method.toUpperCase()}
307
363
  </div>
308
- <div className="items-center p-2 font-mono text-xs break-words">
364
+ <div className="items-center px-2 py-0.5 font-mono text-xs break-all leading-6">
309
365
  {serverSelect}
310
366
  {path}
311
367
  {urlQueryParams.length > 0 ? "?" : ""}
@@ -351,7 +407,7 @@ export const Playground = ({
351
407
  {pathParams.length > 0 && (
352
408
  <div className="flex flex-col gap-4 my-4">
353
409
  <span className="font-semibold">Path Parameters</span>
354
- <PathParams control={control} />
410
+ <PathParams url={url} control={control} />
355
411
  </div>
356
412
  )}
357
413
  <div className="flex flex-col gap-4 my-4">