zudoku 0.1.1-dev.18 → 0.1.1-dev.19

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 (139) hide show
  1. package/dist/lib/plugins/openapi/worker/createSharedWorkerClient.js +2 -3
  2. package/dist/lib/plugins/openapi/worker/createSharedWorkerClient.js.map +1 -1
  3. package/dist/lib/plugins/openapi/worker/shared-worker.d.ts +1 -0
  4. package/dist/lib/plugins/openapi/worker/shared-worker.js +6 -0
  5. package/dist/lib/plugins/openapi/worker/shared-worker.js.map +1 -0
  6. package/dist/vite/config.d.ts +1 -1
  7. package/dist/vite/config.js +13 -13
  8. package/dist/vite/config.js.map +1 -1
  9. package/dist/vite/dev-server.js +1 -1
  10. package/dist/vite/dev-server.js.map +1 -1
  11. package/lib/zudoku.openapi-worker.js +12 -0
  12. package/lib/zudoku.plugins.js +1318 -1323
  13. package/package.json +5 -2
  14. package/src/cli/build/handler.ts +14 -0
  15. package/src/cli/cli.ts +77 -0
  16. package/src/cli/cmds/build.ts +24 -0
  17. package/src/cli/cmds/dev.ts +29 -0
  18. package/src/cli/common/analytics/lib.ts +89 -0
  19. package/src/cli/common/constants.ts +10 -0
  20. package/src/cli/common/logger.ts +5 -0
  21. package/src/cli/common/machine-id/lib.ts +85 -0
  22. package/src/cli/common/outdated.ts +102 -0
  23. package/src/cli/common/output.ts +86 -0
  24. package/src/cli/common/utils/box.license.txt +202 -0
  25. package/src/cli/common/utils/box.ts +116 -0
  26. package/src/cli/common/utils/ports.ts +21 -0
  27. package/src/cli/common/validators/lib.ts +43 -0
  28. package/src/cli/common/xdg/lib.ts +36 -0
  29. package/src/cli/dev/handler.ts +42 -0
  30. package/src/config/config.ts +56 -0
  31. package/src/index.ts +8 -0
  32. package/src/lib/DevPortal.tsx +93 -0
  33. package/src/lib/Heading.tsx +60 -0
  34. package/src/lib/Router.tsx +28 -0
  35. package/src/lib/auth.ts +1 -0
  36. package/src/lib/authentication/authentication.ts +18 -0
  37. package/src/lib/authentication/clerk.ts +45 -0
  38. package/src/lib/authentication/openid.ts +192 -0
  39. package/src/lib/components/AnchorLink.tsx +19 -0
  40. package/src/lib/components/CategoryHeading.tsx +16 -0
  41. package/src/lib/components/Dialog.tsx +119 -0
  42. package/src/lib/components/DynamicIcon.tsx +60 -0
  43. package/src/lib/components/Header.tsx +69 -0
  44. package/src/lib/components/Input.tsx +24 -0
  45. package/src/lib/components/Layout.tsx +56 -0
  46. package/src/lib/components/Markdown.tsx +37 -0
  47. package/src/lib/components/SyntaxHighlight.tsx +94 -0
  48. package/src/lib/components/TopNavigation.tsx +32 -0
  49. package/src/lib/components/context/ComponentsContext.tsx +24 -0
  50. package/src/lib/components/context/DevPortalProvider.ts +54 -0
  51. package/src/lib/components/context/PluginSystem.ts +0 -0
  52. package/src/lib/components/context/ThemeContext.tsx +46 -0
  53. package/src/lib/components/context/ViewportAnchorContext.tsx +139 -0
  54. package/src/lib/components/navigation/SideNavigation.tsx +18 -0
  55. package/src/lib/components/navigation/SideNavigationCategory.tsx +74 -0
  56. package/src/lib/components/navigation/SideNavigationItem.tsx +143 -0
  57. package/src/lib/components/navigation/SideNavigationWrapper.tsx +15 -0
  58. package/src/lib/components/navigation/useNavigationCollapsibleState.ts +27 -0
  59. package/src/lib/components/navigation/util.ts +38 -0
  60. package/src/lib/components.ts +3 -0
  61. package/src/lib/core/DevPortalContext.ts +164 -0
  62. package/src/lib/core/helmet.ts +5 -0
  63. package/src/lib/core/icons.tsx +1 -0
  64. package/src/lib/core/plugins.ts +43 -0
  65. package/src/lib/core/router.tsx +1 -0
  66. package/src/lib/core/types/combine.ts +16 -0
  67. package/src/lib/oas/graphql/index.ts +422 -0
  68. package/src/lib/oas/graphql/server.ts +10 -0
  69. package/src/lib/oas/parser/dereference/index.ts +59 -0
  70. package/src/lib/oas/parser/dereference/resolveRef.ts +32 -0
  71. package/src/lib/oas/parser/index.ts +94 -0
  72. package/src/lib/oas/parser/schemas/v3.0.json +1489 -0
  73. package/src/lib/oas/parser/schemas/v3.1.json +1298 -0
  74. package/src/lib/oas/parser/upgrade/index.ts +108 -0
  75. package/src/lib/plugins/api-key/SettingsApiKeys.tsx +22 -0
  76. package/src/lib/plugins/api-key/index.tsx +123 -0
  77. package/src/lib/plugins/markdown/MdxPage.tsx +128 -0
  78. package/src/lib/plugins/markdown/Toc.tsx +122 -0
  79. package/src/lib/plugins/markdown/generateRoutes.tsx +72 -0
  80. package/src/lib/plugins/markdown/index.tsx +31 -0
  81. package/src/lib/plugins/openapi/ColorizedParam.tsx +82 -0
  82. package/src/lib/plugins/openapi/MakeRequest.tsx +49 -0
  83. package/src/lib/plugins/openapi/MethodBadge.tsx +36 -0
  84. package/src/lib/plugins/openapi/OperationList.tsx +117 -0
  85. package/src/lib/plugins/openapi/OperationListItem.tsx +55 -0
  86. package/src/lib/plugins/openapi/ParameterList.tsx +32 -0
  87. package/src/lib/plugins/openapi/ParameterListItem.tsx +60 -0
  88. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +51 -0
  89. package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +60 -0
  90. package/src/lib/plugins/openapi/Select.tsx +35 -0
  91. package/src/lib/plugins/openapi/Sidecar.tsx +160 -0
  92. package/src/lib/plugins/openapi/SidecarBox.tsx +36 -0
  93. package/src/lib/plugins/openapi/graphql/fragment-masking.ts +111 -0
  94. package/src/lib/plugins/openapi/graphql/gql.ts +70 -0
  95. package/src/lib/plugins/openapi/graphql/graphql.ts +795 -0
  96. package/src/lib/plugins/openapi/graphql/index.ts +2 -0
  97. package/src/lib/plugins/openapi/index.tsx +142 -0
  98. package/src/lib/plugins/openapi/playground/Playground.tsx +309 -0
  99. package/src/lib/plugins/openapi/queries.graphql +6 -0
  100. package/src/lib/plugins/openapi/util/generateSchemaExample.ts +59 -0
  101. package/src/lib/plugins/openapi/util/urql.ts +8 -0
  102. package/src/lib/plugins/openapi/worker/createSharedWorkerClient.ts +60 -0
  103. package/src/lib/plugins/openapi/worker/shared-worker.ts +5 -0
  104. package/src/lib/plugins/openapi/worker/worker.ts +30 -0
  105. package/src/lib/plugins/redirect/index.tsx +20 -0
  106. package/src/lib/plugins.ts +5 -0
  107. package/src/lib/ui/Button.tsx +56 -0
  108. package/src/lib/ui/Callout.tsx +87 -0
  109. package/src/lib/ui/Card.tsx +82 -0
  110. package/src/lib/ui/Note.tsx +58 -0
  111. package/src/lib/ui/Tabs.tsx +52 -0
  112. package/src/lib/util/MdxComponents.tsx +70 -0
  113. package/src/lib/util/cn.ts +6 -0
  114. package/src/lib/util/createVariantComponent.tsx +30 -0
  115. package/src/lib/util/createWaitForNotify.ts +18 -0
  116. package/src/lib/util/groupBy.ts +24 -0
  117. package/src/lib/util/joinPath.tsx +10 -0
  118. package/src/lib/util/pastellize.ts +25 -0
  119. package/src/lib/util/slugify.ts +3 -0
  120. package/src/lib/util/traverseNavigation.ts +55 -0
  121. package/src/lib/util/useScrollToAnchor.ts +38 -0
  122. package/src/lib/util/useScrollToTop.ts +13 -0
  123. package/src/ts.ts +94 -0
  124. package/src/types.d.ts +24 -0
  125. package/src/vite/build.ts +33 -0
  126. package/src/vite/config.test.ts +10 -0
  127. package/src/vite/config.ts +183 -0
  128. package/src/vite/dev-server.ts +64 -0
  129. package/src/vite/html.ts +37 -0
  130. package/src/vite/plugin-api.ts +57 -0
  131. package/src/vite/plugin-auth.ts +32 -0
  132. package/src/vite/plugin-component.ts +26 -0
  133. package/src/vite/plugin-config.ts +31 -0
  134. package/src/vite/plugin-docs.test.ts +32 -0
  135. package/src/vite/plugin-docs.ts +52 -0
  136. package/src/vite/plugin-html.ts +50 -0
  137. package/src/vite/plugin-mdx.ts +74 -0
  138. package/src/vite/plugin-metadata.ts +30 -0
  139. package/src/vite/plugin.ts +23 -0
@@ -0,0 +1,56 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+ import { cn } from "../util/cn.js";
5
+
6
+ const buttonVariants = cva(
7
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
13
+ destructive:
14
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
15
+ outline:
16
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
19
+ ghost: "hover:bg-accent hover:text-accent-foreground",
20
+ link: "text-primary underline-offset-4 hover:underline",
21
+ },
22
+ size: {
23
+ default: "h-9 px-4 py-2",
24
+ sm: "h-8 rounded-md px-3 text-xs",
25
+ lg: "h-10 rounded-md px-8",
26
+ icon: "h-9 w-9",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: "default",
31
+ size: "default",
32
+ },
33
+ }
34
+ )
35
+
36
+ export interface ButtonProps
37
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38
+ VariantProps<typeof buttonVariants> {
39
+ asChild?: boolean
40
+ }
41
+
42
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
44
+ const Comp = asChild ? Slot : "button"
45
+ return (
46
+ <Comp
47
+ className={cn(buttonVariants({ variant, size, className }))}
48
+ ref={ref}
49
+ {...props}
50
+ />
51
+ )
52
+ }
53
+ )
54
+ Button.displayName = "Button"
55
+
56
+ export { Button, buttonVariants }
@@ -0,0 +1,87 @@
1
+ import type { ReactNode } from "react";
2
+ import {
3
+ AlertTriangleIcon,
4
+ InfoIcon,
5
+ LightbulbIcon,
6
+ ShieldAlertIcon,
7
+ } from "../core/icons.js";
8
+ import { cn } from "../util/cn.js";
9
+
10
+ const stylesMap = {
11
+ note: {
12
+ border: "border-gray-300 dark:border-zinc-800",
13
+ bg: "bg-gray-100 dark:bg-zinc-800/50",
14
+ iconColor: "text-gray-600 dark:text-zinc-300",
15
+ titleColor: "text-gray-600 dark:text-zinc-300",
16
+ textColor: "text-gray-600 dark:text-zinc-300",
17
+ Icon: InfoIcon,
18
+ },
19
+ tip: {
20
+ border: "border-green-500 dark:border-green-800",
21
+ bg: "bg-green-200/25 dark:bg-green-950/70",
22
+ iconColor: "text-green-600 dark:text-green-200",
23
+ titleColor: "text-green-700 dark:text-green-200",
24
+ textColor: "text-green-600 dark:text-green-50",
25
+ Icon: LightbulbIcon,
26
+ },
27
+ info: {
28
+ border: "border-blue-400 dark:border-blue-900/60",
29
+ bg: "bg-blue-50 dark:bg-blue-950/40",
30
+ iconColor: "text-blue-400 dark:text-blue-200",
31
+ titleColor: "text-blue-700 dark:text-blue-200",
32
+ textColor: "text-blue-600 dark:text-blue-100",
33
+ Icon: InfoIcon,
34
+ },
35
+ caution: {
36
+ border: "border-yellow-400 dark:border-yellow-400/25",
37
+ bg: "bg-yellow-100/60 dark:bg-yellow-400/10",
38
+ iconColor: "text-yellow-500 dark:text-yellow-300",
39
+ titleColor: "text-yellow-600 dark:text-yellow-300",
40
+ textColor: "text-yellow-700 dark:text-yellow-200",
41
+ Icon: AlertTriangleIcon,
42
+ },
43
+ danger: {
44
+ border: "border-rose-400 dark:border-rose-800",
45
+ bg: "bg-rose-50 dark:bg-rose-950/40",
46
+ iconColor: "text-rose-400 dark:text-rose-300",
47
+ titleColor: "text-rose-800 dark:text-rose-300",
48
+ textColor: "text-rose-700 dark:text-rose-100",
49
+ Icon: ShieldAlertIcon,
50
+ },
51
+ };
52
+
53
+ type CalloutProps = {
54
+ type: keyof typeof stylesMap;
55
+ title?: string;
56
+ children: ReactNode;
57
+ className?: string;
58
+ };
59
+
60
+ export const Callout = ({ type, children, title, className }: CalloutProps) => {
61
+ const { border, bg, iconColor, titleColor, textColor, Icon } =
62
+ stylesMap[type];
63
+
64
+ return (
65
+ <div
66
+ className={cn(
67
+ "not-prose grid grid-cols-[fit-content_1fr] grid-rows-[fit-content_1fr] gap-x-4 gap-y-2 text-md rounded-md border p-4",
68
+ "[&_a]:underline [&_a]:decoration-current [&_a]:decoration-from-font [&_a]:underline-offset-4 hover:[&_a]:decoration-1",
69
+ "[&_code]:!bg-transparent [&_code]:!border-none",
70
+ title && "items-center",
71
+ border,
72
+ bg,
73
+ className,
74
+ )}
75
+ >
76
+ <Icon
77
+ className={cn(!title && "mt-1 translate-y-px", iconColor)}
78
+ size={20}
79
+ aria-hidden="true"
80
+ />
81
+ {title && <h3 className={cn("font-medium", titleColor)}>{title}</h3>}
82
+ <div className={cn("col-start-2", !title && "row-start-1", textColor)}>
83
+ {children}
84
+ </div>
85
+ </div>
86
+ );
87
+ };
@@ -0,0 +1,82 @@
1
+ import * as React from "react";
2
+ import { cn } from "../util/cn.js";
3
+
4
+ const Card = React.forwardRef<
5
+ HTMLDivElement,
6
+ React.HTMLAttributes<HTMLDivElement>
7
+ >(({ className, ...props }, ref) => (
8
+ <div
9
+ ref={ref}
10
+ className={cn(
11
+ "rounded-xl border border-border bg-card text-card-foreground shadow",
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ ));
17
+ Card.displayName = "Card";
18
+
19
+ const CardHeader = React.forwardRef<
20
+ HTMLDivElement,
21
+ React.HTMLAttributes<HTMLDivElement>
22
+ >(({ className, ...props }, ref) => (
23
+ <div
24
+ ref={ref}
25
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
26
+ {...props}
27
+ />
28
+ ));
29
+ CardHeader.displayName = "CardHeader";
30
+
31
+ const CardTitle = React.forwardRef<
32
+ HTMLParagraphElement,
33
+ React.HTMLAttributes<HTMLHeadingElement>
34
+ >(({ className, ...props }, ref) => (
35
+ <h3
36
+ ref={ref}
37
+ className={cn("font-semibold leading-none tracking-tight", className)}
38
+ {...props}
39
+ />
40
+ ));
41
+ CardTitle.displayName = "CardTitle";
42
+
43
+ const CardDescription = React.forwardRef<
44
+ HTMLParagraphElement,
45
+ React.HTMLAttributes<HTMLParagraphElement>
46
+ >(({ className, ...props }, ref) => (
47
+ <p
48
+ ref={ref}
49
+ className={cn("text-sm text-muted-foreground", className)}
50
+ {...props}
51
+ />
52
+ ));
53
+ CardDescription.displayName = "CardDescription";
54
+
55
+ const CardContent = React.forwardRef<
56
+ HTMLDivElement,
57
+ React.HTMLAttributes<HTMLDivElement>
58
+ >(({ className, ...props }, ref) => (
59
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
60
+ ));
61
+ CardContent.displayName = "CardContent";
62
+
63
+ const CardFooter = React.forwardRef<
64
+ HTMLDivElement,
65
+ React.HTMLAttributes<HTMLDivElement>
66
+ >(({ className, ...props }, ref) => (
67
+ <div
68
+ ref={ref}
69
+ className={cn("flex items-center p-6 pt-0", className)}
70
+ {...props}
71
+ />
72
+ ));
73
+ CardFooter.displayName = "CardFooter";
74
+
75
+ export {
76
+ Card,
77
+ CardContent,
78
+ CardDescription,
79
+ CardFooter,
80
+ CardHeader,
81
+ CardTitle,
82
+ };
@@ -0,0 +1,58 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
+ import { cn } from "../util/cn.js";
4
+
5
+ const noteVariants = cva(
6
+ "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-background text-foreground",
11
+ destructive:
12
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ variant: "default",
17
+ },
18
+ },
19
+ );
20
+
21
+ const Note = React.forwardRef<
22
+ HTMLDivElement,
23
+ React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof noteVariants>
24
+ >(({ className, variant, ...props }, ref) => (
25
+ <div
26
+ ref={ref}
27
+ role="alert"
28
+ className={cn(noteVariants({ variant }), className)}
29
+ {...props}
30
+ />
31
+ ));
32
+ Note.displayName = "Alert";
33
+
34
+ const NoteTitle = React.forwardRef<
35
+ HTMLParagraphElement,
36
+ React.HTMLAttributes<HTMLHeadingElement>
37
+ >(({ className, ...props }, ref) => (
38
+ <h5
39
+ ref={ref}
40
+ className={cn("mb-1 font-medium leading-none tracking-tight", className)}
41
+ {...props}
42
+ />
43
+ ));
44
+ NoteTitle.displayName = "AlertTitle";
45
+
46
+ const NoteDescription = React.forwardRef<
47
+ HTMLParagraphElement,
48
+ React.HTMLAttributes<HTMLParagraphElement>
49
+ >(({ className, ...props }, ref) => (
50
+ <div
51
+ ref={ref}
52
+ className={cn("text-sm [&_p]:leading-relaxed", className)}
53
+ {...props}
54
+ />
55
+ ));
56
+ NoteDescription.displayName = "AlertDescription";
57
+
58
+ export { Note, NoteDescription, NoteTitle };
@@ -0,0 +1,52 @@
1
+ import * as React from "react";
2
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
3
+ import { cn } from "../util/cn.js";
4
+
5
+ const Tabs = TabsPrimitive.Root;
6
+
7
+ const TabsList = React.forwardRef<
8
+ React.ElementRef<typeof TabsPrimitive.List>,
9
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
10
+ >(({ className, ...props }, ref) => (
11
+ <TabsPrimitive.List
12
+ ref={ref}
13
+ className={cn(
14
+ "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
15
+ className,
16
+ )}
17
+ {...props}
18
+ />
19
+ ));
20
+ TabsList.displayName = TabsPrimitive.List.displayName;
21
+
22
+ const TabsTrigger = React.forwardRef<
23
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
24
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
25
+ >(({ className, ...props }, ref) => (
26
+ <TabsPrimitive.Trigger
27
+ ref={ref}
28
+ className={cn(
29
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
30
+ className,
31
+ )}
32
+ {...props}
33
+ />
34
+ ));
35
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
36
+
37
+ const TabsContent = React.forwardRef<
38
+ React.ElementRef<typeof TabsPrimitive.Content>,
39
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
40
+ >(({ className, ...props }, ref) => (
41
+ <TabsPrimitive.Content
42
+ ref={ref}
43
+ className={cn(
44
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
45
+ className,
46
+ )}
47
+ {...props}
48
+ />
49
+ ));
50
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
51
+
52
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,70 @@
1
+ import { MDXProvider } from "@mdx-js/react";
2
+ import type { ComponentProps } from "react";
3
+
4
+ import { Link } from "react-router-dom";
5
+ import { Heading } from "../Heading.js";
6
+ import { SyntaxHighlight } from "../components/SyntaxHighlight.js";
7
+ import { Callout } from "../ui/Callout.js";
8
+ import { cn } from "./cn.js";
9
+
10
+ export type MdxComponentsType = ComponentProps<
11
+ typeof MDXProvider
12
+ >["components"];
13
+
14
+ export const MdxComponents = {
15
+ img: (props) => {
16
+ if (/\.(mp4|webm|mov|avi)$/.test(props.src ?? "")) {
17
+ return <video src={props.src} controls playsInline autoPlay loop />;
18
+ }
19
+ return <img {...props} className="rounded-md" />;
20
+ },
21
+ h1: ({ children, id }) => <Heading level={1} id={id} children={children} />,
22
+ h2: ({ children, id }) => <Heading level={2} id={id} children={children} />,
23
+ h3: ({ children, id }) => <Heading level={3} id={id} children={children} />,
24
+ h4: ({ children, id }) => <Heading level={4} id={id} children={children} />,
25
+ h5: ({ children, id }) => <Heading level={5} id={id} children={children} />,
26
+ h6: ({ children, id }) => <Heading level={6} id={id} children={children} />,
27
+ a: ({ href, ...props }) =>
28
+ href && !href.startsWith("http") ? (
29
+ <Link to={href} relative="path" {...props} />
30
+ ) : (
31
+ <a href={href} target="_blank" {...props} />
32
+ ),
33
+ Callout,
34
+ tip: (props) => <Callout type="tip" {...props} />,
35
+ info: (props) => <Callout type="info" {...props} />,
36
+ note: (props) => <Callout type="note" {...props} />,
37
+ caution: (props) => <Callout type="caution" {...props} />,
38
+ warning: (props) => <Callout type="caution" {...props} />,
39
+ danger: (props) => <Callout type="danger" {...props} />,
40
+
41
+ pre: ({ children }) => <>{children}</>,
42
+ code: ({ className, children, ...props }) => {
43
+ // `inline` provided by the rehype plugin, as react-markdown removed support for that
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const inline = (props as any).inline;
46
+
47
+ if (!inline) {
48
+ const match = className?.match(/language?-(\w+)/);
49
+
50
+ return (
51
+ <SyntaxHighlight
52
+ language={match?.[1] ?? "markup"}
53
+ className="rounded-xl overflow-x-auto p-4 border border-border dark:!bg-foreground/10 dark:border-transparent"
54
+ code={String(children).trim()}
55
+ />
56
+ );
57
+ }
58
+
59
+ return (
60
+ <code
61
+ className={cn(
62
+ className,
63
+ "font-mono border border-border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70",
64
+ )}
65
+ >
66
+ {children}
67
+ </code>
68
+ );
69
+ },
70
+ } satisfies MdxComponentsType;
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,30 @@
1
+ import { cva } from "class-variance-authority";
2
+ import { ClassValue } from "clsx";
3
+ import * as React from "react";
4
+ import { JSX } from "react/jsx-runtime";
5
+ import { cn } from "./cn.js";
6
+
7
+ const createVariantComponent = <
8
+ E extends keyof React.ReactHTML,
9
+ C extends ReturnType<typeof cva>,
10
+ >(
11
+ tag: E,
12
+ cvx: ClassValue | C,
13
+ // variantProps: Array<keyof VariantProps<C>> = [],
14
+ ) => {
15
+ const MyVariant = ({
16
+ className,
17
+ ...props
18
+ }: JSX.IntrinsicElements[E] & { className?: ClassValue }) =>
19
+ React.createElement(tag, {
20
+ ...props,
21
+ className:
22
+ typeof cvx === "function" ? cvx({ className }) : cn(cvx, className),
23
+ });
24
+
25
+ MyVariant.displayName = `VariantComponent(${tag})`;
26
+
27
+ return MyVariant;
28
+ };
29
+
30
+ export default createVariantComponent;
@@ -0,0 +1,18 @@
1
+ export const createWaitForNotify = <T extends NonNullable<unknown>>() => {
2
+ const resolveMap = new Map<string, (value: T | PromiseLike<T>) => void>();
3
+
4
+ const waitFor = (id: string) =>
5
+ new Promise<T>((resolve) => {
6
+ resolveMap.set(id, resolve);
7
+ });
8
+
9
+ const notify = (id: string, data: T) => {
10
+ const resolveFn = resolveMap.get(id);
11
+ if (resolveFn) {
12
+ resolveFn(data);
13
+ resolveMap.delete(id);
14
+ }
15
+ };
16
+
17
+ return [waitFor, notify] as const;
18
+ };
@@ -0,0 +1,24 @@
1
+ type MapValuesToKeysIfAllowed<T> = {
2
+ [K in keyof T]: T[K] extends PropertyKey ? K : never;
3
+ };
4
+ type Filter<T> = MapValuesToKeysIfAllowed<T>[keyof T];
5
+
6
+ export const groupBy = <
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ T extends Record<PropertyKey, any>,
9
+ Key extends Filter<T>,
10
+ >(
11
+ arr: T[],
12
+ key: Key,
13
+ ): Record<T[Key], T[]> =>
14
+ arr.reduce(
15
+ (accumulator, val) => {
16
+ const groupedKey = val[key];
17
+ if (!accumulator[groupedKey]) {
18
+ accumulator[groupedKey] = [];
19
+ }
20
+ accumulator[groupedKey].push(val);
21
+ return accumulator;
22
+ },
23
+ {} as Record<T[Key], T[]>,
24
+ );
@@ -0,0 +1,10 @@
1
+ export const joinPath = (
2
+ ...parts: Array<string | null | undefined | boolean>
3
+ ) => {
4
+ const cleanPath = parts
5
+ .filter((part): part is string => Boolean(part))
6
+ .map((part) => part.replace(/(^\/+|\/+$)/g, "")) // Strip leading and trailing slashes
7
+ .join("/");
8
+
9
+ return cleanPath ? `/${cleanPath}` : "";
10
+ };
@@ -0,0 +1,25 @@
1
+ const c2n = (c: string) =>
2
+ Math.abs(
3
+ isNaN(parseInt(c))
4
+ ? c.toLowerCase().charCodeAt(0) - 96
5
+ : isNaN(parseInt(c))
6
+ ? 0
7
+ : parseInt(c),
8
+ );
9
+ const s2n = (s: string) =>
10
+ s.length > 1
11
+ ? parseInt(s.split("").reduce((a, c) => `${c2n(a) + c2n(c)}`))
12
+ : c2n(s);
13
+
14
+ export const pastellize = (
15
+ s: string,
16
+ options: {
17
+ saturation?: number;
18
+ lightness?: number;
19
+ } = {},
20
+ ) => {
21
+ const hue = (3 * s2n(s) + 2 * s2n(s) + s2n(s)) % 360;
22
+ const { saturation = 75, lightness = 60 } = options;
23
+
24
+ return `${hue}deg ${saturation}% ${lightness}%`;
25
+ };
@@ -0,0 +1,3 @@
1
+ import slugify from "slugify";
2
+
3
+ export default slugify;
@@ -0,0 +1,55 @@
1
+ import { isPathItem } from "../components/navigation/util.js";
2
+ import type {
3
+ NavigationCategory,
4
+ NavigationCategoryItem,
5
+ NavigationItem,
6
+ } from "../core/DevPortalContext.js";
7
+ import { joinPath } from "./joinPath.js";
8
+
9
+ export type NavigationNode = NavigationCategoryItem | NavigationCategory;
10
+ type Callback<T> = (
11
+ node: NavigationNode,
12
+ fullPath: string,
13
+ parentNodes: NavigationNode[],
14
+ ) => T | undefined;
15
+
16
+ export const traverseNavigationNode = <T>(
17
+ node: NavigationNode,
18
+ callback: Callback<T>,
19
+ parentPath: string,
20
+ parentNodes: NavigationNode[] = [],
21
+ ): T | undefined => {
22
+ const newPath = isPathItem(node)
23
+ ? joinPath(parentPath, node.path)
24
+ : parentPath;
25
+ const result = callback(node, newPath, parentNodes);
26
+
27
+ if (result !== undefined) return result;
28
+
29
+ if ("children" in node && node.children) {
30
+ const newParentNodes = [...parentNodes, node];
31
+ for (const child of node.children) {
32
+ const childResult = traverseNavigationNode(
33
+ child,
34
+ callback,
35
+ newPath,
36
+ newParentNodes,
37
+ );
38
+ if (childResult !== undefined) return childResult;
39
+ }
40
+ }
41
+ return undefined;
42
+ };
43
+
44
+ export const traverseNavigation = <T>(
45
+ navItem: NavigationItem,
46
+ callback: Callback<T>,
47
+ ): T | undefined => {
48
+ if (navItem.categories) {
49
+ for (const category of navItem.categories) {
50
+ const result = traverseNavigationNode(category, callback, navItem.path);
51
+ if (result !== undefined) return result;
52
+ }
53
+ }
54
+ return undefined;
55
+ };
@@ -0,0 +1,38 @@
1
+ import { useEffect } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+ import { useViewportAnchor } from "../components/context/ViewportAnchorContext.js";
4
+
5
+ export const useScrollToAnchor = () => {
6
+ const location = useLocation();
7
+ const { setActiveAnchor } = useViewportAnchor();
8
+
9
+ useEffect(() => {
10
+ if (!location.hash) return;
11
+
12
+ const hash = location.hash.split("/")[0].slice(1);
13
+
14
+ const element = document.getElementById(decodeURIComponent(hash));
15
+ if (element) {
16
+ // on page navigation element might be in DOM but not yet scrollable, so wait for a frame
17
+ requestAnimationFrame(() => {
18
+ element.scrollIntoView();
19
+ requestIdleCallback(() => setActiveAnchor(hash));
20
+ });
21
+ return;
22
+ }
23
+
24
+ // on page load, the element might not be available yet
25
+ const observer = new MutationObserver((_mutations, obs) => {
26
+ const element = document.getElementById(decodeURIComponent(hash));
27
+ if (!element) return;
28
+
29
+ element.scrollIntoView();
30
+ requestIdleCallback(() => setActiveAnchor(hash));
31
+ obs.disconnect();
32
+ });
33
+
34
+ observer.observe(document.body, { childList: true, subtree: true });
35
+
36
+ return () => observer.disconnect();
37
+ }, [location.hash, setActiveAnchor]);
38
+ };
@@ -0,0 +1,13 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+
4
+ export const useScrollToTop = () => {
5
+ const location = useLocation();
6
+ const previousPath = useRef(location.pathname);
7
+
8
+ useEffect(() => {
9
+ if (previousPath.current === location.pathname) return;
10
+ window.scrollTo(0, 0);
11
+ previousPath.current = location.pathname;
12
+ }, [location.pathname]);
13
+ };