zudoku 0.24.1 → 0.25.1

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 (108) hide show
  1. package/dist/config/validators/InputSidebarSchema.d.ts +15 -0
  2. package/dist/config/validators/InputSidebarSchema.js +1 -0
  3. package/dist/config/validators/InputSidebarSchema.js.map +1 -1
  4. package/dist/config/validators/common.d.ts +45 -34
  5. package/dist/config/validators/common.js +2 -1
  6. package/dist/config/validators/common.js.map +1 -1
  7. package/dist/config/validators/validate.d.ts +19 -14
  8. package/dist/lib/authentication/components/SignOut.js +1 -1
  9. package/dist/lib/authentication/components/SignOut.js.map +1 -1
  10. package/dist/lib/authentication/providers/clerk.js +29 -6
  11. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  12. package/dist/lib/components/Header.js +13 -13
  13. package/dist/lib/components/Header.js.map +1 -1
  14. package/dist/lib/components/Layout.js +1 -1
  15. package/dist/lib/components/Layout.js.map +1 -1
  16. package/dist/lib/components/TopNavigation.js +2 -2
  17. package/dist/lib/components/TopNavigation.js.map +1 -1
  18. package/dist/lib/components/navigation/SidebarBadge.d.ts +11 -1
  19. package/dist/lib/components/navigation/SidebarBadge.js +11 -2
  20. package/dist/lib/components/navigation/SidebarBadge.js.map +1 -1
  21. package/dist/lib/components/navigation/SidebarCategory.js +2 -2
  22. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  23. package/dist/lib/components/navigation/SidebarWrapper.js +1 -1
  24. package/dist/lib/components/navigation/SidebarWrapper.js.map +1 -1
  25. package/dist/lib/oas/graphql/index.js +16 -3
  26. package/dist/lib/oas/graphql/index.js.map +1 -1
  27. package/dist/lib/oas/parser/upgrade/index.js +17 -3
  28. package/dist/lib/oas/parser/upgrade/index.js.map +1 -1
  29. package/dist/lib/plugins/openapi/CollapsibleCode.js +2 -1
  30. package/dist/lib/plugins/openapi/CollapsibleCode.js.map +1 -1
  31. package/dist/lib/plugins/openapi/Endpoint.d.ts +1 -1
  32. package/dist/lib/plugins/openapi/Endpoint.js +3 -1
  33. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  34. package/dist/lib/plugins/openapi/ExampleDisplay.d.ts +12 -0
  35. package/dist/lib/plugins/openapi/ExampleDisplay.js +78 -0
  36. package/dist/lib/plugins/openapi/ExampleDisplay.js.map +1 -0
  37. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  38. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  39. package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
  40. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  41. package/dist/lib/plugins/openapi/RequestBodySidecarBox.d.ts +2 -4
  42. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +6 -13
  43. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  44. package/dist/lib/plugins/openapi/ResponsesSidecarBox.js +11 -13
  45. package/dist/lib/plugins/openapi/ResponsesSidecarBox.js.map +1 -1
  46. package/dist/lib/plugins/openapi/Sidecar.js +1 -1
  47. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  48. package/dist/lib/plugins/openapi/SidecarBox.js +4 -4
  49. package/dist/lib/plugins/openapi/SidecarBox.js.map +1 -1
  50. package/dist/lib/plugins/openapi/index.js +1 -0
  51. package/dist/lib/plugins/openapi/index.js.map +1 -1
  52. package/dist/lib/plugins/openapi/playground/Headers.js +1 -1
  53. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  54. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
  55. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
  56. package/dist/lib/ui/Card.js +1 -1
  57. package/dist/lib/ui/Card.js.map +1 -1
  58. package/dist/vite/build.js +10 -8
  59. package/dist/vite/build.js.map +1 -1
  60. package/dist/vite/config.js +10 -0
  61. package/dist/vite/config.js.map +1 -1
  62. package/lib/{AuthenticationPlugin-DVLEc6cm.js → AuthenticationPlugin-D7G3me8L.js} +16 -16
  63. package/lib/AuthenticationPlugin-D7G3me8L.js.map +1 -0
  64. package/lib/{OperationList-CqLL5P5l.js → OperationList-BLdHAQ39.js} +1865 -1811
  65. package/lib/OperationList-BLdHAQ39.js.map +1 -0
  66. package/lib/assets/{worker-DV9Ecqy9.js → worker-Cbp2r2BQ.js} +26 -14
  67. package/lib/assets/{worker-DV9Ecqy9.js.map → worker-Cbp2r2BQ.js.map} +1 -1
  68. package/lib/{createServer-C4C0OO0m.js → createServer-Bf5_6o6G.js} +796 -784
  69. package/lib/{createServer-C4C0OO0m.js.map → createServer-Bf5_6o6G.js.map} +1 -1
  70. package/lib/{index-DzRORsY1.js → index-BNx95gkf.js} +7 -5
  71. package/lib/index-BNx95gkf.js.map +1 -0
  72. package/lib/ui/Card.js +7 -7
  73. package/lib/ui/Card.js.map +1 -1
  74. package/lib/zudoku.auth-clerk.js +80 -52
  75. package/lib/zudoku.auth-clerk.js.map +1 -1
  76. package/lib/zudoku.auth-openid.js +1 -1
  77. package/lib/zudoku.components.js +222 -218
  78. package/lib/zudoku.components.js.map +1 -1
  79. package/lib/zudoku.openapi-worker.js +1 -1
  80. package/lib/zudoku.plugin-openapi.js +1 -1
  81. package/package.json +4 -4
  82. package/src/app/main.css +50 -37
  83. package/src/lib/authentication/components/SignOut.tsx +2 -1
  84. package/src/lib/authentication/providers/clerk.tsx +38 -7
  85. package/src/lib/components/Header.tsx +9 -5
  86. package/src/lib/components/Layout.tsx +1 -1
  87. package/src/lib/components/TopNavigation.tsx +2 -2
  88. package/src/lib/components/navigation/SidebarBadge.tsx +13 -1
  89. package/src/lib/components/navigation/SidebarCategory.tsx +3 -7
  90. package/src/lib/components/navigation/SidebarWrapper.tsx +3 -2
  91. package/src/lib/oas/graphql/index.ts +16 -7
  92. package/src/lib/oas/parser/upgrade/index.ts +19 -4
  93. package/src/lib/plugins/openapi/CollapsibleCode.tsx +10 -7
  94. package/src/lib/plugins/openapi/Endpoint.tsx +3 -3
  95. package/src/lib/plugins/openapi/ExampleDisplay.tsx +163 -0
  96. package/src/lib/plugins/openapi/OperationListItem.tsx +5 -3
  97. package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -1
  98. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +11 -37
  99. package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +49 -63
  100. package/src/lib/plugins/openapi/Sidecar.tsx +4 -6
  101. package/src/lib/plugins/openapi/SidecarBox.tsx +4 -16
  102. package/src/lib/plugins/openapi/index.tsx +1 -0
  103. package/src/lib/plugins/openapi/playground/Headers.tsx +1 -0
  104. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +1 -1
  105. package/src/lib/ui/Card.tsx +1 -1
  106. package/lib/AuthenticationPlugin-DVLEc6cm.js.map +0 -1
  107. package/lib/OperationList-CqLL5P5l.js.map +0 -1
  108. package/lib/index-DzRORsY1.js.map +0 -1
@@ -2,7 +2,7 @@ const o = () => {
2
2
  const r = new SharedWorker(
3
3
  new URL(
4
4
  /* @vite-ignore */
5
- "./assets/worker-DV9Ecqy9.js",
5
+ "./assets/worker-Cbp2r2BQ.js",
6
6
  import.meta.url
7
7
  ),
8
8
  { type: "module" }
@@ -1,6 +1,6 @@
1
1
  import "./jsx-runtime-Dx-03ztt.js";
2
2
  import "./chunk-D52XG6IA-Dl7HLe6j.js";
3
- import { o as a } from "./index-DzRORsY1.js";
3
+ import { o as a } from "./index-BNx95gkf.js";
4
4
  import "./ZudokuContext-hmLMUdf2.js";
5
5
  import "lucide-react";
6
6
  import "./hook-CHq7pFyz.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.24.1",
3
+ "version": "0.25.1",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -147,7 +147,7 @@
147
147
  "@sentry/node": "8.42.0",
148
148
  "@sindresorhus/slugify": "2.2.1",
149
149
  "@stefanprobst/rehype-extract-toc": "2.2.0",
150
- "@tailwindcss/typography": "0.5.15",
150
+ "@tailwindcss/typography": "0.5.16",
151
151
  "@tanstack/react-query": "5.62.3",
152
152
  "@types/react": "19.0.1",
153
153
  "@types/react-dom": "19.0.1",
@@ -240,7 +240,7 @@
240
240
  "mdast-util-mdx": "3.0.0",
241
241
  "react": "19.0.0",
242
242
  "react-dom": "19.0.0",
243
- "rollup-plugin-visualizer": "5.12.0",
243
+ "rollup-plugin-visualizer": "5.14.0",
244
244
  "typescript": "5.7.2",
245
245
  "vitest": "2.1.8"
246
246
  },
@@ -250,7 +250,7 @@
250
250
  },
251
251
  "optionalDependencies": {
252
252
  "@clerk/clerk-js": "^5.43.4",
253
- "@sentry/react": "^8.48.0"
253
+ "@sentry/react": "^8.50.0"
254
254
  },
255
255
  "scripts": {
256
256
  "build": "tsc --project tsconfig.json",
package/src/app/main.css CHANGED
@@ -85,8 +85,8 @@
85
85
  var(--top-header-height) + var(--top-nav-height) + var(--banner-height)
86
86
  );
87
87
  --scroll-padding: calc(var(--header-height) + 10px);
88
- --side-nav-width: theme("spacing.72");
89
- --padding-content-top: theme("spacing.12");
88
+ --side-nav-width: theme("spacing.80");
89
+ --padding-content-top: theme("spacing.6");
90
90
  --padding-content-bottom: theme("spacing.12");
91
91
  --padding-nav-item: theme("spacing[2.5]");
92
92
  --sidecar-grid-cols: 1fr minmax(200px, 260px);
@@ -238,48 +238,61 @@
238
238
  }
239
239
 
240
240
  /* Theme */
241
+
242
+ @layer base {
241
243
  :root {
242
244
  --background: 0 0% 100%;
243
- --foreground: 222.2 84% 4.9%;
245
+ --foreground: 240 10% 3.9%;
244
246
  --card: 0 0% 100%;
245
- --card-foreground: 222.2 84% 4.9%;
247
+ --card-foreground: 240 10% 3.9%;
246
248
  --popover: 0 0% 100%;
247
- --popover-foreground: 222.2 84% 4.9%;
248
- --primary: 221.2 83.2% 53.3%;
249
- --primary-foreground: 210 40% 98%;
250
- --secondary: 210 40% 96.1%;
251
- --secondary-foreground: 222.2 47.4% 11.2%;
252
- --muted: 210 40% 96.1%;
253
- --muted-foreground: 215.4 16.3% 46.9%;
254
- --accent: 210 40% 96.1%;
255
- --accent-foreground: 222.2 47.4% 11.2%;
256
- --destructive: 0 72.22% 50.59%;
257
- --destructive-foreground: 210 40% 98%;
258
- --border: 214.3 31.8% 91.4%;
259
- --input: 214.3 31.8% 91.4%;
260
- --ring: var(--primary);
261
- --radius: 0.5rem;
249
+ --popover-foreground: 240 10% 3.9%;
250
+ --primary: 240 5.9% 10%;
251
+ --primary-foreground: 0 0% 98%;
252
+ --secondary: 240 4.8% 95.9%;
253
+ --secondary-foreground: 240 5.9% 10%;
254
+ --muted: 240 4.8% 95.9%;
255
+ --muted-foreground: 240 3.8% 46.1%;
256
+ --accent: 240 4.8% 95.9%;
257
+ --accent-foreground: 240 5.9% 10%;
258
+ --destructive: 0 84.2% 60.2%;
259
+ --destructive-foreground: 0 0% 98%;
260
+ --border: 240 5.9% 95%;
261
+ --input: 240 5.9% 90%;
262
+ --ring: 240 5.9% 10%;
263
+ --radius: 0.75rem;
264
+ --chart-1: 12 76% 61%;
265
+ --chart-2: 173 58% 39%;
266
+ --chart-3: 197 37% 24%;
267
+ --chart-4: 43 74% 66%;
268
+ --chart-5: 27 87% 67%;
262
269
  }
263
270
 
264
271
  .dark {
265
- --background: 222.2 84% 4.9%;
266
- --foreground: 210 40% 98%;
267
- --card: 222.2 84% 4.9%;
268
- --card-foreground: 210 40% 98%;
269
- --popover: 222.2 84% 4.9%;
270
- --popover-foreground: 210 40% 98%;
271
- --primary: 217.2 91.2% 59.8%;
272
- --primary-foreground: 210 40% 98%;
273
- --secondary: 217.2 32.6% 17.5%;
274
- --secondary-foreground: 210 40% 98%;
275
- --muted: 217.2 32.6% 17.5%;
276
- --muted-foreground: 215 20.2% 65.1%;
277
- --accent: 217.2 32.6% 17.5%;
278
- --accent-foreground: 210 40% 98%;
272
+ --background: 240 10% 3.9%;
273
+ --foreground: 0 0% 98%;
274
+ --card: 240 10% 3.9%;
275
+ --card-foreground: 0 0% 98%;
276
+ --popover: 240 10% 3.9%;
277
+ --popover-foreground: 0 0% 98%;
278
+ --primary: 0 0% 98%;
279
+ --primary-foreground: 240 5.9% 10%;
280
+ --secondary: 240 3.7% 15.9%;
281
+ --secondary-foreground: 0 0% 98%;
282
+ --muted: 240 3.7% 15.9%;
283
+ --muted-foreground: 240 5% 64.9%;
284
+ --accent: 240 3.7% 15.9%;
285
+ --accent-foreground: 0 0% 98%;
279
286
  --destructive: 0 62.8% 30.6%;
280
- --destructive-foreground: 210 40% 98%;
281
- --border: 217.2 32.6% 17.5%;
282
- --input: 217.2 32.6% 17.5%;
283
- --ring: var(--primary);
287
+ --destructive-foreground: 0 0% 98%;
288
+ --border: 240 3.7% 15.9%;
289
+ --input: 240 3.7% 15.9%;
290
+ --ring: 240 4.9% 83.9%;
291
+ --chart-1: 220 70% 50%;
292
+ --chart-2: 160 60% 45%;
293
+ --chart-3: 30 80% 55%;
294
+ --chart-4: 280 65% 60%;
295
+ --chart-5: 340 75% 55%;
296
+ }
284
297
  }
285
298
  }
@@ -5,9 +5,10 @@ import { useZudoku } from "../../components/context/ZudokuContext.js";
5
5
  export const SignOut = () => {
6
6
  const context = useZudoku();
7
7
  const navigate = useNavigate();
8
+
8
9
  useEffect(() => {
9
10
  void context.authentication?.signOut().then(() => navigate("/"));
10
- }, [navigate, context.authentication]);
11
+ }, []);
11
12
 
12
13
  return null;
13
14
  };
@@ -16,14 +16,19 @@ class ClerkAuthPlugin extends AuthenticationPlugin {
16
16
  }
17
17
 
18
18
  if (clerk.session) {
19
+ const verifiedEmail = clerk.session.user.emailAddresses.find(
20
+ (email) => email.verification.status === "verified",
21
+ );
19
22
  useAuthState.setState({
20
23
  isAuthenticated: true,
21
24
  isPending: false,
22
25
  profile: {
23
26
  sub: clerk.session.user.id,
24
27
  name: clerk.session.user.fullName ?? undefined,
25
- email: clerk.session.user.emailAddresses[0]?.emailAddress,
26
- emailVerified: false, // TODO: Check this
28
+ email:
29
+ verifiedEmail?.emailAddress ??
30
+ clerk.session.user.emailAddresses[0]?.emailAddress,
31
+ emailVerified: verifiedEmail !== undefined,
27
32
  pictureUrl: clerk.session.user.imageUrl,
28
33
  },
29
34
  });
@@ -45,19 +50,39 @@ const clerkAuth: AuthenticationProviderInitializer<
45
50
  redirectToAfterSignUp = "/",
46
51
  redirectToAfterSignIn = "/",
47
52
  }) => {
48
- let clerkApi: Clerk;
53
+ let clerkApi: Clerk | undefined;
49
54
  const ensureLoaded = (async () => {
50
55
  if (typeof window === "undefined") return;
51
56
  const { Clerk } = await import("@clerk/clerk-js");
52
57
  clerkApi = new Clerk(clerkPubKey);
53
58
 
54
59
  await clerkApi.load();
60
+
61
+ if (clerkApi.user) {
62
+ const verifiedEmail = clerkApi.user.emailAddresses.find(
63
+ (email) => email.verification.status === "verified",
64
+ );
65
+ useAuthState.setState({
66
+ isAuthenticated: true,
67
+ isPending: false,
68
+ profile: {
69
+ sub: clerkApi.user.id,
70
+ name: clerkApi.user.fullName ?? undefined,
71
+ email:
72
+ verifiedEmail?.emailAddress ??
73
+ clerkApi.user.emailAddresses[0]?.emailAddress,
74
+ emailVerified: verifiedEmail !== undefined,
75
+ pictureUrl: clerkApi.user.imageUrl,
76
+ },
77
+ });
78
+ }
79
+
55
80
  return clerkApi;
56
81
  })();
57
82
 
58
83
  async function getAccessToken() {
59
84
  await ensureLoaded;
60
- if (!clerkApi.session) {
85
+ if (!clerkApi?.session) {
61
86
  throw new Error("No session available");
62
87
  }
63
88
  const response = await clerkApi.session.getToken();
@@ -71,20 +96,26 @@ const clerkAuth: AuthenticationProviderInitializer<
71
96
  getAccessToken,
72
97
  signOut: async () => {
73
98
  await ensureLoaded;
74
- await clerkApi.signOut({
99
+ await clerkApi?.signOut({
75
100
  redirectUrl: window.location.origin + redirectToAfterSignOut,
76
101
  });
102
+ useAuthState.setState({
103
+ isAuthenticated: false,
104
+ isPending: false,
105
+ profile: null,
106
+ providerData: null,
107
+ });
77
108
  },
78
109
  signIn: async () => {
79
110
  await ensureLoaded;
80
- await clerkApi.redirectToSignIn({
111
+ await clerkApi?.redirectToSignIn({
81
112
  signInForceRedirectUrl: window.location.origin + redirectToAfterSignIn,
82
113
  signUpForceRedirectUrl: window.location.origin + redirectToAfterSignUp,
83
114
  });
84
115
  },
85
116
  signUp: async () => {
86
117
  await ensureLoaded;
87
- await clerkApi.redirectToSignUp({
118
+ await clerkApi?.redirectToSignUp({
88
119
  signInForceRedirectUrl: window.location.origin + redirectToAfterSignIn,
89
120
  signUpForceRedirectUrl: window.location.origin + redirectToAfterSignUp,
90
121
  });
@@ -65,8 +65,8 @@ export const Header = memo(function HeaderInner() {
65
65
  return (
66
66
  <header className="sticky lg:top-0 z-10 bg-background/80 backdrop-blur w-full">
67
67
  <Banner />
68
- <div className="max-w-screen-2xl mx-auto">
69
- <div className="grid grid-cols-[1fr_auto] lg:grid-cols-[calc(var(--side-nav-width))_1fr] lg:gap-12 items-center border-b px-4 lg:px-12 h-[--top-header-height]">
68
+ <div className="border-b">
69
+ <div className="max-w-screen-2xl border-l border-r mx-auto grid grid-cols-[1fr_auto] lg:grid-cols-[calc(var(--side-nav-width))_1fr] lg:gap-12 items-center px-4 lg:px-12 h-[--top-header-height]">
70
70
  <div className="flex">
71
71
  <Link to="/">
72
72
  <div className="flex items-center gap-3.5">
@@ -176,9 +176,13 @@ export const Header = memo(function HeaderInner() {
176
176
  </div>
177
177
  </div>
178
178
  </div>
179
- <Slotlet name="top-navigation-before" />
180
- <TopNavigation />
181
- <Slotlet name="top-navigation-after" />
179
+ </div>
180
+ <div className="border-b">
181
+ <div className="max-w-screen-2xl mx-auto border-l border-r">
182
+ <Slotlet name="top-navigation-before" />
183
+ <TopNavigation />
184
+ <Slotlet name="top-navigation-after" />
185
+ </div>
182
186
  </div>
183
187
  </header>
184
188
  );
@@ -66,7 +66,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
66
66
  <Header />
67
67
  <Slotlet name="layout-after-head" />
68
68
 
69
- <div className="w-full max-w-screen-2xl mx-auto px-4 lg:px-12">
69
+ <div className="w-full max-w-screen-2xl mx-auto px-4 lg:px-12 border-l border-r">
70
70
  {showSpinner ? (
71
71
  <LoadingFallback />
72
72
  ) : (
@@ -30,7 +30,7 @@ export const TopNavigation = () => {
30
30
 
31
31
  return (
32
32
  <Suspense>
33
- <nav className="hidden lg:block border-b text-sm px-12 h-[--top-nav-height]">
33
+ <nav className="hidden lg:block text-sm px-12 h-[--top-nav-height]">
34
34
  <ul className="flex flex-row items-center gap-8">
35
35
  {topNavigation.filter(isHiddenItem(isAuthenticated)).map((item) => (
36
36
  <li key={item.id}>
@@ -78,7 +78,7 @@ export const TopNavItem = ({
78
78
  <NavLink
79
79
  className={({ isPending }) =>
80
80
  cx(
81
- "block lg:py-3.5 font-medium -mb-px border-b-2",
81
+ "block lg:py-3.5 font-medium -mb-px",
82
82
  isActive || isPending
83
83
  ? "border-primary text-foreground"
84
84
  : "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
@@ -10,20 +10,32 @@ export const ColorMap = {
10
10
  gray: "bg-gray-400 dark:bg-gray-600",
11
11
  };
12
12
 
13
+ export const ColorMapInvert = {
14
+ green: "text-green-500 dark:text-green-600",
15
+ blue: "text-sky-400 dark:text-sky-600",
16
+ yellow: "text-yellow-400 dark:text-yellow-600",
17
+ red: "text-red-400 dark:text-red-600",
18
+ purple: "text-purple-400 dark:text-purple-600",
19
+ indigo: "text-indigo-400 dark:text-indigo-600",
20
+ gray: "text-gray-400 dark:text-gray-600",
21
+ };
22
+
13
23
  export const SidebarBadge = ({
14
24
  color,
15
25
  label,
16
26
  className,
27
+ invert,
17
28
  }: {
18
29
  color: keyof typeof ColorMap;
19
30
  label: string;
20
31
  className?: string;
32
+ invert?: boolean;
21
33
  }) => {
22
34
  return (
23
35
  <span
24
36
  className={cn(
25
37
  "mt-0.5 flex items-center duration-200 transition-opacity text-center uppercase font-mono text-[0.65rem] font-bold rounded text-background dark:text-zinc-50 h-4 px-1",
26
- ColorMap[color],
38
+ invert ? ColorMapInvert[color] : ColorMap[color],
27
39
  className,
28
40
  )}
29
41
  >
@@ -66,7 +66,7 @@ export const SidebarCategory = ({
66
66
  className={navigationListItem({
67
67
  isActive: false,
68
68
  className: [
69
- "text-start",
69
+ "text-start font-medium",
70
70
  isCollapsible
71
71
  ? "cursor-pointer"
72
72
  : "cursor-default hover:bg-transparent",
@@ -112,14 +112,10 @@ export const SidebarCategory = ({
112
112
  className={cn(
113
113
  // CollapsibleContent class is used to animate and it should only be applied when the user has triggered the toggle
114
114
  hasInteracted && "CollapsibleContent",
115
- "ms-6 my-1",
115
+ "my-1",
116
116
  )}
117
117
  >
118
- <ul
119
- className={
120
- "relative after:absolute after:-left-[--padding-nav-item] after:translate-x-[1.5px] after:top-0 after:bottom-0 after:w-px after:bg-border"
121
- }
122
- >
118
+ <ul className={"relative"}>
123
119
  {category.items.map((item) => (
124
120
  <SidebarItem
125
121
  key={
@@ -12,9 +12,10 @@ export const SidebarWrapper = forwardRef<
12
12
  // maybe this could be simplified by adjusting the layout
13
13
  data-navigation={String(pushMainContent)}
14
14
  className={cn(
15
- "scrollbar peer hidden lg:flex flex-col fixed text-sm overflow-y-auto shrink-0",
16
- "-mx-[--padding-nav-item] pb-20 mt-[--padding-content-top]",
15
+ "scrollbar peer hidden lg:flex flex-col fixed text-sm overflow-y-auto shrink-0 border-r pr-10",
16
+ "-mx-[--padding-nav-item] pb-20 pt-[--padding-content-top]",
17
17
  "w-[--side-nav-width] h-[calc(100%-var(--header-height))] scroll-pt-2 gap-2",
18
+ !pushMainContent && "border-r-0",
18
19
  className,
19
20
  )}
20
21
  ref={ref}
@@ -329,9 +329,12 @@ const OperationItem = builder
329
329
  ([mediaType, content]) => ({
330
330
  mediaType,
331
331
  schema: content.schema,
332
- examples: Object.entries(content.examples ?? {}).map(
333
- ([name, value]) => ({ name, ...value }),
334
- ),
332
+ examples: content.examples
333
+ ? Object.entries(content.examples).map(([name, value]) => ({
334
+ name,
335
+ ...(typeof value === "string" ? { value } : value),
336
+ }))
337
+ : [],
335
338
  encoding: Object.entries(content.encoding ?? {}).map(
336
339
  ([name, value]) => ({ name, ...value }),
337
340
  ),
@@ -351,9 +354,12 @@ const OperationItem = builder
351
354
  ([mediaType, { schema, examples }]) => ({
352
355
  mediaType,
353
356
  schema,
354
- examples: Object.entries(examples ?? {}).map(
355
- ([name, value]) => ({ name, ...value }),
356
- ),
357
+ examples: examples
358
+ ? Object.entries(examples).map(([name, value]) => ({
359
+ name,
360
+ ...(typeof value === "string" ? { value } : value),
361
+ }))
362
+ : [],
357
363
  }),
358
364
  ),
359
365
  headers: response.headers,
@@ -379,7 +385,10 @@ const OperationItem = builder
379
385
  const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
380
386
  fields: (t) => ({
381
387
  openapi: t.string({ resolve: (root) => root.openapi }),
382
- url: t.string({ resolve: (root) => root.servers?.at(0)?.url ?? "/" }),
388
+ url: t.string({
389
+ resolve: (root) => root.servers?.at(0)?.url,
390
+ nullable: true,
391
+ }),
383
392
  servers: t.field({
384
393
  type: [ServerItem],
385
394
  resolve: (root) => root.servers ?? [],
@@ -42,12 +42,27 @@ export const upgradeSchema = (schema: RecordAny): OpenAPIDocument => {
42
42
 
43
43
  schema = traverse(schema, (sub) => {
44
44
  if (sub.example !== undefined) {
45
- sub.examples = {
46
- default: sub.example,
47
- };
45
+ const isExampleObject =
46
+ typeof sub.example === "object" &&
47
+ (sub.example.summary !== undefined ||
48
+ sub.example.description !== undefined ||
49
+ sub.example.value !== undefined ||
50
+ sub.example.externalValue !== undefined);
51
+
52
+ const exampleValue = isExampleObject
53
+ ? sub.example
54
+ : { value: sub.example };
55
+
56
+ if (!sub.examples) {
57
+ sub.examples = { default: exampleValue };
58
+ } else {
59
+ sub.examples = {
60
+ default: exampleValue,
61
+ ...sub.examples,
62
+ };
63
+ }
48
64
  delete sub.example;
49
65
  }
50
-
51
66
  return sub;
52
67
  });
53
68
 
@@ -1,3 +1,4 @@
1
+ import { FoldVerticalIcon, UnfoldVerticalIcon } from "lucide-react";
1
2
  import { type CSSProperties, type ReactNode, useRef, useState } from "react";
2
3
  import { Button } from "zudoku/ui/Button.js";
3
4
  import {
@@ -43,22 +44,23 @@ export const CollapsibleCode = ({
43
44
  <CollapsibleContent
44
45
  forceMount
45
46
  className={cn(
46
- "relative overflow-hidden",
47
+ "relative overflow-hidden group",
47
48
  !open && isOverflowing && "max-h-[--max-height]",
48
49
  )}
49
50
  >
50
51
  {!open && isOverflowing && (
51
- <div className="absolute inset-0 bg-gradient-to-b from-transparent to-zinc-50/90 dark:to-zinc-800/90 z-10"></div>
52
+ <div className=" absolute inset-0 bg-gradient-to-b from-transparent to-zinc-50/60 dark:to-zinc-950/90 z-10 group-hover:to-transparent"></div>
52
53
  )}
53
54
  <div ref={contentRef}>{children}</div>
54
55
  {!open && isOverflowing && (
55
56
  <CollapsibleTrigger
56
- className="absolute inset-0 grid place-items-center z-10"
57
+ className="absolute inset-0 grid place-items-center z-10 cursor-pointer peer"
57
58
  asChild
58
59
  >
59
60
  <div>
60
- <Button className="bg-primary/70 border border-accent-foreground/25">
61
- Expand code
61
+ <Button variant="outline" className="hidden group-hover:flex">
62
+ <UnfoldVerticalIcon size={14} className="mr-1.5" />
63
+ Click to expand
62
64
  </Button>
63
65
  </div>
64
66
  </CollapsibleTrigger>
@@ -69,8 +71,9 @@ export const CollapsibleCode = ({
69
71
  className={cn("flex justify-center w-full mb-2", !open && "hidden")}
70
72
  >
71
73
  <CollapsibleTrigger asChild>
72
- <Button className="border border-accent-foreground/25">
73
- Collapse code
74
+ <Button variant="outline" size="sm">
75
+ Collapse
76
+ <FoldVerticalIcon size={14} className="ml-1.5" />
74
77
  </Button>
75
78
  </CollapsibleTrigger>
76
79
  </div>
@@ -52,6 +52,8 @@ export const Endpoint = () => {
52
52
 
53
53
  const { servers } = result.data.schema;
54
54
 
55
+ if (servers.length === 0) return null;
56
+
55
57
  if (servers.length === 1) {
56
58
  return (
57
59
  <div className="flex items-center gap-2">
@@ -66,9 +68,7 @@ export const Endpoint = () => {
66
68
 
67
69
  return (
68
70
  <div className="flex flex-wrap items-center gap-2">
69
- <span className="font-medium text-sm">
70
- {servers.length > 1 ? "Endpoints" : "Endpoint"}:
71
- </span>
71
+ <span className="font-medium text-sm">Endpoint</span>
72
72
 
73
73
  <SimpleSelect
74
74
  className="font-mono text-xs bg-border/50 dark:bg-border/70 py-1.5 max-w-[450px] truncate"