specra 0.1.13 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.MD +25 -4
- package/README.md +67 -58
- package/config/specra.config.schema.json +16 -0
- package/config/svelte-config.js +63 -0
- package/dist/api-parser.types.d.ts +59 -0
- package/dist/api-parser.types.js +5 -0
- package/dist/api.types.d.ts +137 -0
- package/dist/api.types.js +5 -0
- package/dist/category.d.ts +21 -0
- package/dist/category.js +48 -0
- package/dist/components/ConfigProvider.svelte +13 -0
- package/dist/components/ConfigProvider.svelte.d.ts +31 -0
- package/dist/components/docs/Accordion.svelte +18 -0
- package/dist/components/docs/Accordion.svelte.d.ts +10 -0
- package/dist/components/docs/AccordionItem.svelte +41 -0
- package/dist/components/docs/AccordionItem.svelte.d.ts +10 -0
- package/dist/components/docs/Badge.svelte +28 -0
- package/dist/components/docs/Badge.svelte.d.ts +9 -0
- package/dist/components/docs/Breadcrumb.svelte +80 -0
- package/dist/components/docs/Breadcrumb.svelte.d.ts +8 -0
- package/dist/components/docs/Callout.svelte +96 -0
- package/dist/components/docs/Callout.svelte.d.ts +10 -0
- package/dist/components/docs/Card.svelte +63 -0
- package/dist/components/docs/Card.svelte.d.ts +12 -0
- package/dist/components/docs/CardGrid.svelte +24 -0
- package/dist/components/docs/CardGrid.svelte.d.ts +8 -0
- package/dist/components/docs/CategoryIndex.svelte +110 -0
- package/dist/components/docs/CategoryIndex.svelte.d.ts +29 -0
- package/dist/components/docs/CodeBlock.svelte +172 -0
- package/dist/components/docs/CodeBlock.svelte.d.ts +8 -0
- package/dist/components/docs/Column.svelte +25 -0
- package/dist/components/docs/Column.svelte.d.ts +8 -0
- package/dist/components/docs/Columns.svelte +38 -0
- package/dist/components/docs/Columns.svelte.d.ts +13 -0
- package/dist/components/docs/DevModeBadge.svelte +15 -0
- package/dist/components/docs/DevModeBadge.svelte.d.ts +18 -0
- package/dist/components/docs/DocBadge.svelte +28 -0
- package/dist/components/docs/DocBadge.svelte.d.ts +9 -0
- package/dist/components/docs/DocLayout.svelte +107 -0
- package/dist/components/docs/DocLayout.svelte.d.ts +32 -0
- package/dist/components/docs/DocLoading.svelte +53 -0
- package/dist/components/docs/DocLoading.svelte.d.ts +18 -0
- package/dist/components/docs/DocMetadata.svelte +106 -0
- package/dist/components/docs/DocMetadata.svelte.d.ts +18 -0
- package/dist/components/docs/DocNavigation.svelte +56 -0
- package/dist/components/docs/DocNavigation.svelte.d.ts +12 -0
- package/dist/components/docs/DocTags.svelte +22 -0
- package/dist/components/docs/DocTags.svelte.d.ts +6 -0
- package/dist/components/docs/DraftBadge.svelte +10 -0
- package/dist/components/docs/DraftBadge.svelte.d.ts +18 -0
- package/dist/components/docs/Footer.svelte +72 -0
- package/dist/components/docs/Footer.svelte.d.ts +7 -0
- package/dist/components/docs/Frame.svelte +27 -0
- package/dist/components/docs/Frame.svelte.d.ts +9 -0
- package/dist/components/docs/Header.svelte +123 -0
- package/dist/components/docs/Header.svelte.d.ts +9 -0
- package/dist/components/docs/HeaderWithMenu.svelte +34 -0
- package/dist/components/docs/HeaderWithMenu.svelte.d.ts +17 -0
- package/dist/components/docs/HotReloadIndicator.svelte +44 -0
- package/dist/components/docs/HotReloadIndicator.svelte.d.ts +3 -0
- package/dist/components/docs/Icon.svelte +103 -0
- package/dist/components/docs/Icon.svelte.d.ts +11 -0
- package/dist/components/docs/Image.svelte +88 -0
- package/dist/components/docs/Image.svelte.d.ts +11 -0
- package/dist/components/docs/ImageCard.svelte +91 -0
- package/dist/components/docs/ImageCard.svelte.d.ts +12 -0
- package/dist/components/docs/ImageCardGrid.svelte +25 -0
- package/dist/components/docs/ImageCardGrid.svelte.d.ts +8 -0
- package/dist/components/docs/LayoutProviders.svelte +57 -0
- package/dist/components/docs/LayoutProviders.svelte.d.ts +9 -0
- package/dist/components/docs/Logo.svelte +25 -0
- package/dist/components/docs/Logo.svelte.d.ts +11 -0
- package/dist/components/docs/Math.svelte +54 -0
- package/dist/components/docs/Math.svelte.d.ts +7 -0
- package/dist/components/docs/MdxContent.svelte +41 -0
- package/dist/components/docs/MdxHotReload.svelte +78 -0
- package/dist/components/docs/MdxHotReload.svelte.d.ts +9 -0
- package/dist/components/docs/MdxLayout.svelte +16 -0
- package/dist/components/docs/MdxLayout.svelte.d.ts +6 -0
- package/dist/components/docs/Mermaid.svelte +88 -0
- package/dist/components/docs/Mermaid.svelte.d.ts +7 -0
- package/dist/components/docs/MobileDocLayout.svelte +211 -0
- package/dist/components/docs/MobileDocLayout.svelte.d.ts +35 -0
- package/dist/components/docs/MobileSidebar.svelte +122 -0
- package/dist/components/docs/MobileSidebar.svelte.d.ts +31 -0
- package/dist/components/docs/MobileSidebarWrapper.svelte +122 -0
- package/dist/components/docs/MobileSidebarWrapper.svelte.d.ts +32 -0
- package/dist/components/docs/NotFoundContent.svelte +40 -0
- package/dist/components/docs/NotFoundContent.svelte.d.ts +6 -0
- package/dist/components/docs/SearchHighlight.svelte +116 -0
- package/dist/components/docs/SearchHighlight.svelte.d.ts +3 -0
- package/dist/components/docs/SearchModal.svelte +239 -0
- package/dist/components/docs/SearchModal.svelte.d.ts +9 -0
- package/dist/components/docs/Sidebar.svelte +69 -0
- package/dist/components/docs/Sidebar.svelte.d.ts +31 -0
- package/dist/components/docs/SidebarMenuItems.svelte +344 -0
- package/dist/components/docs/SidebarMenuItems.svelte.d.ts +33 -0
- package/dist/components/docs/SidebarSkeleton.svelte +50 -0
- package/dist/components/docs/SidebarSkeleton.svelte.d.ts +18 -0
- package/dist/components/docs/SiteBanner.svelte +92 -0
- package/dist/components/docs/SiteBanner.svelte.d.ts +7 -0
- package/dist/components/docs/Step.svelte +44 -0
- package/dist/components/docs/Step.svelte.d.ts +8 -0
- package/dist/components/docs/Steps.svelte +15 -0
- package/dist/components/docs/Steps.svelte.d.ts +7 -0
- package/dist/components/docs/Tab.svelte +40 -0
- package/dist/components/docs/Tab.svelte.d.ts +8 -0
- package/dist/components/docs/TabGroups.svelte +183 -0
- package/dist/components/docs/TabGroups.svelte.d.ts +25 -0
- package/dist/components/docs/TableOfContents.svelte +100 -0
- package/dist/components/docs/TableOfContents.svelte.d.ts +9 -0
- package/dist/components/docs/Tabs.svelte +69 -0
- package/dist/components/docs/Tabs.svelte.d.ts +8 -0
- package/dist/components/docs/ThemeToggle.svelte +16 -0
- package/dist/components/docs/ThemeToggle.svelte.d.ts +18 -0
- package/dist/components/docs/Tooltip.svelte +44 -0
- package/dist/components/docs/Tooltip.svelte.d.ts +10 -0
- package/dist/components/docs/VersionSwitcher.svelte +95 -0
- package/dist/components/docs/VersionSwitcher.svelte.d.ts +7 -0
- package/dist/components/docs/Video.svelte +84 -0
- package/dist/components/docs/Video.svelte.d.ts +12 -0
- package/dist/components/docs/api/ApiEndpoint.svelte +61 -0
- package/dist/components/docs/api/ApiEndpoint.svelte.d.ts +11 -0
- package/dist/components/docs/api/ApiParams.svelte +80 -0
- package/dist/components/docs/api/ApiParams.svelte.d.ts +14 -0
- package/dist/components/docs/api/ApiPlayground.svelte +259 -0
- package/dist/components/docs/api/ApiPlayground.svelte.d.ts +16 -0
- package/dist/components/docs/api/ApiReference.svelte +278 -0
- package/dist/components/docs/api/ApiReference.svelte.d.ts +23 -0
- package/dist/components/docs/api/ApiResponse.svelte +66 -0
- package/dist/components/docs/api/ApiResponse.svelte.d.ts +9 -0
- package/dist/components/docs/api/index.d.ts +5 -0
- package/dist/components/docs/api/index.js +5 -0
- package/dist/components/docs/componentTextProps.d.ts +3 -0
- package/dist/components/docs/componentTextProps.js +61 -0
- package/dist/components/docs/index.d.ts +54 -0
- package/dist/components/docs/index.js +56 -0
- package/dist/components/global/VersionNotFound.svelte +48 -0
- package/dist/components/global/VersionNotFound.svelte.d.ts +7 -0
- package/dist/components/global/index.d.ts +1 -0
- package/dist/components/global/index.js +1 -0
- package/dist/components/index.d.ts +6 -822
- package/dist/components/index.js +11 -3854
- package/dist/components/ui/Badge.svelte +48 -0
- package/dist/components/ui/Badge.svelte.d.ts +15 -0
- package/dist/components/ui/Button.svelte +58 -0
- package/dist/components/ui/Button.svelte.d.ts +17 -0
- package/dist/components/ui/Dialog.svelte +16 -0
- package/dist/components/ui/Dialog.svelte.d.ts +9 -0
- package/dist/components/ui/DialogClose.svelte +16 -0
- package/dist/components/ui/DialogClose.svelte.d.ts +9 -0
- package/dist/components/ui/DialogContent.svelte +43 -0
- package/dist/components/ui/DialogContent.svelte.d.ts +10 -0
- package/dist/components/ui/DialogDescription.svelte +21 -0
- package/dist/components/ui/DialogDescription.svelte.d.ts +9 -0
- package/dist/components/ui/DialogFooter.svelte +20 -0
- package/dist/components/ui/DialogFooter.svelte.d.ts +9 -0
- package/dist/components/ui/DialogHeader.svelte +20 -0
- package/dist/components/ui/DialogHeader.svelte.d.ts +9 -0
- package/dist/components/ui/DialogTitle.svelte +21 -0
- package/dist/components/ui/DialogTitle.svelte.d.ts +9 -0
- package/dist/components/ui/Input.svelte +23 -0
- package/dist/components/ui/Input.svelte.d.ts +8 -0
- package/dist/components/ui/Textarea.svelte +19 -0
- package/dist/components/ui/Textarea.svelte.d.ts +7 -0
- package/dist/components/ui/index.d.ts +11 -0
- package/dist/components/ui/index.js +11 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +9 -0
- package/dist/config.schema.json +471 -0
- package/dist/config.server.d.ts +46 -0
- package/dist/config.server.js +149 -0
- package/dist/{mdx-ColN3Cyg.d.mts → config.types.d.ts} +22 -75
- package/dist/config.types.js +39 -0
- package/dist/dev-utils.d.ts +29 -0
- package/dist/dev-utils.js +63 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.js +25 -4861
- package/dist/mdx-cache.d.ts +41 -0
- package/dist/mdx-cache.js +160 -0
- package/dist/mdx-components.js +50 -1931
- package/dist/mdx-security.d.ts +76 -0
- package/dist/mdx-security.js +217 -0
- package/dist/mdx.d.ts +73 -0
- package/dist/mdx.js +1099 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/security.d.ts +22 -47
- package/dist/middleware/security.js +111 -137
- package/dist/parsers/base-parser.d.ts +14 -0
- package/dist/parsers/base-parser.js +1 -0
- package/dist/parsers/index.d.ts +16 -0
- package/dist/parsers/index.js +51 -0
- package/dist/parsers/openapi-parser.d.ts +18 -0
- package/dist/parsers/openapi-parser.js +209 -0
- package/dist/parsers/postman-parser.d.ts +20 -0
- package/dist/parsers/postman-parser.js +260 -0
- package/dist/parsers/specra-parser.d.ts +10 -0
- package/dist/parsers/specra-parser.js +18 -0
- package/dist/redirects.d.ts +12 -0
- package/dist/redirects.js +30 -0
- package/dist/remark-code-meta.d.ts +6 -0
- package/dist/remark-code-meta.js +21 -0
- package/dist/sidebar-utils.d.ts +59 -0
- package/dist/sidebar-utils.js +144 -0
- package/dist/stores/config.d.ts +20 -0
- package/dist/stores/config.js +45 -0
- package/dist/stores/index.d.ts +4 -0
- package/dist/stores/index.js +4 -0
- package/dist/stores/sidebar.d.ts +7 -0
- package/dist/stores/sidebar.js +12 -0
- package/dist/stores/tabs.d.ts +6 -0
- package/dist/stores/tabs.js +41 -0
- package/dist/stores/theme.d.ts +7 -0
- package/dist/stores/theme.js +75 -0
- package/dist/{styles.css → styles/globals.css} +136 -6
- package/dist/toc.d.ts +9 -0
- package/dist/toc.js +15 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +30 -0
- package/package.json +47 -90
- package/dist/app/api/mdx-watch/route.d.mts +0 -10
- package/dist/app/api/mdx-watch/route.d.ts +0 -10
- package/dist/app/api/mdx-watch/route.js +0 -118
- package/dist/app/api/mdx-watch/route.js.map +0 -1
- package/dist/app/api/mdx-watch/route.mjs +0 -91
- package/dist/app/api/mdx-watch/route.mjs.map +0 -1
- package/dist/chunk-6S3EJVEO.mjs +0 -259
- package/dist/chunk-6S3EJVEO.mjs.map +0 -1
- package/dist/chunk-BE7EROIW.mjs +0 -212
- package/dist/chunk-BE7EROIW.mjs.map +0 -1
- package/dist/chunk-CWHRZHZO.mjs +0 -168
- package/dist/chunk-CWHRZHZO.mjs.map +0 -1
- package/dist/chunk-D5VDVYFY.mjs +0 -1325
- package/dist/chunk-D5VDVYFY.mjs.map +0 -1
- package/dist/chunk-WMCO2UX5.mjs +0 -585
- package/dist/chunk-WMCO2UX5.mjs.map +0 -1
- package/dist/chunk-XEMGCPZZ.mjs +0 -475
- package/dist/chunk-XEMGCPZZ.mjs.map +0 -1
- package/dist/components/index.d.mts +0 -822
- package/dist/components/index.js.map +0 -1
- package/dist/components/index.mjs +0 -3741
- package/dist/components/index.mjs.map +0 -1
- package/dist/index.d.mts +0 -4
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -1897
- package/dist/index.mjs.map +0 -1
- package/dist/layouts/index.d.mts +0 -34
- package/dist/layouts/index.d.ts +0 -34
- package/dist/layouts/index.js +0 -453
- package/dist/layouts/index.js.map +0 -1
- package/dist/layouts/index.mjs +0 -173
- package/dist/layouts/index.mjs.map +0 -1
- package/dist/lib/index.d.mts +0 -583
- package/dist/lib/index.d.ts +0 -583
- package/dist/lib/index.js +0 -1595
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/index.mjs +0 -111
- package/dist/lib/index.mjs.map +0 -1
- package/dist/mdx-ColN3Cyg.d.ts +0 -352
- package/dist/mdx-components.d.mts +0 -86
- package/dist/mdx-components.d.ts +0 -86
- package/dist/mdx-components.js.map +0 -1
- package/dist/mdx-components.mjs +0 -206
- package/dist/mdx-components.mjs.map +0 -1
- package/dist/middleware/security.d.mts +0 -82
- package/dist/middleware/security.js.map +0 -1
- package/dist/middleware/security.mjs +0 -84
- package/dist/middleware/security.mjs.map +0 -1
- package/dist/styles.css.map +0 -1
- package/dist/styles.d.mts +0 -2
- package/dist/styles.d.ts +0 -2
- package/dist/styles.js +0 -2
- package/dist/styles.js.map +0 -1
- package/dist/styles.mjs +0 -1
- package/dist/styles.mjs.map +0 -1
|
@@ -1,3741 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
// src/components/docs/accordion.tsx
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import { ChevronDown } from "lucide-react";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
function AccordionItem({ title, children, defaultOpen = false }) {
|
|
8
|
-
const [isOpen, setIsOpen] = React.useState(defaultOpen);
|
|
9
|
-
return /* @__PURE__ */ jsxs("div", { className: "border border-border rounded-xl overflow-hidden mb-2", children: [
|
|
10
|
-
/* @__PURE__ */ jsxs(
|
|
11
|
-
"button",
|
|
12
|
-
{
|
|
13
|
-
onClick: () => setIsOpen(!isOpen),
|
|
14
|
-
className: "w-full flex items-center justify-between p-4 text-left bg-muted/30 hover:bg-muted/50 transition-colors",
|
|
15
|
-
children: [
|
|
16
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: title }),
|
|
17
|
-
/* @__PURE__ */ jsx(
|
|
18
|
-
ChevronDown,
|
|
19
|
-
{
|
|
20
|
-
className: `h-5 w-5 text-muted-foreground transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
21
|
-
}
|
|
22
|
-
)
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
),
|
|
26
|
-
isOpen && /* @__PURE__ */ jsx("div", { className: "p-4 border-t border-border bg-background", children: /* @__PURE__ */ jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none [&>*:last-child]:mb-0", children }) })
|
|
27
|
-
] });
|
|
28
|
-
}
|
|
29
|
-
function Accordion({ children, type = "multiple", className }) {
|
|
30
|
-
return /* @__PURE__ */ jsx("div", { className: className || "my-6 space-y-2", children });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// src/components/docs/badge.tsx
|
|
34
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
35
|
-
function Badge({ children, variant = "default" }) {
|
|
36
|
-
const variants = {
|
|
37
|
-
default: "bg-muted text-foreground border-border",
|
|
38
|
-
success: "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20",
|
|
39
|
-
warning: "bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 border-yellow-500/20",
|
|
40
|
-
error: "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20",
|
|
41
|
-
info: "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20"
|
|
42
|
-
};
|
|
43
|
-
return /* @__PURE__ */ jsx2(
|
|
44
|
-
"span",
|
|
45
|
-
{
|
|
46
|
-
className: `inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium border ${variants[variant]}`,
|
|
47
|
-
children
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/components/docs/breadcrumb.tsx
|
|
53
|
-
import Link from "next/link";
|
|
54
|
-
import { ChevronRight } from "lucide-react";
|
|
55
|
-
|
|
56
|
-
// src/lib/config.types.ts
|
|
57
|
-
var defaultConfig = {
|
|
58
|
-
site: {
|
|
59
|
-
title: "Documentation",
|
|
60
|
-
description: "Project documentation",
|
|
61
|
-
baseUrl: "/",
|
|
62
|
-
language: "en"
|
|
63
|
-
},
|
|
64
|
-
theme: {
|
|
65
|
-
defaultMode: "system",
|
|
66
|
-
respectPrefersColorScheme: true
|
|
67
|
-
},
|
|
68
|
-
navigation: {
|
|
69
|
-
showSidebar: true,
|
|
70
|
-
collapsibleSidebar: true,
|
|
71
|
-
showBreadcrumbs: true,
|
|
72
|
-
showTableOfContents: true,
|
|
73
|
-
tocPosition: "right",
|
|
74
|
-
tocMaxDepth: 3
|
|
75
|
-
},
|
|
76
|
-
search: {
|
|
77
|
-
enabled: true,
|
|
78
|
-
provider: "local",
|
|
79
|
-
placeholder: "Search documentation..."
|
|
80
|
-
},
|
|
81
|
-
features: {
|
|
82
|
-
showLastUpdated: true,
|
|
83
|
-
showReadingTime: true,
|
|
84
|
-
showAuthors: false,
|
|
85
|
-
showTags: true,
|
|
86
|
-
versioning: true,
|
|
87
|
-
i18n: false
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// src/lib/config.server.ts
|
|
92
|
-
function deepMerge(target, source) {
|
|
93
|
-
const result = { ...target };
|
|
94
|
-
for (const key in source) {
|
|
95
|
-
const sourceValue = source[key];
|
|
96
|
-
const targetValue = result[key];
|
|
97
|
-
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue)) {
|
|
98
|
-
result[key] = deepMerge(
|
|
99
|
-
targetValue && typeof targetValue === "object" ? targetValue : {},
|
|
100
|
-
sourceValue
|
|
101
|
-
);
|
|
102
|
-
} else if (sourceValue !== void 0) {
|
|
103
|
-
result[key] = sourceValue;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
function loadConfig(userConfig) {
|
|
109
|
-
try {
|
|
110
|
-
const config = deepMerge(defaultConfig, userConfig);
|
|
111
|
-
return config;
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.error(`\u274C Error loading configuration:`, error);
|
|
114
|
-
console.warn("Using default configuration.");
|
|
115
|
-
return defaultConfig;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
var configInstance = null;
|
|
119
|
-
function getConfig() {
|
|
120
|
-
if (!configInstance) {
|
|
121
|
-
configInstance = loadConfig({});
|
|
122
|
-
}
|
|
123
|
-
return configInstance;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// src/components/docs/breadcrumb.tsx
|
|
127
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
128
|
-
function Breadcrumb({ version, slug, title }) {
|
|
129
|
-
const config = getConfig();
|
|
130
|
-
const i18n = config.features?.i18n;
|
|
131
|
-
const locales = typeof i18n === "object" ? i18n.locales : i18n ? ["en"] : [];
|
|
132
|
-
const defaultLocale = typeof i18n === "object" ? i18n.defaultLocale : "en";
|
|
133
|
-
const parts = slug.split("/");
|
|
134
|
-
const potentialLocale = parts[0];
|
|
135
|
-
const isLc = locales.includes(potentialLocale);
|
|
136
|
-
const isDefaultLc = potentialLocale === defaultLocale;
|
|
137
|
-
const homeHref = isLc ? `/docs/${version}/${potentialLocale}` : `/docs/${version}`;
|
|
138
|
-
const breadcrumbs = [
|
|
139
|
-
{ label: "Docs", href: homeHref }
|
|
140
|
-
];
|
|
141
|
-
let currentPath = "";
|
|
142
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
143
|
-
const part = parts[i];
|
|
144
|
-
currentPath += (currentPath ? "/" : "") + part;
|
|
145
|
-
if (i === 0 && isLc) {
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
breadcrumbs.push({
|
|
149
|
-
label: part.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
150
|
-
href: `/docs/${version}/${currentPath}`
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
breadcrumbs.push({
|
|
154
|
-
label: title,
|
|
155
|
-
href: `/docs/${version}/${slug}`
|
|
156
|
-
});
|
|
157
|
-
return /* @__PURE__ */ jsx3("nav", { className: "flex items-center gap-2 text-sm text-muted-foreground mb-4", "aria-label": "Breadcrumb", children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
158
|
-
index > 0 && /* @__PURE__ */ jsx3(ChevronRight, { className: "h-4 w-4" }),
|
|
159
|
-
index === breadcrumbs.length - 1 ? /* @__PURE__ */ jsx3("span", { className: "text-foreground font-medium", children: crumb.label }) : /* @__PURE__ */ jsx3(
|
|
160
|
-
Link,
|
|
161
|
-
{
|
|
162
|
-
href: crumb.href,
|
|
163
|
-
className: "hover:text-foreground transition-colors",
|
|
164
|
-
children: crumb.label
|
|
165
|
-
}
|
|
166
|
-
)
|
|
167
|
-
] }, crumb.href)) });
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// src/components/docs/callout.tsx
|
|
171
|
-
import { cloneElement, isValidElement } from "react";
|
|
172
|
-
import { Info, AlertTriangle, CheckCircle2, XCircle, Lightbulb } from "lucide-react";
|
|
173
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
174
|
-
function Callout({ children, type = "info", title }) {
|
|
175
|
-
const configs = {
|
|
176
|
-
info: {
|
|
177
|
-
icon: Info,
|
|
178
|
-
className: "bg-blue-500/10 border-blue-500/30 text-blue-900 dark:bg-blue-400/5 dark:border-blue-500/20 dark:text-blue-400",
|
|
179
|
-
iconClassName: "text-blue-600 dark:text-blue-400",
|
|
180
|
-
titleClassName: "text-blue-700 dark:text-blue-300",
|
|
181
|
-
defaultTitle: "Info"
|
|
182
|
-
},
|
|
183
|
-
note: {
|
|
184
|
-
icon: Info,
|
|
185
|
-
className: "bg-blue-500/10 border-blue-500/30 text-blue-900 dark:bg-blue-400/5 dark:border-blue-500/20 dark:text-blue-400",
|
|
186
|
-
iconClassName: "text-blue-600 dark:text-blue-400",
|
|
187
|
-
titleClassName: "text-blue-700 dark:text-blue-300",
|
|
188
|
-
defaultTitle: "Note"
|
|
189
|
-
},
|
|
190
|
-
warning: {
|
|
191
|
-
icon: AlertTriangle,
|
|
192
|
-
className: "bg-yellow-500/10 border-yellow-500/30 text-yellow-900 dark:bg-yellow-400/5 dark:border-yellow-500/20 dark:text-yellow-400",
|
|
193
|
-
iconClassName: "text-yellow-600 dark:text-yellow-400",
|
|
194
|
-
titleClassName: "text-yellow-700 dark:text-yellow-300",
|
|
195
|
-
defaultTitle: "Warning"
|
|
196
|
-
},
|
|
197
|
-
success: {
|
|
198
|
-
icon: CheckCircle2,
|
|
199
|
-
className: "bg-green-500/10 border-green-500/30 text-green-900 dark:bg-green-400/5 dark:border-green-500/20 dark:text-green-400",
|
|
200
|
-
iconClassName: "text-green-600 dark:text-green-400",
|
|
201
|
-
titleClassName: "text-green-700 dark:text-green-300",
|
|
202
|
-
defaultTitle: "Success"
|
|
203
|
-
},
|
|
204
|
-
error: {
|
|
205
|
-
icon: XCircle,
|
|
206
|
-
className: "bg-red-500/10 border-red-500/30 text-red-900 dark:bg-red-400/5 dark:border-red-500/20 dark:text-red-400",
|
|
207
|
-
iconClassName: "text-red-600 dark:text-red-400",
|
|
208
|
-
titleClassName: "text-red-700 dark:text-red-300",
|
|
209
|
-
defaultTitle: "Error"
|
|
210
|
-
},
|
|
211
|
-
danger: {
|
|
212
|
-
icon: XCircle,
|
|
213
|
-
className: "bg-red-500/10 border-red-500/30 text-red-900 dark:bg-red-400/5 dark:border-red-500/20 dark:text-red-400",
|
|
214
|
-
iconClassName: "text-red-600 dark:text-red-400",
|
|
215
|
-
titleClassName: "text-red-700 dark:text-red-300",
|
|
216
|
-
defaultTitle: "Danger"
|
|
217
|
-
},
|
|
218
|
-
tip: {
|
|
219
|
-
icon: Lightbulb,
|
|
220
|
-
className: "bg-purple-500/10 border-purple-500/30 text-purple-900 dark:bg-purple-400/5 dark:border-purple-500/20 dark:text-purple-400",
|
|
221
|
-
iconClassName: "text-purple-600 dark:text-purple-400",
|
|
222
|
-
titleClassName: "text-purple-700 dark:text-purple-300",
|
|
223
|
-
defaultTitle: "Tip"
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
const config = configs[type];
|
|
227
|
-
const Icon2 = config.icon;
|
|
228
|
-
let _title = title || config.defaultTitle;
|
|
229
|
-
let content = children;
|
|
230
|
-
if (!title && children && typeof children === "object") {
|
|
231
|
-
const childArray = Array.isArray(children) ? children : [children];
|
|
232
|
-
const firstElement = childArray[0];
|
|
233
|
-
if (firstElement && typeof firstElement === "object" && "props" in firstElement) {
|
|
234
|
-
const props = firstElement.props;
|
|
235
|
-
if (props.children && Array.isArray(props.children)) {
|
|
236
|
-
const strongChild = props.children.find(
|
|
237
|
-
(child) => child && typeof child === "object" && child.type === "strong"
|
|
238
|
-
);
|
|
239
|
-
if (strongChild) {
|
|
240
|
-
_title = strongChild.props.children;
|
|
241
|
-
content = childArray.map((child, idx) => {
|
|
242
|
-
if (idx === 0 && isValidElement(child)) {
|
|
243
|
-
const newChildren = child.props.children.filter((c) => c !== strongChild);
|
|
244
|
-
const childProps = child.props;
|
|
245
|
-
return cloneElement(child, { ...childProps, children: newChildren });
|
|
246
|
-
}
|
|
247
|
-
return child;
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return /* @__PURE__ */ jsxs3("div", { className: `flex gap-3 p-4 rounded-xl border my-2 ${config.className}`, children: [
|
|
254
|
-
/* @__PURE__ */ jsx4("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx4(Icon2, { className: `h-5 w-5 ${config.iconClassName}` }) }),
|
|
255
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex-1 space-y-0", children: [
|
|
256
|
-
/* @__PURE__ */ jsx4("div", { className: `font-semibold text-sm ${config.titleClassName}`, children: _title }),
|
|
257
|
-
/* @__PURE__ */ jsx4("div", { className: "text-sm leading-relaxed [&>p]:mb-0 [&>p]:text-current", children: content })
|
|
258
|
-
] })
|
|
259
|
-
] });
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// src/components/docs/card.tsx
|
|
263
|
-
import { ArrowRight, ExternalLink } from "lucide-react";
|
|
264
|
-
import Link2 from "next/link";
|
|
265
|
-
|
|
266
|
-
// src/components/docs/icon.tsx
|
|
267
|
-
import * as LucideIcons from "lucide-react";
|
|
268
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
269
|
-
function Icon({ icon, iconType = "regular", color, size = 20, className = "" }) {
|
|
270
|
-
if (typeof icon !== "string") {
|
|
271
|
-
return /* @__PURE__ */ jsx5("span", { className: `inline-flex items-center ${className}`, style: { color }, children: icon });
|
|
272
|
-
}
|
|
273
|
-
if (icon.startsWith("http") || icon.startsWith("/")) {
|
|
274
|
-
return /* @__PURE__ */ jsx5(
|
|
275
|
-
"img",
|
|
276
|
-
{
|
|
277
|
-
src: icon,
|
|
278
|
-
alt: "",
|
|
279
|
-
width: size,
|
|
280
|
-
height: size,
|
|
281
|
-
className: `inline-block ${className}`,
|
|
282
|
-
style: { color }
|
|
283
|
-
}
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
if (icon.startsWith("fa-")) {
|
|
287
|
-
const faClass = `fa-${iconType} ${icon}`;
|
|
288
|
-
return /* @__PURE__ */ jsx5(
|
|
289
|
-
"i",
|
|
290
|
-
{
|
|
291
|
-
className: `${faClass} ${className}`,
|
|
292
|
-
style: { fontSize: size, color },
|
|
293
|
-
"aria-hidden": "true"
|
|
294
|
-
}
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
const iconName = icon.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
298
|
-
const LucideIcon = LucideIcons[iconName];
|
|
299
|
-
if (LucideIcon) {
|
|
300
|
-
return /* @__PURE__ */ jsx5(
|
|
301
|
-
LucideIcon,
|
|
302
|
-
{
|
|
303
|
-
size,
|
|
304
|
-
className: `inline-block ${className}`,
|
|
305
|
-
style: { color },
|
|
306
|
-
"aria-hidden": "true"
|
|
307
|
-
}
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
return /* @__PURE__ */ jsxs4("span", { className: `inline-flex items-center font-mono text-xs ${className}`, style: { color }, children: [
|
|
311
|
-
"[",
|
|
312
|
-
icon,
|
|
313
|
-
"]"
|
|
314
|
-
] });
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// src/components/docs/card.tsx
|
|
318
|
-
import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
319
|
-
function Card({ title, description, href, icon, children, external = false }) {
|
|
320
|
-
const content = /* @__PURE__ */ jsx6(Fragment, { children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
|
|
321
|
-
icon && /* @__PURE__ */ jsx6("div", { className: "shrink-0 w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary", children: typeof icon === "string" ? /* @__PURE__ */ jsx6(Icon, { icon, size: 20 }) : icon }),
|
|
322
|
-
/* @__PURE__ */ jsxs5("div", { className: "flex-1 min-w-0", children: [
|
|
323
|
-
/* @__PURE__ */ jsx6("h3", { className: `font-semibold text-foreground mb-1 no-underline ${href ? "group-hover:text-primary transition-colors" : ""}`, children: title }),
|
|
324
|
-
description && /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground line-clamp-2 no-underline", children: description }),
|
|
325
|
-
children && /* @__PURE__ */ jsx6("div", { className: "mt-2 text-sm text-muted-foreground no-underline", children })
|
|
326
|
-
] }),
|
|
327
|
-
href && /* @__PURE__ */ jsx6("div", { className: "shrink-0 self-start mt-1", children: external ? /* @__PURE__ */ jsx6(ExternalLink, { className: "h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" }) : /* @__PURE__ */ jsx6(ArrowRight, { className: "h-4 w-4 text-muted-foreground group-hover:text-primary group-hover:translate-x-1 transition-all" }) })
|
|
328
|
-
] }) });
|
|
329
|
-
if (href) {
|
|
330
|
-
const Component = external ? "a" : Link2;
|
|
331
|
-
return /* @__PURE__ */ jsx6(
|
|
332
|
-
Component,
|
|
333
|
-
{
|
|
334
|
-
href,
|
|
335
|
-
className: "card-link group block p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all",
|
|
336
|
-
...external ? { target: "_blank", rel: "noopener noreferrer" } : {},
|
|
337
|
-
children: content
|
|
338
|
-
}
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
return /* @__PURE__ */ jsx6("div", { className: "p-4 rounded-xl border border-border bg-muted/30 no-underline", children: content });
|
|
342
|
-
}
|
|
343
|
-
function CardGrid({ children, cols = 2 }) {
|
|
344
|
-
const gridCols = {
|
|
345
|
-
1: "grid-cols-1",
|
|
346
|
-
2: "grid-cols-1 md:grid-cols-2",
|
|
347
|
-
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
|
|
348
|
-
};
|
|
349
|
-
return /* @__PURE__ */ jsx6("div", { className: `grid ${gridCols[cols]} gap-4 my-6`, children });
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// src/components/docs/code-block.tsx
|
|
353
|
-
import { useState as useState2 } from "react";
|
|
354
|
-
import { Check, Copy } from "lucide-react";
|
|
355
|
-
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
356
|
-
function CodeBlock({ code, language, filename }) {
|
|
357
|
-
const [copied, setCopied] = useState2(false);
|
|
358
|
-
const handleCopy = async () => {
|
|
359
|
-
await navigator.clipboard.writeText(code);
|
|
360
|
-
setCopied(true);
|
|
361
|
-
setTimeout(() => setCopied(false), 2e3);
|
|
362
|
-
};
|
|
363
|
-
const highlightCode = (code2, lang) => {
|
|
364
|
-
const lines = code2.split("\n");
|
|
365
|
-
return lines.map((line, i) => {
|
|
366
|
-
const isDeletion = line.startsWith("-");
|
|
367
|
-
const isAddition = line.startsWith("+");
|
|
368
|
-
const isDiff = isDeletion || isAddition;
|
|
369
|
-
const diffBgClass = isDeletion ? "bg-red-500/5 dark:bg-red-500/10" : isAddition ? "bg-green-500/5 dark:bg-green-500/10" : "";
|
|
370
|
-
const diffMarkerClass = isDeletion ? "text-red-600 dark:text-red-400" : isAddition ? "text-green-600 dark:text-green-400" : "";
|
|
371
|
-
const tokens = [];
|
|
372
|
-
let currentPos = 0;
|
|
373
|
-
const patterns = [
|
|
374
|
-
{ type: "comment", regex: /(\/\/.*$|\/\*[\s\S]*?\*\/|#.*$)/ },
|
|
375
|
-
{ type: "string", regex: /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/ },
|
|
376
|
-
{
|
|
377
|
-
type: "keyword",
|
|
378
|
-
regex: /\b(const|let|var|function|return|if|else|for|while|do|break|continue|switch|case|default|import|export|from|as|class|extends|implements|interface|type|enum|namespace|async|await|try|catch|finally|throw|new|this|super|static|public|private|protected|readonly|abstract|void|null|undefined|true|false|typeof|instanceof|delete|in|of)\b/
|
|
379
|
-
},
|
|
380
|
-
{ type: "operator", regex: /([+\-*/%=<>!&|^~?:]+)/ },
|
|
381
|
-
{ type: "number", regex: /\b(0x[a-fA-F0-9]+|0b[01]+|\d+\.?\d*(?:e[+-]?\d+)?)\b/ },
|
|
382
|
-
{ type: "function", regex: /\b([a-zA-Z_$][\w$]*)\s*(?=\()/ },
|
|
383
|
-
{ type: "property", regex: /\.([a-zA-Z_$][\w$]*)/ },
|
|
384
|
-
{ type: "punctuation", regex: /([{}[\]();,])/ }
|
|
385
|
-
];
|
|
386
|
-
while (currentPos < line.length) {
|
|
387
|
-
let matched = false;
|
|
388
|
-
for (const { type, regex } of patterns) {
|
|
389
|
-
const match = line.slice(currentPos).match(regex);
|
|
390
|
-
if (match && match.index === 0) {
|
|
391
|
-
tokens.push({ type, value: match[0] });
|
|
392
|
-
currentPos += match[0].length;
|
|
393
|
-
matched = true;
|
|
394
|
-
break;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
if (!matched) {
|
|
398
|
-
const nextSpecialChar = line.slice(currentPos).search(/["'`/\w.+\-*/%=<>!&|^~?:;,()[\]{}#]/);
|
|
399
|
-
if (nextSpecialChar === -1) {
|
|
400
|
-
tokens.push({ type: "text", value: line.slice(currentPos) });
|
|
401
|
-
break;
|
|
402
|
-
} else if (nextSpecialChar > 0) {
|
|
403
|
-
tokens.push({ type: "text", value: line.slice(currentPos, currentPos + nextSpecialChar) });
|
|
404
|
-
currentPos += nextSpecialChar;
|
|
405
|
-
} else {
|
|
406
|
-
tokens.push({ type: "text", value: line[currentPos] });
|
|
407
|
-
currentPos++;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
return /* @__PURE__ */ jsxs6("div", { className: `table-row ${diffBgClass}`, children: [
|
|
412
|
-
/* @__PURE__ */ jsx7("span", { className: "table-cell pr-4 text-right select-none text-muted-foreground/40 w-8 align-top", children: i + 1 }),
|
|
413
|
-
/* @__PURE__ */ jsx7("span", { className: "table-cell align-top", children: tokens.length === 0 ? /* @__PURE__ */ jsx7("span", { children: "\xA0" }) : tokens.map((token, j) => {
|
|
414
|
-
if (j === 0 && isDiff && token.value.length > 0 && (token.value[0] === "+" || token.value[0] === "-")) {
|
|
415
|
-
const marker = token.value[0];
|
|
416
|
-
const rest = token.value.slice(1);
|
|
417
|
-
return /* @__PURE__ */ jsxs6("span", { children: [
|
|
418
|
-
/* @__PURE__ */ jsx7("span", { className: `${diffMarkerClass} font-bold`, children: marker }),
|
|
419
|
-
rest && /* @__PURE__ */ jsx7("span", { className: `token-${token.type}`, children: rest })
|
|
420
|
-
] }, j);
|
|
421
|
-
}
|
|
422
|
-
return /* @__PURE__ */ jsx7("span", { className: `token-${token.type}`, children: token.value }, j);
|
|
423
|
-
}) })
|
|
424
|
-
] }, i);
|
|
425
|
-
});
|
|
426
|
-
};
|
|
427
|
-
return /* @__PURE__ */ jsxs6("div", { className: "relative group my-2", children: [
|
|
428
|
-
/* @__PURE__ */ jsxs6("div", { className: "bg-muted/50 dark:bg-muted/30 px-4 py-2 rounded-t-xl border border-b-0 border-border/50 flex items-center justify-between", children: [
|
|
429
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
430
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5", children: [
|
|
431
|
-
/* @__PURE__ */ jsx7("div", { className: "w-3 h-3 rounded-full bg-red-500/80 dark:bg-red-500/60" }),
|
|
432
|
-
/* @__PURE__ */ jsx7("div", { className: "w-3 h-3 rounded-full bg-yellow-500/80 dark:bg-yellow-500/60" }),
|
|
433
|
-
/* @__PURE__ */ jsx7("div", { className: "w-3 h-3 rounded-full bg-green-500/80 dark:bg-green-500/60" })
|
|
434
|
-
] }),
|
|
435
|
-
/* @__PURE__ */ jsx7("span", { className: "text-xs font-mono text-foreground", children: filename || "Code" })
|
|
436
|
-
] }),
|
|
437
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
438
|
-
/* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground/60 font-mono uppercase tracking-wide", children: language }),
|
|
439
|
-
/* @__PURE__ */ jsx7(
|
|
440
|
-
"button",
|
|
441
|
-
{
|
|
442
|
-
onClick: handleCopy,
|
|
443
|
-
className: "p-1.5 rounded-md hover:bg-muted/50 transition-colors",
|
|
444
|
-
"aria-label": "Copy code",
|
|
445
|
-
children: copied ? /* @__PURE__ */ jsx7(Check, { className: "h-4 w-4 text-green-400" }) : /* @__PURE__ */ jsx7(Copy, { className: "h-4 w-4 text-muted-foreground" })
|
|
446
|
-
}
|
|
447
|
-
)
|
|
448
|
-
] })
|
|
449
|
-
] }),
|
|
450
|
-
/* @__PURE__ */ jsx7("div", { className: "bg-gray-200/50 dark:bg-[#0d1117] rounded-b-xl overflow-x-auto border border-border/50", children: /* @__PURE__ */ jsx7("pre", { className: "p-2 text-[13px] font-mono leading-relaxed text-gray-800 dark:text-gray-200", children: /* @__PURE__ */ jsx7("code", { className: "table w-full", children: highlightCode(code, language) }) }) })
|
|
451
|
-
] });
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// src/components/docs/columns.tsx
|
|
455
|
-
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
456
|
-
function Columns({ children, cols = { sm: 1, md: 2, lg: 3 } }) {
|
|
457
|
-
const colClasses = {
|
|
458
|
-
1: "grid-cols-1",
|
|
459
|
-
2: "grid-cols-2",
|
|
460
|
-
3: "grid-cols-3",
|
|
461
|
-
4: "grid-cols-4"
|
|
462
|
-
};
|
|
463
|
-
const smClass = cols.sm ? colClasses[cols.sm] : "grid-cols-1";
|
|
464
|
-
const mdClass = cols.md ? `md:${colClasses[cols.md]}` : "";
|
|
465
|
-
const lgClass = cols.lg ? `lg:${colClasses[cols.lg]}` : "";
|
|
466
|
-
const xlClass = cols.xl ? `xl:${colClasses[cols.xl]}` : "";
|
|
467
|
-
return /* @__PURE__ */ jsx8("div", { className: `grid ${smClass} ${mdClass} ${lgClass} ${xlClass} gap-4 my-6`, children });
|
|
468
|
-
}
|
|
469
|
-
function Column({ children, span = 1 }) {
|
|
470
|
-
const spanClass = {
|
|
471
|
-
1: "col-span-1",
|
|
472
|
-
2: "col-span-2",
|
|
473
|
-
3: "col-span-3",
|
|
474
|
-
4: "col-span-4"
|
|
475
|
-
};
|
|
476
|
-
return /* @__PURE__ */ jsx8("div", { className: spanClass[span], children });
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// src/components/docs/componentTextProps.ts
|
|
480
|
-
var COMPONENT_TEXT_PROPS = {
|
|
481
|
-
// Accordion components
|
|
482
|
-
Accordion: ["title"],
|
|
483
|
-
AccordionItem: ["title"],
|
|
484
|
-
// Alert/Callout components
|
|
485
|
-
Alert: ["title", "description"],
|
|
486
|
-
Banner: ["title"],
|
|
487
|
-
Callout: ["title", "content"],
|
|
488
|
-
Note: ["title"],
|
|
489
|
-
Warning: ["title", "text"],
|
|
490
|
-
// Navigation components
|
|
491
|
-
BreadCrumb: ["title", "slug", "version"],
|
|
492
|
-
// Card components
|
|
493
|
-
Card: ["title", "description"],
|
|
494
|
-
ImageCard: ["title", "description", "alt"],
|
|
495
|
-
// Media components
|
|
496
|
-
Image: ["alt", "caption"],
|
|
497
|
-
Video: ["caption"],
|
|
498
|
-
Frame: ["title"],
|
|
499
|
-
Mermaid: ["caption"],
|
|
500
|
-
// Interactive components
|
|
501
|
-
Tooltip: ["content"],
|
|
502
|
-
// Code components
|
|
503
|
-
CodeBlock: ["filename"],
|
|
504
|
-
// Step components
|
|
505
|
-
Step: ["title"]
|
|
506
|
-
};
|
|
507
|
-
function extractComponentPropsText(mdx) {
|
|
508
|
-
return mdx.replace(
|
|
509
|
-
/<([A-Z][\w]*)\b([^/>]*)\/>/g,
|
|
510
|
-
(_, component, props) => {
|
|
511
|
-
const searchableProps = COMPONENT_TEXT_PROPS[component];
|
|
512
|
-
if (!searchableProps) return " ";
|
|
513
|
-
let extracted = "";
|
|
514
|
-
for (const prop of searchableProps) {
|
|
515
|
-
const match = props.match(
|
|
516
|
-
new RegExp(`${prop}="([^"]+)"`, "i")
|
|
517
|
-
);
|
|
518
|
-
if (match) {
|
|
519
|
-
extracted += " " + match[1];
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
return extracted || " ";
|
|
523
|
-
}
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
|
-
function extractSearchText(mdx) {
|
|
527
|
-
return extractComponentPropsText(mdx).replace(/```[\s\S]*?```/g, " ").replace(/<([A-Z][\w]*)\b[^>]*>[\s\S]*?<\/\1>/g, " ").replace(/<\/?[A-Za-z][^>]*>/g, " ").replace(/`[^`]+`/g, " ").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[#>*_~=-]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 1e3);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// src/components/docs/dev-mode-badge.tsx
|
|
531
|
-
import { useEffect, useState as useState3 } from "react";
|
|
532
|
-
import { Code2 } from "lucide-react";
|
|
533
|
-
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
534
|
-
function DevModeBadge() {
|
|
535
|
-
const [isConnected, setIsConnected] = useState3(true);
|
|
536
|
-
useEffect(() => {
|
|
537
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
538
|
-
const checkConnection = () => {
|
|
539
|
-
setIsConnected(navigator.onLine);
|
|
540
|
-
};
|
|
541
|
-
window.addEventListener("online", checkConnection);
|
|
542
|
-
window.addEventListener("offline", checkConnection);
|
|
543
|
-
return () => {
|
|
544
|
-
window.removeEventListener("online", checkConnection);
|
|
545
|
-
window.removeEventListener("offline", checkConnection);
|
|
546
|
-
};
|
|
547
|
-
}, []);
|
|
548
|
-
if (process.env.NODE_ENV !== "development") return null;
|
|
549
|
-
return /* @__PURE__ */ jsxs7("div", { className: "fixed top-20 left-4 z-40 flex items-center gap-2 px-3 py-1.5 bg-orange-500/10 text-orange-600 dark:text-orange-400 border border-orange-500/20 rounded-full text-xs font-medium", children: [
|
|
550
|
-
/* @__PURE__ */ jsx9(Code2, { className: "h-3 w-3" }),
|
|
551
|
-
/* @__PURE__ */ jsx9("span", { children: "Dev Mode" }),
|
|
552
|
-
/* @__PURE__ */ jsx9("div", { className: `h-2 w-2 rounded-full ${isConnected ? "bg-green-500" : "bg-red-500"} animate-pulse` })
|
|
553
|
-
] });
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// src/components/docs/mobile-doc-layout.tsx
|
|
557
|
-
import { useState as useState8, cloneElement as cloneElement2, isValidElement as isValidElement2 } from "react";
|
|
558
|
-
import Link5 from "next/link";
|
|
559
|
-
|
|
560
|
-
// src/components/docs/footer.tsx
|
|
561
|
-
import Link3 from "next/link";
|
|
562
|
-
|
|
563
|
-
// src/components/docs/logo.tsx
|
|
564
|
-
import { useTheme } from "next-themes";
|
|
565
|
-
import { useEffect as useEffect2, useState as useState4 } from "react";
|
|
566
|
-
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
567
|
-
function Logo({ logo, alt = "Logo", className = "h-8 w-8 object-contain" }) {
|
|
568
|
-
const { resolvedTheme } = useTheme();
|
|
569
|
-
const [mounted, setMounted] = useState4(false);
|
|
570
|
-
useEffect2(() => {
|
|
571
|
-
setMounted(true);
|
|
572
|
-
}, []);
|
|
573
|
-
if (!logo) return null;
|
|
574
|
-
if (typeof logo === "string") {
|
|
575
|
-
return /* @__PURE__ */ jsx10("img", { src: logo, alt, className });
|
|
576
|
-
}
|
|
577
|
-
if (!mounted) {
|
|
578
|
-
return /* @__PURE__ */ jsx10("img", { src: logo.light, alt, className });
|
|
579
|
-
}
|
|
580
|
-
const logoSrc = resolvedTheme === "dark" ? logo.dark : logo.light;
|
|
581
|
-
return /* @__PURE__ */ jsx10("img", { src: logoSrc, alt, className });
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// src/components/docs/footer.tsx
|
|
585
|
-
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
586
|
-
function Footer({ config }) {
|
|
587
|
-
if (!config.footer) {
|
|
588
|
-
return null;
|
|
589
|
-
}
|
|
590
|
-
return /* @__PURE__ */ jsx11("footer", { className: "bg-muted/30 dark:bg-muted/10 rounded-2xl mt-24", children: /* @__PURE__ */ jsxs8("div", { className: "px-2 md:px-6 py-12", children: [
|
|
591
|
-
config.footer.links && config.footer.links.length > 0 && /* @__PURE__ */ jsx11("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-8 mb-8", children: config.footer.links.map((column, idx) => /* @__PURE__ */ jsxs8("div", { children: [
|
|
592
|
-
/* @__PURE__ */ jsx11("h3", { className: "font-semibold text-foreground mb-4", children: column.title }),
|
|
593
|
-
/* @__PURE__ */ jsx11("ul", { className: "space-y-2", children: column.items.map((item, itemIdx) => /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsx11(
|
|
594
|
-
Link3,
|
|
595
|
-
{
|
|
596
|
-
href: item.href,
|
|
597
|
-
className: "text-sm text-muted-foreground hover:text-foreground transition-colors",
|
|
598
|
-
children: item.label
|
|
599
|
-
}
|
|
600
|
-
) }, itemIdx)) })
|
|
601
|
-
] }, idx)) }),
|
|
602
|
-
/* @__PURE__ */ jsx11("div", { className: "pt-8 border-t border-border/50", children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col md:flex-row items-center justify-between gap-4", children: [
|
|
603
|
-
config.footer.copyright && /* @__PURE__ */ jsx11("p", { className: "text-sm text-muted-foreground text-center md:text-left", children: config.footer.copyright }),
|
|
604
|
-
config.footer.branding?.showBranding && /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
605
|
-
config.footer.branding.logo && /* @__PURE__ */ jsx11(
|
|
606
|
-
Logo,
|
|
607
|
-
{
|
|
608
|
-
logo: config.footer.branding.logo,
|
|
609
|
-
alt: config.footer.branding.title || "Powered by",
|
|
610
|
-
className: "h-5 w-auto object-contain"
|
|
611
|
-
}
|
|
612
|
-
),
|
|
613
|
-
/* @__PURE__ */ jsx11("span", { children: "Powered by" }),
|
|
614
|
-
config.footer.branding.url ? /* @__PURE__ */ jsx11(
|
|
615
|
-
Link3,
|
|
616
|
-
{
|
|
617
|
-
href: config.footer.branding.url,
|
|
618
|
-
target: "_blank",
|
|
619
|
-
rel: "noopener noreferrer",
|
|
620
|
-
className: "font-semibold hover:text-foreground transition-colors",
|
|
621
|
-
children: config.footer.branding.title || "Specra"
|
|
622
|
-
}
|
|
623
|
-
) : /* @__PURE__ */ jsx11("span", { className: "font-semibold", children: config.footer.branding.title || "Specra" })
|
|
624
|
-
] })
|
|
625
|
-
] }) })
|
|
626
|
-
] }) });
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// src/components/docs/site-banner.tsx
|
|
630
|
-
import { X, AlertCircle, CheckCircle, Info as Info2, XCircle as XCircle2 } from "lucide-react";
|
|
631
|
-
import { useState as useState5, useEffect as useEffect3 } from "react";
|
|
632
|
-
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
633
|
-
function SiteBanner({ config }) {
|
|
634
|
-
const [dismissed, setDismissed] = useState5(false);
|
|
635
|
-
const [mounted, setMounted] = useState5(false);
|
|
636
|
-
const banner = config.banner;
|
|
637
|
-
const storageKey = "site-banner-dismissed";
|
|
638
|
-
useEffect3(() => {
|
|
639
|
-
setMounted(true);
|
|
640
|
-
const isDismissed = localStorage.getItem(storageKey) === "true";
|
|
641
|
-
setDismissed(isDismissed);
|
|
642
|
-
}, []);
|
|
643
|
-
const handleDismiss = () => {
|
|
644
|
-
setDismissed(true);
|
|
645
|
-
localStorage.setItem(storageKey, "true");
|
|
646
|
-
};
|
|
647
|
-
if (!mounted || !banner || !banner.enabled || dismissed) {
|
|
648
|
-
return null;
|
|
649
|
-
}
|
|
650
|
-
const typeConfig = {
|
|
651
|
-
info: {
|
|
652
|
-
icon: Info2,
|
|
653
|
-
bg: "bg-blue-500/10 dark:bg-blue-400/5",
|
|
654
|
-
border: "border-blue-500/30 dark:border-blue-500/20",
|
|
655
|
-
iconColor: "text-blue-600 dark:text-blue-400",
|
|
656
|
-
textColor: "text-blue-900 dark:text-blue-300"
|
|
657
|
-
},
|
|
658
|
-
success: {
|
|
659
|
-
icon: CheckCircle,
|
|
660
|
-
bg: "bg-green-500/10 dark:bg-green-400/5",
|
|
661
|
-
border: "border-green-500/30 dark:border-green-500/20",
|
|
662
|
-
iconColor: "text-green-600 dark:text-green-400",
|
|
663
|
-
textColor: "text-green-900 dark:text-green-300"
|
|
664
|
-
},
|
|
665
|
-
warning: {
|
|
666
|
-
icon: AlertCircle,
|
|
667
|
-
bg: "bg-yellow-500/10 dark:bg-yellow-400/5",
|
|
668
|
-
border: "border-yellow-500/30 dark:border-yellow-500/20",
|
|
669
|
-
iconColor: "text-yellow-600 dark:text-yellow-400",
|
|
670
|
-
textColor: "text-yellow-900 dark:text-yellow-300"
|
|
671
|
-
},
|
|
672
|
-
error: {
|
|
673
|
-
icon: XCircle2,
|
|
674
|
-
bg: "bg-red-500/10 dark:bg-red-400/5",
|
|
675
|
-
border: "border-red-500/30 dark:border-red-500/20",
|
|
676
|
-
iconColor: "text-red-600 dark:text-red-400",
|
|
677
|
-
textColor: "text-red-900 dark:text-red-300"
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
const type = banner.type || "info";
|
|
681
|
-
const { icon: IconComponent, bg, border, iconColor, textColor } = typeConfig[type];
|
|
682
|
-
return /* @__PURE__ */ jsx12("div", { className: `w-full border-b ${border} ${bg}`, children: /* @__PURE__ */ jsx12("div", { className: "container mx-auto px-2 md:px-6 py-3", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3", children: [
|
|
683
|
-
/* @__PURE__ */ jsx12(IconComponent, { className: `h-5 w-5 shrink-0 ${iconColor}` }),
|
|
684
|
-
/* @__PURE__ */ jsx12("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx12("p", { className: `text-sm font-medium ${textColor}`, children: banner.message }) }),
|
|
685
|
-
banner.dismissible && /* @__PURE__ */ jsx12(
|
|
686
|
-
"button",
|
|
687
|
-
{
|
|
688
|
-
onClick: handleDismiss,
|
|
689
|
-
className: `shrink-0 p-1 rounded-md hover:bg-black/5 dark:hover:bg-white/5 transition-colors ${iconColor}`,
|
|
690
|
-
"aria-label": "Dismiss banner",
|
|
691
|
-
children: /* @__PURE__ */ jsx12(X, { className: "h-4 w-4" })
|
|
692
|
-
}
|
|
693
|
-
)
|
|
694
|
-
] }) }) });
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// src/components/docs/tab-groups.tsx
|
|
698
|
-
import { useState as useState6 } from "react";
|
|
699
|
-
import { useRouter } from "next/navigation";
|
|
700
|
-
import { ChevronDown as ChevronDown2 } from "lucide-react";
|
|
701
|
-
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
702
|
-
function TabGroups({ tabGroups, activeTabId, onTabChange, mobileOnly = false, docs, version }) {
|
|
703
|
-
const [dropdownOpen, setDropdownOpen] = useState6(false);
|
|
704
|
-
const router = useRouter();
|
|
705
|
-
const filteredTabGroups = docs ? tabGroups.filter((tab) => {
|
|
706
|
-
const hasDocsInTab = docs.some((doc) => {
|
|
707
|
-
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
708
|
-
return docTabGroup === tab.id || !docTabGroup && tab.id === tabGroups[0]?.id;
|
|
709
|
-
});
|
|
710
|
-
return hasDocsInTab;
|
|
711
|
-
}) : tabGroups;
|
|
712
|
-
const activeTab = activeTabId || filteredTabGroups[0]?.id || "";
|
|
713
|
-
const activeTabData = filteredTabGroups.find((tab) => tab.id === activeTab);
|
|
714
|
-
const handleTabChange = (tabId) => {
|
|
715
|
-
onTabChange?.(tabId);
|
|
716
|
-
setDropdownOpen(false);
|
|
717
|
-
if (docs && version) {
|
|
718
|
-
const firstDocInTab = docs.find((doc) => {
|
|
719
|
-
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
720
|
-
return docTabGroup === tabId || !docTabGroup && tabId === filteredTabGroups[0]?.id;
|
|
721
|
-
});
|
|
722
|
-
if (firstDocInTab) {
|
|
723
|
-
router.push(`/docs/${version}/${firstDocInTab.slug}`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
if (!filteredTabGroups || filteredTabGroups.length === 0) {
|
|
728
|
-
return null;
|
|
729
|
-
}
|
|
730
|
-
if (mobileOnly) {
|
|
731
|
-
return /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
732
|
-
/* @__PURE__ */ jsxs10(
|
|
733
|
-
"button",
|
|
734
|
-
{
|
|
735
|
-
onClick: () => setDropdownOpen(!dropdownOpen),
|
|
736
|
-
className: "flex items-center justify-between w-full px-3 py-2 text-sm font-medium text-foreground bg-muted/50 rounded-lg hover:bg-muted transition-colors",
|
|
737
|
-
"aria-label": "Select tab group",
|
|
738
|
-
"aria-expanded": dropdownOpen,
|
|
739
|
-
children: [
|
|
740
|
-
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
|
|
741
|
-
activeTabData?.icon && /* @__PURE__ */ jsx13(Icon, { icon: activeTabData.icon, size: 16, className: "shrink-0" }),
|
|
742
|
-
/* @__PURE__ */ jsx13("span", { children: activeTabData?.label })
|
|
743
|
-
] }),
|
|
744
|
-
/* @__PURE__ */ jsx13(
|
|
745
|
-
ChevronDown2,
|
|
746
|
-
{
|
|
747
|
-
className: `h-4 w-4 transition-transform ${dropdownOpen ? "rotate-180" : ""}`
|
|
748
|
-
}
|
|
749
|
-
)
|
|
750
|
-
]
|
|
751
|
-
}
|
|
752
|
-
),
|
|
753
|
-
dropdownOpen && /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
754
|
-
/* @__PURE__ */ jsx13(
|
|
755
|
-
"div",
|
|
756
|
-
{
|
|
757
|
-
className: "fixed inset-0 z-40",
|
|
758
|
-
onClick: () => setDropdownOpen(false)
|
|
759
|
-
}
|
|
760
|
-
),
|
|
761
|
-
/* @__PURE__ */ jsx13("div", { className: "absolute top-full left-0 right-0 mt-2 bg-background border border-border rounded-lg shadow-lg z-50 max-h-[60vh] overflow-y-auto", children: filteredTabGroups.map((tab) => {
|
|
762
|
-
const isActive = tab.id === activeTab;
|
|
763
|
-
return /* @__PURE__ */ jsxs10(
|
|
764
|
-
"button",
|
|
765
|
-
{
|
|
766
|
-
onClick: () => handleTabChange(tab.id),
|
|
767
|
-
className: `flex items-center gap-2 w-full px-3 py-2 text-sm font-medium text-left transition-colors first:rounded-t-lg last:rounded-b-lg ${isActive ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-accent hover:text-foreground"}`,
|
|
768
|
-
children: [
|
|
769
|
-
tab.icon && /* @__PURE__ */ jsx13(Icon, { icon: tab.icon, size: 16, className: "shrink-0" }),
|
|
770
|
-
tab.label
|
|
771
|
-
]
|
|
772
|
-
},
|
|
773
|
-
tab.id
|
|
774
|
-
);
|
|
775
|
-
}) })
|
|
776
|
-
] })
|
|
777
|
-
] });
|
|
778
|
-
}
|
|
779
|
-
return /* @__PURE__ */ jsx13("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60", children: /* @__PURE__ */ jsxs10("div", { className: "container mx-auto px-2 md:px-6", children: [
|
|
780
|
-
/* @__PURE__ */ jsxs10("div", { className: "md:hidden relative", children: [
|
|
781
|
-
/* @__PURE__ */ jsxs10(
|
|
782
|
-
"button",
|
|
783
|
-
{
|
|
784
|
-
onClick: () => setDropdownOpen(!dropdownOpen),
|
|
785
|
-
className: "flex items-center justify-between w-full px-4 py-3 text-sm font-medium text-foreground",
|
|
786
|
-
"aria-label": "Select tab",
|
|
787
|
-
"aria-expanded": dropdownOpen,
|
|
788
|
-
children: [
|
|
789
|
-
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
|
|
790
|
-
activeTabData?.icon && /* @__PURE__ */ jsx13(Icon, { icon: activeTabData.icon, size: 16, className: "shrink-0" }),
|
|
791
|
-
activeTabData?.label
|
|
792
|
-
] }),
|
|
793
|
-
/* @__PURE__ */ jsx13(
|
|
794
|
-
ChevronDown2,
|
|
795
|
-
{
|
|
796
|
-
className: `h-4 w-4 transition-transform ${dropdownOpen ? "rotate-180" : ""}`
|
|
797
|
-
}
|
|
798
|
-
)
|
|
799
|
-
]
|
|
800
|
-
}
|
|
801
|
-
),
|
|
802
|
-
dropdownOpen && /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
803
|
-
/* @__PURE__ */ jsx13(
|
|
804
|
-
"div",
|
|
805
|
-
{
|
|
806
|
-
className: "fixed inset-0 z-40",
|
|
807
|
-
onClick: () => setDropdownOpen(false)
|
|
808
|
-
}
|
|
809
|
-
),
|
|
810
|
-
/* @__PURE__ */ jsx13("div", { className: "absolute top-full left-0 right-0 bg-background border border-border shadow-lg z-50 max-h-[60vh] overflow-y-auto", children: filteredTabGroups.map((tab) => {
|
|
811
|
-
const isActive = tab.id === activeTab;
|
|
812
|
-
return /* @__PURE__ */ jsxs10(
|
|
813
|
-
"button",
|
|
814
|
-
{
|
|
815
|
-
onClick: () => handleTabChange(tab.id),
|
|
816
|
-
className: `flex items-center gap-2 w-full px-4 py-3 text-sm font-medium text-left transition-colors ${isActive ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-accent hover:text-foreground"}`,
|
|
817
|
-
children: [
|
|
818
|
-
tab.icon && /* @__PURE__ */ jsx13(Icon, { icon: tab.icon, size: 16, className: "shrink-0" }),
|
|
819
|
-
tab.label
|
|
820
|
-
]
|
|
821
|
-
},
|
|
822
|
-
tab.id
|
|
823
|
-
);
|
|
824
|
-
}) })
|
|
825
|
-
] })
|
|
826
|
-
] }),
|
|
827
|
-
/* @__PURE__ */ jsx13("nav", { className: "hidden md:flex gap-1", "aria-label": "Documentation tabs", children: filteredTabGroups.map((tab) => {
|
|
828
|
-
const isActive = tab.id === activeTab;
|
|
829
|
-
return /* @__PURE__ */ jsxs10(
|
|
830
|
-
"button",
|
|
831
|
-
{
|
|
832
|
-
onClick: () => handleTabChange(tab.id),
|
|
833
|
-
className: `flex items-center gap-2 px-4 py-3 text-sm font-medium whitespace-nowrap transition-all border-b-2 ${isActive ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground hover:border-border"}`,
|
|
834
|
-
"aria-current": isActive ? "page" : void 0,
|
|
835
|
-
children: [
|
|
836
|
-
tab.icon && /* @__PURE__ */ jsx13(Icon, { icon: tab.icon, size: 16, className: "shrink-0" }),
|
|
837
|
-
tab.label
|
|
838
|
-
]
|
|
839
|
-
},
|
|
840
|
-
tab.id
|
|
841
|
-
);
|
|
842
|
-
}) })
|
|
843
|
-
] }) });
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
// src/components/docs/sidebar-menu-items.tsx
|
|
847
|
-
import Link4 from "next/link";
|
|
848
|
-
import { usePathname } from "next/navigation";
|
|
849
|
-
import { ChevronRight as ChevronRight2, ChevronDown as ChevronDown3, FolderOpen } from "lucide-react";
|
|
850
|
-
import { useState as useState7 } from "react";
|
|
851
|
-
|
|
852
|
-
// src/lib/sidebar-utils.ts
|
|
853
|
-
function sortSidebarItems(items) {
|
|
854
|
-
return [...items].sort((a, b) => {
|
|
855
|
-
const posA = a.sidebar_position ?? a.meta?.sidebar_position ?? a.meta?.order ?? 999;
|
|
856
|
-
const posB = b.sidebar_position ?? b.meta?.sidebar_position ?? b.meta?.order ?? 999;
|
|
857
|
-
return posA - posB;
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
function sortSidebarGroups(groups) {
|
|
861
|
-
return Object.entries(groups).sort(([, a], [, b]) => {
|
|
862
|
-
const posA = a.position ?? 999;
|
|
863
|
-
const posB = b.position ?? 999;
|
|
864
|
-
return posA - posB;
|
|
865
|
-
});
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// src/components/docs/sidebar-menu-items.tsx
|
|
869
|
-
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
870
|
-
function SidebarMenuItems({ docs, version, onLinkClick, config, activeTabGroup }) {
|
|
871
|
-
const pathname = usePathname();
|
|
872
|
-
const [collapsed, setCollapsed] = useState7(() => {
|
|
873
|
-
const initial = {};
|
|
874
|
-
return initial;
|
|
875
|
-
});
|
|
876
|
-
const hasTabGroups = config.navigation?.tabGroups && config.navigation.tabGroups.length > 0;
|
|
877
|
-
const filteredDocs = hasTabGroups && activeTabGroup ? docs.filter((doc) => {
|
|
878
|
-
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
879
|
-
if (!docTabGroup) {
|
|
880
|
-
return activeTabGroup === config.navigation?.tabGroups?.[0]?.id;
|
|
881
|
-
}
|
|
882
|
-
return docTabGroup === activeTabGroup;
|
|
883
|
-
}) : docs;
|
|
884
|
-
const rootGroups = {};
|
|
885
|
-
const standalone = [];
|
|
886
|
-
filteredDocs.forEach((doc) => {
|
|
887
|
-
const pathParts = doc.filePath.split("/");
|
|
888
|
-
const isIndexFile = doc.filePath.endsWith("/index") || doc.filePath === "index" || pathParts.length > 1 && doc.slug === pathParts.slice(0, -1).join("/");
|
|
889
|
-
const customGroup = doc.sidebar || doc.group;
|
|
890
|
-
if (customGroup) {
|
|
891
|
-
const groupName = customGroup.charAt(0).toUpperCase() + customGroup.slice(1);
|
|
892
|
-
if (!rootGroups[groupName]) {
|
|
893
|
-
rootGroups[groupName] = {
|
|
894
|
-
label: groupName,
|
|
895
|
-
path: customGroup,
|
|
896
|
-
items: [],
|
|
897
|
-
position: 999,
|
|
898
|
-
collapsible: doc.categoryCollapsible ?? true,
|
|
899
|
-
defaultCollapsed: doc.categoryCollapsed ?? false,
|
|
900
|
-
children: {}
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
if (isIndexFile) {
|
|
904
|
-
rootGroups[groupName].position = doc.sidebar_position ?? 999;
|
|
905
|
-
rootGroups[groupName].icon = doc.categoryIcon;
|
|
906
|
-
} else {
|
|
907
|
-
rootGroups[groupName].items.push(doc);
|
|
908
|
-
}
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
if (pathParts.length > 1) {
|
|
912
|
-
const folderParts = pathParts.slice(0, -1);
|
|
913
|
-
let currentLevel = rootGroups;
|
|
914
|
-
let currentPath = "";
|
|
915
|
-
for (let i = 0; i < folderParts.length; i++) {
|
|
916
|
-
const folder = folderParts[i];
|
|
917
|
-
currentPath = currentPath ? `${currentPath}/${folder}` : folder;
|
|
918
|
-
const folderLabel = folder.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
919
|
-
if (!currentLevel[folder]) {
|
|
920
|
-
currentLevel[folder] = {
|
|
921
|
-
label: doc.categoryLabel && i === folderParts.length - 1 ? doc.categoryLabel : folderLabel,
|
|
922
|
-
path: currentPath,
|
|
923
|
-
icon: doc.categoryIcon,
|
|
924
|
-
items: [],
|
|
925
|
-
position: doc.categoryPosition ?? 999,
|
|
926
|
-
collapsible: doc.categoryCollapsible ?? true,
|
|
927
|
-
defaultCollapsed: doc.categoryCollapsed ?? false,
|
|
928
|
-
children: {}
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
if (i === folderParts.length - 1) {
|
|
932
|
-
if (isIndexFile) {
|
|
933
|
-
currentLevel[folder].position = doc.categoryPosition ?? doc.sidebar_position ?? 999;
|
|
934
|
-
if (doc.categoryLabel) {
|
|
935
|
-
currentLevel[folder].label = doc.categoryLabel;
|
|
936
|
-
}
|
|
937
|
-
if (doc.categoryIcon) {
|
|
938
|
-
currentLevel[folder].icon = doc.categoryIcon;
|
|
939
|
-
}
|
|
940
|
-
} else {
|
|
941
|
-
currentLevel[folder].items.push(doc);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
currentLevel = currentLevel[folder].children;
|
|
945
|
-
}
|
|
946
|
-
} else {
|
|
947
|
-
if (!isIndexFile) {
|
|
948
|
-
standalone.push(doc);
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
});
|
|
952
|
-
const toggleSection = (section) => {
|
|
953
|
-
setCollapsed((prev) => ({ ...prev, [section]: !prev[section] }));
|
|
954
|
-
};
|
|
955
|
-
const renderGroup = (groupKey, group, depth = 0) => {
|
|
956
|
-
const sortedItems = sortSidebarItems(group.items);
|
|
957
|
-
const sortedChildren = sortSidebarGroups(group.children);
|
|
958
|
-
const hasChildren = sortedChildren.length > 0;
|
|
959
|
-
const hasItems = sortedItems.length > 0;
|
|
960
|
-
const hasContent = hasChildren || hasItems;
|
|
961
|
-
const isActiveInGroup = (g) => {
|
|
962
|
-
const hasActiveItem2 = g.items.some((doc) => pathname === `/docs/${version}/${doc.slug}`);
|
|
963
|
-
if (hasActiveItem2) return true;
|
|
964
|
-
return Object.values(g.children).some((child) => isActiveInGroup(child));
|
|
965
|
-
};
|
|
966
|
-
const hasActiveItem = isActiveInGroup(group);
|
|
967
|
-
const isGroupActive = pathname === `/docs/${version}/${group.path}`;
|
|
968
|
-
const isCollapsed = hasActiveItem || isGroupActive ? false : collapsed[groupKey] ?? group.defaultCollapsed;
|
|
969
|
-
const marginLeft = depth > 0 ? "ml-4" : "";
|
|
970
|
-
let groupHref = `/docs/${version}/${group.path}`;
|
|
971
|
-
if (config.features?.i18n) {
|
|
972
|
-
const i18n = config.features.i18n;
|
|
973
|
-
const locales = typeof i18n === "object" ? i18n.locales : ["en"];
|
|
974
|
-
const pathParts = pathname?.split("/") || [];
|
|
975
|
-
const potentialLocale = pathParts[3];
|
|
976
|
-
if (potentialLocale && locales.includes(potentialLocale)) {
|
|
977
|
-
groupHref = `/docs/${version}/${potentialLocale}/${group.path}`;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
return /* @__PURE__ */ jsxs11("div", { className: `space-y-1 ${marginLeft}`, children: [
|
|
981
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-center group", children: [
|
|
982
|
-
/* @__PURE__ */ jsxs11(
|
|
983
|
-
Link4,
|
|
984
|
-
{
|
|
985
|
-
href: groupHref,
|
|
986
|
-
onClick: (e) => {
|
|
987
|
-
e.preventDefault();
|
|
988
|
-
toggleSection(groupKey);
|
|
989
|
-
},
|
|
990
|
-
className: `flex items-center gap-2 flex-1 px-3 py-2 text-sm font-semibold rounded-l-xl transition-all ${isGroupActive ? "bg-primary/10 text-primary" : "text-foreground hover:bg-accent/50"}`,
|
|
991
|
-
children: [
|
|
992
|
-
group.icon ? /* @__PURE__ */ jsx14(Icon, { icon: group.icon, size: 16, className: "shrink-0" }) : /* @__PURE__ */ jsx14(FolderOpen, { size: 16, className: "shrink-0" }),
|
|
993
|
-
group.label
|
|
994
|
-
]
|
|
995
|
-
}
|
|
996
|
-
),
|
|
997
|
-
hasContent && group.collapsible && config.navigation?.collapsibleSidebar && /* @__PURE__ */ jsx14(
|
|
998
|
-
"button",
|
|
999
|
-
{
|
|
1000
|
-
onClick: (e) => {
|
|
1001
|
-
e.preventDefault();
|
|
1002
|
-
e.stopPropagation();
|
|
1003
|
-
toggleSection(groupKey);
|
|
1004
|
-
},
|
|
1005
|
-
className: `p-2 rounded-r-xl transition-all ${isGroupActive ? "hover:bg-primary/20" : "hover:bg-accent/50"}`,
|
|
1006
|
-
"aria-label": isCollapsed ? "Expand section" : "Collapse section",
|
|
1007
|
-
children: isCollapsed ? /* @__PURE__ */ jsx14(ChevronRight2, { className: `h-4 w-4 ${isGroupActive ? "text-primary" : "text-muted-foreground"}` }) : /* @__PURE__ */ jsx14(ChevronDown3, { className: `h-4 w-4 ${isGroupActive ? "text-primary" : "text-muted-foreground"}` })
|
|
1008
|
-
}
|
|
1009
|
-
)
|
|
1010
|
-
] }),
|
|
1011
|
-
!isCollapsed && hasContent && /* @__PURE__ */ jsx14("div", { className: "ml-4 space-y-1", children: (() => {
|
|
1012
|
-
const merged = [
|
|
1013
|
-
...sortedChildren.map(([childKey, childGroup]) => ({
|
|
1014
|
-
type: "group",
|
|
1015
|
-
key: childKey,
|
|
1016
|
-
group: childGroup,
|
|
1017
|
-
position: childGroup.position
|
|
1018
|
-
})),
|
|
1019
|
-
...sortedItems.map((doc) => ({
|
|
1020
|
-
type: "item",
|
|
1021
|
-
doc,
|
|
1022
|
-
position: doc.sidebar_position ?? doc.meta?.sidebar_position ?? doc.meta?.order ?? 999
|
|
1023
|
-
}))
|
|
1024
|
-
];
|
|
1025
|
-
merged.sort((a, b) => a.position - b.position);
|
|
1026
|
-
return merged.map((item) => {
|
|
1027
|
-
if (item.type === "group") {
|
|
1028
|
-
return renderGroup(`${groupKey}/${item.key}`, item.group, depth + 1);
|
|
1029
|
-
} else {
|
|
1030
|
-
const href = `/docs/${version}/${item.doc.slug}`;
|
|
1031
|
-
const isActive = pathname === href;
|
|
1032
|
-
return /* @__PURE__ */ jsxs11(
|
|
1033
|
-
Link4,
|
|
1034
|
-
{
|
|
1035
|
-
href,
|
|
1036
|
-
onClick: onLinkClick,
|
|
1037
|
-
className: `flex items-center gap-2 px-3 py-2 text-sm rounded-xl transition-all ${isActive ? "bg-primary/10 text-primary font-medium" : "text-foreground hover:text-foreground hover:bg-accent/50"}`,
|
|
1038
|
-
children: [
|
|
1039
|
-
item.doc.meta?.icon && /* @__PURE__ */ jsx14(Icon, { icon: item.doc.meta.icon, size: 16, className: "shrink-0" }),
|
|
1040
|
-
item.doc.title
|
|
1041
|
-
]
|
|
1042
|
-
},
|
|
1043
|
-
`grouped-${item.doc.slug}`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
});
|
|
1047
|
-
})() })
|
|
1048
|
-
] }, `group-${groupKey}`);
|
|
1049
|
-
};
|
|
1050
|
-
const sortedRootGroups = sortSidebarGroups(rootGroups);
|
|
1051
|
-
const sortedStandalone = sortSidebarItems(standalone);
|
|
1052
|
-
return /* @__PURE__ */ jsxs11("nav", { className: "space-y-1", children: [
|
|
1053
|
-
sortedStandalone.length > 0 && sortedStandalone.map((doc) => {
|
|
1054
|
-
const href = `/docs/${version}/${doc.slug}`;
|
|
1055
|
-
const isActive = pathname === href;
|
|
1056
|
-
return /* @__PURE__ */ jsxs11(
|
|
1057
|
-
Link4,
|
|
1058
|
-
{
|
|
1059
|
-
href,
|
|
1060
|
-
onClick: onLinkClick,
|
|
1061
|
-
className: `flex items-center gap-2 px-3 py-2 text-sm rounded-xl transition-all ${isActive ? "bg-primary/10 text-primary font-medium" : "text-foreground hover:text-foreground hover:bg-accent/50"}`,
|
|
1062
|
-
children: [
|
|
1063
|
-
doc.meta?.icon && /* @__PURE__ */ jsx14(Icon, { icon: doc.meta.icon, size: 16, className: "shrink-0" }),
|
|
1064
|
-
doc.title
|
|
1065
|
-
]
|
|
1066
|
-
},
|
|
1067
|
-
`standalone-${doc.slug}`
|
|
1068
|
-
);
|
|
1069
|
-
}),
|
|
1070
|
-
sortedRootGroups.map(([groupKey, group]) => renderGroup(groupKey, group, 0))
|
|
1071
|
-
] });
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
// src/components/docs/sidebar.tsx
|
|
1075
|
-
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1076
|
-
function Sidebar({ docs, version, onLinkClick, config, activeTabGroup }) {
|
|
1077
|
-
if (!config.navigation?.showSidebar) {
|
|
1078
|
-
return null;
|
|
1079
|
-
}
|
|
1080
|
-
const hasTabGroups = config.navigation?.tabGroups && config.navigation.tabGroups.length > 0;
|
|
1081
|
-
const stickyTop = hasTabGroups ? "top-[7.5rem]" : "top-24";
|
|
1082
|
-
const maxHeight = hasTabGroups ? "max-h-[calc(100vh-10rem)]" : "max-h-[calc(100vh-7rem)]";
|
|
1083
|
-
return /* @__PURE__ */ jsx15("aside", { className: `w-64 shrink-0 sticky ${stickyTop} self-start`, children: /* @__PURE__ */ jsxs12("div", { className: `${maxHeight} overflow-y-auto bg-muted/30 dark:bg-muted/10 rounded-2xl p-4 border border-border/50`, children: [
|
|
1084
|
-
/* @__PURE__ */ jsx15("h2", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4 px-2", children: "Documentation" }),
|
|
1085
|
-
/* @__PURE__ */ jsx15(
|
|
1086
|
-
SidebarMenuItems,
|
|
1087
|
-
{
|
|
1088
|
-
docs,
|
|
1089
|
-
version,
|
|
1090
|
-
onLinkClick,
|
|
1091
|
-
config,
|
|
1092
|
-
activeTabGroup
|
|
1093
|
-
}
|
|
1094
|
-
)
|
|
1095
|
-
] }) });
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
// src/components/docs/mobile-doc-layout.tsx
|
|
1099
|
-
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1100
|
-
function MobileDocLayout({ header, docs, version, children, toc, config, activeTabGroup, onTabChange }) {
|
|
1101
|
-
const [sidebarOpen, setSidebarOpen] = useState8(false);
|
|
1102
|
-
const handleTabChange = (tabId) => {
|
|
1103
|
-
onTabChange?.(tabId);
|
|
1104
|
-
};
|
|
1105
|
-
const closeSidebar = () => setSidebarOpen(false);
|
|
1106
|
-
const toggleSidebar = () => setSidebarOpen(!sidebarOpen);
|
|
1107
|
-
const headerWithProps = isValidElement2(header) ? cloneElement2(header, {
|
|
1108
|
-
onMenuClick: toggleSidebar
|
|
1109
|
-
}) : header;
|
|
1110
|
-
return /* @__PURE__ */ jsxs13("div", { className: "min-h-screen bg-background", children: [
|
|
1111
|
-
headerWithProps,
|
|
1112
|
-
/* @__PURE__ */ jsx16(SiteBanner, { config }),
|
|
1113
|
-
config.navigation?.tabGroups && config.navigation.tabGroups.length > 0 && /* @__PURE__ */ jsx16(
|
|
1114
|
-
TabGroups,
|
|
1115
|
-
{
|
|
1116
|
-
tabGroups: config.navigation.tabGroups,
|
|
1117
|
-
activeTabId: activeTabGroup,
|
|
1118
|
-
onTabChange: handleTabChange,
|
|
1119
|
-
docs,
|
|
1120
|
-
version
|
|
1121
|
-
}
|
|
1122
|
-
),
|
|
1123
|
-
sidebarOpen && /* @__PURE__ */ jsx16(
|
|
1124
|
-
"div",
|
|
1125
|
-
{
|
|
1126
|
-
className: "lg:hidden fixed inset-0 bg-background/80 backdrop-blur-sm z-40",
|
|
1127
|
-
onClick: () => setSidebarOpen(false)
|
|
1128
|
-
}
|
|
1129
|
-
),
|
|
1130
|
-
/* @__PURE__ */ jsx16(
|
|
1131
|
-
"div",
|
|
1132
|
-
{
|
|
1133
|
-
className: `lg:hidden fixed top-0 left-0 h-full w-72 bg-background border-r border-border z-50 transform transition-transform duration-300 ease-in-out ${sidebarOpen ? "translate-x-0" : "-translate-x-full"}`,
|
|
1134
|
-
children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-col h-full", children: [
|
|
1135
|
-
/* @__PURE__ */ jsx16("div", { className: "shrink-0 px-4 py-4 border-b border-border", children: /* @__PURE__ */ jsxs13(Link5, { href: "/", className: "flex items-center gap-2 group justify-center", children: [
|
|
1136
|
-
!config.site?.hideLogo && /* @__PURE__ */ jsx16(
|
|
1137
|
-
Logo,
|
|
1138
|
-
{
|
|
1139
|
-
logo: config.site?.logo,
|
|
1140
|
-
alt: config.site?.title || "Logo",
|
|
1141
|
-
className: "w-18 object-contain"
|
|
1142
|
-
}
|
|
1143
|
-
),
|
|
1144
|
-
/* @__PURE__ */ jsxs13("div", { className: "flex flex-col", children: [
|
|
1145
|
-
/* @__PURE__ */ jsx16("span", { className: "font-semibold text-foreground group-hover:text-primary transition-colors", children: config.site?.title || "Documentation" }),
|
|
1146
|
-
config.site?.description && /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground line-clamp-1", children: config.site.description })
|
|
1147
|
-
] })
|
|
1148
|
-
] }) }),
|
|
1149
|
-
/* @__PURE__ */ jsx16("div", { className: "shrink-0 px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx16("h2", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider px-2", children: "Documentation" }) }),
|
|
1150
|
-
config.navigation?.tabGroups && config.navigation.tabGroups.length > 0 && /* @__PURE__ */ jsx16("div", { className: "shrink-0 px-4 py-3 border-b border-border", children: /* @__PURE__ */ jsx16(
|
|
1151
|
-
TabGroups,
|
|
1152
|
-
{
|
|
1153
|
-
tabGroups: config.navigation.tabGroups,
|
|
1154
|
-
activeTabId: activeTabGroup,
|
|
1155
|
-
onTabChange: handleTabChange,
|
|
1156
|
-
mobileOnly: true,
|
|
1157
|
-
docs,
|
|
1158
|
-
version
|
|
1159
|
-
}
|
|
1160
|
-
) }),
|
|
1161
|
-
/* @__PURE__ */ jsx16("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: /* @__PURE__ */ jsx16(
|
|
1162
|
-
SidebarMenuItems,
|
|
1163
|
-
{
|
|
1164
|
-
docs,
|
|
1165
|
-
version,
|
|
1166
|
-
config,
|
|
1167
|
-
onLinkClick: closeSidebar,
|
|
1168
|
-
activeTabGroup
|
|
1169
|
-
}
|
|
1170
|
-
) })
|
|
1171
|
-
] })
|
|
1172
|
-
}
|
|
1173
|
-
),
|
|
1174
|
-
/* @__PURE__ */ jsx16("main", { className: "container mx-auto px-2 md:px-6 py-8", children: /* @__PURE__ */ jsxs13("div", { className: "flex", children: [
|
|
1175
|
-
/* @__PURE__ */ jsx16("div", { className: "hidden lg:block", children: /* @__PURE__ */ jsx16(
|
|
1176
|
-
Sidebar,
|
|
1177
|
-
{
|
|
1178
|
-
docs,
|
|
1179
|
-
version,
|
|
1180
|
-
config,
|
|
1181
|
-
activeTabGroup
|
|
1182
|
-
}
|
|
1183
|
-
) }),
|
|
1184
|
-
/* @__PURE__ */ jsx16("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-2 px-2 md:px-8", children: [
|
|
1185
|
-
children,
|
|
1186
|
-
/* @__PURE__ */ jsx16(Footer, { config })
|
|
1187
|
-
] }) }),
|
|
1188
|
-
toc
|
|
1189
|
-
] }) })
|
|
1190
|
-
] });
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
// src/components/docs/tab-context.tsx
|
|
1194
|
-
import * as React2 from "react";
|
|
1195
|
-
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1196
|
-
var TabContext = React2.createContext(void 0);
|
|
1197
|
-
var TAB_STORAGE_KEY = "specra-active-tab-group";
|
|
1198
|
-
function TabProvider({ children, defaultTab }) {
|
|
1199
|
-
const [activeTabGroup, setActiveTabGroupState] = React2.useState(defaultTab);
|
|
1200
|
-
const isInitialMount = React2.useRef(true);
|
|
1201
|
-
React2.useEffect(() => {
|
|
1202
|
-
if (isInitialMount.current) {
|
|
1203
|
-
isInitialMount.current = false;
|
|
1204
|
-
if (typeof window !== "undefined") {
|
|
1205
|
-
try {
|
|
1206
|
-
const stored = localStorage.getItem(TAB_STORAGE_KEY);
|
|
1207
|
-
if (stored && stored !== defaultTab) {
|
|
1208
|
-
setActiveTabGroupState(stored);
|
|
1209
|
-
}
|
|
1210
|
-
} catch {
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
}, [defaultTab]);
|
|
1215
|
-
const setActiveTabGroup = (tabId) => {
|
|
1216
|
-
setActiveTabGroupState(tabId);
|
|
1217
|
-
if (typeof window !== "undefined") {
|
|
1218
|
-
try {
|
|
1219
|
-
localStorage.setItem(TAB_STORAGE_KEY, tabId);
|
|
1220
|
-
} catch {
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
};
|
|
1224
|
-
return /* @__PURE__ */ jsx17(TabContext.Provider, { value: { activeTabGroup, setActiveTabGroup }, children });
|
|
1225
|
-
}
|
|
1226
|
-
function useTabContext() {
|
|
1227
|
-
const context = React2.useContext(TabContext);
|
|
1228
|
-
if (!context) {
|
|
1229
|
-
throw new Error("useTabContext must be used within TabProvider");
|
|
1230
|
-
}
|
|
1231
|
-
return context;
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
// src/components/docs/doc-layout-wrapper.tsx
|
|
1235
|
-
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1236
|
-
function DocLayoutWrapper({ header, docs, version, children, toc, config }) {
|
|
1237
|
-
const { activeTabGroup, setActiveTabGroup } = useTabContext();
|
|
1238
|
-
return /* @__PURE__ */ jsx18(
|
|
1239
|
-
MobileDocLayout,
|
|
1240
|
-
{
|
|
1241
|
-
header,
|
|
1242
|
-
docs,
|
|
1243
|
-
version,
|
|
1244
|
-
toc,
|
|
1245
|
-
config,
|
|
1246
|
-
activeTabGroup,
|
|
1247
|
-
onTabChange: setActiveTabGroup,
|
|
1248
|
-
children
|
|
1249
|
-
}
|
|
1250
|
-
);
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
// src/components/docs/doc-loading.tsx
|
|
1254
|
-
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1255
|
-
function DocLoading() {
|
|
1256
|
-
return /* @__PURE__ */ jsx19("div", { className: "max-w-4xl mx-auto px-2 md:px-6 py-8", children: /* @__PURE__ */ jsxs14("div", { className: "animate-pulse space-y-4", children: [
|
|
1257
|
-
/* @__PURE__ */ jsx19("div", { className: "h-8 bg-gray-200 rounded w-3/4" }),
|
|
1258
|
-
/* @__PURE__ */ jsx19("div", { className: "h-4 bg-gray-200 rounded w-1/2" }),
|
|
1259
|
-
/* @__PURE__ */ jsxs14("div", { className: "space-y-3 mt-8", children: [
|
|
1260
|
-
/* @__PURE__ */ jsx19("div", { className: "h-4 bg-gray-200 rounded" }),
|
|
1261
|
-
/* @__PURE__ */ jsx19("div", { className: "h-4 bg-gray-200 rounded w-5/6" }),
|
|
1262
|
-
/* @__PURE__ */ jsx19("div", { className: "h-4 bg-gray-200 rounded w-4/6" })
|
|
1263
|
-
] })
|
|
1264
|
-
] }) });
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
// src/components/docs/doc-metadata.tsx
|
|
1268
|
-
import { Clock, Calendar, User } from "lucide-react";
|
|
1269
|
-
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1270
|
-
function DocMetadata({ meta, config }) {
|
|
1271
|
-
const showReadingTime = config.features?.showReadingTime && meta.reading_time;
|
|
1272
|
-
const showLastUpdated = config.features?.showLastUpdated && meta.last_updated;
|
|
1273
|
-
const showAuthors = config.features?.showAuthors && meta.authors?.length;
|
|
1274
|
-
const hasMetadata = showReadingTime || showLastUpdated || showAuthors;
|
|
1275
|
-
if (!hasMetadata) {
|
|
1276
|
-
return null;
|
|
1277
|
-
}
|
|
1278
|
-
return /* @__PURE__ */ jsxs15("div", { className: "flex flex-wrap items-center gap-4 text-sm text-muted-foreground border-b border-border pb-4 mb-6", children: [
|
|
1279
|
-
showReadingTime && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
1280
|
-
/* @__PURE__ */ jsx20(Clock, { className: "h-4 w-4" }),
|
|
1281
|
-
/* @__PURE__ */ jsxs15("span", { children: [
|
|
1282
|
-
meta.reading_time,
|
|
1283
|
-
" min read"
|
|
1284
|
-
] })
|
|
1285
|
-
] }),
|
|
1286
|
-
showLastUpdated && meta.last_updated && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
1287
|
-
/* @__PURE__ */ jsx20(Calendar, { className: "h-4 w-4" }),
|
|
1288
|
-
/* @__PURE__ */ jsxs15("span", { children: [
|
|
1289
|
-
"Updated ",
|
|
1290
|
-
new Date(meta.last_updated).toLocaleDateString(meta.locale || "en")
|
|
1291
|
-
] })
|
|
1292
|
-
] }),
|
|
1293
|
-
showAuthors && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
1294
|
-
/* @__PURE__ */ jsx20(User, { className: "h-4 w-4" }),
|
|
1295
|
-
/* @__PURE__ */ jsx20("span", { children: meta.authors.map((author, idx) => /* @__PURE__ */ jsxs15("span", { children: [
|
|
1296
|
-
author.name || author.id,
|
|
1297
|
-
idx < meta.authors.length - 1 && ", "
|
|
1298
|
-
] }, author.id)) })
|
|
1299
|
-
] })
|
|
1300
|
-
] });
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
// src/components/docs/doc-navigation.tsx
|
|
1304
|
-
import Link6 from "next/link";
|
|
1305
|
-
import { ChevronLeft, ChevronRight as ChevronRight3 } from "lucide-react";
|
|
1306
|
-
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1307
|
-
function DocNavigation({ previousDoc, nextDoc, version }) {
|
|
1308
|
-
if (!previousDoc && !nextDoc) return null;
|
|
1309
|
-
return /* @__PURE__ */ jsxs16("div", { className: "mt-12 pt-8 border-t border-border grid grid-cols-2 gap-4", children: [
|
|
1310
|
-
previousDoc ? /* @__PURE__ */ jsxs16(
|
|
1311
|
-
Link6,
|
|
1312
|
-
{
|
|
1313
|
-
href: `/docs/${version}/${previousDoc.slug}`,
|
|
1314
|
-
className: "group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all",
|
|
1315
|
-
style: {
|
|
1316
|
-
textDecoration: "none !important"
|
|
1317
|
-
},
|
|
1318
|
-
children: [
|
|
1319
|
-
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
1320
|
-
/* @__PURE__ */ jsx21(ChevronLeft, { className: "h-4 w-4" }),
|
|
1321
|
-
/* @__PURE__ */ jsx21("span", { children: "Previous" })
|
|
1322
|
-
] }),
|
|
1323
|
-
/* @__PURE__ */ jsx21("div", { className: "text-base font-medium text-foreground group-hover:text-primary transition-colors", children: previousDoc.title })
|
|
1324
|
-
]
|
|
1325
|
-
}
|
|
1326
|
-
) : /* @__PURE__ */ jsx21("div", {}),
|
|
1327
|
-
nextDoc ? /* @__PURE__ */ jsxs16(
|
|
1328
|
-
Link6,
|
|
1329
|
-
{
|
|
1330
|
-
href: `/docs/${version}/${nextDoc.slug}`,
|
|
1331
|
-
className: "group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all text-right",
|
|
1332
|
-
style: {
|
|
1333
|
-
textDecoration: "none !important"
|
|
1334
|
-
},
|
|
1335
|
-
children: [
|
|
1336
|
-
/* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-end gap-2 text-sm text-muted-foreground", children: [
|
|
1337
|
-
/* @__PURE__ */ jsx21("span", { children: "Next" }),
|
|
1338
|
-
/* @__PURE__ */ jsx21(ChevronRight3, { className: "h-4 w-4" })
|
|
1339
|
-
] }),
|
|
1340
|
-
/* @__PURE__ */ jsx21("div", { className: "text-base font-medium text-foreground group-hover:text-primary transition-colors", children: nextDoc.title })
|
|
1341
|
-
]
|
|
1342
|
-
}
|
|
1343
|
-
) : /* @__PURE__ */ jsx21("div", {})
|
|
1344
|
-
] });
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
// src/components/docs/doc-tags.tsx
|
|
1348
|
-
import { Tag } from "lucide-react";
|
|
1349
|
-
import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1350
|
-
function DocTags({ tags }) {
|
|
1351
|
-
if (!tags || tags.length === 0) {
|
|
1352
|
-
return null;
|
|
1353
|
-
}
|
|
1354
|
-
return /* @__PURE__ */ jsxs17("div", { className: "flex flex-wrap items-center gap-2 mt-6 pt-6 border-t border-border", children: [
|
|
1355
|
-
/* @__PURE__ */ jsx22(Tag, { className: "h-4 w-4 text-muted-foreground" }),
|
|
1356
|
-
tags.map((tag) => /* @__PURE__ */ jsx22(
|
|
1357
|
-
"span",
|
|
1358
|
-
{
|
|
1359
|
-
className: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-primary/10 text-primary border border-primary/20",
|
|
1360
|
-
children: tag
|
|
1361
|
-
},
|
|
1362
|
-
tag
|
|
1363
|
-
))
|
|
1364
|
-
] });
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
// src/components/docs/draft-badge.tsx
|
|
1368
|
-
import { FileWarning } from "lucide-react";
|
|
1369
|
-
import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1370
|
-
function DraftBadge() {
|
|
1371
|
-
return /* @__PURE__ */ jsxs18("div", { className: "inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-yellow-500/10 border border-yellow-500/20 text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-4", children: [
|
|
1372
|
-
/* @__PURE__ */ jsx23(FileWarning, { className: "h-4 w-4" }),
|
|
1373
|
-
/* @__PURE__ */ jsx23("span", { children: "Draft - Not visible in production" })
|
|
1374
|
-
] });
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
// src/components/docs/frame.tsx
|
|
1378
|
-
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1379
|
-
function Frame({ src, title = "Embedded content", height = 500, width = "100%" }) {
|
|
1380
|
-
return /* @__PURE__ */ jsx24("div", { className: "my-6 rounded-xl border border-border overflow-hidden bg-muted/30", children: /* @__PURE__ */ jsx24(
|
|
1381
|
-
"iframe",
|
|
1382
|
-
{
|
|
1383
|
-
src,
|
|
1384
|
-
title,
|
|
1385
|
-
width,
|
|
1386
|
-
height,
|
|
1387
|
-
className: "w-full",
|
|
1388
|
-
loading: "lazy",
|
|
1389
|
-
sandbox: "allow-scripts allow-same-origin allow-forms allow-popups"
|
|
1390
|
-
}
|
|
1391
|
-
) });
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
// src/components/docs/header.tsx
|
|
1395
|
-
import Link7 from "next/link";
|
|
1396
|
-
import { Search as Search2, Menu, Github, Twitter, MessageCircle } from "lucide-react";
|
|
1397
|
-
|
|
1398
|
-
// src/components/docs/version-switcher.tsx
|
|
1399
|
-
import { useState as useState10 } from "react";
|
|
1400
|
-
import { Check as Check2, ChevronDown as ChevronDown4 } from "lucide-react";
|
|
1401
|
-
import { useRouter as useRouter2 } from "next/navigation";
|
|
1402
|
-
import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1403
|
-
function VersionSwitcher({ currentVersion, versions }) {
|
|
1404
|
-
const [open, setOpen] = useState10(false);
|
|
1405
|
-
const router = useRouter2();
|
|
1406
|
-
const handleVersionChange = (version) => {
|
|
1407
|
-
router.push(`/docs/${version}`);
|
|
1408
|
-
setOpen(false);
|
|
1409
|
-
};
|
|
1410
|
-
return /* @__PURE__ */ jsxs19("div", { className: "relative", children: [
|
|
1411
|
-
/* @__PURE__ */ jsxs19(
|
|
1412
|
-
"button",
|
|
1413
|
-
{
|
|
1414
|
-
onClick: () => setOpen(!open),
|
|
1415
|
-
className: "flex items-center gap-2 px-3 py-2 text-sm text-foreground bg-muted rounded-md hover:bg-muted/80 transition-colors",
|
|
1416
|
-
children: [
|
|
1417
|
-
/* @__PURE__ */ jsx25("span", { className: "font-medium", children: currentVersion }),
|
|
1418
|
-
/* @__PURE__ */ jsx25(ChevronDown4, { className: "h-4 w-4" })
|
|
1419
|
-
]
|
|
1420
|
-
}
|
|
1421
|
-
),
|
|
1422
|
-
open && /* @__PURE__ */ jsxs19(Fragment3, { children: [
|
|
1423
|
-
/* @__PURE__ */ jsx25("div", { className: "fixed inset-0 z-40", onClick: () => setOpen(false) }),
|
|
1424
|
-
/* @__PURE__ */ jsx25("div", { className: "absolute right-0 mt-2 w-48 bg-background border border-border rounded-md shadow-lg z-50", children: /* @__PURE__ */ jsx25("div", { className: "p-2", children: versions.map((version) => /* @__PURE__ */ jsxs19(
|
|
1425
|
-
"button",
|
|
1426
|
-
{
|
|
1427
|
-
onClick: () => handleVersionChange(version),
|
|
1428
|
-
className: "flex items-center justify-between w-full px-3 py-2 text-sm text-foreground hover:bg-muted rounded-md transition-colors",
|
|
1429
|
-
children: [
|
|
1430
|
-
/* @__PURE__ */ jsx25("span", { children: version }),
|
|
1431
|
-
version === currentVersion && /* @__PURE__ */ jsx25(Check2, { className: "h-4 w-4 text-primary" })
|
|
1432
|
-
]
|
|
1433
|
-
},
|
|
1434
|
-
version
|
|
1435
|
-
)) }) })
|
|
1436
|
-
] })
|
|
1437
|
-
] });
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
// src/components/docs/language-switcher.tsx
|
|
1441
|
-
import { useState as useState11 } from "react";
|
|
1442
|
-
import { Languages, Check as Check3, ChevronDown as ChevronDown5 } from "lucide-react";
|
|
1443
|
-
import { usePathname as usePathname2, useRouter as useRouter3 } from "next/navigation";
|
|
1444
|
-
|
|
1445
|
-
// src/components/config-provider.tsx
|
|
1446
|
-
import * as React3 from "react";
|
|
1447
|
-
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
1448
|
-
var ConfigContext = React3.createContext(defaultConfig);
|
|
1449
|
-
function ConfigProvider({ config, children }) {
|
|
1450
|
-
return /* @__PURE__ */ jsx26(ConfigContext.Provider, { value: config, children });
|
|
1451
|
-
}
|
|
1452
|
-
function useConfig() {
|
|
1453
|
-
const config = React3.useContext(ConfigContext);
|
|
1454
|
-
if (!config) {
|
|
1455
|
-
throw new Error("useConfig must be used within a ConfigProvider");
|
|
1456
|
-
}
|
|
1457
|
-
return config;
|
|
1458
|
-
}
|
|
1459
|
-
function useConfigValue(path) {
|
|
1460
|
-
const config = useConfig();
|
|
1461
|
-
const keys = path.split(".");
|
|
1462
|
-
let value = config;
|
|
1463
|
-
for (const key of keys) {
|
|
1464
|
-
if (value && typeof value === "object" && key in value) {
|
|
1465
|
-
value = value[key];
|
|
1466
|
-
} else {
|
|
1467
|
-
return void 0;
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
return value;
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
// src/components/docs/language-switcher.tsx
|
|
1474
|
-
import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1475
|
-
function LanguageSwitcher() {
|
|
1476
|
-
const [open, setOpen] = useState11(false);
|
|
1477
|
-
const pathname = usePathname2();
|
|
1478
|
-
const router = useRouter3();
|
|
1479
|
-
const config = useConfig();
|
|
1480
|
-
const i18n = config.features?.i18n;
|
|
1481
|
-
if (!i18n || typeof i18n === "boolean") return null;
|
|
1482
|
-
const { locales, localeNames, defaultLocale, prefixDefault } = i18n;
|
|
1483
|
-
const pathParts = pathname.split("/");
|
|
1484
|
-
const version = pathParts[2];
|
|
1485
|
-
let currentLocale = defaultLocale;
|
|
1486
|
-
if (pathParts[3] && locales.includes(pathParts[3])) {
|
|
1487
|
-
currentLocale = pathParts[3];
|
|
1488
|
-
}
|
|
1489
|
-
const handleLocaleChange = (newLocale) => {
|
|
1490
|
-
if (newLocale === currentLocale) {
|
|
1491
|
-
setOpen(false);
|
|
1492
|
-
return;
|
|
1493
|
-
}
|
|
1494
|
-
const parts = [...pathParts];
|
|
1495
|
-
const hasLocalePrefix = locales.includes(parts[3]);
|
|
1496
|
-
if (newLocale === defaultLocale && !prefixDefault) {
|
|
1497
|
-
if (hasLocalePrefix) {
|
|
1498
|
-
parts.splice(3, 1);
|
|
1499
|
-
}
|
|
1500
|
-
} else {
|
|
1501
|
-
if (hasLocalePrefix) {
|
|
1502
|
-
parts[3] = newLocale;
|
|
1503
|
-
} else {
|
|
1504
|
-
parts.splice(3, 0, newLocale);
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
const newPath = parts.join("/");
|
|
1508
|
-
router.push(newPath);
|
|
1509
|
-
setOpen(false);
|
|
1510
|
-
};
|
|
1511
|
-
return /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
|
|
1512
|
-
/* @__PURE__ */ jsxs20(
|
|
1513
|
-
"button",
|
|
1514
|
-
{
|
|
1515
|
-
onClick: () => setOpen(!open),
|
|
1516
|
-
className: "flex items-center gap-1.5 px-2 h-9 rounded-md hover:bg-muted transition-colors",
|
|
1517
|
-
"aria-label": "Switch language",
|
|
1518
|
-
children: [
|
|
1519
|
-
/* @__PURE__ */ jsx27(Languages, { className: "h-4 w-4" }),
|
|
1520
|
-
/* @__PURE__ */ jsx27("span", { className: "text-xs font-bold uppercase", children: currentLocale }),
|
|
1521
|
-
/* @__PURE__ */ jsx27(ChevronDown5, { className: "h-3 w-3 text-muted-foreground" })
|
|
1522
|
-
]
|
|
1523
|
-
}
|
|
1524
|
-
),
|
|
1525
|
-
open && /* @__PURE__ */ jsxs20(Fragment4, { children: [
|
|
1526
|
-
/* @__PURE__ */ jsx27("div", { className: "fixed inset-0 z-40", onClick: () => setOpen(false) }),
|
|
1527
|
-
/* @__PURE__ */ jsx27("div", { className: "absolute right-0 mt-2 w-40 bg-background border border-border rounded-md shadow-lg z-50", children: /* @__PURE__ */ jsx27("div", { className: "p-2", children: locales.map((locale) => /* @__PURE__ */ jsxs20(
|
|
1528
|
-
"button",
|
|
1529
|
-
{
|
|
1530
|
-
onClick: () => handleLocaleChange(locale),
|
|
1531
|
-
className: "flex items-center justify-between w-full px-3 py-2 text-sm text-foreground hover:bg-muted rounded-md transition-colors",
|
|
1532
|
-
children: [
|
|
1533
|
-
/* @__PURE__ */ jsx27("span", { children: localeNames?.[locale] || locale.toUpperCase() }),
|
|
1534
|
-
currentLocale === locale && /* @__PURE__ */ jsx27(Check3, { className: "h-4 w-4 text-primary" })
|
|
1535
|
-
]
|
|
1536
|
-
},
|
|
1537
|
-
locale
|
|
1538
|
-
)) }) })
|
|
1539
|
-
] })
|
|
1540
|
-
] });
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
// src/components/docs/theme-toggle.tsx
|
|
1544
|
-
import { Moon, Sun } from "lucide-react";
|
|
1545
|
-
import { useEffect as useEffect5, useState as useState12 } from "react";
|
|
1546
|
-
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1547
|
-
function ThemeToggle() {
|
|
1548
|
-
const [theme, setTheme] = useState12("dark");
|
|
1549
|
-
useEffect5(() => {
|
|
1550
|
-
const savedTheme = localStorage.getItem("theme");
|
|
1551
|
-
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
1552
|
-
const initialTheme = savedTheme || (prefersDark ? "dark" : "light");
|
|
1553
|
-
setTheme(initialTheme);
|
|
1554
|
-
document.documentElement.classList.toggle("dark", initialTheme === "dark");
|
|
1555
|
-
}, []);
|
|
1556
|
-
const toggleTheme = () => {
|
|
1557
|
-
const newTheme = theme === "dark" ? "light" : "dark";
|
|
1558
|
-
setTheme(newTheme);
|
|
1559
|
-
localStorage.setItem("theme", newTheme);
|
|
1560
|
-
document.documentElement.classList.toggle("dark", newTheme === "dark");
|
|
1561
|
-
};
|
|
1562
|
-
return /* @__PURE__ */ jsx28(
|
|
1563
|
-
"button",
|
|
1564
|
-
{
|
|
1565
|
-
onClick: toggleTheme,
|
|
1566
|
-
className: "flex items-center justify-center w-9 h-9 rounded-md border border-border bg-background hover:bg-accent transition-colors",
|
|
1567
|
-
"aria-label": "Toggle theme",
|
|
1568
|
-
children: theme === "dark" ? /* @__PURE__ */ jsx28(Sun, { className: "h-4 w-4 text-foreground" }) : /* @__PURE__ */ jsx28(Moon, { className: "h-4 w-4 text-foreground" })
|
|
1569
|
-
}
|
|
1570
|
-
);
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// src/components/docs/search-modal.tsx
|
|
1574
|
-
import { useState as useState13, useEffect as useEffect6, useCallback } from "react";
|
|
1575
|
-
import { Search, FileText, Loader2 } from "lucide-react";
|
|
1576
|
-
import { useRouter as useRouter4 } from "next/navigation";
|
|
1577
|
-
|
|
1578
|
-
// src/components/ui/dialog.tsx
|
|
1579
|
-
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
1580
|
-
import { XIcon } from "lucide-react";
|
|
1581
|
-
|
|
1582
|
-
// src/lib/utils.ts
|
|
1583
|
-
import { clsx } from "clsx";
|
|
1584
|
-
import { twMerge } from "tailwind-merge";
|
|
1585
|
-
function cn(...inputs) {
|
|
1586
|
-
return twMerge(clsx(inputs));
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
// src/components/ui/dialog.tsx
|
|
1590
|
-
import { jsx as jsx29, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1591
|
-
function Dialog({
|
|
1592
|
-
...props
|
|
1593
|
-
}) {
|
|
1594
|
-
return /* @__PURE__ */ jsx29(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
1595
|
-
}
|
|
1596
|
-
function DialogTrigger({
|
|
1597
|
-
...props
|
|
1598
|
-
}) {
|
|
1599
|
-
return /* @__PURE__ */ jsx29(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
|
|
1600
|
-
}
|
|
1601
|
-
function DialogPortal({
|
|
1602
|
-
...props
|
|
1603
|
-
}) {
|
|
1604
|
-
return /* @__PURE__ */ jsx29(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
|
|
1605
|
-
}
|
|
1606
|
-
function DialogClose({
|
|
1607
|
-
...props
|
|
1608
|
-
}) {
|
|
1609
|
-
return /* @__PURE__ */ jsx29(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
|
|
1610
|
-
}
|
|
1611
|
-
function DialogOverlay({
|
|
1612
|
-
className,
|
|
1613
|
-
...props
|
|
1614
|
-
}) {
|
|
1615
|
-
return /* @__PURE__ */ jsx29(
|
|
1616
|
-
DialogPrimitive.Overlay,
|
|
1617
|
-
{
|
|
1618
|
-
"data-slot": "dialog-overlay",
|
|
1619
|
-
className: cn(
|
|
1620
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 dark:bg-black/70 backdrop-blur-md",
|
|
1621
|
-
className
|
|
1622
|
-
),
|
|
1623
|
-
...props
|
|
1624
|
-
}
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1627
|
-
function DialogContent({
|
|
1628
|
-
className,
|
|
1629
|
-
children,
|
|
1630
|
-
showCloseButton = true,
|
|
1631
|
-
...props
|
|
1632
|
-
}) {
|
|
1633
|
-
return /* @__PURE__ */ jsxs21(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
1634
|
-
/* @__PURE__ */ jsx29(DialogOverlay, {}),
|
|
1635
|
-
/* @__PURE__ */ jsxs21(
|
|
1636
|
-
DialogPrimitive.Content,
|
|
1637
|
-
{
|
|
1638
|
-
"data-slot": "dialog-content",
|
|
1639
|
-
className: cn(
|
|
1640
|
-
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
|
|
1641
|
-
className
|
|
1642
|
-
),
|
|
1643
|
-
...props,
|
|
1644
|
-
children: [
|
|
1645
|
-
children,
|
|
1646
|
-
showCloseButton && /* @__PURE__ */ jsxs21(
|
|
1647
|
-
DialogPrimitive.Close,
|
|
1648
|
-
{
|
|
1649
|
-
"data-slot": "dialog-close",
|
|
1650
|
-
className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1651
|
-
children: [
|
|
1652
|
-
/* @__PURE__ */ jsx29(XIcon, {}),
|
|
1653
|
-
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Close" })
|
|
1654
|
-
]
|
|
1655
|
-
}
|
|
1656
|
-
)
|
|
1657
|
-
]
|
|
1658
|
-
}
|
|
1659
|
-
)
|
|
1660
|
-
] });
|
|
1661
|
-
}
|
|
1662
|
-
function DialogHeader({ className, ...props }) {
|
|
1663
|
-
return /* @__PURE__ */ jsx29(
|
|
1664
|
-
"div",
|
|
1665
|
-
{
|
|
1666
|
-
"data-slot": "dialog-header",
|
|
1667
|
-
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
1668
|
-
...props
|
|
1669
|
-
}
|
|
1670
|
-
);
|
|
1671
|
-
}
|
|
1672
|
-
function DialogFooter({ className, ...props }) {
|
|
1673
|
-
return /* @__PURE__ */ jsx29(
|
|
1674
|
-
"div",
|
|
1675
|
-
{
|
|
1676
|
-
"data-slot": "dialog-footer",
|
|
1677
|
-
className: cn(
|
|
1678
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
1679
|
-
className
|
|
1680
|
-
),
|
|
1681
|
-
...props
|
|
1682
|
-
}
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
|
-
function DialogTitle({
|
|
1686
|
-
className,
|
|
1687
|
-
...props
|
|
1688
|
-
}) {
|
|
1689
|
-
return /* @__PURE__ */ jsx29(
|
|
1690
|
-
DialogPrimitive.Title,
|
|
1691
|
-
{
|
|
1692
|
-
"data-slot": "dialog-title",
|
|
1693
|
-
className: cn("text-lg leading-none font-semibold", className),
|
|
1694
|
-
...props
|
|
1695
|
-
}
|
|
1696
|
-
);
|
|
1697
|
-
}
|
|
1698
|
-
function DialogDescription({
|
|
1699
|
-
className,
|
|
1700
|
-
...props
|
|
1701
|
-
}) {
|
|
1702
|
-
return /* @__PURE__ */ jsx29(
|
|
1703
|
-
DialogPrimitive.Description,
|
|
1704
|
-
{
|
|
1705
|
-
"data-slot": "dialog-description",
|
|
1706
|
-
className: cn("text-muted-foreground text-sm", className),
|
|
1707
|
-
...props
|
|
1708
|
-
}
|
|
1709
|
-
);
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
// src/components/docs/search-modal.tsx
|
|
1713
|
-
import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1714
|
-
function SearchModal({ isOpen, onClose, config }) {
|
|
1715
|
-
const [query, setQuery] = useState13("");
|
|
1716
|
-
const [results, setResults] = useState13([]);
|
|
1717
|
-
const [isLoading, setIsLoading] = useState13(false);
|
|
1718
|
-
const [selectedIndex, setSelectedIndex] = useState13(0);
|
|
1719
|
-
const router = useRouter4();
|
|
1720
|
-
const searchConfig = config.search;
|
|
1721
|
-
const performSearch = useCallback(async (searchQuery) => {
|
|
1722
|
-
if (!searchQuery.trim() || !searchConfig?.enabled) {
|
|
1723
|
-
setResults([]);
|
|
1724
|
-
return;
|
|
1725
|
-
}
|
|
1726
|
-
setIsLoading(true);
|
|
1727
|
-
try {
|
|
1728
|
-
const response = await fetch("/api/search", {
|
|
1729
|
-
method: "POST",
|
|
1730
|
-
headers: { "Content-Type": "application/json" },
|
|
1731
|
-
body: JSON.stringify({
|
|
1732
|
-
query: searchQuery,
|
|
1733
|
-
// filter: 'version = "v1.0.0"',
|
|
1734
|
-
distinct: "version",
|
|
1735
|
-
limit: 2
|
|
1736
|
-
})
|
|
1737
|
-
});
|
|
1738
|
-
if (response.ok) {
|
|
1739
|
-
const data = await response.json();
|
|
1740
|
-
console.log("Search response:", data);
|
|
1741
|
-
setResults(data.hits || []);
|
|
1742
|
-
} else {
|
|
1743
|
-
console.error("Search failed:", response.status, await response.text());
|
|
1744
|
-
}
|
|
1745
|
-
} catch (error) {
|
|
1746
|
-
console.error("Search error:", error);
|
|
1747
|
-
setResults([]);
|
|
1748
|
-
} finally {
|
|
1749
|
-
setIsLoading(false);
|
|
1750
|
-
}
|
|
1751
|
-
}, [searchConfig]);
|
|
1752
|
-
useEffect6(() => {
|
|
1753
|
-
const timer = setTimeout(() => {
|
|
1754
|
-
performSearch(query);
|
|
1755
|
-
}, 300);
|
|
1756
|
-
return () => clearTimeout(timer);
|
|
1757
|
-
}, [query, performSearch]);
|
|
1758
|
-
useEffect6(() => {
|
|
1759
|
-
const handleKeyDown = (e) => {
|
|
1760
|
-
if (!isOpen) return;
|
|
1761
|
-
switch (e.key) {
|
|
1762
|
-
case "Escape":
|
|
1763
|
-
onClose();
|
|
1764
|
-
break;
|
|
1765
|
-
case "ArrowDown":
|
|
1766
|
-
e.preventDefault();
|
|
1767
|
-
setSelectedIndex((prev) => Math.min(prev + 1, results.length - 1));
|
|
1768
|
-
break;
|
|
1769
|
-
case "ArrowUp":
|
|
1770
|
-
e.preventDefault();
|
|
1771
|
-
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
|
1772
|
-
break;
|
|
1773
|
-
case "Enter":
|
|
1774
|
-
e.preventDefault();
|
|
1775
|
-
if (results[selectedIndex]) {
|
|
1776
|
-
handleResultClick(results[selectedIndex]);
|
|
1777
|
-
}
|
|
1778
|
-
break;
|
|
1779
|
-
}
|
|
1780
|
-
};
|
|
1781
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1782
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1783
|
-
}, [isOpen, results, selectedIndex, onClose]);
|
|
1784
|
-
useEffect6(() => {
|
|
1785
|
-
if (isOpen) {
|
|
1786
|
-
setQuery("");
|
|
1787
|
-
setResults([]);
|
|
1788
|
-
setSelectedIndex(0);
|
|
1789
|
-
}
|
|
1790
|
-
}, [isOpen]);
|
|
1791
|
-
const handleResultClick = (result) => {
|
|
1792
|
-
const params = new URLSearchParams();
|
|
1793
|
-
params.set("q", query);
|
|
1794
|
-
if (result.tab_group) {
|
|
1795
|
-
params.set("tab", result.tab_group);
|
|
1796
|
-
}
|
|
1797
|
-
const url = `/docs/${result.version}/${result.slug}?${params.toString()}`;
|
|
1798
|
-
router.push(url);
|
|
1799
|
-
onClose();
|
|
1800
|
-
};
|
|
1801
|
-
const highlightText = (text, query2) => {
|
|
1802
|
-
if (!query2.trim()) return text;
|
|
1803
|
-
const parts = text.split(new RegExp(`(${query2})`, "gi"));
|
|
1804
|
-
return parts.map(
|
|
1805
|
-
(part, i) => part.toLowerCase() === query2.toLowerCase() ? /* @__PURE__ */ jsx30("mark", { className: "bg-yellow-200 dark:bg-yellow-900/50 text-foreground", children: part }, i) : part
|
|
1806
|
-
);
|
|
1807
|
-
};
|
|
1808
|
-
return /* @__PURE__ */ jsx30(Dialog, { open: isOpen, onOpenChange: onClose, modal: true, children: /* @__PURE__ */ jsxs22(
|
|
1809
|
-
DialogContent,
|
|
1810
|
-
{
|
|
1811
|
-
className: "max-w-2xl p-0 gap-0 top-[10vh] translate-y-0",
|
|
1812
|
-
showCloseButton: false,
|
|
1813
|
-
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
1814
|
-
children: [
|
|
1815
|
-
/* @__PURE__ */ jsx30(DialogTitle, { className: "sr-only", children: "Search Documentation" }),
|
|
1816
|
-
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border", children: [
|
|
1817
|
-
/* @__PURE__ */ jsx30(Search, { className: "h-5 w-5 text-muted-foreground shrink-0" }),
|
|
1818
|
-
/* @__PURE__ */ jsx30(
|
|
1819
|
-
"input",
|
|
1820
|
-
{
|
|
1821
|
-
type: "text",
|
|
1822
|
-
value: query,
|
|
1823
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1824
|
-
placeholder: searchConfig?.placeholder || "Search documentation...",
|
|
1825
|
-
className: "flex-1 bg-transparent border-none outline-none text-foreground placeholder:text-muted-foreground",
|
|
1826
|
-
autoFocus: true
|
|
1827
|
-
}
|
|
1828
|
-
),
|
|
1829
|
-
isLoading && /* @__PURE__ */ jsx30(Loader2, { className: "h-5 w-5 text-muted-foreground animate-spin" })
|
|
1830
|
-
] }),
|
|
1831
|
-
/* @__PURE__ */ jsxs22("div", { className: "max-h-[60vh] overflow-y-auto", children: [
|
|
1832
|
-
query.trim() && results.length === 0 && !isLoading && /* @__PURE__ */ jsxs22("div", { className: "px-4 py-8 text-center text-muted-foreground", children: [
|
|
1833
|
-
'No results found for "',
|
|
1834
|
-
query,
|
|
1835
|
-
'"'
|
|
1836
|
-
] }),
|
|
1837
|
-
results.length > 0 && /* @__PURE__ */ jsx30("div", { className: "py-2", children: results.map((result, index) => /* @__PURE__ */ jsx30(
|
|
1838
|
-
"button",
|
|
1839
|
-
{
|
|
1840
|
-
onClick: () => handleResultClick(result),
|
|
1841
|
-
className: `w-full px-4 py-3 text-left hover:bg-muted/50 transition-colors border-l-2 ${index === selectedIndex ? "bg-muted/50 border-primary" : "border-transparent"}`,
|
|
1842
|
-
onMouseEnter: () => setSelectedIndex(index),
|
|
1843
|
-
children: /* @__PURE__ */ jsxs22("div", { className: "flex items-start gap-3", children: [
|
|
1844
|
-
/* @__PURE__ */ jsx30(FileText, { className: "h-5 w-5 text-muted-foreground shrink-0 mt-0.5" }),
|
|
1845
|
-
/* @__PURE__ */ jsxs22("div", { className: "flex-1 min-w-0", children: [
|
|
1846
|
-
/* @__PURE__ */ jsx30("div", { className: "font-medium text-foreground mb-1", children: highlightText(result.title, query) }),
|
|
1847
|
-
result.content && /* @__PURE__ */ jsx30("div", { className: "text-sm text-muted-foreground line-clamp-2", children: highlightText(result.content, query) }),
|
|
1848
|
-
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2 mt-1 text-xs text-muted-foreground", children: [
|
|
1849
|
-
/* @__PURE__ */ jsx30("span", { children: result.version }),
|
|
1850
|
-
result.category && /* @__PURE__ */ jsxs22(Fragment5, { children: [
|
|
1851
|
-
/* @__PURE__ */ jsx30("span", { children: "\u2022" }),
|
|
1852
|
-
/* @__PURE__ */ jsx30("span", { children: result.category })
|
|
1853
|
-
] })
|
|
1854
|
-
] })
|
|
1855
|
-
] })
|
|
1856
|
-
] })
|
|
1857
|
-
},
|
|
1858
|
-
result.id
|
|
1859
|
-
)) }),
|
|
1860
|
-
!query.trim() && /* @__PURE__ */ jsxs22("div", { className: "px-4 py-8 text-center text-muted-foreground text-sm", children: [
|
|
1861
|
-
/* @__PURE__ */ jsx30("p", { children: "Start typing to search documentation..." }),
|
|
1862
|
-
/* @__PURE__ */ jsxs22("div", { className: "mt-4 flex items-center justify-center gap-4 text-xs", children: [
|
|
1863
|
-
/* @__PURE__ */ jsx30("kbd", { className: "px-2 py-1 bg-muted rounded border border-border", children: "\u2191\u2193" }),
|
|
1864
|
-
/* @__PURE__ */ jsx30("span", { children: "Navigate" }),
|
|
1865
|
-
/* @__PURE__ */ jsx30("kbd", { className: "px-2 py-1 bg-muted rounded border border-border", children: "Enter" }),
|
|
1866
|
-
/* @__PURE__ */ jsx30("span", { children: "Select" }),
|
|
1867
|
-
/* @__PURE__ */ jsx30("kbd", { className: "px-2 py-1 bg-muted rounded border border-border", children: "Esc" }),
|
|
1868
|
-
/* @__PURE__ */ jsx30("span", { children: "Close" })
|
|
1869
|
-
] })
|
|
1870
|
-
] })
|
|
1871
|
-
] })
|
|
1872
|
-
]
|
|
1873
|
-
}
|
|
1874
|
-
) });
|
|
1875
|
-
}
|
|
1876
|
-
|
|
1877
|
-
// src/components/docs/header.tsx
|
|
1878
|
-
import { useState as useState14, useEffect as useEffect7 } from "react";
|
|
1879
|
-
import { jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1880
|
-
function Header({ currentVersion, versions, onMenuClick, config: configProp }) {
|
|
1881
|
-
const contextConfig = useConfig();
|
|
1882
|
-
const config = configProp || contextConfig;
|
|
1883
|
-
const [searchOpen, setSearchOpen] = useState14(false);
|
|
1884
|
-
useEffect7(() => {
|
|
1885
|
-
const handleKeyDown = (e) => {
|
|
1886
|
-
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
1887
|
-
e.preventDefault();
|
|
1888
|
-
setSearchOpen(true);
|
|
1889
|
-
}
|
|
1890
|
-
};
|
|
1891
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1892
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1893
|
-
}, []);
|
|
1894
|
-
return /* @__PURE__ */ jsxs23("header", { className: "sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60", children: [
|
|
1895
|
-
/* @__PURE__ */ jsxs23("div", { className: "container flex h-16 items-center justify-between px-2 md:px-6 mx-auto", children: [
|
|
1896
|
-
/* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1", children: [
|
|
1897
|
-
/* @__PURE__ */ jsx31(
|
|
1898
|
-
"button",
|
|
1899
|
-
{
|
|
1900
|
-
onClick: onMenuClick,
|
|
1901
|
-
className: "lg:hidden hover:bg-muted p-2 rounded-md transition-colors",
|
|
1902
|
-
"aria-label": "Toggle menu",
|
|
1903
|
-
children: /* @__PURE__ */ jsx31(Menu, { className: "h-5 w-5" })
|
|
1904
|
-
}
|
|
1905
|
-
),
|
|
1906
|
-
/* @__PURE__ */ jsxs23(Link7, { href: "/", className: "flex items-center gap-2", children: [
|
|
1907
|
-
!config.site.hideLogo && (config.site.logo ? /* @__PURE__ */ jsx31(Logo, { logo: config.site.logo, alt: config.site.title, className: "h-12 w-auto object-contain" }) : /* @__PURE__ */ jsx31("div", { className: "h-8 w-8 rounded-xl bg-primary flex items-center justify-center", children: /* @__PURE__ */ jsx31("span", { className: "text-primary-foreground font-bold text-lg", children: config.site.title.charAt(0).toUpperCase() }) })),
|
|
1908
|
-
!config.site.hideTitle && /* @__PURE__ */ jsx31("span", { className: "font-semibold text-lg text-foreground", children: config.site.title ?? "Specra" })
|
|
1909
|
-
] })
|
|
1910
|
-
] }),
|
|
1911
|
-
/* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
|
|
1912
|
-
config.search?.enabled && /* @__PURE__ */ jsxs23(
|
|
1913
|
-
"button",
|
|
1914
|
-
{
|
|
1915
|
-
onClick: () => setSearchOpen(true),
|
|
1916
|
-
className: "flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground hover:text-foreground bg-muted rounded-md transition-colors",
|
|
1917
|
-
children: [
|
|
1918
|
-
/* @__PURE__ */ jsx31(Search2, { className: "h-4 w-4" }),
|
|
1919
|
-
/* @__PURE__ */ jsx31("span", { className: "hidden sm:inline", children: config.search.placeholder || "Search" }),
|
|
1920
|
-
/* @__PURE__ */ jsx31("kbd", { className: "hidden sm:inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-background px-1.5 font-mono text-xs font-medium", children: "\u2318K" })
|
|
1921
|
-
]
|
|
1922
|
-
}
|
|
1923
|
-
),
|
|
1924
|
-
config.features?.versioning && /* @__PURE__ */ jsx31(VersionSwitcher, { currentVersion, versions }),
|
|
1925
|
-
config.social?.github && /* @__PURE__ */ jsx31(
|
|
1926
|
-
"a",
|
|
1927
|
-
{
|
|
1928
|
-
href: config.social.github,
|
|
1929
|
-
target: "_blank",
|
|
1930
|
-
rel: "noopener noreferrer",
|
|
1931
|
-
className: "hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors",
|
|
1932
|
-
"aria-label": "GitHub",
|
|
1933
|
-
children: /* @__PURE__ */ jsx31(Github, { className: "h-4 w-4" })
|
|
1934
|
-
}
|
|
1935
|
-
),
|
|
1936
|
-
config.social?.twitter && /* @__PURE__ */ jsx31(
|
|
1937
|
-
"a",
|
|
1938
|
-
{
|
|
1939
|
-
href: config.social.twitter,
|
|
1940
|
-
target: "_blank",
|
|
1941
|
-
rel: "noopener noreferrer",
|
|
1942
|
-
className: "hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors",
|
|
1943
|
-
"aria-label": "Twitter",
|
|
1944
|
-
children: /* @__PURE__ */ jsx31(Twitter, { className: "h-4 w-4" })
|
|
1945
|
-
}
|
|
1946
|
-
),
|
|
1947
|
-
config.social?.discord && /* @__PURE__ */ jsx31(
|
|
1948
|
-
"a",
|
|
1949
|
-
{
|
|
1950
|
-
href: config.social.discord,
|
|
1951
|
-
target: "_blank",
|
|
1952
|
-
rel: "noopener noreferrer",
|
|
1953
|
-
className: "hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors",
|
|
1954
|
-
"aria-label": "Discord",
|
|
1955
|
-
children: /* @__PURE__ */ jsx31(MessageCircle, { className: "h-4 w-4" })
|
|
1956
|
-
}
|
|
1957
|
-
),
|
|
1958
|
-
/* @__PURE__ */ jsx31(ThemeToggle, {}),
|
|
1959
|
-
/* @__PURE__ */ jsx31(LanguageSwitcher, {})
|
|
1960
|
-
] })
|
|
1961
|
-
] }),
|
|
1962
|
-
/* @__PURE__ */ jsx31(SearchModal, { isOpen: searchOpen, onClose: () => setSearchOpen(false), config })
|
|
1963
|
-
] });
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
// src/components/docs/hot-reload-indicator.tsx
|
|
1967
|
-
import { useEffect as useEffect8, useState as useState15 } from "react";
|
|
1968
|
-
import { usePathname as usePathname3 } from "next/navigation";
|
|
1969
|
-
import { RefreshCw } from "lucide-react";
|
|
1970
|
-
import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1971
|
-
function HotReloadIndicator() {
|
|
1972
|
-
const [isReloading, setIsReloading] = useState15(false);
|
|
1973
|
-
const [lastReload, setLastReload] = useState15(null);
|
|
1974
|
-
const pathname = usePathname3();
|
|
1975
|
-
useEffect8(() => {
|
|
1976
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
1977
|
-
setIsReloading(true);
|
|
1978
|
-
const timer = setTimeout(() => {
|
|
1979
|
-
setIsReloading(false);
|
|
1980
|
-
setLastReload(/* @__PURE__ */ new Date());
|
|
1981
|
-
setTimeout(() => {
|
|
1982
|
-
setLastReload(null);
|
|
1983
|
-
}, 3e3);
|
|
1984
|
-
}, 500);
|
|
1985
|
-
return () => clearTimeout(timer);
|
|
1986
|
-
}, [pathname]);
|
|
1987
|
-
useEffect8(() => {
|
|
1988
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
1989
|
-
const handleBeforeRefresh = () => {
|
|
1990
|
-
setIsReloading(true);
|
|
1991
|
-
};
|
|
1992
|
-
const handleAfterRefresh = () => {
|
|
1993
|
-
setIsReloading(false);
|
|
1994
|
-
setLastReload(/* @__PURE__ */ new Date());
|
|
1995
|
-
setTimeout(() => setLastReload(null), 3e3);
|
|
1996
|
-
};
|
|
1997
|
-
if (typeof window !== "undefined" && window.__NEXT_DATA__) {
|
|
1998
|
-
window.addEventListener("beforeunload", handleBeforeRefresh);
|
|
1999
|
-
}
|
|
2000
|
-
return () => {
|
|
2001
|
-
window.removeEventListener("beforeunload", handleBeforeRefresh);
|
|
2002
|
-
};
|
|
2003
|
-
}, []);
|
|
2004
|
-
if (process.env.NODE_ENV !== "development") return null;
|
|
2005
|
-
return /* @__PURE__ */ jsxs24(Fragment6, { children: [
|
|
2006
|
-
isReloading && /* @__PURE__ */ jsxs24("div", { className: "fixed bottom-4 right-4 z-50 flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-xl shadow-lg animate-in slide-in-from-bottom-2", children: [
|
|
2007
|
-
/* @__PURE__ */ jsx32(RefreshCw, { className: "h-4 w-4 animate-spin" }),
|
|
2008
|
-
/* @__PURE__ */ jsx32("span", { className: "text-sm font-medium", children: "Reloading..." })
|
|
2009
|
-
] }),
|
|
2010
|
-
lastReload && !isReloading && /* @__PURE__ */ jsxs24("div", { className: "fixed bottom-4 right-4 z-50 flex items-center gap-2 px-4 py-2 bg-green-500 text-white rounded-xl shadow-lg animate-in slide-in-from-bottom-2", children: [
|
|
2011
|
-
/* @__PURE__ */ jsx32(RefreshCw, { className: "h-4 w-4" }),
|
|
2012
|
-
/* @__PURE__ */ jsxs24("span", { className: "text-sm font-medium", children: [
|
|
2013
|
-
"Updated at ",
|
|
2014
|
-
lastReload.toLocaleTimeString()
|
|
2015
|
-
] })
|
|
2016
|
-
] })
|
|
2017
|
-
] });
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
// src/components/docs/image-card.tsx
|
|
2021
|
-
import NextImage from "next/image";
|
|
2022
|
-
import Link8 from "next/link";
|
|
2023
|
-
import { jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2024
|
-
function ImageCard({
|
|
2025
|
-
src,
|
|
2026
|
-
alt,
|
|
2027
|
-
title,
|
|
2028
|
-
description,
|
|
2029
|
-
href,
|
|
2030
|
-
external = false,
|
|
2031
|
-
aspectRatio = "video"
|
|
2032
|
-
}) {
|
|
2033
|
-
const aspectRatios = {
|
|
2034
|
-
square: "aspect-square",
|
|
2035
|
-
video: "aspect-video",
|
|
2036
|
-
portrait: "aspect-[3/4]"
|
|
2037
|
-
};
|
|
2038
|
-
const content = /* @__PURE__ */ jsxs25("div", { className: "flex flex-col gap-0 p-0", children: [
|
|
2039
|
-
/* @__PURE__ */ jsx33("div", { className: `w-full ${aspectRatios[aspectRatio]} overflow-hidden ${title || description ? "rounded-t-xl" : "rounded-xl"} bg-muted relative`, children: /* @__PURE__ */ jsx33(
|
|
2040
|
-
NextImage,
|
|
2041
|
-
{
|
|
2042
|
-
src,
|
|
2043
|
-
alt,
|
|
2044
|
-
fill: true,
|
|
2045
|
-
sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw",
|
|
2046
|
-
className: "object-cover transition-transform duration-300 group-hover:scale-105"
|
|
2047
|
-
}
|
|
2048
|
-
) }),
|
|
2049
|
-
(title || description) && /* @__PURE__ */ jsxs25("div", { className: "p-3 flex flex-col gap-1", children: [
|
|
2050
|
-
title && /* @__PURE__ */ jsx33("h3", { className: `font-semibold text-foreground mb-0 no-underline ${href ? "group-hover:text-primary transition-colors" : ""}`, children: title }),
|
|
2051
|
-
description && /* @__PURE__ */ jsx33("p", { className: "text-sm text-muted-foreground line-clamp-2 no-underline mb-0", children: description })
|
|
2052
|
-
] })
|
|
2053
|
-
] });
|
|
2054
|
-
if (href) {
|
|
2055
|
-
const Component = external ? "a" : Link8;
|
|
2056
|
-
return /* @__PURE__ */ jsx33(
|
|
2057
|
-
Component,
|
|
2058
|
-
{
|
|
2059
|
-
href,
|
|
2060
|
-
className: "image-card-link group block rounded-xl border border-border hover:border-primary/50 hover:shadow-lg transition-all overflow-hidden p-0",
|
|
2061
|
-
...external ? { target: "_blank", rel: "noopener noreferrer" } : {},
|
|
2062
|
-
children: content
|
|
2063
|
-
}
|
|
2064
|
-
);
|
|
2065
|
-
}
|
|
2066
|
-
return /* @__PURE__ */ jsx33("div", { className: "block rounded-xl border border-border overflow-hidden bg-card p-0", children: content });
|
|
2067
|
-
}
|
|
2068
|
-
function ImageCardGrid({ children, cols = 3 }) {
|
|
2069
|
-
const gridCols = {
|
|
2070
|
-
1: "grid-cols-1",
|
|
2071
|
-
2: "grid-cols-1 md:grid-cols-2",
|
|
2072
|
-
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
|
2073
|
-
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
|
|
2074
|
-
};
|
|
2075
|
-
return /* @__PURE__ */ jsx33("div", { className: `grid ${gridCols[cols]} gap-4 my-6`, children });
|
|
2076
|
-
}
|
|
2077
|
-
|
|
2078
|
-
// src/components/docs/image.tsx
|
|
2079
|
-
import NextImage2 from "next/image";
|
|
2080
|
-
import { useState as useState16 } from "react";
|
|
2081
|
-
import { ZoomIn, X as X2 } from "lucide-react";
|
|
2082
|
-
import { Fragment as Fragment7, jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2083
|
-
function Image({ src, alt, caption, width, height, zoom = true }) {
|
|
2084
|
-
const [isZoomed, setIsZoomed] = useState16(false);
|
|
2085
|
-
return /* @__PURE__ */ jsxs26(Fragment7, { children: [
|
|
2086
|
-
/* @__PURE__ */ jsxs26("figure", { className: "my-6", children: [
|
|
2087
|
-
/* @__PURE__ */ jsxs26("div", { className: "relative group rounded-xl border border-border overflow-hidden bg-muted/30", children: [
|
|
2088
|
-
/* @__PURE__ */ jsx34(
|
|
2089
|
-
NextImage2,
|
|
2090
|
-
{
|
|
2091
|
-
src,
|
|
2092
|
-
alt,
|
|
2093
|
-
width: width || 1200,
|
|
2094
|
-
height: height || 675,
|
|
2095
|
-
className: "w-full h-auto"
|
|
2096
|
-
}
|
|
2097
|
-
),
|
|
2098
|
-
zoom && /* @__PURE__ */ jsx34(
|
|
2099
|
-
"button",
|
|
2100
|
-
{
|
|
2101
|
-
onClick: () => setIsZoomed(true),
|
|
2102
|
-
className: "absolute top-3 right-3 p-2 rounded-md bg-background/80 backdrop-blur-sm border border-border opacity-0 group-hover:opacity-100 transition-opacity hover:bg-background",
|
|
2103
|
-
"aria-label": "Zoom image",
|
|
2104
|
-
children: /* @__PURE__ */ jsx34(ZoomIn, { className: "h-4 w-4 text-foreground" })
|
|
2105
|
-
}
|
|
2106
|
-
)
|
|
2107
|
-
] }),
|
|
2108
|
-
caption && /* @__PURE__ */ jsx34("figcaption", { className: "mt-2 text-center text-sm text-muted-foreground italic", children: caption })
|
|
2109
|
-
] }),
|
|
2110
|
-
isZoomed && /* @__PURE__ */ jsxs26(
|
|
2111
|
-
"div",
|
|
2112
|
-
{
|
|
2113
|
-
className: "fixed inset-0 z-50 bg-background/95 backdrop-blur-sm flex items-center justify-center p-4",
|
|
2114
|
-
onClick: () => setIsZoomed(false),
|
|
2115
|
-
children: [
|
|
2116
|
-
/* @__PURE__ */ jsx34(
|
|
2117
|
-
"button",
|
|
2118
|
-
{
|
|
2119
|
-
onClick: () => setIsZoomed(false),
|
|
2120
|
-
className: "absolute top-4 right-4 p-2 rounded-md bg-muted hover:bg-muted/80 transition-colors",
|
|
2121
|
-
"aria-label": "Close",
|
|
2122
|
-
children: /* @__PURE__ */ jsx34(X2, { className: "h-5 w-5 text-foreground" })
|
|
2123
|
-
}
|
|
2124
|
-
),
|
|
2125
|
-
/* @__PURE__ */ jsx34("div", { className: "max-w-7xl max-h-[90vh] overflow-auto", children: /* @__PURE__ */ jsx34(
|
|
2126
|
-
NextImage2,
|
|
2127
|
-
{
|
|
2128
|
-
src,
|
|
2129
|
-
alt,
|
|
2130
|
-
width: width || 1920,
|
|
2131
|
-
height: height || 1080,
|
|
2132
|
-
className: "w-full h-auto"
|
|
2133
|
-
}
|
|
2134
|
-
) })
|
|
2135
|
-
]
|
|
2136
|
-
}
|
|
2137
|
-
)
|
|
2138
|
-
] });
|
|
2139
|
-
}
|
|
2140
|
-
|
|
2141
|
-
// src/components/docs/math.tsx
|
|
2142
|
-
import { useEffect as useEffect9, useRef as useRef2 } from "react";
|
|
2143
|
-
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
2144
|
-
function Math2({ children, block = false }) {
|
|
2145
|
-
const containerRef = useRef2(null);
|
|
2146
|
-
useEffect9(() => {
|
|
2147
|
-
const renderMath = async () => {
|
|
2148
|
-
try {
|
|
2149
|
-
const katex = (await import("katex")).default;
|
|
2150
|
-
if (containerRef.current) {
|
|
2151
|
-
katex.render(children, containerRef.current, {
|
|
2152
|
-
throwOnError: false,
|
|
2153
|
-
displayMode: block
|
|
2154
|
-
});
|
|
2155
|
-
}
|
|
2156
|
-
} catch (err) {
|
|
2157
|
-
console.error("KaTeX rendering error:", err);
|
|
2158
|
-
if (containerRef.current) {
|
|
2159
|
-
containerRef.current.textContent = children;
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
};
|
|
2163
|
-
renderMath();
|
|
2164
|
-
}, [children, block]);
|
|
2165
|
-
if (block) {
|
|
2166
|
-
return /* @__PURE__ */ jsx35(
|
|
2167
|
-
"div",
|
|
2168
|
-
{
|
|
2169
|
-
ref: containerRef,
|
|
2170
|
-
className: "my-6 overflow-x-auto text-center"
|
|
2171
|
-
}
|
|
2172
|
-
);
|
|
2173
|
-
}
|
|
2174
|
-
return /* @__PURE__ */ jsx35("span", { ref: containerRef, className: "inline-block" });
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
|
-
// src/components/docs/mdx-hot-reload.tsx
|
|
2178
|
-
import { useEffect as useEffect10 } from "react";
|
|
2179
|
-
import { useRouter as useRouter5 } from "next/navigation";
|
|
2180
|
-
function MdxHotReload() {
|
|
2181
|
-
const router = useRouter5();
|
|
2182
|
-
useEffect10(() => {
|
|
2183
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
2184
|
-
const eventSource = new EventSource("/api/mdx-watch");
|
|
2185
|
-
eventSource.onmessage = (event) => {
|
|
2186
|
-
const data = JSON.parse(event.data);
|
|
2187
|
-
if (data.type === "change") {
|
|
2188
|
-
console.log("[MDX Hot Reload] File changed:", data.file);
|
|
2189
|
-
router.refresh();
|
|
2190
|
-
} else if (data.type === "connected") {
|
|
2191
|
-
console.log("[MDX Hot Reload] Watching for changes...");
|
|
2192
|
-
}
|
|
2193
|
-
};
|
|
2194
|
-
eventSource.onerror = (error) => {
|
|
2195
|
-
console.error("[MDX Hot Reload] Connection error:", error);
|
|
2196
|
-
eventSource.close();
|
|
2197
|
-
};
|
|
2198
|
-
return () => {
|
|
2199
|
-
eventSource.close();
|
|
2200
|
-
};
|
|
2201
|
-
}, [router]);
|
|
2202
|
-
return null;
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
// src/components/docs/mermaid.tsx
|
|
2206
|
-
import { useEffect as useEffect11, useRef as useRef3, useState as useState17 } from "react";
|
|
2207
|
-
import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2208
|
-
function Mermaid({ chart, caption }) {
|
|
2209
|
-
const containerRef = useRef3(null);
|
|
2210
|
-
const [error, setError] = useState17(null);
|
|
2211
|
-
useEffect11(() => {
|
|
2212
|
-
const renderChart = async () => {
|
|
2213
|
-
try {
|
|
2214
|
-
const mermaid = (await import("mermaid")).default;
|
|
2215
|
-
mermaid.initialize({
|
|
2216
|
-
startOnLoad: false,
|
|
2217
|
-
theme: document.documentElement.classList.contains("dark") ? "dark" : "default",
|
|
2218
|
-
securityLevel: "loose",
|
|
2219
|
-
fontFamily: "inherit"
|
|
2220
|
-
});
|
|
2221
|
-
if (containerRef.current) {
|
|
2222
|
-
const id = `mermaid-${Math.random().toString(36).substr(2, 9)}`;
|
|
2223
|
-
const { svg } = await mermaid.render(id, chart);
|
|
2224
|
-
containerRef.current.innerHTML = svg;
|
|
2225
|
-
}
|
|
2226
|
-
} catch (err) {
|
|
2227
|
-
console.error("Mermaid rendering error:", err);
|
|
2228
|
-
setError(err instanceof Error ? err.message : "Failed to render diagram");
|
|
2229
|
-
}
|
|
2230
|
-
};
|
|
2231
|
-
renderChart();
|
|
2232
|
-
const observer = new MutationObserver((mutations) => {
|
|
2233
|
-
mutations.forEach((mutation) => {
|
|
2234
|
-
if (mutation.attributeName === "class") {
|
|
2235
|
-
renderChart();
|
|
2236
|
-
}
|
|
2237
|
-
});
|
|
2238
|
-
});
|
|
2239
|
-
observer.observe(document.documentElement, { attributes: true });
|
|
2240
|
-
return () => observer.disconnect();
|
|
2241
|
-
}, [chart]);
|
|
2242
|
-
if (error) {
|
|
2243
|
-
return /* @__PURE__ */ jsx36("div", { className: "my-6 p-4 rounded-xl border border-red-500/50 bg-red-500/10", children: /* @__PURE__ */ jsxs27("p", { className: "text-sm text-red-600 dark:text-red-400 font-mono", children: [
|
|
2244
|
-
"Mermaid Error: ",
|
|
2245
|
-
error
|
|
2246
|
-
] }) });
|
|
2247
|
-
}
|
|
2248
|
-
return /* @__PURE__ */ jsxs27("figure", { className: "my-6", children: [
|
|
2249
|
-
/* @__PURE__ */ jsx36(
|
|
2250
|
-
"div",
|
|
2251
|
-
{
|
|
2252
|
-
ref: containerRef,
|
|
2253
|
-
className: "flex justify-center items-center p-6 rounded-xl border border-border bg-muted/30 overflow-x-auto"
|
|
2254
|
-
}
|
|
2255
|
-
),
|
|
2256
|
-
caption && /* @__PURE__ */ jsx36("figcaption", { className: "mt-2 text-center text-sm text-muted-foreground italic", children: caption })
|
|
2257
|
-
] });
|
|
2258
|
-
}
|
|
2259
|
-
|
|
2260
|
-
// src/components/docs/not-found-content.tsx
|
|
2261
|
-
import Link9 from "next/link";
|
|
2262
|
-
import { AlertTriangle as AlertTriangle2, Home, ArrowLeft } from "lucide-react";
|
|
2263
|
-
import { jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2264
|
-
function NotFoundContent({ version }) {
|
|
2265
|
-
return /* @__PURE__ */ jsx37("div", { className: "flex min-h-[calc(100vh-12rem)] items-center justify-center px-4 py-12", children: /* @__PURE__ */ jsxs28("div", { className: "w-full max-w-2xl text-center", children: [
|
|
2266
|
-
/* @__PURE__ */ jsx37("div", { className: "mb-6 flex justify-center", children: /* @__PURE__ */ jsx37("div", { className: "rounded-full bg-yellow-500/10 p-4", children: /* @__PURE__ */ jsx37(AlertTriangle2, { className: "h-16 w-16 text-yellow-500" }) }) }),
|
|
2267
|
-
/* @__PURE__ */ jsx37("h1", { className: "mb-3 text-5xl font-bold tracking-tight", children: "404" }),
|
|
2268
|
-
/* @__PURE__ */ jsx37("h2", { className: "mb-4 text-2xl font-semibold", children: "Page Not Found" }),
|
|
2269
|
-
/* @__PURE__ */ jsxs28("p", { className: "mb-8 text-base text-muted-foreground", children: [
|
|
2270
|
-
"The documentation page you're looking for doesn't exist or may have been moved.",
|
|
2271
|
-
/* @__PURE__ */ jsx37("br", {}),
|
|
2272
|
-
"Try using the sidebar to find what you're looking for, or return to the documentation home."
|
|
2273
|
-
] }),
|
|
2274
|
-
/* @__PURE__ */ jsxs28("div", { className: "flex flex-col items-center justify-center gap-3 sm:flex-row", children: [
|
|
2275
|
-
/* @__PURE__ */ jsxs28(
|
|
2276
|
-
Link9,
|
|
2277
|
-
{
|
|
2278
|
-
href: `/docs/${version}`,
|
|
2279
|
-
className: "inline-flex items-center gap-2 rounded-lg bg-primary px-6 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors",
|
|
2280
|
-
children: [
|
|
2281
|
-
/* @__PURE__ */ jsx37(ArrowLeft, { className: "h-4 w-4" }),
|
|
2282
|
-
"Back to Documentation"
|
|
2283
|
-
]
|
|
2284
|
-
}
|
|
2285
|
-
),
|
|
2286
|
-
/* @__PURE__ */ jsxs28(
|
|
2287
|
-
Link9,
|
|
2288
|
-
{
|
|
2289
|
-
href: "/",
|
|
2290
|
-
className: "inline-flex items-center gap-2 rounded-lg border border-border bg-background px-6 py-3 text-sm font-medium hover:bg-muted transition-colors",
|
|
2291
|
-
children: [
|
|
2292
|
-
/* @__PURE__ */ jsx37(Home, { className: "h-4 w-4" }),
|
|
2293
|
-
"Go to Homepage"
|
|
2294
|
-
]
|
|
2295
|
-
}
|
|
2296
|
-
)
|
|
2297
|
-
] }),
|
|
2298
|
-
/* @__PURE__ */ jsx37("div", { className: "mt-12 rounded-lg border border-border bg-muted/30 p-6", children: /* @__PURE__ */ jsxs28("p", { className: "text-sm text-muted-foreground", children: [
|
|
2299
|
-
/* @__PURE__ */ jsx37("strong", { className: "font-medium text-foreground", children: "Tip:" }),
|
|
2300
|
-
" Use the sidebar navigation on the left to browse all available documentation pages."
|
|
2301
|
-
] }) })
|
|
2302
|
-
] }) });
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
// src/components/docs/search-highlight.tsx
|
|
2306
|
-
import { useEffect as useEffect12 } from "react";
|
|
2307
|
-
import { useSearchParams } from "next/navigation";
|
|
2308
|
-
function SearchHighlight() {
|
|
2309
|
-
const searchParams = useSearchParams();
|
|
2310
|
-
const query = searchParams.get("q");
|
|
2311
|
-
useEffect12(() => {
|
|
2312
|
-
if (!query) {
|
|
2313
|
-
document.querySelectorAll("mark.search-highlight").forEach((mark) => {
|
|
2314
|
-
const parent = mark.parentNode;
|
|
2315
|
-
if (parent) {
|
|
2316
|
-
parent.replaceChild(document.createTextNode(mark.textContent || ""), mark);
|
|
2317
|
-
parent.normalize();
|
|
2318
|
-
}
|
|
2319
|
-
});
|
|
2320
|
-
return;
|
|
2321
|
-
}
|
|
2322
|
-
const timeout = setTimeout(() => {
|
|
2323
|
-
highlightSearchTerm(query);
|
|
2324
|
-
}, 100);
|
|
2325
|
-
return () => {
|
|
2326
|
-
clearTimeout(timeout);
|
|
2327
|
-
document.querySelectorAll("mark.search-highlight").forEach((mark) => {
|
|
2328
|
-
const parent = mark.parentNode;
|
|
2329
|
-
if (parent) {
|
|
2330
|
-
parent.replaceChild(document.createTextNode(mark.textContent || ""), mark);
|
|
2331
|
-
parent.normalize();
|
|
2332
|
-
}
|
|
2333
|
-
});
|
|
2334
|
-
};
|
|
2335
|
-
}, [query]);
|
|
2336
|
-
return null;
|
|
2337
|
-
}
|
|
2338
|
-
function highlightSearchTerm(searchTerm) {
|
|
2339
|
-
document.querySelectorAll("mark.search-highlight").forEach((mark) => {
|
|
2340
|
-
const parent = mark.parentNode;
|
|
2341
|
-
if (parent) {
|
|
2342
|
-
parent.replaceChild(document.createTextNode(mark.textContent || ""), mark);
|
|
2343
|
-
parent.normalize();
|
|
2344
|
-
}
|
|
2345
|
-
});
|
|
2346
|
-
const contentArea = document.querySelector("main") || document.body;
|
|
2347
|
-
const walker = document.createTreeWalker(
|
|
2348
|
-
contentArea,
|
|
2349
|
-
NodeFilter.SHOW_TEXT,
|
|
2350
|
-
{
|
|
2351
|
-
acceptNode: (node) => {
|
|
2352
|
-
const parent = node.parentElement;
|
|
2353
|
-
if (!parent) return NodeFilter.FILTER_REJECT;
|
|
2354
|
-
const tagName = parent.tagName.toLowerCase();
|
|
2355
|
-
if (["mark", "script", "style", "code", "pre"].includes(tagName)) {
|
|
2356
|
-
return NodeFilter.FILTER_REJECT;
|
|
2357
|
-
}
|
|
2358
|
-
if (node.textContent && node.textContent.toLowerCase().includes(searchTerm.toLowerCase())) {
|
|
2359
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
2360
|
-
}
|
|
2361
|
-
return NodeFilter.FILTER_REJECT;
|
|
2362
|
-
}
|
|
2363
|
-
}
|
|
2364
|
-
);
|
|
2365
|
-
const nodesToHighlight = [];
|
|
2366
|
-
let currentNode;
|
|
2367
|
-
while (currentNode = walker.nextNode()) {
|
|
2368
|
-
if (currentNode.textContent) {
|
|
2369
|
-
nodesToHighlight.push({
|
|
2370
|
-
node: currentNode,
|
|
2371
|
-
text: currentNode.textContent
|
|
2372
|
-
});
|
|
2373
|
-
}
|
|
2374
|
-
}
|
|
2375
|
-
nodesToHighlight.forEach(({ node, text }) => {
|
|
2376
|
-
const regex = new RegExp(`(${escapeRegex(searchTerm)})`, "gi");
|
|
2377
|
-
const parts = text.split(regex);
|
|
2378
|
-
if (parts.length > 1) {
|
|
2379
|
-
const fragment = document.createDocumentFragment();
|
|
2380
|
-
parts.forEach((part) => {
|
|
2381
|
-
if (part.toLowerCase() === searchTerm.toLowerCase()) {
|
|
2382
|
-
const mark = document.createElement("mark");
|
|
2383
|
-
mark.className = "search-highlight bg-yellow-200 dark:bg-yellow-900/50 text-foreground px-1 rounded";
|
|
2384
|
-
mark.textContent = part;
|
|
2385
|
-
fragment.appendChild(mark);
|
|
2386
|
-
} else if (part) {
|
|
2387
|
-
fragment.appendChild(document.createTextNode(part));
|
|
2388
|
-
}
|
|
2389
|
-
});
|
|
2390
|
-
node.parentNode?.replaceChild(fragment, node);
|
|
2391
|
-
}
|
|
2392
|
-
});
|
|
2393
|
-
const firstHighlight = document.querySelector("mark.search-highlight");
|
|
2394
|
-
if (firstHighlight) {
|
|
2395
|
-
setTimeout(() => {
|
|
2396
|
-
firstHighlight.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
2397
|
-
}, 200);
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
function escapeRegex(string) {
|
|
2401
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
// src/components/docs/sidebar-skeleton.tsx
|
|
2405
|
-
import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2406
|
-
function SidebarSkeleton() {
|
|
2407
|
-
return /* @__PURE__ */ jsx38("aside", { className: "w-64 pr-8 py-6", children: /* @__PURE__ */ jsxs29("div", { className: "space-y-6", children: [
|
|
2408
|
-
/* @__PURE__ */ jsx38("div", { className: "px-2", children: /* @__PURE__ */ jsx38("div", { className: "h-5 w-32 bg-muted/50 rounded animate-pulse" }) }),
|
|
2409
|
-
/* @__PURE__ */ jsx38("div", { className: "space-y-1", children: [...Array(8)].map((_, i) => /* @__PURE__ */ jsx38("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx38(
|
|
2410
|
-
"div",
|
|
2411
|
-
{
|
|
2412
|
-
className: "h-4 bg-muted/50 rounded animate-pulse",
|
|
2413
|
-
style: { width: `${60 + Math.random() * 40}%` }
|
|
2414
|
-
}
|
|
2415
|
-
) }, i)) }),
|
|
2416
|
-
/* @__PURE__ */ jsxs29("div", { className: "space-y-1", children: [
|
|
2417
|
-
/* @__PURE__ */ jsx38("div", { className: "px-2 mb-2", children: /* @__PURE__ */ jsx38("div", { className: "h-4 w-24 bg-muted/50 rounded animate-pulse" }) }),
|
|
2418
|
-
[...Array(5)].map((_, i) => /* @__PURE__ */ jsx38("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx38(
|
|
2419
|
-
"div",
|
|
2420
|
-
{
|
|
2421
|
-
className: "h-4 bg-muted/50 rounded animate-pulse",
|
|
2422
|
-
style: { width: `${50 + Math.random() * 50}%` }
|
|
2423
|
-
}
|
|
2424
|
-
) }, i))
|
|
2425
|
-
] })
|
|
2426
|
-
] }) });
|
|
2427
|
-
}
|
|
2428
|
-
|
|
2429
|
-
// src/components/docs/steps.tsx
|
|
2430
|
-
import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2431
|
-
function Steps({ children }) {
|
|
2432
|
-
return /* @__PURE__ */ jsx39("div", { className: "my-6 ml-4 space-y-6 [counter-reset:step]", children });
|
|
2433
|
-
}
|
|
2434
|
-
function Step({ title, children }) {
|
|
2435
|
-
return /* @__PURE__ */ jsxs30("div", { className: "relative pl-8 pb-6 border-l-2 border-border last:border-l-0 last:pb-0 [counter-increment:step] before:content-[counter(step)] before:absolute before:left-0 before:-translate-x-1/2 before:w-8 before:h-8 before:rounded-full before:bg-primary before:text-primary-foreground before:flex before:items-center before:justify-center before:text-sm before:font-semibold before:z-10", children: [
|
|
2436
|
-
/* @__PURE__ */ jsx39("div", { className: "mb-2", children: /* @__PURE__ */ jsx39("h3", { className: "text-lg font-semibold text-foreground", children: title }) }),
|
|
2437
|
-
/* @__PURE__ */ jsx39("div", { className: "prose prose-sm dark:prose-invert max-w-none [&>*:last-child]:mb-0", children })
|
|
2438
|
-
] });
|
|
2439
|
-
}
|
|
2440
|
-
|
|
2441
|
-
// src/components/docs/table-of-contents.tsx
|
|
2442
|
-
import { useEffect as useEffect13, useState as useState18 } from "react";
|
|
2443
|
-
import { jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2444
|
-
function TableOfContents({ items, config }) {
|
|
2445
|
-
const [activeId, setActiveId] = useState18("");
|
|
2446
|
-
if (!config.navigation?.showTableOfContents) {
|
|
2447
|
-
return null;
|
|
2448
|
-
}
|
|
2449
|
-
const maxDepth = config.navigation?.tocMaxDepth || 3;
|
|
2450
|
-
const filteredItems = items.filter((item) => item.level <= maxDepth);
|
|
2451
|
-
const hasTabGroups = config.navigation?.tabGroups && config.navigation.tabGroups.length > 0;
|
|
2452
|
-
useEffect13(() => {
|
|
2453
|
-
const observer = new IntersectionObserver(
|
|
2454
|
-
(entries) => {
|
|
2455
|
-
entries.forEach((entry) => {
|
|
2456
|
-
if (entry.isIntersecting) {
|
|
2457
|
-
setActiveId(entry.target.id);
|
|
2458
|
-
}
|
|
2459
|
-
});
|
|
2460
|
-
},
|
|
2461
|
-
{ rootMargin: "-80px 0px -80% 0px" }
|
|
2462
|
-
);
|
|
2463
|
-
filteredItems.forEach((item) => {
|
|
2464
|
-
const element = document.getElementById(item.id);
|
|
2465
|
-
if (element) {
|
|
2466
|
-
observer.observe(element);
|
|
2467
|
-
}
|
|
2468
|
-
});
|
|
2469
|
-
return () => observer.disconnect();
|
|
2470
|
-
}, [filteredItems]);
|
|
2471
|
-
const handleClick = (e, id) => {
|
|
2472
|
-
e.preventDefault();
|
|
2473
|
-
const element = document.getElementById(id);
|
|
2474
|
-
if (element) {
|
|
2475
|
-
const offset = 100;
|
|
2476
|
-
const elementPosition = element.getBoundingClientRect().top;
|
|
2477
|
-
const offsetPosition = elementPosition + window.scrollY - offset;
|
|
2478
|
-
window.scrollTo({
|
|
2479
|
-
top: offsetPosition,
|
|
2480
|
-
behavior: "smooth"
|
|
2481
|
-
});
|
|
2482
|
-
window.history.replaceState(null, "", `#${id}`);
|
|
2483
|
-
setActiveId(id);
|
|
2484
|
-
}
|
|
2485
|
-
};
|
|
2486
|
-
const stickyTop = hasTabGroups ? "top-[7.5rem]" : "top-24";
|
|
2487
|
-
const maxHeight = hasTabGroups ? "max-h-[calc(100vh-10rem)]" : "max-h-[calc(100vh-7rem)]";
|
|
2488
|
-
return /* @__PURE__ */ jsx40("aside", { className: `w-64 hidden xl:block shrink-0 sticky ${stickyTop} self-start`, children: filteredItems.length > 0 && /* @__PURE__ */ jsxs31("div", { className: `${maxHeight} overflow-y-auto bg-muted/30 dark:bg-muted/10 rounded-2xl p-4 border border-border/50`, children: [
|
|
2489
|
-
/* @__PURE__ */ jsx40("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4 px-2", children: "On this page" }),
|
|
2490
|
-
/* @__PURE__ */ jsx40("nav", { className: "space-y-1", children: filteredItems.map((item, index) => /* @__PURE__ */ jsx40(
|
|
2491
|
-
"a",
|
|
2492
|
-
{
|
|
2493
|
-
href: `#${item.id}`,
|
|
2494
|
-
onClick: (e) => handleClick(e, item.id),
|
|
2495
|
-
className: `block text-sm transition-all cursor-pointer rounded-xl px-3 py-2 ${item.level === 3 ? "ml-3" : ""} ${activeId === item.id ? "text-primary font-medium" : "text-foreground hover:bg-accent/50"}`,
|
|
2496
|
-
children: item.title
|
|
2497
|
-
},
|
|
2498
|
-
`${item.id}-${index}`
|
|
2499
|
-
)) })
|
|
2500
|
-
] }) });
|
|
2501
|
-
}
|
|
2502
|
-
|
|
2503
|
-
// src/components/docs/tabs.tsx
|
|
2504
|
-
import { useState as useState19, Children, isValidElement as isValidElement3 } from "react";
|
|
2505
|
-
import { Fragment as Fragment8, jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2506
|
-
function Tab({ children }) {
|
|
2507
|
-
return /* @__PURE__ */ jsx41(Fragment8, { children });
|
|
2508
|
-
}
|
|
2509
|
-
function Tabs({ children, defaultValue }) {
|
|
2510
|
-
const tabs = Children.toArray(children).filter(isValidElement3);
|
|
2511
|
-
const firstTabLabel = tabs[0]?.props.label || "";
|
|
2512
|
-
const [activeTab, setActiveTab] = useState19(defaultValue || firstTabLabel);
|
|
2513
|
-
return /* @__PURE__ */ jsxs32("div", { className: "my-6", children: [
|
|
2514
|
-
/* @__PURE__ */ jsx41("div", { className: "flex items-center gap-1 border-b border-border mb-4", children: tabs.map((tab) => {
|
|
2515
|
-
const label = tab.props.label;
|
|
2516
|
-
const isActive = activeTab === label;
|
|
2517
|
-
return /* @__PURE__ */ jsx41(
|
|
2518
|
-
"button",
|
|
2519
|
-
{
|
|
2520
|
-
onClick: () => setActiveTab(label),
|
|
2521
|
-
className: `px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${isActive ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground hover:border-border"}`,
|
|
2522
|
-
children: label
|
|
2523
|
-
},
|
|
2524
|
-
label
|
|
2525
|
-
);
|
|
2526
|
-
}) }),
|
|
2527
|
-
tabs.map((tab) => {
|
|
2528
|
-
const label = tab.props.label;
|
|
2529
|
-
if (activeTab !== label) return null;
|
|
2530
|
-
return /* @__PURE__ */ jsx41("div", { className: "prose prose-slate dark:prose-invert max-w-none [&>*:first-child]:mt-0", children: tab.props.children }, label);
|
|
2531
|
-
})
|
|
2532
|
-
] });
|
|
2533
|
-
}
|
|
2534
|
-
|
|
2535
|
-
// src/components/docs/tooltip.tsx
|
|
2536
|
-
import { useState as useState20 } from "react";
|
|
2537
|
-
import { jsx as jsx42, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2538
|
-
function Tooltip({ children, content, position = "top" }) {
|
|
2539
|
-
const [isVisible, setIsVisible] = useState20(false);
|
|
2540
|
-
const positions = {
|
|
2541
|
-
top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
|
|
2542
|
-
bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
|
|
2543
|
-
left: "right-full top-1/2 -translate-y-1/2 mr-2",
|
|
2544
|
-
right: "left-full top-1/2 -translate-y-1/2 ml-2"
|
|
2545
|
-
};
|
|
2546
|
-
return /* @__PURE__ */ jsxs33(
|
|
2547
|
-
"span",
|
|
2548
|
-
{
|
|
2549
|
-
className: "relative inline-flex underline decoration-dotted cursor-help",
|
|
2550
|
-
onMouseEnter: () => setIsVisible(true),
|
|
2551
|
-
onMouseLeave: () => setIsVisible(false),
|
|
2552
|
-
children: [
|
|
2553
|
-
children,
|
|
2554
|
-
isVisible && /* @__PURE__ */ jsx42(
|
|
2555
|
-
"span",
|
|
2556
|
-
{
|
|
2557
|
-
className: `absolute ${positions[position]} z-50 px-2 py-1 text-xs text-white bg-gray-900 dark:bg-gray-700 rounded whitespace-nowrap pointer-events-none`,
|
|
2558
|
-
children: content
|
|
2559
|
-
}
|
|
2560
|
-
)
|
|
2561
|
-
]
|
|
2562
|
-
}
|
|
2563
|
-
);
|
|
2564
|
-
}
|
|
2565
|
-
|
|
2566
|
-
// src/components/docs/video.tsx
|
|
2567
|
-
import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2568
|
-
function Video({
|
|
2569
|
-
src,
|
|
2570
|
-
caption,
|
|
2571
|
-
autoplay = false,
|
|
2572
|
-
loop = false,
|
|
2573
|
-
muted = false,
|
|
2574
|
-
controls = true,
|
|
2575
|
-
poster
|
|
2576
|
-
}) {
|
|
2577
|
-
const isYouTube = src.includes("youtube.com") || src.includes("youtu.be");
|
|
2578
|
-
const isVimeo = src.includes("vimeo.com");
|
|
2579
|
-
const getYouTubeId = (url) => {
|
|
2580
|
-
const match = url.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/);
|
|
2581
|
-
return match ? match[1] : null;
|
|
2582
|
-
};
|
|
2583
|
-
const getVimeoId = (url) => {
|
|
2584
|
-
const match = url.match(/vimeo\.com\/(\d+)/);
|
|
2585
|
-
return match ? match[1] : null;
|
|
2586
|
-
};
|
|
2587
|
-
return /* @__PURE__ */ jsxs34("figure", { className: "my-6", children: [
|
|
2588
|
-
/* @__PURE__ */ jsx43("div", { className: "relative rounded-xl border border-border overflow-hidden bg-muted/30", children: isYouTube ? /* @__PURE__ */ jsx43("div", { className: "relative w-full", style: { paddingBottom: "56.25%" }, children: /* @__PURE__ */ jsx43(
|
|
2589
|
-
"iframe",
|
|
2590
|
-
{
|
|
2591
|
-
className: "absolute top-0 left-0 w-full h-full",
|
|
2592
|
-
src: `https://www.youtube.com/embed/${getYouTubeId(src)}${autoplay ? "?autoplay=1" : ""}`,
|
|
2593
|
-
title: "YouTube video",
|
|
2594
|
-
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
|
|
2595
|
-
allowFullScreen: true
|
|
2596
|
-
}
|
|
2597
|
-
) }) : isVimeo ? /* @__PURE__ */ jsx43("div", { className: "relative w-full", style: { paddingBottom: "56.25%" }, children: /* @__PURE__ */ jsx43(
|
|
2598
|
-
"iframe",
|
|
2599
|
-
{
|
|
2600
|
-
className: "absolute top-0 left-0 w-full h-full",
|
|
2601
|
-
src: `https://player.vimeo.com/video/${getVimeoId(src)}${autoplay ? "?autoplay=1" : ""}`,
|
|
2602
|
-
title: "Vimeo video",
|
|
2603
|
-
allow: "autoplay; fullscreen; picture-in-picture",
|
|
2604
|
-
allowFullScreen: true
|
|
2605
|
-
}
|
|
2606
|
-
) }) : /* @__PURE__ */ jsx43(
|
|
2607
|
-
"video",
|
|
2608
|
-
{
|
|
2609
|
-
src,
|
|
2610
|
-
controls,
|
|
2611
|
-
autoPlay: autoplay,
|
|
2612
|
-
loop,
|
|
2613
|
-
muted,
|
|
2614
|
-
poster,
|
|
2615
|
-
className: "w-full h-auto",
|
|
2616
|
-
children: "Your browser does not support the video tag."
|
|
2617
|
-
}
|
|
2618
|
-
) }),
|
|
2619
|
-
caption && /* @__PURE__ */ jsx43("figcaption", { className: "mt-2 text-center text-sm text-muted-foreground italic", children: caption })
|
|
2620
|
-
] });
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
// src/components/docs/api/api-endpoint.tsx
|
|
2624
|
-
import { useState as useState21 } from "react";
|
|
2625
|
-
import { ChevronDown as ChevronDown6 } from "lucide-react";
|
|
2626
|
-
import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2627
|
-
var methodColors = {
|
|
2628
|
-
GET: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
|
|
2629
|
-
POST: "bg-green-500/10 text-green-600 dark:text-green-400",
|
|
2630
|
-
PUT: "bg-orange-500/10 text-orange-600 dark:text-orange-400",
|
|
2631
|
-
PATCH: "bg-purple-500/10 text-purple-600 dark:text-purple-400",
|
|
2632
|
-
DELETE: "bg-red-500/10 text-red-600 dark:text-red-400"
|
|
2633
|
-
};
|
|
2634
|
-
function ApiEndpoint({ method, path, summary, children, defaultOpen = false }) {
|
|
2635
|
-
const [isOpen, setIsOpen] = useState21(defaultOpen);
|
|
2636
|
-
return /* @__PURE__ */ jsxs35("div", { className: "not-prose mb-4 rounded-xl border border-border overflow-hidden", children: [
|
|
2637
|
-
/* @__PURE__ */ jsxs35(
|
|
2638
|
-
"button",
|
|
2639
|
-
{
|
|
2640
|
-
onClick: () => setIsOpen(!isOpen),
|
|
2641
|
-
className: "w-full flex items-center gap-3 px-4 py-3 text-left bg-muted/30 hover:bg-muted/50 transition-colors",
|
|
2642
|
-
children: [
|
|
2643
|
-
/* @__PURE__ */ jsx44(
|
|
2644
|
-
"span",
|
|
2645
|
-
{
|
|
2646
|
-
className: cn(
|
|
2647
|
-
"text-xs font-semibold px-2 py-0.5 rounded",
|
|
2648
|
-
methodColors[method]
|
|
2649
|
-
),
|
|
2650
|
-
children: method
|
|
2651
|
-
}
|
|
2652
|
-
),
|
|
2653
|
-
/* @__PURE__ */ jsx44("code", { className: "text-sm font-mono", children: path }),
|
|
2654
|
-
summary && /* @__PURE__ */ jsx44("span", { className: "text-sm text-muted-foreground ml-auto mr-2", children: summary }),
|
|
2655
|
-
/* @__PURE__ */ jsx44(
|
|
2656
|
-
ChevronDown6,
|
|
2657
|
-
{
|
|
2658
|
-
className: cn(
|
|
2659
|
-
"h-5 w-5 text-muted-foreground transition-transform flex-shrink-0",
|
|
2660
|
-
isOpen ? "rotate-180" : ""
|
|
2661
|
-
)
|
|
2662
|
-
}
|
|
2663
|
-
)
|
|
2664
|
-
]
|
|
2665
|
-
}
|
|
2666
|
-
),
|
|
2667
|
-
isOpen && children && /* @__PURE__ */ jsx44("div", { className: "border-t border-border bg-background", children: /* @__PURE__ */ jsx44("div", { className: "px-4 py-4 space-y-6", children }) })
|
|
2668
|
-
] });
|
|
2669
|
-
}
|
|
2670
|
-
|
|
2671
|
-
// src/components/docs/api/api-params.tsx
|
|
2672
|
-
import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2673
|
-
function ApiParams({ title = "Parameters", params }) {
|
|
2674
|
-
if (!params || params.length === 0) return null;
|
|
2675
|
-
return /* @__PURE__ */ jsxs36("div", { className: "mb-6", children: [
|
|
2676
|
-
/* @__PURE__ */ jsx45("h4", { className: "text-sm font-semibold text-foreground mb-3", children: title }),
|
|
2677
|
-
/* @__PURE__ */ jsx45("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs36("table", { className: "w-full border-collapse", children: [
|
|
2678
|
-
/* @__PURE__ */ jsx45("thead", { children: /* @__PURE__ */ jsxs36("tr", { className: "border-b border-border", children: [
|
|
2679
|
-
/* @__PURE__ */ jsx45("th", { className: "text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Property" }),
|
|
2680
|
-
/* @__PURE__ */ jsx45("th", { className: "text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Type" }),
|
|
2681
|
-
/* @__PURE__ */ jsx45("th", { className: "text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Required" }),
|
|
2682
|
-
/* @__PURE__ */ jsx45("th", { className: "text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Default" }),
|
|
2683
|
-
/* @__PURE__ */ jsx45("th", { className: "text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Description" })
|
|
2684
|
-
] }) }),
|
|
2685
|
-
/* @__PURE__ */ jsx45("tbody", { children: params.map((param, index) => /* @__PURE__ */ jsxs36(
|
|
2686
|
-
"tr",
|
|
2687
|
-
{
|
|
2688
|
-
className: index !== params.length - 1 ? "border-b border-border/50" : "",
|
|
2689
|
-
children: [
|
|
2690
|
-
/* @__PURE__ */ jsx45("td", { className: "py-2.5 px-3", children: /* @__PURE__ */ jsx45("code", { className: "text-sm font-mono text-foreground", children: param.name }) }),
|
|
2691
|
-
/* @__PURE__ */ jsx45("td", { className: "py-2.5 px-3", children: /* @__PURE__ */ jsx45("span", { className: "text-sm text-muted-foreground font-mono", children: param.type }) }),
|
|
2692
|
-
/* @__PURE__ */ jsx45("td", { className: "py-2.5 px-3", children: param.required ? /* @__PURE__ */ jsx45("span", { className: "text-sm text-red-600 dark:text-red-400", children: "Yes" }) : /* @__PURE__ */ jsx45("span", { className: "text-sm text-muted-foreground", children: "No" }) }),
|
|
2693
|
-
/* @__PURE__ */ jsx45("td", { className: "py-2.5 px-3", children: param.default ? /* @__PURE__ */ jsx45("code", { className: "text-sm font-mono text-muted-foreground", children: param.default }) : /* @__PURE__ */ jsx45("span", { className: "text-sm text-muted-foreground", children: "-" }) }),
|
|
2694
|
-
/* @__PURE__ */ jsx45("td", { className: "py-2.5 px-3", children: param.description ? /* @__PURE__ */ jsx45("span", { className: "text-sm text-muted-foreground", children: param.description }) : /* @__PURE__ */ jsx45("span", { className: "text-sm text-muted-foreground", children: "-" }) })
|
|
2695
|
-
]
|
|
2696
|
-
},
|
|
2697
|
-
param.name
|
|
2698
|
-
)) })
|
|
2699
|
-
] }) })
|
|
2700
|
-
] });
|
|
2701
|
-
}
|
|
2702
|
-
|
|
2703
|
-
// src/components/docs/api/api-response.tsx
|
|
2704
|
-
import { jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
2705
|
-
var statusColors = {
|
|
2706
|
-
"2": "text-green-600 dark:text-green-400",
|
|
2707
|
-
"3": "text-blue-600 dark:text-blue-400",
|
|
2708
|
-
"4": "text-orange-600 dark:text-orange-400",
|
|
2709
|
-
"5": "text-red-600 dark:text-red-400"
|
|
2710
|
-
};
|
|
2711
|
-
function ApiResponse({ status, description, example, schema }) {
|
|
2712
|
-
const statusClass = statusColors[String(status)[0]] || "text-muted-foreground";
|
|
2713
|
-
return /* @__PURE__ */ jsxs37("div", { className: "mb-4", children: [
|
|
2714
|
-
/* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
2715
|
-
/* @__PURE__ */ jsx46("span", { className: `text-sm font-semibold ${statusClass}`, children: status }),
|
|
2716
|
-
description && /* @__PURE__ */ jsx46("span", { className: "text-sm text-muted-foreground", children: description })
|
|
2717
|
-
] }),
|
|
2718
|
-
example && /* @__PURE__ */ jsxs37("div", { className: "mb-3", children: [
|
|
2719
|
-
/* @__PURE__ */ jsx46("p", { className: "text-xs font-semibold text-muted-foreground mb-2", children: "Example Response" }),
|
|
2720
|
-
/* @__PURE__ */ jsx46(
|
|
2721
|
-
CodeBlock,
|
|
2722
|
-
{
|
|
2723
|
-
code: typeof example === "string" ? example : JSON.stringify(example, null, 2),
|
|
2724
|
-
language: "json"
|
|
2725
|
-
}
|
|
2726
|
-
)
|
|
2727
|
-
] }),
|
|
2728
|
-
schema && /* @__PURE__ */ jsxs37("div", { children: [
|
|
2729
|
-
/* @__PURE__ */ jsx46("p", { className: "text-xs font-semibold text-muted-foreground mb-2", children: "Schema" }),
|
|
2730
|
-
/* @__PURE__ */ jsx46(
|
|
2731
|
-
CodeBlock,
|
|
2732
|
-
{
|
|
2733
|
-
code: typeof schema === "string" ? schema : JSON.stringify(schema, null, 2),
|
|
2734
|
-
language: "json"
|
|
2735
|
-
}
|
|
2736
|
-
)
|
|
2737
|
-
] })
|
|
2738
|
-
] });
|
|
2739
|
-
}
|
|
2740
|
-
|
|
2741
|
-
// src/components/docs/api/api-playground.tsx
|
|
2742
|
-
import { useState as useState22, useMemo } from "react";
|
|
2743
|
-
|
|
2744
|
-
// src/components/ui/button.tsx
|
|
2745
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
2746
|
-
import { cva } from "class-variance-authority";
|
|
2747
|
-
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
2748
|
-
var buttonVariants = cva(
|
|
2749
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
2750
|
-
{
|
|
2751
|
-
variants: {
|
|
2752
|
-
variant: {
|
|
2753
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
2754
|
-
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
2755
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
2756
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
2757
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
2758
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
2759
|
-
},
|
|
2760
|
-
size: {
|
|
2761
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
2762
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
2763
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
2764
|
-
icon: "size-9",
|
|
2765
|
-
"icon-sm": "size-8",
|
|
2766
|
-
"icon-lg": "size-10"
|
|
2767
|
-
}
|
|
2768
|
-
},
|
|
2769
|
-
defaultVariants: {
|
|
2770
|
-
variant: "default",
|
|
2771
|
-
size: "default"
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
|
-
);
|
|
2775
|
-
function Button({
|
|
2776
|
-
className,
|
|
2777
|
-
variant,
|
|
2778
|
-
size,
|
|
2779
|
-
asChild = false,
|
|
2780
|
-
...props
|
|
2781
|
-
}) {
|
|
2782
|
-
const Comp = asChild ? Slot : "button";
|
|
2783
|
-
return /* @__PURE__ */ jsx47(
|
|
2784
|
-
Comp,
|
|
2785
|
-
{
|
|
2786
|
-
"data-slot": "button",
|
|
2787
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
2788
|
-
...props
|
|
2789
|
-
}
|
|
2790
|
-
);
|
|
2791
|
-
}
|
|
2792
|
-
|
|
2793
|
-
// src/components/ui/input.tsx
|
|
2794
|
-
import { jsx as jsx48 } from "react/jsx-runtime";
|
|
2795
|
-
function Input({ className, type, ...props }) {
|
|
2796
|
-
return /* @__PURE__ */ jsx48(
|
|
2797
|
-
"input",
|
|
2798
|
-
{
|
|
2799
|
-
type,
|
|
2800
|
-
"data-slot": "input",
|
|
2801
|
-
className: cn(
|
|
2802
|
-
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
2803
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
2804
|
-
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
2805
|
-
className
|
|
2806
|
-
),
|
|
2807
|
-
...props
|
|
2808
|
-
}
|
|
2809
|
-
);
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
// src/components/ui/textarea.tsx
|
|
2813
|
-
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
2814
|
-
function Textarea({ className, ...props }) {
|
|
2815
|
-
return /* @__PURE__ */ jsx49(
|
|
2816
|
-
"textarea",
|
|
2817
|
-
{
|
|
2818
|
-
"data-slot": "textarea",
|
|
2819
|
-
className: cn(
|
|
2820
|
-
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
2821
|
-
className
|
|
2822
|
-
),
|
|
2823
|
-
...props
|
|
2824
|
-
}
|
|
2825
|
-
);
|
|
2826
|
-
}
|
|
2827
|
-
|
|
2828
|
-
// src/components/ui/badge.tsx
|
|
2829
|
-
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
2830
|
-
import { cva as cva2 } from "class-variance-authority";
|
|
2831
|
-
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
2832
|
-
var badgeVariants = cva2(
|
|
2833
|
-
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
2834
|
-
{
|
|
2835
|
-
variants: {
|
|
2836
|
-
variant: {
|
|
2837
|
-
default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
2838
|
-
secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
2839
|
-
destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
2840
|
-
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
|
|
2841
|
-
}
|
|
2842
|
-
},
|
|
2843
|
-
defaultVariants: {
|
|
2844
|
-
variant: "default"
|
|
2845
|
-
}
|
|
2846
|
-
}
|
|
2847
|
-
);
|
|
2848
|
-
function Badge2({
|
|
2849
|
-
className,
|
|
2850
|
-
variant,
|
|
2851
|
-
asChild = false,
|
|
2852
|
-
...props
|
|
2853
|
-
}) {
|
|
2854
|
-
const Comp = asChild ? Slot2 : "span";
|
|
2855
|
-
return /* @__PURE__ */ jsx50(
|
|
2856
|
-
Comp,
|
|
2857
|
-
{
|
|
2858
|
-
"data-slot": "badge",
|
|
2859
|
-
className: cn(badgeVariants({ variant }), className),
|
|
2860
|
-
...props
|
|
2861
|
-
}
|
|
2862
|
-
);
|
|
2863
|
-
}
|
|
2864
|
-
|
|
2865
|
-
// src/components/docs/api/api-playground.tsx
|
|
2866
|
-
import { Play, Loader2 as Loader22 } from "lucide-react";
|
|
2867
|
-
import { Fragment as Fragment9, jsx as jsx51, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
2868
|
-
function ApiPlayground({
|
|
2869
|
-
method,
|
|
2870
|
-
path,
|
|
2871
|
-
baseUrl = "",
|
|
2872
|
-
headers = {},
|
|
2873
|
-
defaultBody,
|
|
2874
|
-
pathParams = []
|
|
2875
|
-
}) {
|
|
2876
|
-
const [loading, setLoading] = useState22(false);
|
|
2877
|
-
const [response, setResponse] = useState22(null);
|
|
2878
|
-
const [error, setError] = useState22(null);
|
|
2879
|
-
const [requestBody, setRequestBody] = useState22(defaultBody || "");
|
|
2880
|
-
const initialHeaders = useMemo(() => {
|
|
2881
|
-
const cleanHeaders = {};
|
|
2882
|
-
Object.entries(headers).forEach(([key, value]) => {
|
|
2883
|
-
cleanHeaders[key] = value || "";
|
|
2884
|
-
});
|
|
2885
|
-
return cleanHeaders;
|
|
2886
|
-
}, [headers]);
|
|
2887
|
-
const [requestHeaders, setRequestHeaders] = useState22(JSON.stringify(initialHeaders, null, 2));
|
|
2888
|
-
const extractedParams = useMemo(() => {
|
|
2889
|
-
const params = {};
|
|
2890
|
-
const pathParamPattern = /:(\w+)/g;
|
|
2891
|
-
let match;
|
|
2892
|
-
while ((match = pathParamPattern.exec(path)) !== null) {
|
|
2893
|
-
const paramName = match[1];
|
|
2894
|
-
const paramConfig = pathParams.find((p) => p.name === paramName);
|
|
2895
|
-
if (paramConfig?.example !== void 0) {
|
|
2896
|
-
params[paramName] = String(paramConfig.example);
|
|
2897
|
-
} else if (paramConfig?.type === "number") {
|
|
2898
|
-
params[paramName] = "1";
|
|
2899
|
-
} else {
|
|
2900
|
-
params[paramName] = "";
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
return params;
|
|
2904
|
-
}, [path, pathParams]);
|
|
2905
|
-
const [pathParamValues, setPathParamValues] = useState22(extractedParams);
|
|
2906
|
-
const buildUrl = () => {
|
|
2907
|
-
let finalPath = path;
|
|
2908
|
-
Object.entries(pathParamValues).forEach(([key, value]) => {
|
|
2909
|
-
finalPath = finalPath.replace(`:${key}`, value);
|
|
2910
|
-
});
|
|
2911
|
-
return `${baseUrl}${finalPath}`;
|
|
2912
|
-
};
|
|
2913
|
-
const handleSend = async () => {
|
|
2914
|
-
setLoading(true);
|
|
2915
|
-
setError(null);
|
|
2916
|
-
setResponse(null);
|
|
2917
|
-
try {
|
|
2918
|
-
const url = buildUrl();
|
|
2919
|
-
const parsedHeaders = JSON.parse(requestHeaders);
|
|
2920
|
-
const options = {
|
|
2921
|
-
method,
|
|
2922
|
-
headers: {
|
|
2923
|
-
"Content-Type": "application/json",
|
|
2924
|
-
...parsedHeaders
|
|
2925
|
-
}
|
|
2926
|
-
};
|
|
2927
|
-
if (method !== "GET" && method !== "DELETE" && requestBody) {
|
|
2928
|
-
options.body = requestBody;
|
|
2929
|
-
}
|
|
2930
|
-
const res = await fetch(url, options);
|
|
2931
|
-
const data = await res.json();
|
|
2932
|
-
setResponse({
|
|
2933
|
-
status: res.status,
|
|
2934
|
-
statusText: res.statusText,
|
|
2935
|
-
headers: Object.fromEntries(res.headers.entries()),
|
|
2936
|
-
body: data
|
|
2937
|
-
});
|
|
2938
|
-
} catch (err) {
|
|
2939
|
-
setError(err instanceof Error ? err.message : "An error occurred");
|
|
2940
|
-
} finally {
|
|
2941
|
-
setLoading(false);
|
|
2942
|
-
}
|
|
2943
|
-
};
|
|
2944
|
-
return /* @__PURE__ */ jsxs38("div", { className: "not-prose border border-border rounded-lg overflow-hidden bg-card/30", children: [
|
|
2945
|
-
/* @__PURE__ */ jsx51("div", { className: "bg-muted/50 px-4 py-2 border-b border-border", children: /* @__PURE__ */ jsx51("h4", { className: "text-sm font-semibold text-foreground", children: "API Playground" }) }),
|
|
2946
|
-
/* @__PURE__ */ jsxs38("div", { className: "p-4 space-y-4", children: [
|
|
2947
|
-
Object.keys(pathParamValues).length > 0 && /* @__PURE__ */ jsxs38("div", { children: [
|
|
2948
|
-
/* @__PURE__ */ jsx51("label", { className: "text-xs font-semibold text-muted-foreground mb-2 block", children: "Path Parameters" }),
|
|
2949
|
-
/* @__PURE__ */ jsx51("div", { className: "space-y-2", children: Object.entries(pathParamValues).map(([paramName, paramValue]) => {
|
|
2950
|
-
const paramConfig = pathParams.find((p) => p.name === paramName);
|
|
2951
|
-
return /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2", children: [
|
|
2952
|
-
/* @__PURE__ */ jsxs38("span", { className: "text-xs text-muted-foreground min-w-[80px]", children: [
|
|
2953
|
-
":",
|
|
2954
|
-
paramName
|
|
2955
|
-
] }),
|
|
2956
|
-
/* @__PURE__ */ jsx51(
|
|
2957
|
-
Input,
|
|
2958
|
-
{
|
|
2959
|
-
value: paramValue,
|
|
2960
|
-
onChange: (e) => setPathParamValues((prev) => ({ ...prev, [paramName]: e.target.value })),
|
|
2961
|
-
placeholder: paramConfig?.example || paramConfig?.type || "value",
|
|
2962
|
-
className: "font-mono text-sm"
|
|
2963
|
-
}
|
|
2964
|
-
)
|
|
2965
|
-
] }, paramName);
|
|
2966
|
-
}) })
|
|
2967
|
-
] }),
|
|
2968
|
-
/* @__PURE__ */ jsxs38("div", { children: [
|
|
2969
|
-
/* @__PURE__ */ jsx51("label", { className: "text-xs font-semibold text-muted-foreground mb-2 block", children: "Request URL" }),
|
|
2970
|
-
/* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2", children: [
|
|
2971
|
-
/* @__PURE__ */ jsx51(Badge2, { variant: "outline", className: "font-mono", children: method }),
|
|
2972
|
-
/* @__PURE__ */ jsx51(Input, { value: buildUrl(), readOnly: true, className: "font-mono text-sm" })
|
|
2973
|
-
] })
|
|
2974
|
-
] }),
|
|
2975
|
-
/* @__PURE__ */ jsxs38("div", { children: [
|
|
2976
|
-
/* @__PURE__ */ jsx51("label", { className: "text-xs font-semibold text-muted-foreground mb-2 block", children: "Headers (JSON)" }),
|
|
2977
|
-
/* @__PURE__ */ jsx51(
|
|
2978
|
-
Textarea,
|
|
2979
|
-
{
|
|
2980
|
-
value: requestHeaders,
|
|
2981
|
-
onChange: (e) => setRequestHeaders(e.target.value),
|
|
2982
|
-
className: "font-mono text-sm",
|
|
2983
|
-
rows: 4
|
|
2984
|
-
}
|
|
2985
|
-
)
|
|
2986
|
-
] }),
|
|
2987
|
-
method !== "GET" && method !== "DELETE" && /* @__PURE__ */ jsxs38("div", { children: [
|
|
2988
|
-
/* @__PURE__ */ jsx51("label", { className: "text-xs font-semibold text-muted-foreground mb-2 block", children: "Request Body (JSON)" }),
|
|
2989
|
-
/* @__PURE__ */ jsx51(
|
|
2990
|
-
Textarea,
|
|
2991
|
-
{
|
|
2992
|
-
value: requestBody,
|
|
2993
|
-
onChange: (e) => setRequestBody(e.target.value),
|
|
2994
|
-
className: "font-mono text-sm",
|
|
2995
|
-
rows: 6,
|
|
2996
|
-
placeholder: '{\\n "key": "value"\\n}'
|
|
2997
|
-
}
|
|
2998
|
-
)
|
|
2999
|
-
] }),
|
|
3000
|
-
/* @__PURE__ */ jsx51(Button, { onClick: handleSend, disabled: loading, className: "w-full", children: loading ? /* @__PURE__ */ jsxs38(Fragment9, { children: [
|
|
3001
|
-
/* @__PURE__ */ jsx51(Loader22, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
3002
|
-
"Sending..."
|
|
3003
|
-
] }) : /* @__PURE__ */ jsxs38(Fragment9, { children: [
|
|
3004
|
-
/* @__PURE__ */ jsx51(Play, { className: "mr-2 h-4 w-4" }),
|
|
3005
|
-
"Send Request"
|
|
3006
|
-
] }) }),
|
|
3007
|
-
response && /* @__PURE__ */ jsxs38("div", { className: "mt-4", children: [
|
|
3008
|
-
/* @__PURE__ */ jsxs38("label", { className: "text-xs font-semibold text-muted-foreground mb-2 block", children: [
|
|
3009
|
-
"Response (",
|
|
3010
|
-
response.status,
|
|
3011
|
-
" ",
|
|
3012
|
-
response.statusText,
|
|
3013
|
-
")"
|
|
3014
|
-
] }),
|
|
3015
|
-
/* @__PURE__ */ jsx51(CodeBlock, { code: JSON.stringify(response.body, null, 2), language: "json" })
|
|
3016
|
-
] }),
|
|
3017
|
-
error && /* @__PURE__ */ jsx51("div", { className: "mt-4 p-3 bg-red-500/10 border border-red-500/20 rounded-md", children: /* @__PURE__ */ jsx51("p", { className: "text-sm text-red-600 dark:text-red-400", children: error }) })
|
|
3018
|
-
] })
|
|
3019
|
-
] });
|
|
3020
|
-
}
|
|
3021
|
-
|
|
3022
|
-
// src/components/docs/api/api-reference.tsx
|
|
3023
|
-
import { useState as useState23, useEffect as useEffect14 } from "react";
|
|
3024
|
-
|
|
3025
|
-
// src/lib/parsers/specra-parser.ts
|
|
3026
|
-
var SpecraParser = class {
|
|
3027
|
-
validate(input) {
|
|
3028
|
-
return typeof input === "object" && input !== null && "endpoints" in input && Array.isArray(input.endpoints);
|
|
3029
|
-
}
|
|
3030
|
-
parse(input) {
|
|
3031
|
-
if (!this.validate(input)) {
|
|
3032
|
-
throw new Error("Invalid Specra API spec format");
|
|
3033
|
-
}
|
|
3034
|
-
return input;
|
|
3035
|
-
}
|
|
3036
|
-
};
|
|
3037
|
-
|
|
3038
|
-
// src/lib/parsers/openapi-parser.ts
|
|
3039
|
-
var OpenApiParser = class {
|
|
3040
|
-
validate(input) {
|
|
3041
|
-
return typeof input === "object" && input !== null && ("openapi" in input || "swagger" in input) && "paths" in input;
|
|
3042
|
-
}
|
|
3043
|
-
parse(input) {
|
|
3044
|
-
if (!this.validate(input)) {
|
|
3045
|
-
throw new Error("Invalid OpenAPI spec format");
|
|
3046
|
-
}
|
|
3047
|
-
const baseUrl = this.extractBaseUrl(input);
|
|
3048
|
-
const endpoints = [];
|
|
3049
|
-
for (const [path, pathItem] of Object.entries(input.paths || {})) {
|
|
3050
|
-
const methods = ["get", "post", "put", "patch", "delete"];
|
|
3051
|
-
for (const method of methods) {
|
|
3052
|
-
const operation = pathItem[method];
|
|
3053
|
-
if (!operation) continue;
|
|
3054
|
-
const endpoint = this.parseOperation(path, method.toUpperCase(), operation, input);
|
|
3055
|
-
endpoints.push(endpoint);
|
|
3056
|
-
}
|
|
3057
|
-
}
|
|
3058
|
-
return {
|
|
3059
|
-
version: input.info?.version,
|
|
3060
|
-
title: input.info?.title,
|
|
3061
|
-
description: input.info?.description,
|
|
3062
|
-
baseUrl,
|
|
3063
|
-
auth: this.extractAuth(input),
|
|
3064
|
-
endpoints
|
|
3065
|
-
};
|
|
3066
|
-
}
|
|
3067
|
-
extractBaseUrl(spec) {
|
|
3068
|
-
if (spec.servers && spec.servers.length > 0) {
|
|
3069
|
-
return spec.servers[0].url;
|
|
3070
|
-
}
|
|
3071
|
-
if (spec.host) {
|
|
3072
|
-
const scheme = spec.schemes?.[0] || "https";
|
|
3073
|
-
const basePath = spec.basePath || "";
|
|
3074
|
-
return `${scheme}://${spec.host}${basePath}`;
|
|
3075
|
-
}
|
|
3076
|
-
return "";
|
|
3077
|
-
}
|
|
3078
|
-
extractAuth(spec) {
|
|
3079
|
-
const securitySchemes = spec.components?.securitySchemes || spec.securityDefinitions;
|
|
3080
|
-
if (!securitySchemes) return void 0;
|
|
3081
|
-
const firstScheme = Object.values(securitySchemes)[0];
|
|
3082
|
-
if (!firstScheme) return void 0;
|
|
3083
|
-
if (firstScheme.type === "http" && firstScheme.scheme === "bearer") {
|
|
3084
|
-
return {
|
|
3085
|
-
type: "bearer",
|
|
3086
|
-
description: firstScheme.description,
|
|
3087
|
-
tokenPrefix: "Bearer"
|
|
3088
|
-
};
|
|
3089
|
-
}
|
|
3090
|
-
if (firstScheme.type === "apiKey") {
|
|
3091
|
-
return {
|
|
3092
|
-
type: "apiKey",
|
|
3093
|
-
description: firstScheme.description,
|
|
3094
|
-
headerName: firstScheme.name || "X-API-Key"
|
|
3095
|
-
};
|
|
3096
|
-
}
|
|
3097
|
-
if (firstScheme.type === "http" && firstScheme.scheme === "basic") {
|
|
3098
|
-
return {
|
|
3099
|
-
type: "basic",
|
|
3100
|
-
description: firstScheme.description
|
|
3101
|
-
};
|
|
3102
|
-
}
|
|
3103
|
-
return void 0;
|
|
3104
|
-
}
|
|
3105
|
-
parseOperation(path, method, operation, spec) {
|
|
3106
|
-
const endpoint = {
|
|
3107
|
-
title: operation.summary || operation.operationId || `${method} ${path}`,
|
|
3108
|
-
method,
|
|
3109
|
-
path: this.convertPathParams(path),
|
|
3110
|
-
description: operation.description
|
|
3111
|
-
};
|
|
3112
|
-
const params = this.parseParameters(operation.parameters || [], spec);
|
|
3113
|
-
if (params.path.length > 0) endpoint.pathParams = params.path;
|
|
3114
|
-
if (params.query.length > 0) endpoint.queryParams = params.query;
|
|
3115
|
-
if (params.header.length > 0) {
|
|
3116
|
-
endpoint.headers = params.header.map((p) => ({
|
|
3117
|
-
name: p.name,
|
|
3118
|
-
value: p.example || "",
|
|
3119
|
-
description: p.description
|
|
3120
|
-
}));
|
|
3121
|
-
}
|
|
3122
|
-
if (operation.requestBody) {
|
|
3123
|
-
endpoint.body = this.parseRequestBody(operation.requestBody, spec);
|
|
3124
|
-
}
|
|
3125
|
-
const responses = this.parseResponses(operation.responses || {}, spec);
|
|
3126
|
-
if (responses.success) endpoint.successResponse = responses.success;
|
|
3127
|
-
if (responses.errors.length > 0) endpoint.errorResponses = responses.errors;
|
|
3128
|
-
return endpoint;
|
|
3129
|
-
}
|
|
3130
|
-
convertPathParams(path) {
|
|
3131
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
3132
|
-
}
|
|
3133
|
-
parseParameters(parameters, spec) {
|
|
3134
|
-
const result = { path: [], query: [], header: [] };
|
|
3135
|
-
for (const param of parameters) {
|
|
3136
|
-
const resolved = param.$ref ? this.resolveRef(param.$ref, spec) : param;
|
|
3137
|
-
const apiParam = {
|
|
3138
|
-
name: resolved.name,
|
|
3139
|
-
type: resolved.schema?.type || resolved.type || "string",
|
|
3140
|
-
required: resolved.required,
|
|
3141
|
-
description: resolved.description,
|
|
3142
|
-
example: resolved.example || resolved.schema?.example
|
|
3143
|
-
};
|
|
3144
|
-
if (resolved.in === "path") result.path.push(apiParam);
|
|
3145
|
-
else if (resolved.in === "query") result.query.push(apiParam);
|
|
3146
|
-
else if (resolved.in === "header") result.header.push(apiParam);
|
|
3147
|
-
}
|
|
3148
|
-
return result;
|
|
3149
|
-
}
|
|
3150
|
-
parseRequestBody(requestBody, spec) {
|
|
3151
|
-
const content = requestBody.content?.["application/json"];
|
|
3152
|
-
if (!content) return void 0;
|
|
3153
|
-
return {
|
|
3154
|
-
description: requestBody.description,
|
|
3155
|
-
example: content.example || this.generateExample(content.schema, spec),
|
|
3156
|
-
schema: content.schema
|
|
3157
|
-
};
|
|
3158
|
-
}
|
|
3159
|
-
parseResponses(responses, spec) {
|
|
3160
|
-
const result = { errors: [] };
|
|
3161
|
-
for (const [statusCode, response] of Object.entries(responses)) {
|
|
3162
|
-
const status = parseInt(statusCode);
|
|
3163
|
-
if (isNaN(status)) continue;
|
|
3164
|
-
const resolved = response.$ref ? this.resolveRef(response.$ref, spec) : response;
|
|
3165
|
-
const content = resolved.content?.["application/json"];
|
|
3166
|
-
const apiResponse = {
|
|
3167
|
-
status,
|
|
3168
|
-
description: resolved.description,
|
|
3169
|
-
example: content?.example || this.generateExample(content?.schema, spec),
|
|
3170
|
-
schema: content?.schema
|
|
3171
|
-
};
|
|
3172
|
-
if (status >= 200 && status < 300) {
|
|
3173
|
-
result.success = apiResponse;
|
|
3174
|
-
} else {
|
|
3175
|
-
result.errors.push(apiResponse);
|
|
3176
|
-
}
|
|
3177
|
-
}
|
|
3178
|
-
return result;
|
|
3179
|
-
}
|
|
3180
|
-
generateExample(schema, spec) {
|
|
3181
|
-
if (!schema) return void 0;
|
|
3182
|
-
if (schema.$ref) schema = this.resolveRef(schema.$ref, spec);
|
|
3183
|
-
if (schema.example) return schema.example;
|
|
3184
|
-
if (schema.type === "object" && schema.properties) {
|
|
3185
|
-
const example = {};
|
|
3186
|
-
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
3187
|
-
example[key] = this.generateExample(prop, spec);
|
|
3188
|
-
}
|
|
3189
|
-
return example;
|
|
3190
|
-
}
|
|
3191
|
-
if (schema.type === "array" && schema.items) {
|
|
3192
|
-
return [this.generateExample(schema.items, spec)];
|
|
3193
|
-
}
|
|
3194
|
-
const defaults = {
|
|
3195
|
-
string: "string",
|
|
3196
|
-
number: 0,
|
|
3197
|
-
integer: 0,
|
|
3198
|
-
boolean: false,
|
|
3199
|
-
object: {},
|
|
3200
|
-
array: []
|
|
3201
|
-
};
|
|
3202
|
-
return defaults[schema.type] || null;
|
|
3203
|
-
}
|
|
3204
|
-
resolveRef(ref, spec) {
|
|
3205
|
-
const path = ref.replace(/^#\//, "").split("/");
|
|
3206
|
-
let current = spec;
|
|
3207
|
-
for (const segment of path) {
|
|
3208
|
-
current = current[segment];
|
|
3209
|
-
if (!current) return {};
|
|
3210
|
-
}
|
|
3211
|
-
return current;
|
|
3212
|
-
}
|
|
3213
|
-
};
|
|
3214
|
-
|
|
3215
|
-
// src/lib/parsers/postman-parser.ts
|
|
3216
|
-
var PostmanParser = class {
|
|
3217
|
-
validate(input) {
|
|
3218
|
-
return typeof input === "object" && input !== null && "info" in input && input.info?.schema?.includes("v2");
|
|
3219
|
-
}
|
|
3220
|
-
parse(input) {
|
|
3221
|
-
if (!this.validate(input)) {
|
|
3222
|
-
throw new Error("Invalid Postman Collection format (requires v2.0 or v2.1)");
|
|
3223
|
-
}
|
|
3224
|
-
const baseUrl = this.extractBaseUrl(input);
|
|
3225
|
-
const endpoints = [];
|
|
3226
|
-
this.parseItems(input.item || [], endpoints, baseUrl, input);
|
|
3227
|
-
return {
|
|
3228
|
-
version: input.info?.version,
|
|
3229
|
-
title: input.info?.name,
|
|
3230
|
-
description: input.info?.description,
|
|
3231
|
-
baseUrl,
|
|
3232
|
-
auth: this.extractAuth(input.auth),
|
|
3233
|
-
globalHeaders: this.extractGlobalHeaders(input),
|
|
3234
|
-
endpoints
|
|
3235
|
-
};
|
|
3236
|
-
}
|
|
3237
|
-
extractBaseUrl(collection) {
|
|
3238
|
-
const baseUrlVar = collection.variable?.find(
|
|
3239
|
-
(v) => v.key === "baseUrl" || v.key === "base_url" || v.key === "url"
|
|
3240
|
-
);
|
|
3241
|
-
if (baseUrlVar) return baseUrlVar.value;
|
|
3242
|
-
if (collection.item && collection.item.length > 0) {
|
|
3243
|
-
const firstRequest = this.findFirstRequest(collection.item);
|
|
3244
|
-
if (firstRequest?.request?.url) {
|
|
3245
|
-
const url = this.parseUrl(firstRequest.request.url);
|
|
3246
|
-
if (url.host) {
|
|
3247
|
-
return `${url.protocol}://${url.host.join(".")}`;
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
}
|
|
3251
|
-
return "";
|
|
3252
|
-
}
|
|
3253
|
-
findFirstRequest(items) {
|
|
3254
|
-
for (const item of items) {
|
|
3255
|
-
if (item.request) return item;
|
|
3256
|
-
if (item.item) {
|
|
3257
|
-
const found = this.findFirstRequest(item.item);
|
|
3258
|
-
if (found) return found;
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
return null;
|
|
3262
|
-
}
|
|
3263
|
-
extractAuth(auth) {
|
|
3264
|
-
if (!auth) return void 0;
|
|
3265
|
-
if (auth.type === "bearer") {
|
|
3266
|
-
return {
|
|
3267
|
-
type: "bearer",
|
|
3268
|
-
tokenPrefix: "Bearer"
|
|
3269
|
-
};
|
|
3270
|
-
}
|
|
3271
|
-
if (auth.type === "apikey") {
|
|
3272
|
-
const keyData = auth.apikey?.find((a) => a.key === "key");
|
|
3273
|
-
const keyName = keyData?.value || "X-API-Key";
|
|
3274
|
-
return {
|
|
3275
|
-
type: "apiKey",
|
|
3276
|
-
headerName: keyName
|
|
3277
|
-
};
|
|
3278
|
-
}
|
|
3279
|
-
if (auth.type === "basic") {
|
|
3280
|
-
return {
|
|
3281
|
-
type: "basic"
|
|
3282
|
-
};
|
|
3283
|
-
}
|
|
3284
|
-
return void 0;
|
|
3285
|
-
}
|
|
3286
|
-
extractGlobalHeaders(collection) {
|
|
3287
|
-
return [];
|
|
3288
|
-
}
|
|
3289
|
-
parseItems(items, endpoints, baseUrl, collection) {
|
|
3290
|
-
for (const item of items) {
|
|
3291
|
-
if (item.item && Array.isArray(item.item)) {
|
|
3292
|
-
this.parseItems(item.item, endpoints, baseUrl, collection);
|
|
3293
|
-
} else if (item.request) {
|
|
3294
|
-
const endpoint = this.parseRequest(item, baseUrl, collection);
|
|
3295
|
-
endpoints.push(endpoint);
|
|
3296
|
-
}
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
parseRequest(item, baseUrl, collection) {
|
|
3300
|
-
const request = item.request;
|
|
3301
|
-
const url = this.parseUrl(request.url);
|
|
3302
|
-
const endpoint = {
|
|
3303
|
-
title: item.name,
|
|
3304
|
-
method: request.method.toUpperCase(),
|
|
3305
|
-
path: this.buildPath(url, baseUrl),
|
|
3306
|
-
description: item.request.description || item.description
|
|
3307
|
-
};
|
|
3308
|
-
const params = this.parseUrlParams(url);
|
|
3309
|
-
if (params.path.length > 0) endpoint.pathParams = params.path;
|
|
3310
|
-
if (params.query.length > 0) endpoint.queryParams = params.query;
|
|
3311
|
-
if (request.header && request.header.length > 0) {
|
|
3312
|
-
endpoint.headers = request.header.filter((h) => !h.disabled).map((h) => ({
|
|
3313
|
-
name: h.key,
|
|
3314
|
-
value: h.value || "",
|
|
3315
|
-
description: h.description
|
|
3316
|
-
}));
|
|
3317
|
-
}
|
|
3318
|
-
if (request.body) {
|
|
3319
|
-
endpoint.body = this.parseBody(request.body);
|
|
3320
|
-
}
|
|
3321
|
-
const responses = this.parseResponses(item.response || []);
|
|
3322
|
-
if (responses.success) endpoint.successResponse = responses.success;
|
|
3323
|
-
if (responses.errors.length > 0) endpoint.errorResponses = responses.errors;
|
|
3324
|
-
return endpoint;
|
|
3325
|
-
}
|
|
3326
|
-
parseUrl(url) {
|
|
3327
|
-
if (typeof url === "string") {
|
|
3328
|
-
const urlObj = new URL(url);
|
|
3329
|
-
return {
|
|
3330
|
-
protocol: urlObj.protocol.replace(":", ""),
|
|
3331
|
-
host: urlObj.hostname.split("."),
|
|
3332
|
-
path: urlObj.pathname.split("/").filter(Boolean),
|
|
3333
|
-
query: [],
|
|
3334
|
-
variable: []
|
|
3335
|
-
};
|
|
3336
|
-
}
|
|
3337
|
-
return {
|
|
3338
|
-
protocol: url.protocol || "https",
|
|
3339
|
-
host: url.host || [],
|
|
3340
|
-
path: url.path || [],
|
|
3341
|
-
query: url.query || [],
|
|
3342
|
-
variable: url.variable || []
|
|
3343
|
-
};
|
|
3344
|
-
}
|
|
3345
|
-
buildPath(url, baseUrl) {
|
|
3346
|
-
let path = "/";
|
|
3347
|
-
if (url.path && url.path.length > 0) {
|
|
3348
|
-
path += url.path.join("/");
|
|
3349
|
-
}
|
|
3350
|
-
path = path.replace(/\{\{([^}]+)\}\}/g, ":$1");
|
|
3351
|
-
return path;
|
|
3352
|
-
}
|
|
3353
|
-
parseUrlParams(url) {
|
|
3354
|
-
const result = { path: [], query: [] };
|
|
3355
|
-
if (url.variable && url.variable.length > 0) {
|
|
3356
|
-
for (const v of url.variable) {
|
|
3357
|
-
result.path.push({
|
|
3358
|
-
name: v.key,
|
|
3359
|
-
type: v.type || "string",
|
|
3360
|
-
description: v.description,
|
|
3361
|
-
example: v.value
|
|
3362
|
-
});
|
|
3363
|
-
}
|
|
3364
|
-
}
|
|
3365
|
-
if (url.path && url.path.length > 0) {
|
|
3366
|
-
for (const segment of url.path) {
|
|
3367
|
-
if (segment.startsWith(":")) {
|
|
3368
|
-
const paramName = segment.slice(1);
|
|
3369
|
-
if (!result.path.find((p) => p.name === paramName)) {
|
|
3370
|
-
result.path.push({
|
|
3371
|
-
name: paramName,
|
|
3372
|
-
type: "string"
|
|
3373
|
-
});
|
|
3374
|
-
}
|
|
3375
|
-
}
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
if (url.query && url.query.length > 0) {
|
|
3379
|
-
for (const q of url.query) {
|
|
3380
|
-
if (q.disabled) continue;
|
|
3381
|
-
result.query.push({
|
|
3382
|
-
name: q.key,
|
|
3383
|
-
type: "string",
|
|
3384
|
-
description: q.description,
|
|
3385
|
-
example: q.value
|
|
3386
|
-
});
|
|
3387
|
-
}
|
|
3388
|
-
}
|
|
3389
|
-
return result;
|
|
3390
|
-
}
|
|
3391
|
-
parseBody(body) {
|
|
3392
|
-
if (!body) return void 0;
|
|
3393
|
-
let example;
|
|
3394
|
-
let description = body.description;
|
|
3395
|
-
if (body.mode === "raw") {
|
|
3396
|
-
try {
|
|
3397
|
-
example = JSON.parse(body.raw);
|
|
3398
|
-
} catch {
|
|
3399
|
-
example = body.raw;
|
|
3400
|
-
}
|
|
3401
|
-
} else if (body.mode === "formdata" || body.mode === "urlencoded") {
|
|
3402
|
-
example = {};
|
|
3403
|
-
for (const item of body[body.mode] || []) {
|
|
3404
|
-
if (!item.disabled) {
|
|
3405
|
-
example[item.key] = item.value;
|
|
3406
|
-
}
|
|
3407
|
-
}
|
|
3408
|
-
}
|
|
3409
|
-
return {
|
|
3410
|
-
description,
|
|
3411
|
-
example
|
|
3412
|
-
};
|
|
3413
|
-
}
|
|
3414
|
-
parseResponses(responses) {
|
|
3415
|
-
const result = { errors: [] };
|
|
3416
|
-
for (const response of responses) {
|
|
3417
|
-
let example;
|
|
3418
|
-
try {
|
|
3419
|
-
example = JSON.parse(response.body);
|
|
3420
|
-
} catch {
|
|
3421
|
-
example = response.body;
|
|
3422
|
-
}
|
|
3423
|
-
const apiResponse = {
|
|
3424
|
-
status: response.code || 200,
|
|
3425
|
-
description: response.name,
|
|
3426
|
-
example
|
|
3427
|
-
};
|
|
3428
|
-
if (apiResponse.status >= 200 && apiResponse.status < 300) {
|
|
3429
|
-
if (!result.success) result.success = apiResponse;
|
|
3430
|
-
} else {
|
|
3431
|
-
result.errors.push(apiResponse);
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
return result;
|
|
3435
|
-
}
|
|
3436
|
-
};
|
|
3437
|
-
|
|
3438
|
-
// src/lib/parsers/index.ts
|
|
3439
|
-
var parsers = /* @__PURE__ */ new Map([
|
|
3440
|
-
["specra", new SpecraParser()],
|
|
3441
|
-
["openapi", new OpenApiParser()],
|
|
3442
|
-
["postman", new PostmanParser()]
|
|
3443
|
-
]);
|
|
3444
|
-
function detectParserType(input) {
|
|
3445
|
-
if (!input || typeof input !== "object") {
|
|
3446
|
-
throw new Error("Invalid API spec: input must be an object");
|
|
3447
|
-
}
|
|
3448
|
-
if (input.info?.schema?.includes("v2")) {
|
|
3449
|
-
return "postman";
|
|
3450
|
-
}
|
|
3451
|
-
if (input.openapi || input.swagger) {
|
|
3452
|
-
return "openapi";
|
|
3453
|
-
}
|
|
3454
|
-
if (input.endpoints && Array.isArray(input.endpoints)) {
|
|
3455
|
-
return "specra";
|
|
3456
|
-
}
|
|
3457
|
-
throw new Error(
|
|
3458
|
-
"Unable to auto-detect API spec format. Supported formats: Specra, OpenAPI 3.x, Postman Collection v2.x"
|
|
3459
|
-
);
|
|
3460
|
-
}
|
|
3461
|
-
function parseApiSpec(input, parserType = "auto") {
|
|
3462
|
-
const actualType = parserType === "auto" ? detectParserType(input) : parserType;
|
|
3463
|
-
const parser = parsers.get(actualType);
|
|
3464
|
-
if (!parser) {
|
|
3465
|
-
throw new Error(`Unknown parser type: ${actualType}`);
|
|
3466
|
-
}
|
|
3467
|
-
if (!parser.validate(input)) {
|
|
3468
|
-
throw new Error(`Input does not match ${actualType} format`);
|
|
3469
|
-
}
|
|
3470
|
-
return parser.parse(input);
|
|
3471
|
-
}
|
|
3472
|
-
|
|
3473
|
-
// src/components/docs/api/api-reference.tsx
|
|
3474
|
-
import { Loader2 as Loader23 } from "lucide-react";
|
|
3475
|
-
import { jsx as jsx52, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3476
|
-
function ApiReference({ spec, parser = "auto", showPlayground = true }) {
|
|
3477
|
-
const [apiSpec, setApiSpec] = useState23(null);
|
|
3478
|
-
const [loading, setLoading] = useState23(true);
|
|
3479
|
-
const [error, setError] = useState23(null);
|
|
3480
|
-
useEffect14(() => {
|
|
3481
|
-
async function loadSpec() {
|
|
3482
|
-
try {
|
|
3483
|
-
const response = await fetch(spec);
|
|
3484
|
-
if (!response.ok) {
|
|
3485
|
-
throw new Error(`Failed to load API spec: ${response.statusText}`);
|
|
3486
|
-
}
|
|
3487
|
-
const data = await response.json();
|
|
3488
|
-
const parsedSpec = parseApiSpec(data, parser);
|
|
3489
|
-
setApiSpec(parsedSpec);
|
|
3490
|
-
} catch (err) {
|
|
3491
|
-
setError(err instanceof Error ? err.message : "Failed to load API spec");
|
|
3492
|
-
} finally {
|
|
3493
|
-
setLoading(false);
|
|
3494
|
-
}
|
|
3495
|
-
}
|
|
3496
|
-
loadSpec();
|
|
3497
|
-
}, [spec, parser]);
|
|
3498
|
-
const interpolateEnv = (text, env) => {
|
|
3499
|
-
if (!env) return text;
|
|
3500
|
-
return text.replace(/\{(\w+)\}/g, (match, key) => {
|
|
3501
|
-
return env[key] || match;
|
|
3502
|
-
});
|
|
3503
|
-
};
|
|
3504
|
-
if (loading) {
|
|
3505
|
-
return /* @__PURE__ */ jsxs39("div", { className: "flex items-center justify-center py-12", children: [
|
|
3506
|
-
/* @__PURE__ */ jsx52(Loader23, { className: "h-6 w-6 animate-spin text-muted-foreground" }),
|
|
3507
|
-
/* @__PURE__ */ jsx52("span", { className: "ml-2 text-muted-foreground", children: "Loading API specification..." })
|
|
3508
|
-
] });
|
|
3509
|
-
}
|
|
3510
|
-
if (error) {
|
|
3511
|
-
return /* @__PURE__ */ jsx52("div", { className: "rounded-lg border border-red-500/20 bg-red-500/10 p-4", children: /* @__PURE__ */ jsxs39("p", { className: "text-sm text-red-600 dark:text-red-400", children: [
|
|
3512
|
-
"Error: ",
|
|
3513
|
-
error
|
|
3514
|
-
] }) });
|
|
3515
|
-
}
|
|
3516
|
-
if (!apiSpec) {
|
|
3517
|
-
return null;
|
|
3518
|
-
}
|
|
3519
|
-
return /* @__PURE__ */ jsxs39("div", { className: "space-y-6", children: [
|
|
3520
|
-
(apiSpec.title || apiSpec.description) && /* @__PURE__ */ jsxs39("div", { className: "mb-8", children: [
|
|
3521
|
-
apiSpec.title && /* @__PURE__ */ jsx52("h2", { className: "text-2xl font-semibold mb-2 text-foreground", children: apiSpec.title }),
|
|
3522
|
-
apiSpec.description && /* @__PURE__ */ jsx52("p", { className: "text-muted-foreground", children: apiSpec.description }),
|
|
3523
|
-
apiSpec.baseUrl && /* @__PURE__ */ jsxs39("div", { className: "mt-4", children: [
|
|
3524
|
-
/* @__PURE__ */ jsx52("p", { className: "text-sm font-semibold text-muted-foreground mb-1", children: "Base URL" }),
|
|
3525
|
-
/* @__PURE__ */ jsx52("code", { className: "text-sm px-2 py-1 bg-muted rounded", children: apiSpec.baseUrl })
|
|
3526
|
-
] })
|
|
3527
|
-
] }),
|
|
3528
|
-
apiSpec.auth && /* @__PURE__ */ jsxs39("div", { className: "rounded-lg border border-border bg-card/30 p-4 mb-6", children: [
|
|
3529
|
-
/* @__PURE__ */ jsx52("h3", { className: "text-lg font-semibold mb-2 text-foreground", children: "Authentication" }),
|
|
3530
|
-
/* @__PURE__ */ jsx52("p", { className: "text-sm text-muted-foreground mb-2", children: apiSpec.auth.description || `This API uses ${apiSpec.auth.type} authentication.` }),
|
|
3531
|
-
apiSpec.auth.type === "bearer" && /* @__PURE__ */ jsx52(
|
|
3532
|
-
CodeBlock,
|
|
3533
|
-
{
|
|
3534
|
-
code: `Authorization: ${apiSpec.auth.tokenPrefix || "Bearer"} {YOUR_TOKEN}`,
|
|
3535
|
-
language: "bash"
|
|
3536
|
-
}
|
|
3537
|
-
),
|
|
3538
|
-
apiSpec.auth.type === "apiKey" && /* @__PURE__ */ jsx52(
|
|
3539
|
-
CodeBlock,
|
|
3540
|
-
{
|
|
3541
|
-
code: `${apiSpec.auth.headerName || "X-API-Key"}: {YOUR_API_KEY}`,
|
|
3542
|
-
language: "bash"
|
|
3543
|
-
}
|
|
3544
|
-
)
|
|
3545
|
-
] }),
|
|
3546
|
-
/* @__PURE__ */ jsx52(Accordion, { type: "single", collapsible: true, className: "space-y-4", children: apiSpec.endpoints.map((endpoint, index) => {
|
|
3547
|
-
const allHeaders = [
|
|
3548
|
-
...apiSpec.globalHeaders || [],
|
|
3549
|
-
...endpoint.headers || []
|
|
3550
|
-
].map((header) => ({
|
|
3551
|
-
...header,
|
|
3552
|
-
value: interpolateEnv(header.value, apiSpec.env)
|
|
3553
|
-
}));
|
|
3554
|
-
return /* @__PURE__ */ jsx52(
|
|
3555
|
-
AccordionItem,
|
|
3556
|
-
{
|
|
3557
|
-
value: `endpoint-${index}`,
|
|
3558
|
-
title: /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-3", children: [
|
|
3559
|
-
/* @__PURE__ */ jsx52(
|
|
3560
|
-
"span",
|
|
3561
|
-
{
|
|
3562
|
-
className: `text-xs font-semibold px-2 py-0.5 rounded ${endpoint.method === "GET" ? "bg-blue-500/10 text-blue-600 dark:text-blue-400" : endpoint.method === "POST" ? "bg-green-500/10 text-green-600 dark:text-green-400" : endpoint.method === "PUT" ? "bg-orange-500/10 text-orange-600 dark:text-orange-400" : endpoint.method === "PATCH" ? "bg-purple-500/10 text-purple-600 dark:text-purple-400" : "bg-red-500/10 text-red-600 dark:text-red-400"}`,
|
|
3563
|
-
children: endpoint.method
|
|
3564
|
-
}
|
|
3565
|
-
),
|
|
3566
|
-
/* @__PURE__ */ jsx52("code", { className: "text-sm font-mono", children: endpoint.path }),
|
|
3567
|
-
/* @__PURE__ */ jsx52("span", { className: "text-sm text-muted-foreground ml-auto", children: endpoint.title })
|
|
3568
|
-
] }),
|
|
3569
|
-
children: /* @__PURE__ */ jsxs39("div", { className: "space-y-6 pt-4", children: [
|
|
3570
|
-
endpoint.description && /* @__PURE__ */ jsx52("p", { className: "text-sm text-muted-foreground", children: endpoint.description }),
|
|
3571
|
-
endpoint.pathParams && endpoint.pathParams.length > 0 && /* @__PURE__ */ jsx52(ApiParams, { title: "Path Parameters", params: endpoint.pathParams }),
|
|
3572
|
-
endpoint.queryParams && endpoint.queryParams.length > 0 && /* @__PURE__ */ jsx52(ApiParams, { title: "Query Parameters", params: endpoint.queryParams }),
|
|
3573
|
-
allHeaders.length > 0 && /* @__PURE__ */ jsxs39("div", { children: [
|
|
3574
|
-
/* @__PURE__ */ jsx52("h4", { className: "text-sm font-semibold text-foreground mb-3", children: "Headers" }),
|
|
3575
|
-
/* @__PURE__ */ jsx52("div", { className: "space-y-2", children: allHeaders.map((header, idx) => /* @__PURE__ */ jsxs39("div", { className: "flex flex-col gap-1", children: [
|
|
3576
|
-
/* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-2", children: [
|
|
3577
|
-
/* @__PURE__ */ jsx52("code", { className: "text-sm font-mono text-foreground", children: header.name }),
|
|
3578
|
-
/* @__PURE__ */ jsx52("span", { className: "text-xs text-muted-foreground", children: header.value })
|
|
3579
|
-
] }),
|
|
3580
|
-
header.description && /* @__PURE__ */ jsx52("p", { className: "text-sm text-muted-foreground", children: header.description })
|
|
3581
|
-
] }, idx)) })
|
|
3582
|
-
] }),
|
|
3583
|
-
endpoint.body && /* @__PURE__ */ jsxs39("div", { children: [
|
|
3584
|
-
/* @__PURE__ */ jsx52("h4", { className: "text-sm font-semibold text-foreground mb-3", children: "Request Body" }),
|
|
3585
|
-
endpoint.body.description && /* @__PURE__ */ jsx52("p", { className: "text-sm text-muted-foreground mb-2", children: endpoint.body.description }),
|
|
3586
|
-
endpoint.body.example && /* @__PURE__ */ jsx52(
|
|
3587
|
-
CodeBlock,
|
|
3588
|
-
{
|
|
3589
|
-
code: typeof endpoint.body.example === "string" ? endpoint.body.example : JSON.stringify(endpoint.body.example, null, 2),
|
|
3590
|
-
language: "json"
|
|
3591
|
-
}
|
|
3592
|
-
)
|
|
3593
|
-
] }),
|
|
3594
|
-
/* @__PURE__ */ jsxs39("div", { children: [
|
|
3595
|
-
/* @__PURE__ */ jsx52("h4", { className: "text-sm font-semibold text-foreground mb-3", children: "Responses" }),
|
|
3596
|
-
endpoint.successResponse && /* @__PURE__ */ jsx52(
|
|
3597
|
-
ApiResponse,
|
|
3598
|
-
{
|
|
3599
|
-
status: endpoint.successResponse.status,
|
|
3600
|
-
description: endpoint.successResponse.description,
|
|
3601
|
-
example: endpoint.successResponse.example,
|
|
3602
|
-
schema: endpoint.successResponse.schema
|
|
3603
|
-
}
|
|
3604
|
-
),
|
|
3605
|
-
endpoint.errorResponses?.map((response, idx) => /* @__PURE__ */ jsx52(
|
|
3606
|
-
ApiResponse,
|
|
3607
|
-
{
|
|
3608
|
-
status: response.status,
|
|
3609
|
-
description: response.description,
|
|
3610
|
-
example: response.example,
|
|
3611
|
-
schema: response.schema
|
|
3612
|
-
},
|
|
3613
|
-
idx
|
|
3614
|
-
))
|
|
3615
|
-
] }),
|
|
3616
|
-
endpoint.examples && endpoint.examples.length > 0 && /* @__PURE__ */ jsxs39("div", { children: [
|
|
3617
|
-
/* @__PURE__ */ jsx52("h4", { className: "text-sm font-semibold text-foreground mb-3", children: "Examples" }),
|
|
3618
|
-
endpoint.examples.map((example, idx) => /* @__PURE__ */ jsxs39("div", { className: "mb-3", children: [
|
|
3619
|
-
/* @__PURE__ */ jsx52("p", { className: "text-xs font-semibold text-muted-foreground mb-2", children: example.title }),
|
|
3620
|
-
/* @__PURE__ */ jsx52(CodeBlock, { code: example.code, language: example.language })
|
|
3621
|
-
] }, idx))
|
|
3622
|
-
] }),
|
|
3623
|
-
showPlayground && /* @__PURE__ */ jsx52(
|
|
3624
|
-
ApiPlayground,
|
|
3625
|
-
{
|
|
3626
|
-
method: endpoint.method,
|
|
3627
|
-
path: endpoint.path,
|
|
3628
|
-
baseUrl: apiSpec.baseUrl,
|
|
3629
|
-
headers: Object.fromEntries(allHeaders.map((h) => [h.name, h.value])),
|
|
3630
|
-
pathParams: endpoint.pathParams,
|
|
3631
|
-
defaultBody: endpoint.body?.example ? typeof endpoint.body.example === "string" ? endpoint.body.example : JSON.stringify(endpoint.body.example, null, 2) : void 0
|
|
3632
|
-
}
|
|
3633
|
-
)
|
|
3634
|
-
] })
|
|
3635
|
-
},
|
|
3636
|
-
index
|
|
3637
|
-
);
|
|
3638
|
-
}) })
|
|
3639
|
-
] });
|
|
3640
|
-
}
|
|
3641
|
-
|
|
3642
|
-
// src/components/global/version-not-found.tsx
|
|
3643
|
-
import { AlertTriangle as AlertTriangle3 } from "lucide-react";
|
|
3644
|
-
import Link10 from "next/link";
|
|
3645
|
-
import { Fragment as Fragment10, jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3646
|
-
function VersionNotFound() {
|
|
3647
|
-
return /* @__PURE__ */ jsx53(Fragment10, { children: /* @__PURE__ */ jsx53("div", { className: "flex min-h-screen items-center justify-center px-4", children: /* @__PURE__ */ jsxs40("div", { className: "text-center", children: [
|
|
3648
|
-
/* @__PURE__ */ jsx53("div", { className: "mb-4 flex justify-center", children: /* @__PURE__ */ jsx53(AlertTriangle3, { className: "h-16 w-16 text-yellow-500" }) }),
|
|
3649
|
-
/* @__PURE__ */ jsx53("h1", { className: "mb-2 text-4xl font-bold", children: "Version Not Found" }),
|
|
3650
|
-
/* @__PURE__ */ jsx53("p", { className: "mb-6 text-muted-foreground", children: "The documentation version you're looking for doesn't exist." }),
|
|
3651
|
-
/* @__PURE__ */ jsx53(
|
|
3652
|
-
Link10,
|
|
3653
|
-
{
|
|
3654
|
-
href: "/docs/v1.0.0",
|
|
3655
|
-
className: "inline-flex items-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90",
|
|
3656
|
-
children: "Go to Latest Version"
|
|
3657
|
-
}
|
|
3658
|
-
)
|
|
3659
|
-
] }) }) });
|
|
3660
|
-
}
|
|
3661
|
-
export {
|
|
3662
|
-
Accordion,
|
|
3663
|
-
AccordionItem,
|
|
3664
|
-
ApiEndpoint,
|
|
3665
|
-
ApiParams,
|
|
3666
|
-
ApiPlayground,
|
|
3667
|
-
ApiReference,
|
|
3668
|
-
ApiResponse,
|
|
3669
|
-
ApiResponse as ApiResponseDisplay,
|
|
3670
|
-
Badge2 as Badge,
|
|
3671
|
-
Breadcrumb,
|
|
3672
|
-
Button,
|
|
3673
|
-
COMPONENT_TEXT_PROPS,
|
|
3674
|
-
Callout,
|
|
3675
|
-
Card,
|
|
3676
|
-
CardGrid,
|
|
3677
|
-
CodeBlock,
|
|
3678
|
-
Column,
|
|
3679
|
-
Columns,
|
|
3680
|
-
ConfigProvider,
|
|
3681
|
-
DevModeBadge,
|
|
3682
|
-
Dialog,
|
|
3683
|
-
DialogClose,
|
|
3684
|
-
DialogContent,
|
|
3685
|
-
DialogDescription,
|
|
3686
|
-
DialogFooter,
|
|
3687
|
-
DialogHeader,
|
|
3688
|
-
DialogOverlay,
|
|
3689
|
-
DialogPortal,
|
|
3690
|
-
DialogTitle,
|
|
3691
|
-
DialogTrigger,
|
|
3692
|
-
Badge as DocBadge,
|
|
3693
|
-
DocLayoutWrapper,
|
|
3694
|
-
DocLoading,
|
|
3695
|
-
DocMetadata,
|
|
3696
|
-
DocNavigation,
|
|
3697
|
-
DocTags,
|
|
3698
|
-
DraftBadge,
|
|
3699
|
-
Footer,
|
|
3700
|
-
Frame,
|
|
3701
|
-
Header,
|
|
3702
|
-
HotReloadIndicator,
|
|
3703
|
-
Icon,
|
|
3704
|
-
Image,
|
|
3705
|
-
ImageCard,
|
|
3706
|
-
ImageCardGrid,
|
|
3707
|
-
Input,
|
|
3708
|
-
LanguageSwitcher,
|
|
3709
|
-
Logo,
|
|
3710
|
-
Math2 as Math,
|
|
3711
|
-
MdxHotReload,
|
|
3712
|
-
Mermaid,
|
|
3713
|
-
MobileDocLayout,
|
|
3714
|
-
NotFoundContent,
|
|
3715
|
-
SearchHighlight,
|
|
3716
|
-
SearchModal,
|
|
3717
|
-
Sidebar,
|
|
3718
|
-
SidebarSkeleton,
|
|
3719
|
-
SiteBanner,
|
|
3720
|
-
Step,
|
|
3721
|
-
Steps,
|
|
3722
|
-
Tab,
|
|
3723
|
-
TabGroups,
|
|
3724
|
-
TabProvider,
|
|
3725
|
-
TableOfContents,
|
|
3726
|
-
Tabs,
|
|
3727
|
-
Textarea,
|
|
3728
|
-
ThemeToggle,
|
|
3729
|
-
Tooltip,
|
|
3730
|
-
VersionNotFound,
|
|
3731
|
-
VersionSwitcher,
|
|
3732
|
-
Video,
|
|
3733
|
-
badgeVariants,
|
|
3734
|
-
buttonVariants,
|
|
3735
|
-
extractComponentPropsText,
|
|
3736
|
-
extractSearchText,
|
|
3737
|
-
useConfig,
|
|
3738
|
-
useConfigValue,
|
|
3739
|
-
useTabContext
|
|
3740
|
-
};
|
|
3741
|
-
//# sourceMappingURL=index.mjs.map
|