@lukoweb/apitogo 0.1.0 → 0.1.2
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.
- package/dist/cli/cli.js +37 -147
- package/dist/declarations/lib/ui/Command.d.ts +1 -1
- package/dist/declarations/lib/util/MdxComponents.d.ts +1 -1
- package/package.json +1 -1
- package/src/app/main.tsx +150 -150
- package/src/config/loader.ts +245 -245
- package/src/index.ts +33 -33
- package/src/lib/authentication/components/CallbackHandler.tsx +45 -45
- package/src/lib/authentication/components/SignIn.tsx +46 -46
- package/src/lib/authentication/components/SignUp.tsx +48 -48
- package/src/lib/authentication/providers/clerk.tsx +224 -224
- package/src/lib/authentication/ui/AuthCard.tsx +7 -7
- package/src/lib/authentication/ui/EmailLinkCallbackUi.tsx +129 -125
- package/src/lib/authentication/ui/EmailLinkSentUi.tsx +105 -101
- package/src/lib/authentication/ui/EmailLinkSignInUi.tsx +100 -96
- package/src/lib/authentication/ui/EmailVerificationUi.tsx +128 -124
- package/src/lib/authentication/ui/ZudokuAuthUi.tsx +620 -616
- package/src/lib/components/AiAssistantMenuItems.tsx +102 -102
- package/src/lib/components/Autocomplete.tsx +123 -123
- package/src/lib/components/DeveloperHint.tsx +39 -35
- package/src/lib/components/Header.tsx +260 -260
- package/src/lib/components/Layout.tsx +53 -53
- package/src/lib/components/Main.tsx +51 -51
- package/src/lib/components/Mermaid.tsx +74 -70
- package/src/lib/components/MobileTopNavigation.tsx +276 -276
- package/src/lib/components/MultiSelect.tsx +86 -82
- package/src/lib/components/TopNavigation.tsx +103 -103
- package/src/lib/components/index.ts +26 -26
- package/src/lib/components/navigation/NavigationCategory.tsx +157 -157
- package/src/lib/components/navigation/NavigationFilterInput.tsx +35 -35
- package/src/lib/components/navigation/NavigationItem.tsx +181 -177
- package/src/lib/core/RouteGuard.tsx +193 -193
- package/src/lib/errors/ErrorMessage.tsx +50 -46
- package/src/lib/plugins/api-catalog/Catalog.tsx +80 -80
- package/src/lib/plugins/api-keys/CreateApiKey.tsx +128 -124
- package/src/lib/plugins/api-keys/CreateApiKeyDialog.tsx +49 -49
- package/src/lib/plugins/api-keys/SettingsApiKeys.tsx +72 -72
- package/src/lib/plugins/api-keys/settings/ApiKeyItem.tsx +342 -342
- package/src/lib/plugins/api-keys/settings/RevealApiKey.tsx +127 -127
- package/src/lib/plugins/markdown/MdxPage.tsx +285 -285
- package/src/lib/plugins/openapi/ApiHeader.tsx +96 -96
- package/src/lib/plugins/openapi/CollapsibleCode.tsx +88 -88
- package/src/lib/plugins/openapi/DownloadSchemaButton.tsx +94 -94
- package/src/lib/plugins/openapi/GeneratedExampleSidecarBox.tsx +52 -52
- package/src/lib/plugins/openapi/OperationListItem.tsx +183 -183
- package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +63 -63
- package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +120 -117
- package/src/lib/plugins/openapi/SchemaInfo.tsx +344 -344
- package/src/lib/plugins/openapi/SchemaList.tsx +113 -113
- package/src/lib/plugins/openapi/Sidecar.tsx +312 -309
- package/src/lib/plugins/openapi/SidecarExamples.tsx +177 -174
- package/src/lib/plugins/openapi/components/EnumValues.tsx +58 -58
- package/src/lib/plugins/openapi/components/ResponseContent.tsx +117 -114
- package/src/lib/plugins/openapi/playground/BodyPanel.tsx +274 -271
- package/src/lib/plugins/openapi/playground/CollapsibleHeader.tsx +51 -51
- package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +60 -60
- package/src/lib/plugins/openapi/playground/Headers.tsx +188 -181
- package/src/lib/plugins/openapi/playground/IdentityDialog.tsx +75 -75
- package/src/lib/plugins/openapi/playground/IdentitySelector.tsx +38 -38
- package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +45 -45
- package/src/lib/plugins/openapi/playground/Playground.tsx +602 -599
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +56 -56
- package/src/lib/plugins/openapi/playground/QueryParams.tsx +151 -148
- package/src/lib/plugins/openapi/playground/RequestLoginDialog.tsx +70 -70
- package/src/lib/plugins/openapi/playground/request-panel/MultipartField.tsx +91 -91
- package/src/lib/plugins/openapi/playground/result-panel/AudioPlayer.tsx +50 -50
- package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +355 -355
- package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +106 -102
- package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +189 -184
- package/src/lib/plugins/openapi/schema/SchemaView.tsx +299 -299
- package/src/lib/plugins/search-pagefind/IndexingDialog.tsx +162 -162
- package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +202 -202
- package/src/lib/plugins/search-pagefind/ResultList.tsx +122 -118
- package/src/lib/ui/ActionButton.tsx +21 -21
- package/src/lib/ui/Command.tsx +191 -191
- package/src/lib/util/MdxComponents.tsx +150 -150
- package/src/vite/config.ts +234 -231
- package/src/vite/dev-server.ts +291 -291
- package/src/vite/plugin-api-keys.ts +50 -50
- package/src/vite/plugin-api.ts +320 -318
- package/src/vite/plugin-auth.ts +38 -38
- package/src/vite/plugin-component.ts +45 -39
- package/src/vite/plugin-config.ts +75 -75
- package/src/vite/plugin-custom-pages.ts +36 -36
- package/src/vite/plugin-docs.ts +202 -202
- package/src/vite/plugin-markdown-export.ts +214 -214
- package/src/vite/plugin-mdx.ts +149 -149
- package/src/vite/plugin-navigation.ts +106 -106
- package/src/vite/plugin-search.ts +47 -47
- package/src/vite/plugin.ts +42 -42
- package/src/vite/prerender/prerender.ts +233 -233
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "
|
|
10
|
-
import { CategoryHeading } from "../../components/CategoryHeading.js";
|
|
11
|
-
import { Heading } from "../../components/Heading.js";
|
|
12
|
-
import { useOasConfig } from "./context.js";
|
|
13
|
-
import { DownloadSchemaButton } from "./DownloadSchemaButton.js";
|
|
14
|
-
import { buildVersionSwitchUrl } from "./util/getRoutes.js";
|
|
15
|
-
|
|
16
|
-
type ApiHeaderProps = {
|
|
17
|
-
title?: ReactNode;
|
|
18
|
-
heading: ReactNode;
|
|
19
|
-
headingId: string;
|
|
20
|
-
children?: ReactNode;
|
|
21
|
-
tag?: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const ApiHeader = ({
|
|
25
|
-
title,
|
|
26
|
-
heading,
|
|
27
|
-
headingId,
|
|
28
|
-
children,
|
|
29
|
-
tag,
|
|
30
|
-
}: ApiHeaderProps) => {
|
|
31
|
-
const { input, type, versions, version, options } = useOasConfig();
|
|
32
|
-
const navigate = useNavigate();
|
|
33
|
-
|
|
34
|
-
const hasMultipleVersions = Object.keys(versions).length > 1;
|
|
35
|
-
const showVersions =
|
|
36
|
-
options?.showVersionSelect === "always" ||
|
|
37
|
-
(hasMultipleVersions && options?.showVersionSelect !== "hide");
|
|
38
|
-
|
|
39
|
-
const currentVersion = version != null ? versions[version] : undefined;
|
|
40
|
-
const downloadUrl =
|
|
41
|
-
typeof input === "string"
|
|
42
|
-
? type === "url"
|
|
43
|
-
? input
|
|
44
|
-
: currentVersion?.downloadUrl
|
|
45
|
-
: undefined;
|
|
46
|
-
|
|
47
|
-
const handleVersionChange = (newVersion: string) => {
|
|
48
|
-
const target = versions[newVersion];
|
|
49
|
-
if (!target) return;
|
|
50
|
-
|
|
51
|
-
navigate(buildVersionSwitchUrl(target, tag));
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<div className="w-full">
|
|
56
|
-
<div className="flex flex-col gap-4 sm:flex-row justify-around items-start">
|
|
57
|
-
<div className="flex flex-col flex-1 gap-3">
|
|
58
|
-
{title && (
|
|
59
|
-
<CategoryHeading>
|
|
60
|
-
<Link to="..">{title}</Link>
|
|
61
|
-
</CategoryHeading>
|
|
62
|
-
)}
|
|
63
|
-
<Heading level={1} id={headingId} registerNavigationAnchor>
|
|
64
|
-
{heading}
|
|
65
|
-
</Heading>
|
|
66
|
-
{children}
|
|
67
|
-
</div>
|
|
68
|
-
<div className="flex flex-col gap-4 sm:items-end self-start">
|
|
69
|
-
<div className="flex gap-2 items-center">
|
|
70
|
-
{showVersions && (
|
|
71
|
-
<Select
|
|
72
|
-
onValueChange={handleVersionChange}
|
|
73
|
-
value={version}
|
|
74
|
-
disabled={!hasMultipleVersions}
|
|
75
|
-
>
|
|
76
|
-
<SelectTrigger className="w-[180px]" size="sm">
|
|
77
|
-
<SelectValue placeholder="Select version" />
|
|
78
|
-
</SelectTrigger>
|
|
79
|
-
<SelectContent>
|
|
80
|
-
{Object.entries(versions).map(([v, { label }]) => (
|
|
81
|
-
<SelectItem key={v} value={v}>
|
|
82
|
-
{label}
|
|
83
|
-
</SelectItem>
|
|
84
|
-
))}
|
|
85
|
-
</SelectContent>
|
|
86
|
-
</Select>
|
|
87
|
-
)}
|
|
88
|
-
{options?.schemaDownload?.enabled && downloadUrl && (
|
|
89
|
-
<DownloadSchemaButton downloadUrl={downloadUrl} />
|
|
90
|
-
)}
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
Select,
|
|
3
|
+
SelectContent,
|
|
4
|
+
SelectItem,
|
|
5
|
+
SelectTrigger,
|
|
6
|
+
SelectValue,
|
|
7
|
+
} from "@lukoweb/apitogo/ui/Select.js";
|
|
8
|
+
import type { ReactNode } from "react";
|
|
9
|
+
import { Link, useNavigate } from "react-router";
|
|
10
|
+
import { CategoryHeading } from "../../components/CategoryHeading.js";
|
|
11
|
+
import { Heading } from "../../components/Heading.js";
|
|
12
|
+
import { useOasConfig } from "./context.js";
|
|
13
|
+
import { DownloadSchemaButton } from "./DownloadSchemaButton.js";
|
|
14
|
+
import { buildVersionSwitchUrl } from "./util/getRoutes.js";
|
|
15
|
+
|
|
16
|
+
type ApiHeaderProps = {
|
|
17
|
+
title?: ReactNode;
|
|
18
|
+
heading: ReactNode;
|
|
19
|
+
headingId: string;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
tag?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const ApiHeader = ({
|
|
25
|
+
title,
|
|
26
|
+
heading,
|
|
27
|
+
headingId,
|
|
28
|
+
children,
|
|
29
|
+
tag,
|
|
30
|
+
}: ApiHeaderProps) => {
|
|
31
|
+
const { input, type, versions, version, options } = useOasConfig();
|
|
32
|
+
const navigate = useNavigate();
|
|
33
|
+
|
|
34
|
+
const hasMultipleVersions = Object.keys(versions).length > 1;
|
|
35
|
+
const showVersions =
|
|
36
|
+
options?.showVersionSelect === "always" ||
|
|
37
|
+
(hasMultipleVersions && options?.showVersionSelect !== "hide");
|
|
38
|
+
|
|
39
|
+
const currentVersion = version != null ? versions[version] : undefined;
|
|
40
|
+
const downloadUrl =
|
|
41
|
+
typeof input === "string"
|
|
42
|
+
? type === "url"
|
|
43
|
+
? input
|
|
44
|
+
: currentVersion?.downloadUrl
|
|
45
|
+
: undefined;
|
|
46
|
+
|
|
47
|
+
const handleVersionChange = (newVersion: string) => {
|
|
48
|
+
const target = versions[newVersion];
|
|
49
|
+
if (!target) return;
|
|
50
|
+
|
|
51
|
+
navigate(buildVersionSwitchUrl(target, tag));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="w-full">
|
|
56
|
+
<div className="flex flex-col gap-4 sm:flex-row justify-around items-start">
|
|
57
|
+
<div className="flex flex-col flex-1 gap-3">
|
|
58
|
+
{title && (
|
|
59
|
+
<CategoryHeading>
|
|
60
|
+
<Link to="..">{title}</Link>
|
|
61
|
+
</CategoryHeading>
|
|
62
|
+
)}
|
|
63
|
+
<Heading level={1} id={headingId} registerNavigationAnchor>
|
|
64
|
+
{heading}
|
|
65
|
+
</Heading>
|
|
66
|
+
{children}
|
|
67
|
+
</div>
|
|
68
|
+
<div className="flex flex-col gap-4 sm:items-end self-start">
|
|
69
|
+
<div className="flex gap-2 items-center">
|
|
70
|
+
{showVersions && (
|
|
71
|
+
<Select
|
|
72
|
+
onValueChange={handleVersionChange}
|
|
73
|
+
value={version}
|
|
74
|
+
disabled={!hasMultipleVersions}
|
|
75
|
+
>
|
|
76
|
+
<SelectTrigger className="w-[180px]" size="sm">
|
|
77
|
+
<SelectValue placeholder="Select version" />
|
|
78
|
+
</SelectTrigger>
|
|
79
|
+
<SelectContent>
|
|
80
|
+
{Object.entries(versions).map(([v, { label }]) => (
|
|
81
|
+
<SelectItem key={v} value={v}>
|
|
82
|
+
{label}
|
|
83
|
+
</SelectItem>
|
|
84
|
+
))}
|
|
85
|
+
</SelectContent>
|
|
86
|
+
</Select>
|
|
87
|
+
)}
|
|
88
|
+
{options?.schemaDownload?.enabled && downloadUrl && (
|
|
89
|
+
<DownloadSchemaButton downloadUrl={downloadUrl} />
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "
|
|
9
|
-
import { cn } from "../../util/cn.js";
|
|
10
|
-
import useIsomorphicLayoutEffect from "../../util/useIsomorphicLayoutEffect.js";
|
|
11
|
-
|
|
12
|
-
export const OverflowOverlay = () => (
|
|
13
|
-
<div className="absolute inset-0 bg-linear-to-b from-transparent to-zinc-50/60 dark:to-zinc-950/90 z-10 transition-all group-hover:to-transparent" />
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
export const CollapsibleCode = ({
|
|
17
|
-
children,
|
|
18
|
-
maxHeight = 250,
|
|
19
|
-
}: {
|
|
20
|
-
children: ReactNode;
|
|
21
|
-
maxHeight?: number;
|
|
22
|
-
}) => {
|
|
23
|
-
const contentRef = useRef<HTMLDivElement | null>(null);
|
|
24
|
-
const [isOverflowing, setIsOverflowing] = useState(false);
|
|
25
|
-
const [open, setOpen] = useState(false);
|
|
26
|
-
|
|
27
|
-
useIsomorphicLayoutEffect(() => {
|
|
28
|
-
const el = contentRef.current;
|
|
29
|
-
if (!el) return;
|
|
30
|
-
|
|
31
|
-
setIsOverflowing(el.scrollHeight > maxHeight);
|
|
32
|
-
|
|
33
|
-
const observer = new ResizeObserver(() => {
|
|
34
|
-
setIsOverflowing(el.scrollHeight > maxHeight);
|
|
35
|
-
});
|
|
36
|
-
observer.observe(el);
|
|
37
|
-
|
|
38
|
-
return () => observer.disconnect();
|
|
39
|
-
}, [maxHeight]);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<Collapsible
|
|
43
|
-
className="group"
|
|
44
|
-
open={open}
|
|
45
|
-
onOpenChange={setOpen}
|
|
46
|
-
style={{ "--max-height": `${maxHeight}px` } as CSSProperties}
|
|
47
|
-
>
|
|
48
|
-
<CollapsibleContent
|
|
49
|
-
forceMount
|
|
50
|
-
className={cn(
|
|
51
|
-
"relative overflow-hidden group",
|
|
52
|
-
!open && isOverflowing && "max-h-(--max-height)",
|
|
53
|
-
)}
|
|
54
|
-
>
|
|
55
|
-
{!open && isOverflowing && <OverflowOverlay />}
|
|
56
|
-
<div ref={contentRef}>{children}</div>
|
|
57
|
-
{!open && isOverflowing && (
|
|
58
|
-
<CollapsibleTrigger
|
|
59
|
-
className="absolute inset-0 grid place-items-center z-10 cursor-pointer peer"
|
|
60
|
-
asChild
|
|
61
|
-
>
|
|
62
|
-
<div>
|
|
63
|
-
<Button variant="outline" className="hidden group-hover:flex">
|
|
64
|
-
<UnfoldVerticalIcon size={14} className="me-1.5" />
|
|
65
|
-
Click to expand
|
|
66
|
-
</Button>
|
|
67
|
-
</div>
|
|
68
|
-
</CollapsibleTrigger>
|
|
69
|
-
)}
|
|
70
|
-
</CollapsibleContent>
|
|
71
|
-
{isOverflowing && (
|
|
72
|
-
<div
|
|
73
|
-
className={cn(
|
|
74
|
-
"flex justify-center w-full py-2 bg-muted/50",
|
|
75
|
-
!open && "hidden",
|
|
76
|
-
)}
|
|
77
|
-
>
|
|
78
|
-
<CollapsibleTrigger asChild>
|
|
79
|
-
<Button variant="outline" size="sm">
|
|
80
|
-
Collapse
|
|
81
|
-
<FoldVerticalIcon size={14} className="ms-1.5" />
|
|
82
|
-
</Button>
|
|
83
|
-
</CollapsibleTrigger>
|
|
84
|
-
</div>
|
|
85
|
-
)}
|
|
86
|
-
</Collapsible>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
1
|
+
import { Button } from "@lukoweb/apitogo/ui/Button.js";
|
|
2
|
+
import {
|
|
3
|
+
Collapsible,
|
|
4
|
+
CollapsibleContent,
|
|
5
|
+
CollapsibleTrigger,
|
|
6
|
+
} from "@lukoweb/apitogo/ui/Collapsible.js";
|
|
7
|
+
import { FoldVerticalIcon, UnfoldVerticalIcon } from "lucide-react";
|
|
8
|
+
import { type CSSProperties, type ReactNode, useRef, useState } from "react";
|
|
9
|
+
import { cn } from "../../util/cn.js";
|
|
10
|
+
import useIsomorphicLayoutEffect from "../../util/useIsomorphicLayoutEffect.js";
|
|
11
|
+
|
|
12
|
+
export const OverflowOverlay = () => (
|
|
13
|
+
<div className="absolute inset-0 bg-linear-to-b from-transparent to-zinc-50/60 dark:to-zinc-950/90 z-10 transition-all group-hover:to-transparent" />
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export const CollapsibleCode = ({
|
|
17
|
+
children,
|
|
18
|
+
maxHeight = 250,
|
|
19
|
+
}: {
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
maxHeight?: number;
|
|
22
|
+
}) => {
|
|
23
|
+
const contentRef = useRef<HTMLDivElement | null>(null);
|
|
24
|
+
const [isOverflowing, setIsOverflowing] = useState(false);
|
|
25
|
+
const [open, setOpen] = useState(false);
|
|
26
|
+
|
|
27
|
+
useIsomorphicLayoutEffect(() => {
|
|
28
|
+
const el = contentRef.current;
|
|
29
|
+
if (!el) return;
|
|
30
|
+
|
|
31
|
+
setIsOverflowing(el.scrollHeight > maxHeight);
|
|
32
|
+
|
|
33
|
+
const observer = new ResizeObserver(() => {
|
|
34
|
+
setIsOverflowing(el.scrollHeight > maxHeight);
|
|
35
|
+
});
|
|
36
|
+
observer.observe(el);
|
|
37
|
+
|
|
38
|
+
return () => observer.disconnect();
|
|
39
|
+
}, [maxHeight]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Collapsible
|
|
43
|
+
className="group"
|
|
44
|
+
open={open}
|
|
45
|
+
onOpenChange={setOpen}
|
|
46
|
+
style={{ "--max-height": `${maxHeight}px` } as CSSProperties}
|
|
47
|
+
>
|
|
48
|
+
<CollapsibleContent
|
|
49
|
+
forceMount
|
|
50
|
+
className={cn(
|
|
51
|
+
"relative overflow-hidden group",
|
|
52
|
+
!open && isOverflowing && "max-h-(--max-height)",
|
|
53
|
+
)}
|
|
54
|
+
>
|
|
55
|
+
{!open && isOverflowing && <OverflowOverlay />}
|
|
56
|
+
<div ref={contentRef}>{children}</div>
|
|
57
|
+
{!open && isOverflowing && (
|
|
58
|
+
<CollapsibleTrigger
|
|
59
|
+
className="absolute inset-0 grid place-items-center z-10 cursor-pointer peer"
|
|
60
|
+
asChild
|
|
61
|
+
>
|
|
62
|
+
<div>
|
|
63
|
+
<Button variant="outline" className="hidden group-hover:flex">
|
|
64
|
+
<UnfoldVerticalIcon size={14} className="me-1.5" />
|
|
65
|
+
Click to expand
|
|
66
|
+
</Button>
|
|
67
|
+
</div>
|
|
68
|
+
</CollapsibleTrigger>
|
|
69
|
+
)}
|
|
70
|
+
</CollapsibleContent>
|
|
71
|
+
{isOverflowing && (
|
|
72
|
+
<div
|
|
73
|
+
className={cn(
|
|
74
|
+
"flex justify-center w-full py-2 bg-muted/50",
|
|
75
|
+
!open && "hidden",
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
<CollapsibleTrigger asChild>
|
|
79
|
+
<Button variant="outline" size="sm">
|
|
80
|
+
Collapse
|
|
81
|
+
<FoldVerticalIcon size={14} className="ms-1.5" />
|
|
82
|
+
</Button>
|
|
83
|
+
</CollapsibleTrigger>
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
86
|
+
</Collapsible>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "
|
|
16
|
-
import { AiAssistantMenuItems } from "../../components/AiAssistantMenuItems.js";
|
|
17
|
-
import { useZudoku } from "../../components/context/ZudokuContext.js";
|
|
18
|
-
import { useCopyToClipboard } from "../../util/useCopyToClipboard.js";
|
|
19
|
-
|
|
20
|
-
export const DownloadSchemaButton = ({
|
|
21
|
-
downloadUrl,
|
|
22
|
-
}: {
|
|
23
|
-
downloadUrl: string;
|
|
24
|
-
}) => {
|
|
25
|
-
const [, copyToClipboard] = useCopyToClipboard();
|
|
26
|
-
const { options } = useZudoku();
|
|
27
|
-
|
|
28
|
-
const handleDownload: MouseEventHandler<HTMLAnchorElement> = async (e) => {
|
|
29
|
-
const isExternal = downloadUrl.includes("://");
|
|
30
|
-
|
|
31
|
-
if (!isExternal) return;
|
|
32
|
-
|
|
33
|
-
e.preventDefault();
|
|
34
|
-
try {
|
|
35
|
-
const response = await fetch(downloadUrl);
|
|
36
|
-
if (!response.ok)
|
|
37
|
-
throw new Error(`Failed to fetch: ${response.statusText}`);
|
|
38
|
-
|
|
39
|
-
const blob = await response.blob();
|
|
40
|
-
const url = window.URL.createObjectURL(blob);
|
|
41
|
-
const a = document.createElement("a");
|
|
42
|
-
a.href = url;
|
|
43
|
-
a.download = downloadUrl.split("/").pop() || "schema.json";
|
|
44
|
-
document.body.appendChild(a);
|
|
45
|
-
a.click();
|
|
46
|
-
document.body.removeChild(a);
|
|
47
|
-
window.URL.revokeObjectURL(url);
|
|
48
|
-
} catch (error) {
|
|
49
|
-
// biome-ignore lint/suspicious/noConsole: Logging error
|
|
50
|
-
console.error("Failed to download schema:", error);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<ButtonGroup>
|
|
56
|
-
<Button variant="outline" asChild>
|
|
57
|
-
<a href={downloadUrl} download onClick={handleDownload}>
|
|
58
|
-
<DownloadIcon />
|
|
59
|
-
Download schema
|
|
60
|
-
</a>
|
|
61
|
-
</Button>
|
|
62
|
-
<DropdownMenu>
|
|
63
|
-
<DropdownMenuTrigger asChild>
|
|
64
|
-
<Button variant="outline" className="px-1.5">
|
|
65
|
-
<ChevronDownIcon size={14} />
|
|
66
|
-
</Button>
|
|
67
|
-
</DropdownMenuTrigger>
|
|
68
|
-
<DropdownMenuContent align="end">
|
|
69
|
-
<DropdownMenuItem asChild>
|
|
70
|
-
<a href={downloadUrl} target="_blank" rel="noopener noreferrer">
|
|
71
|
-
<ExternalLinkIcon size={14} />
|
|
72
|
-
Open in new tab
|
|
73
|
-
</a>
|
|
74
|
-
</DropdownMenuItem>
|
|
75
|
-
<DropdownMenuItem
|
|
76
|
-
onClick={async () => {
|
|
77
|
-
const response = await fetch(downloadUrl);
|
|
78
|
-
const schema = await response.text();
|
|
79
|
-
copyToClipboard(schema);
|
|
80
|
-
}}
|
|
81
|
-
>
|
|
82
|
-
<CopyIcon size={14} />
|
|
83
|
-
Copy to clipboard
|
|
84
|
-
</DropdownMenuItem>
|
|
85
|
-
<AiAssistantMenuItems
|
|
86
|
-
aiAssistants={options.aiAssistants}
|
|
87
|
-
getPageUrl={() => new URL(downloadUrl, window.location.href).href}
|
|
88
|
-
type="openapi"
|
|
89
|
-
/>
|
|
90
|
-
</DropdownMenuContent>
|
|
91
|
-
</DropdownMenu>
|
|
92
|
-
</ButtonGroup>
|
|
93
|
-
);
|
|
94
|
-
};
|
|
1
|
+
import { Button } from "@lukoweb/apitogo/components";
|
|
2
|
+
import { ButtonGroup } from "@lukoweb/apitogo/ui/ButtonGroup.js";
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from "@lukoweb/apitogo/ui/DropdownMenu.js";
|
|
9
|
+
import {
|
|
10
|
+
ChevronDownIcon,
|
|
11
|
+
CopyIcon,
|
|
12
|
+
DownloadIcon,
|
|
13
|
+
ExternalLinkIcon,
|
|
14
|
+
} from "lucide-react";
|
|
15
|
+
import type { MouseEventHandler } from "react";
|
|
16
|
+
import { AiAssistantMenuItems } from "../../components/AiAssistantMenuItems.js";
|
|
17
|
+
import { useZudoku } from "../../components/context/ZudokuContext.js";
|
|
18
|
+
import { useCopyToClipboard } from "../../util/useCopyToClipboard.js";
|
|
19
|
+
|
|
20
|
+
export const DownloadSchemaButton = ({
|
|
21
|
+
downloadUrl,
|
|
22
|
+
}: {
|
|
23
|
+
downloadUrl: string;
|
|
24
|
+
}) => {
|
|
25
|
+
const [, copyToClipboard] = useCopyToClipboard();
|
|
26
|
+
const { options } = useZudoku();
|
|
27
|
+
|
|
28
|
+
const handleDownload: MouseEventHandler<HTMLAnchorElement> = async (e) => {
|
|
29
|
+
const isExternal = downloadUrl.includes("://");
|
|
30
|
+
|
|
31
|
+
if (!isExternal) return;
|
|
32
|
+
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(downloadUrl);
|
|
36
|
+
if (!response.ok)
|
|
37
|
+
throw new Error(`Failed to fetch: ${response.statusText}`);
|
|
38
|
+
|
|
39
|
+
const blob = await response.blob();
|
|
40
|
+
const url = window.URL.createObjectURL(blob);
|
|
41
|
+
const a = document.createElement("a");
|
|
42
|
+
a.href = url;
|
|
43
|
+
a.download = downloadUrl.split("/").pop() || "schema.json";
|
|
44
|
+
document.body.appendChild(a);
|
|
45
|
+
a.click();
|
|
46
|
+
document.body.removeChild(a);
|
|
47
|
+
window.URL.revokeObjectURL(url);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
// biome-ignore lint/suspicious/noConsole: Logging error
|
|
50
|
+
console.error("Failed to download schema:", error);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<ButtonGroup>
|
|
56
|
+
<Button variant="outline" asChild>
|
|
57
|
+
<a href={downloadUrl} download onClick={handleDownload}>
|
|
58
|
+
<DownloadIcon />
|
|
59
|
+
Download schema
|
|
60
|
+
</a>
|
|
61
|
+
</Button>
|
|
62
|
+
<DropdownMenu>
|
|
63
|
+
<DropdownMenuTrigger asChild>
|
|
64
|
+
<Button variant="outline" className="px-1.5">
|
|
65
|
+
<ChevronDownIcon size={14} />
|
|
66
|
+
</Button>
|
|
67
|
+
</DropdownMenuTrigger>
|
|
68
|
+
<DropdownMenuContent align="end">
|
|
69
|
+
<DropdownMenuItem asChild>
|
|
70
|
+
<a href={downloadUrl} target="_blank" rel="noopener noreferrer">
|
|
71
|
+
<ExternalLinkIcon size={14} />
|
|
72
|
+
Open in new tab
|
|
73
|
+
</a>
|
|
74
|
+
</DropdownMenuItem>
|
|
75
|
+
<DropdownMenuItem
|
|
76
|
+
onClick={async () => {
|
|
77
|
+
const response = await fetch(downloadUrl);
|
|
78
|
+
const schema = await response.text();
|
|
79
|
+
copyToClipboard(schema);
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
<CopyIcon size={14} />
|
|
83
|
+
Copy to clipboard
|
|
84
|
+
</DropdownMenuItem>
|
|
85
|
+
<AiAssistantMenuItems
|
|
86
|
+
aiAssistants={options.aiAssistants}
|
|
87
|
+
getPageUrl={() => new URL(downloadUrl, window.location.href).href}
|
|
88
|
+
type="openapi"
|
|
89
|
+
/>
|
|
90
|
+
</DropdownMenuContent>
|
|
91
|
+
</DropdownMenu>
|
|
92
|
+
</ButtonGroup>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "
|
|
9
|
-
import { NonHighlightedCode } from "./components/NonHighlightedCode.js";
|
|
10
|
-
import * as SidecarBox from "./SidecarBox.js";
|
|
11
|
-
|
|
12
|
-
export const GeneratedExampleSidecarBox = ({
|
|
13
|
-
code,
|
|
14
|
-
isOnScreen,
|
|
15
|
-
shouldLazyHighlight,
|
|
16
|
-
}: {
|
|
17
|
-
code: string;
|
|
18
|
-
isOnScreen: boolean;
|
|
19
|
-
shouldLazyHighlight?: boolean;
|
|
20
|
-
}) => {
|
|
21
|
-
return (
|
|
22
|
-
<SidecarBox.Root>
|
|
23
|
-
<SidecarBox.Head className="text-xs flex justify-between items-center">
|
|
24
|
-
<div className="flex items-center gap-1.5">
|
|
25
|
-
<span className="font-medium">Example Request Body</span>
|
|
26
|
-
<TooltipProvider>
|
|
27
|
-
<Tooltip>
|
|
28
|
-
<TooltipTrigger asChild>
|
|
29
|
-
<InfoIcon size={13} />
|
|
30
|
-
</TooltipTrigger>
|
|
31
|
-
<TooltipContent>
|
|
32
|
-
This example is auto-generated from the schema.
|
|
33
|
-
</TooltipContent>
|
|
34
|
-
</Tooltip>
|
|
35
|
-
</TooltipProvider>
|
|
36
|
-
</div>
|
|
37
|
-
</SidecarBox.Head>
|
|
38
|
-
<SidecarBox.Body className="p-0">
|
|
39
|
-
{shouldLazyHighlight && !isOnScreen ? (
|
|
40
|
-
<NonHighlightedCode code={code} />
|
|
41
|
-
) : (
|
|
42
|
-
<SyntaxHighlight
|
|
43
|
-
embedded
|
|
44
|
-
language="json"
|
|
45
|
-
code={code}
|
|
46
|
-
className="[--scrollbar-color:gray] rounded-none text-xs max-h-[200px]"
|
|
47
|
-
/>
|
|
48
|
-
)}
|
|
49
|
-
</SidecarBox.Body>
|
|
50
|
-
</SidecarBox.Root>
|
|
51
|
-
);
|
|
52
|
-
};
|
|
1
|
+
import { SyntaxHighlight } from "@lukoweb/apitogo/ui/SyntaxHighlight.js";
|
|
2
|
+
import {
|
|
3
|
+
Tooltip,
|
|
4
|
+
TooltipContent,
|
|
5
|
+
TooltipProvider,
|
|
6
|
+
TooltipTrigger,
|
|
7
|
+
} from "@lukoweb/apitogo/ui/Tooltip.js";
|
|
8
|
+
import { InfoIcon } from "lucide-react";
|
|
9
|
+
import { NonHighlightedCode } from "./components/NonHighlightedCode.js";
|
|
10
|
+
import * as SidecarBox from "./SidecarBox.js";
|
|
11
|
+
|
|
12
|
+
export const GeneratedExampleSidecarBox = ({
|
|
13
|
+
code,
|
|
14
|
+
isOnScreen,
|
|
15
|
+
shouldLazyHighlight,
|
|
16
|
+
}: {
|
|
17
|
+
code: string;
|
|
18
|
+
isOnScreen: boolean;
|
|
19
|
+
shouldLazyHighlight?: boolean;
|
|
20
|
+
}) => {
|
|
21
|
+
return (
|
|
22
|
+
<SidecarBox.Root>
|
|
23
|
+
<SidecarBox.Head className="text-xs flex justify-between items-center">
|
|
24
|
+
<div className="flex items-center gap-1.5">
|
|
25
|
+
<span className="font-medium">Example Request Body</span>
|
|
26
|
+
<TooltipProvider>
|
|
27
|
+
<Tooltip>
|
|
28
|
+
<TooltipTrigger asChild>
|
|
29
|
+
<InfoIcon size={13} />
|
|
30
|
+
</TooltipTrigger>
|
|
31
|
+
<TooltipContent>
|
|
32
|
+
This example is auto-generated from the schema.
|
|
33
|
+
</TooltipContent>
|
|
34
|
+
</Tooltip>
|
|
35
|
+
</TooltipProvider>
|
|
36
|
+
</div>
|
|
37
|
+
</SidecarBox.Head>
|
|
38
|
+
<SidecarBox.Body className="p-0">
|
|
39
|
+
{shouldLazyHighlight && !isOnScreen ? (
|
|
40
|
+
<NonHighlightedCode code={code} />
|
|
41
|
+
) : (
|
|
42
|
+
<SyntaxHighlight
|
|
43
|
+
embedded
|
|
44
|
+
language="json"
|
|
45
|
+
code={code}
|
|
46
|
+
className="[--scrollbar-color:gray] rounded-none text-xs max-h-[200px]"
|
|
47
|
+
/>
|
|
48
|
+
)}
|
|
49
|
+
</SidecarBox.Body>
|
|
50
|
+
</SidecarBox.Root>
|
|
51
|
+
);
|
|
52
|
+
};
|