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
package/dist/index.mjs
DELETED
|
@@ -1,1897 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PerfTimer,
|
|
3
|
-
buildRedirectMappings,
|
|
4
|
-
clearAllCaches,
|
|
5
|
-
debugLog,
|
|
6
|
-
extractHeadings,
|
|
7
|
-
extractTableOfContents,
|
|
8
|
-
findRedirect,
|
|
9
|
-
getAdjacentDocs,
|
|
10
|
-
getAllCategoryConfigs,
|
|
11
|
-
getAllDocs,
|
|
12
|
-
getCacheStats,
|
|
13
|
-
getCachedAllDocs,
|
|
14
|
-
getCachedDocBySlug,
|
|
15
|
-
getCachedVersions,
|
|
16
|
-
getCategoryConfig,
|
|
17
|
-
getDocBySlug,
|
|
18
|
-
getI18nConfig,
|
|
19
|
-
getVersions,
|
|
20
|
-
isCategoryPage,
|
|
21
|
-
logCacheOperation,
|
|
22
|
-
logFsOperation,
|
|
23
|
-
logMemoryUsage
|
|
24
|
-
} from "./chunk-WMCO2UX5.mjs";
|
|
25
|
-
import {
|
|
26
|
-
CSP_DIRECTIVES,
|
|
27
|
-
SAFE_MDX_COMPONENTS,
|
|
28
|
-
generateCSPHeader,
|
|
29
|
-
sanitizeMDXContent,
|
|
30
|
-
sanitizePath,
|
|
31
|
-
scanMDXForDangerousPatterns,
|
|
32
|
-
validateMDXComponents,
|
|
33
|
-
validateMDXSecurity,
|
|
34
|
-
validatePathWithinDirectory
|
|
35
|
-
} from "./chunk-BE7EROIW.mjs";
|
|
36
|
-
import {
|
|
37
|
-
Breadcrumb,
|
|
38
|
-
DocMetadata,
|
|
39
|
-
DocNavigation,
|
|
40
|
-
DocTags,
|
|
41
|
-
DraftBadge
|
|
42
|
-
} from "./chunk-CWHRZHZO.mjs";
|
|
43
|
-
import {
|
|
44
|
-
buildSidebarStructure,
|
|
45
|
-
defaultConfig,
|
|
46
|
-
getConfig,
|
|
47
|
-
getConfigValue,
|
|
48
|
-
initConfig,
|
|
49
|
-
loadConfig,
|
|
50
|
-
processContentWithEnv,
|
|
51
|
-
reloadConfig,
|
|
52
|
-
replaceEnvVariables,
|
|
53
|
-
sortSidebarGroups,
|
|
54
|
-
sortSidebarItems,
|
|
55
|
-
validateConfig
|
|
56
|
-
} from "./chunk-6S3EJVEO.mjs";
|
|
57
|
-
import {
|
|
58
|
-
Accordion,
|
|
59
|
-
AccordionItem,
|
|
60
|
-
ApiEndpoint,
|
|
61
|
-
ApiParams,
|
|
62
|
-
ApiPlayground,
|
|
63
|
-
ApiReference,
|
|
64
|
-
ApiResponse,
|
|
65
|
-
Badge,
|
|
66
|
-
Badge2,
|
|
67
|
-
Button,
|
|
68
|
-
Callout,
|
|
69
|
-
Card,
|
|
70
|
-
CardGrid,
|
|
71
|
-
CodeBlock,
|
|
72
|
-
Column,
|
|
73
|
-
Columns,
|
|
74
|
-
Frame,
|
|
75
|
-
Icon,
|
|
76
|
-
Image,
|
|
77
|
-
ImageCard,
|
|
78
|
-
ImageCardGrid,
|
|
79
|
-
Input,
|
|
80
|
-
Math as Math2,
|
|
81
|
-
Mermaid,
|
|
82
|
-
Step,
|
|
83
|
-
Steps,
|
|
84
|
-
Tab,
|
|
85
|
-
Tabs,
|
|
86
|
-
Textarea,
|
|
87
|
-
Tooltip,
|
|
88
|
-
Video,
|
|
89
|
-
badgeVariants,
|
|
90
|
-
buttonVariants
|
|
91
|
-
} from "./chunk-D5VDVYFY.mjs";
|
|
92
|
-
import {
|
|
93
|
-
OpenApiParser,
|
|
94
|
-
PostmanParser,
|
|
95
|
-
SpecraParser,
|
|
96
|
-
cn,
|
|
97
|
-
detectParserType,
|
|
98
|
-
getAssetPath,
|
|
99
|
-
parseApiSpec
|
|
100
|
-
} from "./chunk-XEMGCPZZ.mjs";
|
|
101
|
-
|
|
102
|
-
// src/components/docs/componentTextProps.ts
|
|
103
|
-
var COMPONENT_TEXT_PROPS = {
|
|
104
|
-
// Accordion components
|
|
105
|
-
Accordion: ["title"],
|
|
106
|
-
AccordionItem: ["title"],
|
|
107
|
-
// Alert/Callout components
|
|
108
|
-
Alert: ["title", "description"],
|
|
109
|
-
Banner: ["title"],
|
|
110
|
-
Callout: ["title", "content"],
|
|
111
|
-
Note: ["title"],
|
|
112
|
-
Warning: ["title", "text"],
|
|
113
|
-
// Navigation components
|
|
114
|
-
BreadCrumb: ["title", "slug", "version"],
|
|
115
|
-
// Card components
|
|
116
|
-
Card: ["title", "description"],
|
|
117
|
-
ImageCard: ["title", "description", "alt"],
|
|
118
|
-
// Media components
|
|
119
|
-
Image: ["alt", "caption"],
|
|
120
|
-
Video: ["caption"],
|
|
121
|
-
Frame: ["title"],
|
|
122
|
-
Mermaid: ["caption"],
|
|
123
|
-
// Interactive components
|
|
124
|
-
Tooltip: ["content"],
|
|
125
|
-
// Code components
|
|
126
|
-
CodeBlock: ["filename"],
|
|
127
|
-
// Step components
|
|
128
|
-
Step: ["title"]
|
|
129
|
-
};
|
|
130
|
-
function extractComponentPropsText(mdx) {
|
|
131
|
-
return mdx.replace(
|
|
132
|
-
/<([A-Z][\w]*)\b([^/>]*)\/>/g,
|
|
133
|
-
(_, component, props) => {
|
|
134
|
-
const searchableProps = COMPONENT_TEXT_PROPS[component];
|
|
135
|
-
if (!searchableProps) return " ";
|
|
136
|
-
let extracted = "";
|
|
137
|
-
for (const prop of searchableProps) {
|
|
138
|
-
const match = props.match(
|
|
139
|
-
new RegExp(`${prop}="([^"]+)"`, "i")
|
|
140
|
-
);
|
|
141
|
-
if (match) {
|
|
142
|
-
extracted += " " + match[1];
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return extracted || " ";
|
|
146
|
-
}
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
function extractSearchText(mdx) {
|
|
150
|
-
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);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// src/components/docs/dev-mode-badge.tsx
|
|
154
|
-
import { useEffect, useState } from "react";
|
|
155
|
-
import { Code2 } from "lucide-react";
|
|
156
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
157
|
-
function DevModeBadge() {
|
|
158
|
-
const [isConnected, setIsConnected] = useState(true);
|
|
159
|
-
useEffect(() => {
|
|
160
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
161
|
-
const checkConnection = () => {
|
|
162
|
-
setIsConnected(navigator.onLine);
|
|
163
|
-
};
|
|
164
|
-
window.addEventListener("online", checkConnection);
|
|
165
|
-
window.addEventListener("offline", checkConnection);
|
|
166
|
-
return () => {
|
|
167
|
-
window.removeEventListener("online", checkConnection);
|
|
168
|
-
window.removeEventListener("offline", checkConnection);
|
|
169
|
-
};
|
|
170
|
-
}, []);
|
|
171
|
-
if (process.env.NODE_ENV !== "development") return null;
|
|
172
|
-
return /* @__PURE__ */ jsxs("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: [
|
|
173
|
-
/* @__PURE__ */ jsx(Code2, { className: "h-3 w-3" }),
|
|
174
|
-
/* @__PURE__ */ jsx("span", { children: "Dev Mode" }),
|
|
175
|
-
/* @__PURE__ */ jsx("div", { className: `h-2 w-2 rounded-full ${isConnected ? "bg-green-500" : "bg-red-500"} animate-pulse` })
|
|
176
|
-
] });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// src/components/docs/mobile-doc-layout.tsx
|
|
180
|
-
import { useState as useState6, cloneElement, isValidElement } from "react";
|
|
181
|
-
import Link3 from "next/link";
|
|
182
|
-
|
|
183
|
-
// src/components/docs/footer.tsx
|
|
184
|
-
import Link from "next/link";
|
|
185
|
-
|
|
186
|
-
// src/components/docs/logo.tsx
|
|
187
|
-
import { useTheme } from "next-themes";
|
|
188
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
189
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
190
|
-
function Logo({ logo, alt = "Logo", className = "h-8 w-8 object-contain" }) {
|
|
191
|
-
const { resolvedTheme } = useTheme();
|
|
192
|
-
const [mounted, setMounted] = useState2(false);
|
|
193
|
-
useEffect2(() => {
|
|
194
|
-
setMounted(true);
|
|
195
|
-
}, []);
|
|
196
|
-
if (!logo) return null;
|
|
197
|
-
if (typeof logo === "string") {
|
|
198
|
-
return /* @__PURE__ */ jsx2("img", { src: logo, alt, className });
|
|
199
|
-
}
|
|
200
|
-
if (!mounted) {
|
|
201
|
-
return /* @__PURE__ */ jsx2("img", { src: logo.light, alt, className });
|
|
202
|
-
}
|
|
203
|
-
const logoSrc = resolvedTheme === "dark" ? logo.dark : logo.light;
|
|
204
|
-
return /* @__PURE__ */ jsx2("img", { src: logoSrc, alt, className });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// src/components/docs/footer.tsx
|
|
208
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
209
|
-
function Footer({ config }) {
|
|
210
|
-
if (!config.footer) {
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
return /* @__PURE__ */ jsx3("footer", { className: "bg-muted/30 dark:bg-muted/10 rounded-2xl mt-24", children: /* @__PURE__ */ jsxs2("div", { className: "px-2 md:px-6 py-12", children: [
|
|
214
|
-
config.footer.links && config.footer.links.length > 0 && /* @__PURE__ */ jsx3("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-8 mb-8", children: config.footer.links.map((column, idx) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
215
|
-
/* @__PURE__ */ jsx3("h3", { className: "font-semibold text-foreground mb-4", children: column.title }),
|
|
216
|
-
/* @__PURE__ */ jsx3("ul", { className: "space-y-2", children: column.items.map((item, itemIdx) => /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsx3(
|
|
217
|
-
Link,
|
|
218
|
-
{
|
|
219
|
-
href: item.href,
|
|
220
|
-
className: "text-sm text-muted-foreground hover:text-foreground transition-colors",
|
|
221
|
-
children: item.label
|
|
222
|
-
}
|
|
223
|
-
) }, itemIdx)) })
|
|
224
|
-
] }, idx)) }),
|
|
225
|
-
/* @__PURE__ */ jsx3("div", { className: "pt-8 border-t border-border/50", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col md:flex-row items-center justify-between gap-4", children: [
|
|
226
|
-
config.footer.copyright && /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground text-center md:text-left", children: config.footer.copyright }),
|
|
227
|
-
config.footer.branding?.showBranding && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
228
|
-
config.footer.branding.logo && /* @__PURE__ */ jsx3(
|
|
229
|
-
Logo,
|
|
230
|
-
{
|
|
231
|
-
logo: config.footer.branding.logo,
|
|
232
|
-
alt: config.footer.branding.title || "Powered by",
|
|
233
|
-
className: "h-5 w-auto object-contain"
|
|
234
|
-
}
|
|
235
|
-
),
|
|
236
|
-
/* @__PURE__ */ jsx3("span", { children: "Powered by" }),
|
|
237
|
-
config.footer.branding.url ? /* @__PURE__ */ jsx3(
|
|
238
|
-
Link,
|
|
239
|
-
{
|
|
240
|
-
href: config.footer.branding.url,
|
|
241
|
-
target: "_blank",
|
|
242
|
-
rel: "noopener noreferrer",
|
|
243
|
-
className: "font-semibold hover:text-foreground transition-colors",
|
|
244
|
-
children: config.footer.branding.title || "Specra"
|
|
245
|
-
}
|
|
246
|
-
) : /* @__PURE__ */ jsx3("span", { className: "font-semibold", children: config.footer.branding.title || "Specra" })
|
|
247
|
-
] })
|
|
248
|
-
] }) })
|
|
249
|
-
] }) });
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// src/components/docs/site-banner.tsx
|
|
253
|
-
import { X, AlertCircle, CheckCircle, Info, XCircle } from "lucide-react";
|
|
254
|
-
import { useState as useState3, useEffect as useEffect3 } from "react";
|
|
255
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
256
|
-
function SiteBanner({ config }) {
|
|
257
|
-
const [dismissed, setDismissed] = useState3(false);
|
|
258
|
-
const [mounted, setMounted] = useState3(false);
|
|
259
|
-
const banner = config.banner;
|
|
260
|
-
const storageKey = "site-banner-dismissed";
|
|
261
|
-
useEffect3(() => {
|
|
262
|
-
setMounted(true);
|
|
263
|
-
const isDismissed = localStorage.getItem(storageKey) === "true";
|
|
264
|
-
setDismissed(isDismissed);
|
|
265
|
-
}, []);
|
|
266
|
-
const handleDismiss = () => {
|
|
267
|
-
setDismissed(true);
|
|
268
|
-
localStorage.setItem(storageKey, "true");
|
|
269
|
-
};
|
|
270
|
-
if (!mounted || !banner || !banner.enabled || dismissed) {
|
|
271
|
-
return null;
|
|
272
|
-
}
|
|
273
|
-
const typeConfig = {
|
|
274
|
-
info: {
|
|
275
|
-
icon: Info,
|
|
276
|
-
bg: "bg-blue-500/10 dark:bg-blue-400/5",
|
|
277
|
-
border: "border-blue-500/30 dark:border-blue-500/20",
|
|
278
|
-
iconColor: "text-blue-600 dark:text-blue-400",
|
|
279
|
-
textColor: "text-blue-900 dark:text-blue-300"
|
|
280
|
-
},
|
|
281
|
-
success: {
|
|
282
|
-
icon: CheckCircle,
|
|
283
|
-
bg: "bg-green-500/10 dark:bg-green-400/5",
|
|
284
|
-
border: "border-green-500/30 dark:border-green-500/20",
|
|
285
|
-
iconColor: "text-green-600 dark:text-green-400",
|
|
286
|
-
textColor: "text-green-900 dark:text-green-300"
|
|
287
|
-
},
|
|
288
|
-
warning: {
|
|
289
|
-
icon: AlertCircle,
|
|
290
|
-
bg: "bg-yellow-500/10 dark:bg-yellow-400/5",
|
|
291
|
-
border: "border-yellow-500/30 dark:border-yellow-500/20",
|
|
292
|
-
iconColor: "text-yellow-600 dark:text-yellow-400",
|
|
293
|
-
textColor: "text-yellow-900 dark:text-yellow-300"
|
|
294
|
-
},
|
|
295
|
-
error: {
|
|
296
|
-
icon: XCircle,
|
|
297
|
-
bg: "bg-red-500/10 dark:bg-red-400/5",
|
|
298
|
-
border: "border-red-500/30 dark:border-red-500/20",
|
|
299
|
-
iconColor: "text-red-600 dark:text-red-400",
|
|
300
|
-
textColor: "text-red-900 dark:text-red-300"
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
const type = banner.type || "info";
|
|
304
|
-
const { icon: IconComponent, bg, border, iconColor, textColor } = typeConfig[type];
|
|
305
|
-
return /* @__PURE__ */ jsx4("div", { className: `w-full border-b ${border} ${bg}`, children: /* @__PURE__ */ jsx4("div", { className: "container mx-auto px-2 md:px-6 py-3", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3", children: [
|
|
306
|
-
/* @__PURE__ */ jsx4(IconComponent, { className: `h-5 w-5 shrink-0 ${iconColor}` }),
|
|
307
|
-
/* @__PURE__ */ jsx4("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx4("p", { className: `text-sm font-medium ${textColor}`, children: banner.message }) }),
|
|
308
|
-
banner.dismissible && /* @__PURE__ */ jsx4(
|
|
309
|
-
"button",
|
|
310
|
-
{
|
|
311
|
-
onClick: handleDismiss,
|
|
312
|
-
className: `shrink-0 p-1 rounded-md hover:bg-black/5 dark:hover:bg-white/5 transition-colors ${iconColor}`,
|
|
313
|
-
"aria-label": "Dismiss banner",
|
|
314
|
-
children: /* @__PURE__ */ jsx4(X, { className: "h-4 w-4" })
|
|
315
|
-
}
|
|
316
|
-
)
|
|
317
|
-
] }) }) });
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// src/components/docs/tab-groups.tsx
|
|
321
|
-
import { useState as useState4 } from "react";
|
|
322
|
-
import { useRouter } from "next/navigation";
|
|
323
|
-
import { ChevronDown } from "lucide-react";
|
|
324
|
-
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
325
|
-
function TabGroups({ tabGroups, activeTabId, onTabChange, mobileOnly = false, docs, version }) {
|
|
326
|
-
const [dropdownOpen, setDropdownOpen] = useState4(false);
|
|
327
|
-
const router = useRouter();
|
|
328
|
-
const filteredTabGroups = docs ? tabGroups.filter((tab) => {
|
|
329
|
-
const hasDocsInTab = docs.some((doc) => {
|
|
330
|
-
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
331
|
-
return docTabGroup === tab.id || !docTabGroup && tab.id === tabGroups[0]?.id;
|
|
332
|
-
});
|
|
333
|
-
return hasDocsInTab;
|
|
334
|
-
}) : tabGroups;
|
|
335
|
-
const activeTab = activeTabId || filteredTabGroups[0]?.id || "";
|
|
336
|
-
const activeTabData = filteredTabGroups.find((tab) => tab.id === activeTab);
|
|
337
|
-
const handleTabChange = (tabId) => {
|
|
338
|
-
onTabChange?.(tabId);
|
|
339
|
-
setDropdownOpen(false);
|
|
340
|
-
if (docs && version) {
|
|
341
|
-
const firstDocInTab = docs.find((doc) => {
|
|
342
|
-
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
343
|
-
return docTabGroup === tabId || !docTabGroup && tabId === filteredTabGroups[0]?.id;
|
|
344
|
-
});
|
|
345
|
-
if (firstDocInTab) {
|
|
346
|
-
router.push(`/docs/${version}/${firstDocInTab.slug}`);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
if (!filteredTabGroups || filteredTabGroups.length === 0) {
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
if (mobileOnly) {
|
|
354
|
-
return /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
355
|
-
/* @__PURE__ */ jsxs4(
|
|
356
|
-
"button",
|
|
357
|
-
{
|
|
358
|
-
onClick: () => setDropdownOpen(!dropdownOpen),
|
|
359
|
-
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",
|
|
360
|
-
"aria-label": "Select tab group",
|
|
361
|
-
"aria-expanded": dropdownOpen,
|
|
362
|
-
children: [
|
|
363
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
364
|
-
activeTabData?.icon && /* @__PURE__ */ jsx5(Icon, { icon: activeTabData.icon, size: 16, className: "shrink-0" }),
|
|
365
|
-
/* @__PURE__ */ jsx5("span", { children: activeTabData?.label })
|
|
366
|
-
] }),
|
|
367
|
-
/* @__PURE__ */ jsx5(
|
|
368
|
-
ChevronDown,
|
|
369
|
-
{
|
|
370
|
-
className: `h-4 w-4 transition-transform ${dropdownOpen ? "rotate-180" : ""}`
|
|
371
|
-
}
|
|
372
|
-
)
|
|
373
|
-
]
|
|
374
|
-
}
|
|
375
|
-
),
|
|
376
|
-
dropdownOpen && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
377
|
-
/* @__PURE__ */ jsx5(
|
|
378
|
-
"div",
|
|
379
|
-
{
|
|
380
|
-
className: "fixed inset-0 z-40",
|
|
381
|
-
onClick: () => setDropdownOpen(false)
|
|
382
|
-
}
|
|
383
|
-
),
|
|
384
|
-
/* @__PURE__ */ jsx5("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) => {
|
|
385
|
-
const isActive = tab.id === activeTab;
|
|
386
|
-
return /* @__PURE__ */ jsxs4(
|
|
387
|
-
"button",
|
|
388
|
-
{
|
|
389
|
-
onClick: () => handleTabChange(tab.id),
|
|
390
|
-
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"}`,
|
|
391
|
-
children: [
|
|
392
|
-
tab.icon && /* @__PURE__ */ jsx5(Icon, { icon: tab.icon, size: 16, className: "shrink-0" }),
|
|
393
|
-
tab.label
|
|
394
|
-
]
|
|
395
|
-
},
|
|
396
|
-
tab.id
|
|
397
|
-
);
|
|
398
|
-
}) })
|
|
399
|
-
] })
|
|
400
|
-
] });
|
|
401
|
-
}
|
|
402
|
-
return /* @__PURE__ */ jsx5("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60", children: /* @__PURE__ */ jsxs4("div", { className: "container mx-auto px-2 md:px-6", children: [
|
|
403
|
-
/* @__PURE__ */ jsxs4("div", { className: "md:hidden relative", children: [
|
|
404
|
-
/* @__PURE__ */ jsxs4(
|
|
405
|
-
"button",
|
|
406
|
-
{
|
|
407
|
-
onClick: () => setDropdownOpen(!dropdownOpen),
|
|
408
|
-
className: "flex items-center justify-between w-full px-4 py-3 text-sm font-medium text-foreground",
|
|
409
|
-
"aria-label": "Select tab",
|
|
410
|
-
"aria-expanded": dropdownOpen,
|
|
411
|
-
children: [
|
|
412
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
413
|
-
activeTabData?.icon && /* @__PURE__ */ jsx5(Icon, { icon: activeTabData.icon, size: 16, className: "shrink-0" }),
|
|
414
|
-
activeTabData?.label
|
|
415
|
-
] }),
|
|
416
|
-
/* @__PURE__ */ jsx5(
|
|
417
|
-
ChevronDown,
|
|
418
|
-
{
|
|
419
|
-
className: `h-4 w-4 transition-transform ${dropdownOpen ? "rotate-180" : ""}`
|
|
420
|
-
}
|
|
421
|
-
)
|
|
422
|
-
]
|
|
423
|
-
}
|
|
424
|
-
),
|
|
425
|
-
dropdownOpen && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
426
|
-
/* @__PURE__ */ jsx5(
|
|
427
|
-
"div",
|
|
428
|
-
{
|
|
429
|
-
className: "fixed inset-0 z-40",
|
|
430
|
-
onClick: () => setDropdownOpen(false)
|
|
431
|
-
}
|
|
432
|
-
),
|
|
433
|
-
/* @__PURE__ */ jsx5("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) => {
|
|
434
|
-
const isActive = tab.id === activeTab;
|
|
435
|
-
return /* @__PURE__ */ jsxs4(
|
|
436
|
-
"button",
|
|
437
|
-
{
|
|
438
|
-
onClick: () => handleTabChange(tab.id),
|
|
439
|
-
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"}`,
|
|
440
|
-
children: [
|
|
441
|
-
tab.icon && /* @__PURE__ */ jsx5(Icon, { icon: tab.icon, size: 16, className: "shrink-0" }),
|
|
442
|
-
tab.label
|
|
443
|
-
]
|
|
444
|
-
},
|
|
445
|
-
tab.id
|
|
446
|
-
);
|
|
447
|
-
}) })
|
|
448
|
-
] })
|
|
449
|
-
] }),
|
|
450
|
-
/* @__PURE__ */ jsx5("nav", { className: "hidden md:flex gap-1", "aria-label": "Documentation tabs", children: filteredTabGroups.map((tab) => {
|
|
451
|
-
const isActive = tab.id === activeTab;
|
|
452
|
-
return /* @__PURE__ */ jsxs4(
|
|
453
|
-
"button",
|
|
454
|
-
{
|
|
455
|
-
onClick: () => handleTabChange(tab.id),
|
|
456
|
-
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"}`,
|
|
457
|
-
"aria-current": isActive ? "page" : void 0,
|
|
458
|
-
children: [
|
|
459
|
-
tab.icon && /* @__PURE__ */ jsx5(Icon, { icon: tab.icon, size: 16, className: "shrink-0" }),
|
|
460
|
-
tab.label
|
|
461
|
-
]
|
|
462
|
-
},
|
|
463
|
-
tab.id
|
|
464
|
-
);
|
|
465
|
-
}) })
|
|
466
|
-
] }) });
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// src/components/docs/sidebar-menu-items.tsx
|
|
470
|
-
import Link2 from "next/link";
|
|
471
|
-
import { usePathname } from "next/navigation";
|
|
472
|
-
import { ChevronRight, ChevronDown as ChevronDown2, FolderOpen } from "lucide-react";
|
|
473
|
-
import { useState as useState5 } from "react";
|
|
474
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
475
|
-
function SidebarMenuItems({ docs, version, onLinkClick, config, activeTabGroup }) {
|
|
476
|
-
const pathname = usePathname();
|
|
477
|
-
const [collapsed, setCollapsed] = useState5(() => {
|
|
478
|
-
const initial = {};
|
|
479
|
-
return initial;
|
|
480
|
-
});
|
|
481
|
-
const hasTabGroups = config.navigation?.tabGroups && config.navigation.tabGroups.length > 0;
|
|
482
|
-
const filteredDocs = hasTabGroups && activeTabGroup ? docs.filter((doc) => {
|
|
483
|
-
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
484
|
-
if (!docTabGroup) {
|
|
485
|
-
return activeTabGroup === config.navigation?.tabGroups?.[0]?.id;
|
|
486
|
-
}
|
|
487
|
-
return docTabGroup === activeTabGroup;
|
|
488
|
-
}) : docs;
|
|
489
|
-
const rootGroups = {};
|
|
490
|
-
const standalone = [];
|
|
491
|
-
filteredDocs.forEach((doc) => {
|
|
492
|
-
const pathParts = doc.filePath.split("/");
|
|
493
|
-
const isIndexFile = doc.filePath.endsWith("/index") || doc.filePath === "index" || pathParts.length > 1 && doc.slug === pathParts.slice(0, -1).join("/");
|
|
494
|
-
const customGroup = doc.sidebar || doc.group;
|
|
495
|
-
if (customGroup) {
|
|
496
|
-
const groupName = customGroup.charAt(0).toUpperCase() + customGroup.slice(1);
|
|
497
|
-
if (!rootGroups[groupName]) {
|
|
498
|
-
rootGroups[groupName] = {
|
|
499
|
-
label: groupName,
|
|
500
|
-
path: customGroup,
|
|
501
|
-
items: [],
|
|
502
|
-
position: 999,
|
|
503
|
-
collapsible: doc.categoryCollapsible ?? true,
|
|
504
|
-
defaultCollapsed: doc.categoryCollapsed ?? false,
|
|
505
|
-
children: {}
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
if (isIndexFile) {
|
|
509
|
-
rootGroups[groupName].position = doc.sidebar_position ?? 999;
|
|
510
|
-
rootGroups[groupName].icon = doc.categoryIcon;
|
|
511
|
-
} else {
|
|
512
|
-
rootGroups[groupName].items.push(doc);
|
|
513
|
-
}
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
if (pathParts.length > 1) {
|
|
517
|
-
const folderParts = pathParts.slice(0, -1);
|
|
518
|
-
let currentLevel = rootGroups;
|
|
519
|
-
let currentPath = "";
|
|
520
|
-
for (let i = 0; i < folderParts.length; i++) {
|
|
521
|
-
const folder = folderParts[i];
|
|
522
|
-
currentPath = currentPath ? `${currentPath}/${folder}` : folder;
|
|
523
|
-
const folderLabel = folder.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
524
|
-
if (!currentLevel[folder]) {
|
|
525
|
-
currentLevel[folder] = {
|
|
526
|
-
label: doc.categoryLabel && i === folderParts.length - 1 ? doc.categoryLabel : folderLabel,
|
|
527
|
-
path: currentPath,
|
|
528
|
-
icon: doc.categoryIcon,
|
|
529
|
-
items: [],
|
|
530
|
-
position: doc.categoryPosition ?? 999,
|
|
531
|
-
collapsible: doc.categoryCollapsible ?? true,
|
|
532
|
-
defaultCollapsed: doc.categoryCollapsed ?? false,
|
|
533
|
-
children: {}
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
|
-
if (i === folderParts.length - 1) {
|
|
537
|
-
if (isIndexFile) {
|
|
538
|
-
currentLevel[folder].position = doc.categoryPosition ?? doc.sidebar_position ?? 999;
|
|
539
|
-
if (doc.categoryLabel) {
|
|
540
|
-
currentLevel[folder].label = doc.categoryLabel;
|
|
541
|
-
}
|
|
542
|
-
if (doc.categoryIcon) {
|
|
543
|
-
currentLevel[folder].icon = doc.categoryIcon;
|
|
544
|
-
}
|
|
545
|
-
} else {
|
|
546
|
-
currentLevel[folder].items.push(doc);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
currentLevel = currentLevel[folder].children;
|
|
550
|
-
}
|
|
551
|
-
} else {
|
|
552
|
-
if (!isIndexFile) {
|
|
553
|
-
standalone.push(doc);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
});
|
|
557
|
-
const toggleSection = (section) => {
|
|
558
|
-
setCollapsed((prev) => ({ ...prev, [section]: !prev[section] }));
|
|
559
|
-
};
|
|
560
|
-
const renderGroup = (groupKey, group, depth = 0) => {
|
|
561
|
-
const sortedItems = sortSidebarItems(group.items);
|
|
562
|
-
const sortedChildren = sortSidebarGroups(group.children);
|
|
563
|
-
const hasChildren = sortedChildren.length > 0;
|
|
564
|
-
const hasItems = sortedItems.length > 0;
|
|
565
|
-
const hasContent = hasChildren || hasItems;
|
|
566
|
-
const isActiveInGroup = (g) => {
|
|
567
|
-
const hasActiveItem2 = g.items.some((doc) => pathname === `/docs/${version}/${doc.slug}`);
|
|
568
|
-
if (hasActiveItem2) return true;
|
|
569
|
-
return Object.values(g.children).some((child) => isActiveInGroup(child));
|
|
570
|
-
};
|
|
571
|
-
const hasActiveItem = isActiveInGroup(group);
|
|
572
|
-
const isGroupActive = pathname === `/docs/${version}/${group.path}`;
|
|
573
|
-
const isCollapsed = hasActiveItem || isGroupActive ? false : collapsed[groupKey] ?? group.defaultCollapsed;
|
|
574
|
-
const marginLeft = depth > 0 ? "ml-4" : "";
|
|
575
|
-
let groupHref = `/docs/${version}/${group.path}`;
|
|
576
|
-
if (config.features?.i18n) {
|
|
577
|
-
const i18n = config.features.i18n;
|
|
578
|
-
const locales = typeof i18n === "object" ? i18n.locales : ["en"];
|
|
579
|
-
const pathParts = pathname?.split("/") || [];
|
|
580
|
-
const potentialLocale = pathParts[3];
|
|
581
|
-
if (potentialLocale && locales.includes(potentialLocale)) {
|
|
582
|
-
groupHref = `/docs/${version}/${potentialLocale}/${group.path}`;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
return /* @__PURE__ */ jsxs5("div", { className: `space-y-1 ${marginLeft}`, children: [
|
|
586
|
-
/* @__PURE__ */ jsxs5("div", { className: "flex items-center group", children: [
|
|
587
|
-
/* @__PURE__ */ jsxs5(
|
|
588
|
-
Link2,
|
|
589
|
-
{
|
|
590
|
-
href: groupHref,
|
|
591
|
-
onClick: (e) => {
|
|
592
|
-
e.preventDefault();
|
|
593
|
-
toggleSection(groupKey);
|
|
594
|
-
},
|
|
595
|
-
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"}`,
|
|
596
|
-
children: [
|
|
597
|
-
group.icon ? /* @__PURE__ */ jsx6(Icon, { icon: group.icon, size: 16, className: "shrink-0" }) : /* @__PURE__ */ jsx6(FolderOpen, { size: 16, className: "shrink-0" }),
|
|
598
|
-
group.label
|
|
599
|
-
]
|
|
600
|
-
}
|
|
601
|
-
),
|
|
602
|
-
hasContent && group.collapsible && config.navigation?.collapsibleSidebar && /* @__PURE__ */ jsx6(
|
|
603
|
-
"button",
|
|
604
|
-
{
|
|
605
|
-
onClick: (e) => {
|
|
606
|
-
e.preventDefault();
|
|
607
|
-
e.stopPropagation();
|
|
608
|
-
toggleSection(groupKey);
|
|
609
|
-
},
|
|
610
|
-
className: `p-2 rounded-r-xl transition-all ${isGroupActive ? "hover:bg-primary/20" : "hover:bg-accent/50"}`,
|
|
611
|
-
"aria-label": isCollapsed ? "Expand section" : "Collapse section",
|
|
612
|
-
children: isCollapsed ? /* @__PURE__ */ jsx6(ChevronRight, { className: `h-4 w-4 ${isGroupActive ? "text-primary" : "text-muted-foreground"}` }) : /* @__PURE__ */ jsx6(ChevronDown2, { className: `h-4 w-4 ${isGroupActive ? "text-primary" : "text-muted-foreground"}` })
|
|
613
|
-
}
|
|
614
|
-
)
|
|
615
|
-
] }),
|
|
616
|
-
!isCollapsed && hasContent && /* @__PURE__ */ jsx6("div", { className: "ml-4 space-y-1", children: (() => {
|
|
617
|
-
const merged = [
|
|
618
|
-
...sortedChildren.map(([childKey, childGroup]) => ({
|
|
619
|
-
type: "group",
|
|
620
|
-
key: childKey,
|
|
621
|
-
group: childGroup,
|
|
622
|
-
position: childGroup.position
|
|
623
|
-
})),
|
|
624
|
-
...sortedItems.map((doc) => ({
|
|
625
|
-
type: "item",
|
|
626
|
-
doc,
|
|
627
|
-
position: doc.sidebar_position ?? doc.meta?.sidebar_position ?? doc.meta?.order ?? 999
|
|
628
|
-
}))
|
|
629
|
-
];
|
|
630
|
-
merged.sort((a, b) => a.position - b.position);
|
|
631
|
-
return merged.map((item) => {
|
|
632
|
-
if (item.type === "group") {
|
|
633
|
-
return renderGroup(`${groupKey}/${item.key}`, item.group, depth + 1);
|
|
634
|
-
} else {
|
|
635
|
-
const href = `/docs/${version}/${item.doc.slug}`;
|
|
636
|
-
const isActive = pathname === href;
|
|
637
|
-
return /* @__PURE__ */ jsxs5(
|
|
638
|
-
Link2,
|
|
639
|
-
{
|
|
640
|
-
href,
|
|
641
|
-
onClick: onLinkClick,
|
|
642
|
-
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"}`,
|
|
643
|
-
children: [
|
|
644
|
-
item.doc.meta?.icon && /* @__PURE__ */ jsx6(Icon, { icon: item.doc.meta.icon, size: 16, className: "shrink-0" }),
|
|
645
|
-
item.doc.title
|
|
646
|
-
]
|
|
647
|
-
},
|
|
648
|
-
`grouped-${item.doc.slug}`
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
});
|
|
652
|
-
})() })
|
|
653
|
-
] }, `group-${groupKey}`);
|
|
654
|
-
};
|
|
655
|
-
const sortedRootGroups = sortSidebarGroups(rootGroups);
|
|
656
|
-
const sortedStandalone = sortSidebarItems(standalone);
|
|
657
|
-
return /* @__PURE__ */ jsxs5("nav", { className: "space-y-1", children: [
|
|
658
|
-
sortedStandalone.length > 0 && sortedStandalone.map((doc) => {
|
|
659
|
-
const href = `/docs/${version}/${doc.slug}`;
|
|
660
|
-
const isActive = pathname === href;
|
|
661
|
-
return /* @__PURE__ */ jsxs5(
|
|
662
|
-
Link2,
|
|
663
|
-
{
|
|
664
|
-
href,
|
|
665
|
-
onClick: onLinkClick,
|
|
666
|
-
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"}`,
|
|
667
|
-
children: [
|
|
668
|
-
doc.meta?.icon && /* @__PURE__ */ jsx6(Icon, { icon: doc.meta.icon, size: 16, className: "shrink-0" }),
|
|
669
|
-
doc.title
|
|
670
|
-
]
|
|
671
|
-
},
|
|
672
|
-
`standalone-${doc.slug}`
|
|
673
|
-
);
|
|
674
|
-
}),
|
|
675
|
-
sortedRootGroups.map(([groupKey, group]) => renderGroup(groupKey, group, 0))
|
|
676
|
-
] });
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// src/components/docs/sidebar.tsx
|
|
680
|
-
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
681
|
-
function Sidebar({ docs, version, onLinkClick, config, activeTabGroup }) {
|
|
682
|
-
if (!config.navigation?.showSidebar) {
|
|
683
|
-
return null;
|
|
684
|
-
}
|
|
685
|
-
const hasTabGroups = config.navigation?.tabGroups && config.navigation.tabGroups.length > 0;
|
|
686
|
-
const stickyTop = hasTabGroups ? "top-[7.5rem]" : "top-24";
|
|
687
|
-
const maxHeight = hasTabGroups ? "max-h-[calc(100vh-10rem)]" : "max-h-[calc(100vh-7rem)]";
|
|
688
|
-
return /* @__PURE__ */ jsx7("aside", { className: `w-64 shrink-0 sticky ${stickyTop} self-start`, children: /* @__PURE__ */ jsxs6("div", { className: `${maxHeight} overflow-y-auto bg-muted/30 dark:bg-muted/10 rounded-2xl p-4 border border-border/50`, children: [
|
|
689
|
-
/* @__PURE__ */ jsx7("h2", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4 px-2", children: "Documentation" }),
|
|
690
|
-
/* @__PURE__ */ jsx7(
|
|
691
|
-
SidebarMenuItems,
|
|
692
|
-
{
|
|
693
|
-
docs,
|
|
694
|
-
version,
|
|
695
|
-
onLinkClick,
|
|
696
|
-
config,
|
|
697
|
-
activeTabGroup
|
|
698
|
-
}
|
|
699
|
-
)
|
|
700
|
-
] }) });
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
// src/components/docs/mobile-doc-layout.tsx
|
|
704
|
-
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
705
|
-
function MobileDocLayout({ header, docs, version, children, toc, config, activeTabGroup, onTabChange }) {
|
|
706
|
-
const [sidebarOpen, setSidebarOpen] = useState6(false);
|
|
707
|
-
const handleTabChange = (tabId) => {
|
|
708
|
-
onTabChange?.(tabId);
|
|
709
|
-
};
|
|
710
|
-
const closeSidebar = () => setSidebarOpen(false);
|
|
711
|
-
const toggleSidebar = () => setSidebarOpen(!sidebarOpen);
|
|
712
|
-
const headerWithProps = isValidElement(header) ? cloneElement(header, {
|
|
713
|
-
onMenuClick: toggleSidebar
|
|
714
|
-
}) : header;
|
|
715
|
-
return /* @__PURE__ */ jsxs7("div", { className: "min-h-screen bg-background", children: [
|
|
716
|
-
headerWithProps,
|
|
717
|
-
/* @__PURE__ */ jsx8(SiteBanner, { config }),
|
|
718
|
-
config.navigation?.tabGroups && config.navigation.tabGroups.length > 0 && /* @__PURE__ */ jsx8(
|
|
719
|
-
TabGroups,
|
|
720
|
-
{
|
|
721
|
-
tabGroups: config.navigation.tabGroups,
|
|
722
|
-
activeTabId: activeTabGroup,
|
|
723
|
-
onTabChange: handleTabChange,
|
|
724
|
-
docs,
|
|
725
|
-
version
|
|
726
|
-
}
|
|
727
|
-
),
|
|
728
|
-
sidebarOpen && /* @__PURE__ */ jsx8(
|
|
729
|
-
"div",
|
|
730
|
-
{
|
|
731
|
-
className: "lg:hidden fixed inset-0 bg-background/80 backdrop-blur-sm z-40",
|
|
732
|
-
onClick: () => setSidebarOpen(false)
|
|
733
|
-
}
|
|
734
|
-
),
|
|
735
|
-
/* @__PURE__ */ jsx8(
|
|
736
|
-
"div",
|
|
737
|
-
{
|
|
738
|
-
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"}`,
|
|
739
|
-
children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col h-full", children: [
|
|
740
|
-
/* @__PURE__ */ jsx8("div", { className: "shrink-0 px-4 py-4 border-b border-border", children: /* @__PURE__ */ jsxs7(Link3, { href: "/", className: "flex items-center gap-2 group justify-center", children: [
|
|
741
|
-
!config.site?.hideLogo && /* @__PURE__ */ jsx8(
|
|
742
|
-
Logo,
|
|
743
|
-
{
|
|
744
|
-
logo: config.site?.logo,
|
|
745
|
-
alt: config.site?.title || "Logo",
|
|
746
|
-
className: "w-18 object-contain"
|
|
747
|
-
}
|
|
748
|
-
),
|
|
749
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col", children: [
|
|
750
|
-
/* @__PURE__ */ jsx8("span", { className: "font-semibold text-foreground group-hover:text-primary transition-colors", children: config.site?.title || "Documentation" }),
|
|
751
|
-
config.site?.description && /* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground line-clamp-1", children: config.site.description })
|
|
752
|
-
] })
|
|
753
|
-
] }) }),
|
|
754
|
-
/* @__PURE__ */ jsx8("div", { className: "shrink-0 px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx8("h2", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider px-2", children: "Documentation" }) }),
|
|
755
|
-
config.navigation?.tabGroups && config.navigation.tabGroups.length > 0 && /* @__PURE__ */ jsx8("div", { className: "shrink-0 px-4 py-3 border-b border-border", children: /* @__PURE__ */ jsx8(
|
|
756
|
-
TabGroups,
|
|
757
|
-
{
|
|
758
|
-
tabGroups: config.navigation.tabGroups,
|
|
759
|
-
activeTabId: activeTabGroup,
|
|
760
|
-
onTabChange: handleTabChange,
|
|
761
|
-
mobileOnly: true,
|
|
762
|
-
docs,
|
|
763
|
-
version
|
|
764
|
-
}
|
|
765
|
-
) }),
|
|
766
|
-
/* @__PURE__ */ jsx8("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: /* @__PURE__ */ jsx8(
|
|
767
|
-
SidebarMenuItems,
|
|
768
|
-
{
|
|
769
|
-
docs,
|
|
770
|
-
version,
|
|
771
|
-
config,
|
|
772
|
-
onLinkClick: closeSidebar,
|
|
773
|
-
activeTabGroup
|
|
774
|
-
}
|
|
775
|
-
) })
|
|
776
|
-
] })
|
|
777
|
-
}
|
|
778
|
-
),
|
|
779
|
-
/* @__PURE__ */ jsx8("main", { className: "container mx-auto px-2 md:px-6 py-8", children: /* @__PURE__ */ jsxs7("div", { className: "flex", children: [
|
|
780
|
-
/* @__PURE__ */ jsx8("div", { className: "hidden lg:block", children: /* @__PURE__ */ jsx8(
|
|
781
|
-
Sidebar,
|
|
782
|
-
{
|
|
783
|
-
docs,
|
|
784
|
-
version,
|
|
785
|
-
config,
|
|
786
|
-
activeTabGroup
|
|
787
|
-
}
|
|
788
|
-
) }),
|
|
789
|
-
/* @__PURE__ */ jsx8("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2 px-2 md:px-8", children: [
|
|
790
|
-
children,
|
|
791
|
-
/* @__PURE__ */ jsx8(Footer, { config })
|
|
792
|
-
] }) }),
|
|
793
|
-
toc
|
|
794
|
-
] }) })
|
|
795
|
-
] });
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// src/components/docs/tab-context.tsx
|
|
799
|
-
import * as React from "react";
|
|
800
|
-
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
801
|
-
var TabContext = React.createContext(void 0);
|
|
802
|
-
var TAB_STORAGE_KEY = "specra-active-tab-group";
|
|
803
|
-
function TabProvider({ children, defaultTab }) {
|
|
804
|
-
const [activeTabGroup, setActiveTabGroupState] = React.useState(defaultTab);
|
|
805
|
-
const isInitialMount = React.useRef(true);
|
|
806
|
-
React.useEffect(() => {
|
|
807
|
-
if (isInitialMount.current) {
|
|
808
|
-
isInitialMount.current = false;
|
|
809
|
-
if (typeof window !== "undefined") {
|
|
810
|
-
try {
|
|
811
|
-
const stored = localStorage.getItem(TAB_STORAGE_KEY);
|
|
812
|
-
if (stored && stored !== defaultTab) {
|
|
813
|
-
setActiveTabGroupState(stored);
|
|
814
|
-
}
|
|
815
|
-
} catch {
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}, [defaultTab]);
|
|
820
|
-
const setActiveTabGroup = (tabId) => {
|
|
821
|
-
setActiveTabGroupState(tabId);
|
|
822
|
-
if (typeof window !== "undefined") {
|
|
823
|
-
try {
|
|
824
|
-
localStorage.setItem(TAB_STORAGE_KEY, tabId);
|
|
825
|
-
} catch {
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
return /* @__PURE__ */ jsx9(TabContext.Provider, { value: { activeTabGroup, setActiveTabGroup }, children });
|
|
830
|
-
}
|
|
831
|
-
function useTabContext() {
|
|
832
|
-
const context = React.useContext(TabContext);
|
|
833
|
-
if (!context) {
|
|
834
|
-
throw new Error("useTabContext must be used within TabProvider");
|
|
835
|
-
}
|
|
836
|
-
return context;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// src/components/docs/doc-layout-wrapper.tsx
|
|
840
|
-
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
841
|
-
function DocLayoutWrapper({ header, docs, version, children, toc, config }) {
|
|
842
|
-
const { activeTabGroup, setActiveTabGroup } = useTabContext();
|
|
843
|
-
return /* @__PURE__ */ jsx10(
|
|
844
|
-
MobileDocLayout,
|
|
845
|
-
{
|
|
846
|
-
header,
|
|
847
|
-
docs,
|
|
848
|
-
version,
|
|
849
|
-
toc,
|
|
850
|
-
config,
|
|
851
|
-
activeTabGroup,
|
|
852
|
-
onTabChange: setActiveTabGroup,
|
|
853
|
-
children
|
|
854
|
-
}
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// src/components/docs/doc-loading.tsx
|
|
859
|
-
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
860
|
-
function DocLoading() {
|
|
861
|
-
return /* @__PURE__ */ jsx11("div", { className: "max-w-4xl mx-auto px-2 md:px-6 py-8", children: /* @__PURE__ */ jsxs8("div", { className: "animate-pulse space-y-4", children: [
|
|
862
|
-
/* @__PURE__ */ jsx11("div", { className: "h-8 bg-gray-200 rounded w-3/4" }),
|
|
863
|
-
/* @__PURE__ */ jsx11("div", { className: "h-4 bg-gray-200 rounded w-1/2" }),
|
|
864
|
-
/* @__PURE__ */ jsxs8("div", { className: "space-y-3 mt-8", children: [
|
|
865
|
-
/* @__PURE__ */ jsx11("div", { className: "h-4 bg-gray-200 rounded" }),
|
|
866
|
-
/* @__PURE__ */ jsx11("div", { className: "h-4 bg-gray-200 rounded w-5/6" }),
|
|
867
|
-
/* @__PURE__ */ jsx11("div", { className: "h-4 bg-gray-200 rounded w-4/6" })
|
|
868
|
-
] })
|
|
869
|
-
] }) });
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// src/components/docs/header.tsx
|
|
873
|
-
import Link4 from "next/link";
|
|
874
|
-
import { Search as Search2, Menu, Github, Twitter, MessageCircle } from "lucide-react";
|
|
875
|
-
|
|
876
|
-
// src/components/docs/version-switcher.tsx
|
|
877
|
-
import { useState as useState8 } from "react";
|
|
878
|
-
import { Check, ChevronDown as ChevronDown3 } from "lucide-react";
|
|
879
|
-
import { useRouter as useRouter2 } from "next/navigation";
|
|
880
|
-
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
881
|
-
function VersionSwitcher({ currentVersion, versions }) {
|
|
882
|
-
const [open, setOpen] = useState8(false);
|
|
883
|
-
const router = useRouter2();
|
|
884
|
-
const handleVersionChange = (version) => {
|
|
885
|
-
router.push(`/docs/${version}`);
|
|
886
|
-
setOpen(false);
|
|
887
|
-
};
|
|
888
|
-
return /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
|
|
889
|
-
/* @__PURE__ */ jsxs9(
|
|
890
|
-
"button",
|
|
891
|
-
{
|
|
892
|
-
onClick: () => setOpen(!open),
|
|
893
|
-
className: "flex items-center gap-2 px-3 py-2 text-sm text-foreground bg-muted rounded-md hover:bg-muted/80 transition-colors",
|
|
894
|
-
children: [
|
|
895
|
-
/* @__PURE__ */ jsx12("span", { className: "font-medium", children: currentVersion }),
|
|
896
|
-
/* @__PURE__ */ jsx12(ChevronDown3, { className: "h-4 w-4" })
|
|
897
|
-
]
|
|
898
|
-
}
|
|
899
|
-
),
|
|
900
|
-
open && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
901
|
-
/* @__PURE__ */ jsx12("div", { className: "fixed inset-0 z-40", onClick: () => setOpen(false) }),
|
|
902
|
-
/* @__PURE__ */ jsx12("div", { className: "absolute right-0 mt-2 w-48 bg-background border border-border rounded-md shadow-lg z-50", children: /* @__PURE__ */ jsx12("div", { className: "p-2", children: versions.map((version) => /* @__PURE__ */ jsxs9(
|
|
903
|
-
"button",
|
|
904
|
-
{
|
|
905
|
-
onClick: () => handleVersionChange(version),
|
|
906
|
-
className: "flex items-center justify-between w-full px-3 py-2 text-sm text-foreground hover:bg-muted rounded-md transition-colors",
|
|
907
|
-
children: [
|
|
908
|
-
/* @__PURE__ */ jsx12("span", { children: version }),
|
|
909
|
-
version === currentVersion && /* @__PURE__ */ jsx12(Check, { className: "h-4 w-4 text-primary" })
|
|
910
|
-
]
|
|
911
|
-
},
|
|
912
|
-
version
|
|
913
|
-
)) }) })
|
|
914
|
-
] })
|
|
915
|
-
] });
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
// src/components/docs/language-switcher.tsx
|
|
919
|
-
import { useState as useState9 } from "react";
|
|
920
|
-
import { Languages, Check as Check2, ChevronDown as ChevronDown4 } from "lucide-react";
|
|
921
|
-
import { usePathname as usePathname2, useRouter as useRouter3 } from "next/navigation";
|
|
922
|
-
|
|
923
|
-
// src/components/config-provider.tsx
|
|
924
|
-
import * as React2 from "react";
|
|
925
|
-
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
926
|
-
var ConfigContext = React2.createContext(defaultConfig);
|
|
927
|
-
function ConfigProvider({ config, children }) {
|
|
928
|
-
return /* @__PURE__ */ jsx13(ConfigContext.Provider, { value: config, children });
|
|
929
|
-
}
|
|
930
|
-
function useConfig() {
|
|
931
|
-
const config = React2.useContext(ConfigContext);
|
|
932
|
-
if (!config) {
|
|
933
|
-
throw new Error("useConfig must be used within a ConfigProvider");
|
|
934
|
-
}
|
|
935
|
-
return config;
|
|
936
|
-
}
|
|
937
|
-
function useConfigValue(path) {
|
|
938
|
-
const config = useConfig();
|
|
939
|
-
const keys = path.split(".");
|
|
940
|
-
let value = config;
|
|
941
|
-
for (const key of keys) {
|
|
942
|
-
if (value && typeof value === "object" && key in value) {
|
|
943
|
-
value = value[key];
|
|
944
|
-
} else {
|
|
945
|
-
return void 0;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
return value;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// src/components/docs/language-switcher.tsx
|
|
952
|
-
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
953
|
-
function LanguageSwitcher() {
|
|
954
|
-
const [open, setOpen] = useState9(false);
|
|
955
|
-
const pathname = usePathname2();
|
|
956
|
-
const router = useRouter3();
|
|
957
|
-
const config = useConfig();
|
|
958
|
-
const i18n = config.features?.i18n;
|
|
959
|
-
if (!i18n || typeof i18n === "boolean") return null;
|
|
960
|
-
const { locales, localeNames, defaultLocale, prefixDefault } = i18n;
|
|
961
|
-
const pathParts = pathname.split("/");
|
|
962
|
-
const version = pathParts[2];
|
|
963
|
-
let currentLocale = defaultLocale;
|
|
964
|
-
if (pathParts[3] && locales.includes(pathParts[3])) {
|
|
965
|
-
currentLocale = pathParts[3];
|
|
966
|
-
}
|
|
967
|
-
const handleLocaleChange = (newLocale) => {
|
|
968
|
-
if (newLocale === currentLocale) {
|
|
969
|
-
setOpen(false);
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
const parts = [...pathParts];
|
|
973
|
-
const hasLocalePrefix = locales.includes(parts[3]);
|
|
974
|
-
if (newLocale === defaultLocale && !prefixDefault) {
|
|
975
|
-
if (hasLocalePrefix) {
|
|
976
|
-
parts.splice(3, 1);
|
|
977
|
-
}
|
|
978
|
-
} else {
|
|
979
|
-
if (hasLocalePrefix) {
|
|
980
|
-
parts[3] = newLocale;
|
|
981
|
-
} else {
|
|
982
|
-
parts.splice(3, 0, newLocale);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
const newPath = parts.join("/");
|
|
986
|
-
router.push(newPath);
|
|
987
|
-
setOpen(false);
|
|
988
|
-
};
|
|
989
|
-
return /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
990
|
-
/* @__PURE__ */ jsxs10(
|
|
991
|
-
"button",
|
|
992
|
-
{
|
|
993
|
-
onClick: () => setOpen(!open),
|
|
994
|
-
className: "flex items-center gap-1.5 px-2 h-9 rounded-md hover:bg-muted transition-colors",
|
|
995
|
-
"aria-label": "Switch language",
|
|
996
|
-
children: [
|
|
997
|
-
/* @__PURE__ */ jsx14(Languages, { className: "h-4 w-4" }),
|
|
998
|
-
/* @__PURE__ */ jsx14("span", { className: "text-xs font-bold uppercase", children: currentLocale }),
|
|
999
|
-
/* @__PURE__ */ jsx14(ChevronDown4, { className: "h-3 w-3 text-muted-foreground" })
|
|
1000
|
-
]
|
|
1001
|
-
}
|
|
1002
|
-
),
|
|
1003
|
-
open && /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1004
|
-
/* @__PURE__ */ jsx14("div", { className: "fixed inset-0 z-40", onClick: () => setOpen(false) }),
|
|
1005
|
-
/* @__PURE__ */ jsx14("div", { className: "absolute right-0 mt-2 w-40 bg-background border border-border rounded-md shadow-lg z-50", children: /* @__PURE__ */ jsx14("div", { className: "p-2", children: locales.map((locale) => /* @__PURE__ */ jsxs10(
|
|
1006
|
-
"button",
|
|
1007
|
-
{
|
|
1008
|
-
onClick: () => handleLocaleChange(locale),
|
|
1009
|
-
className: "flex items-center justify-between w-full px-3 py-2 text-sm text-foreground hover:bg-muted rounded-md transition-colors",
|
|
1010
|
-
children: [
|
|
1011
|
-
/* @__PURE__ */ jsx14("span", { children: localeNames?.[locale] || locale.toUpperCase() }),
|
|
1012
|
-
currentLocale === locale && /* @__PURE__ */ jsx14(Check2, { className: "h-4 w-4 text-primary" })
|
|
1013
|
-
]
|
|
1014
|
-
},
|
|
1015
|
-
locale
|
|
1016
|
-
)) }) })
|
|
1017
|
-
] })
|
|
1018
|
-
] });
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// src/components/docs/theme-toggle.tsx
|
|
1022
|
-
import { Moon, Sun } from "lucide-react";
|
|
1023
|
-
import { useEffect as useEffect5, useState as useState10 } from "react";
|
|
1024
|
-
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1025
|
-
function ThemeToggle() {
|
|
1026
|
-
const [theme, setTheme] = useState10("dark");
|
|
1027
|
-
useEffect5(() => {
|
|
1028
|
-
const savedTheme = localStorage.getItem("theme");
|
|
1029
|
-
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
1030
|
-
const initialTheme = savedTheme || (prefersDark ? "dark" : "light");
|
|
1031
|
-
setTheme(initialTheme);
|
|
1032
|
-
document.documentElement.classList.toggle("dark", initialTheme === "dark");
|
|
1033
|
-
}, []);
|
|
1034
|
-
const toggleTheme = () => {
|
|
1035
|
-
const newTheme = theme === "dark" ? "light" : "dark";
|
|
1036
|
-
setTheme(newTheme);
|
|
1037
|
-
localStorage.setItem("theme", newTheme);
|
|
1038
|
-
document.documentElement.classList.toggle("dark", newTheme === "dark");
|
|
1039
|
-
};
|
|
1040
|
-
return /* @__PURE__ */ jsx15(
|
|
1041
|
-
"button",
|
|
1042
|
-
{
|
|
1043
|
-
onClick: toggleTheme,
|
|
1044
|
-
className: "flex items-center justify-center w-9 h-9 rounded-md border border-border bg-background hover:bg-accent transition-colors",
|
|
1045
|
-
"aria-label": "Toggle theme",
|
|
1046
|
-
children: theme === "dark" ? /* @__PURE__ */ jsx15(Sun, { className: "h-4 w-4 text-foreground" }) : /* @__PURE__ */ jsx15(Moon, { className: "h-4 w-4 text-foreground" })
|
|
1047
|
-
}
|
|
1048
|
-
);
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
// src/components/docs/search-modal.tsx
|
|
1052
|
-
import { useState as useState11, useEffect as useEffect6, useCallback } from "react";
|
|
1053
|
-
import { Search, FileText, Loader2 } from "lucide-react";
|
|
1054
|
-
import { useRouter as useRouter4 } from "next/navigation";
|
|
1055
|
-
|
|
1056
|
-
// src/components/ui/dialog.tsx
|
|
1057
|
-
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
1058
|
-
import { XIcon } from "lucide-react";
|
|
1059
|
-
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1060
|
-
function Dialog({
|
|
1061
|
-
...props
|
|
1062
|
-
}) {
|
|
1063
|
-
return /* @__PURE__ */ jsx16(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
1064
|
-
}
|
|
1065
|
-
function DialogTrigger({
|
|
1066
|
-
...props
|
|
1067
|
-
}) {
|
|
1068
|
-
return /* @__PURE__ */ jsx16(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
|
|
1069
|
-
}
|
|
1070
|
-
function DialogPortal({
|
|
1071
|
-
...props
|
|
1072
|
-
}) {
|
|
1073
|
-
return /* @__PURE__ */ jsx16(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
|
|
1074
|
-
}
|
|
1075
|
-
function DialogClose({
|
|
1076
|
-
...props
|
|
1077
|
-
}) {
|
|
1078
|
-
return /* @__PURE__ */ jsx16(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
|
|
1079
|
-
}
|
|
1080
|
-
function DialogOverlay({
|
|
1081
|
-
className,
|
|
1082
|
-
...props
|
|
1083
|
-
}) {
|
|
1084
|
-
return /* @__PURE__ */ jsx16(
|
|
1085
|
-
DialogPrimitive.Overlay,
|
|
1086
|
-
{
|
|
1087
|
-
"data-slot": "dialog-overlay",
|
|
1088
|
-
className: cn(
|
|
1089
|
-
"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",
|
|
1090
|
-
className
|
|
1091
|
-
),
|
|
1092
|
-
...props
|
|
1093
|
-
}
|
|
1094
|
-
);
|
|
1095
|
-
}
|
|
1096
|
-
function DialogContent({
|
|
1097
|
-
className,
|
|
1098
|
-
children,
|
|
1099
|
-
showCloseButton = true,
|
|
1100
|
-
...props
|
|
1101
|
-
}) {
|
|
1102
|
-
return /* @__PURE__ */ jsxs11(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
1103
|
-
/* @__PURE__ */ jsx16(DialogOverlay, {}),
|
|
1104
|
-
/* @__PURE__ */ jsxs11(
|
|
1105
|
-
DialogPrimitive.Content,
|
|
1106
|
-
{
|
|
1107
|
-
"data-slot": "dialog-content",
|
|
1108
|
-
className: cn(
|
|
1109
|
-
"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",
|
|
1110
|
-
className
|
|
1111
|
-
),
|
|
1112
|
-
...props,
|
|
1113
|
-
children: [
|
|
1114
|
-
children,
|
|
1115
|
-
showCloseButton && /* @__PURE__ */ jsxs11(
|
|
1116
|
-
DialogPrimitive.Close,
|
|
1117
|
-
{
|
|
1118
|
-
"data-slot": "dialog-close",
|
|
1119
|
-
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",
|
|
1120
|
-
children: [
|
|
1121
|
-
/* @__PURE__ */ jsx16(XIcon, {}),
|
|
1122
|
-
/* @__PURE__ */ jsx16("span", { className: "sr-only", children: "Close" })
|
|
1123
|
-
]
|
|
1124
|
-
}
|
|
1125
|
-
)
|
|
1126
|
-
]
|
|
1127
|
-
}
|
|
1128
|
-
)
|
|
1129
|
-
] });
|
|
1130
|
-
}
|
|
1131
|
-
function DialogHeader({ className, ...props }) {
|
|
1132
|
-
return /* @__PURE__ */ jsx16(
|
|
1133
|
-
"div",
|
|
1134
|
-
{
|
|
1135
|
-
"data-slot": "dialog-header",
|
|
1136
|
-
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
1137
|
-
...props
|
|
1138
|
-
}
|
|
1139
|
-
);
|
|
1140
|
-
}
|
|
1141
|
-
function DialogFooter({ className, ...props }) {
|
|
1142
|
-
return /* @__PURE__ */ jsx16(
|
|
1143
|
-
"div",
|
|
1144
|
-
{
|
|
1145
|
-
"data-slot": "dialog-footer",
|
|
1146
|
-
className: cn(
|
|
1147
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
1148
|
-
className
|
|
1149
|
-
),
|
|
1150
|
-
...props
|
|
1151
|
-
}
|
|
1152
|
-
);
|
|
1153
|
-
}
|
|
1154
|
-
function DialogTitle({
|
|
1155
|
-
className,
|
|
1156
|
-
...props
|
|
1157
|
-
}) {
|
|
1158
|
-
return /* @__PURE__ */ jsx16(
|
|
1159
|
-
DialogPrimitive.Title,
|
|
1160
|
-
{
|
|
1161
|
-
"data-slot": "dialog-title",
|
|
1162
|
-
className: cn("text-lg leading-none font-semibold", className),
|
|
1163
|
-
...props
|
|
1164
|
-
}
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
function DialogDescription({
|
|
1168
|
-
className,
|
|
1169
|
-
...props
|
|
1170
|
-
}) {
|
|
1171
|
-
return /* @__PURE__ */ jsx16(
|
|
1172
|
-
DialogPrimitive.Description,
|
|
1173
|
-
{
|
|
1174
|
-
"data-slot": "dialog-description",
|
|
1175
|
-
className: cn("text-muted-foreground text-sm", className),
|
|
1176
|
-
...props
|
|
1177
|
-
}
|
|
1178
|
-
);
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// src/components/docs/search-modal.tsx
|
|
1182
|
-
import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1183
|
-
function SearchModal({ isOpen, onClose, config }) {
|
|
1184
|
-
const [query, setQuery] = useState11("");
|
|
1185
|
-
const [results, setResults] = useState11([]);
|
|
1186
|
-
const [isLoading, setIsLoading] = useState11(false);
|
|
1187
|
-
const [selectedIndex, setSelectedIndex] = useState11(0);
|
|
1188
|
-
const router = useRouter4();
|
|
1189
|
-
const searchConfig = config.search;
|
|
1190
|
-
const performSearch = useCallback(async (searchQuery) => {
|
|
1191
|
-
if (!searchQuery.trim() || !searchConfig?.enabled) {
|
|
1192
|
-
setResults([]);
|
|
1193
|
-
return;
|
|
1194
|
-
}
|
|
1195
|
-
setIsLoading(true);
|
|
1196
|
-
try {
|
|
1197
|
-
const response = await fetch("/api/search", {
|
|
1198
|
-
method: "POST",
|
|
1199
|
-
headers: { "Content-Type": "application/json" },
|
|
1200
|
-
body: JSON.stringify({
|
|
1201
|
-
query: searchQuery,
|
|
1202
|
-
// filter: 'version = "v1.0.0"',
|
|
1203
|
-
distinct: "version",
|
|
1204
|
-
limit: 2
|
|
1205
|
-
})
|
|
1206
|
-
});
|
|
1207
|
-
if (response.ok) {
|
|
1208
|
-
const data = await response.json();
|
|
1209
|
-
console.log("Search response:", data);
|
|
1210
|
-
setResults(data.hits || []);
|
|
1211
|
-
} else {
|
|
1212
|
-
console.error("Search failed:", response.status, await response.text());
|
|
1213
|
-
}
|
|
1214
|
-
} catch (error) {
|
|
1215
|
-
console.error("Search error:", error);
|
|
1216
|
-
setResults([]);
|
|
1217
|
-
} finally {
|
|
1218
|
-
setIsLoading(false);
|
|
1219
|
-
}
|
|
1220
|
-
}, [searchConfig]);
|
|
1221
|
-
useEffect6(() => {
|
|
1222
|
-
const timer = setTimeout(() => {
|
|
1223
|
-
performSearch(query);
|
|
1224
|
-
}, 300);
|
|
1225
|
-
return () => clearTimeout(timer);
|
|
1226
|
-
}, [query, performSearch]);
|
|
1227
|
-
useEffect6(() => {
|
|
1228
|
-
const handleKeyDown = (e) => {
|
|
1229
|
-
if (!isOpen) return;
|
|
1230
|
-
switch (e.key) {
|
|
1231
|
-
case "Escape":
|
|
1232
|
-
onClose();
|
|
1233
|
-
break;
|
|
1234
|
-
case "ArrowDown":
|
|
1235
|
-
e.preventDefault();
|
|
1236
|
-
setSelectedIndex((prev) => Math.min(prev + 1, results.length - 1));
|
|
1237
|
-
break;
|
|
1238
|
-
case "ArrowUp":
|
|
1239
|
-
e.preventDefault();
|
|
1240
|
-
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
|
1241
|
-
break;
|
|
1242
|
-
case "Enter":
|
|
1243
|
-
e.preventDefault();
|
|
1244
|
-
if (results[selectedIndex]) {
|
|
1245
|
-
handleResultClick(results[selectedIndex]);
|
|
1246
|
-
}
|
|
1247
|
-
break;
|
|
1248
|
-
}
|
|
1249
|
-
};
|
|
1250
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1251
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1252
|
-
}, [isOpen, results, selectedIndex, onClose]);
|
|
1253
|
-
useEffect6(() => {
|
|
1254
|
-
if (isOpen) {
|
|
1255
|
-
setQuery("");
|
|
1256
|
-
setResults([]);
|
|
1257
|
-
setSelectedIndex(0);
|
|
1258
|
-
}
|
|
1259
|
-
}, [isOpen]);
|
|
1260
|
-
const handleResultClick = (result) => {
|
|
1261
|
-
const params = new URLSearchParams();
|
|
1262
|
-
params.set("q", query);
|
|
1263
|
-
if (result.tab_group) {
|
|
1264
|
-
params.set("tab", result.tab_group);
|
|
1265
|
-
}
|
|
1266
|
-
const url = `/docs/${result.version}/${result.slug}?${params.toString()}`;
|
|
1267
|
-
router.push(url);
|
|
1268
|
-
onClose();
|
|
1269
|
-
};
|
|
1270
|
-
const highlightText = (text, query2) => {
|
|
1271
|
-
if (!query2.trim()) return text;
|
|
1272
|
-
const parts = text.split(new RegExp(`(${query2})`, "gi"));
|
|
1273
|
-
return parts.map(
|
|
1274
|
-
(part, i) => part.toLowerCase() === query2.toLowerCase() ? /* @__PURE__ */ jsx17("mark", { className: "bg-yellow-200 dark:bg-yellow-900/50 text-foreground", children: part }, i) : part
|
|
1275
|
-
);
|
|
1276
|
-
};
|
|
1277
|
-
return /* @__PURE__ */ jsx17(Dialog, { open: isOpen, onOpenChange: onClose, modal: true, children: /* @__PURE__ */ jsxs12(
|
|
1278
|
-
DialogContent,
|
|
1279
|
-
{
|
|
1280
|
-
className: "max-w-2xl p-0 gap-0 top-[10vh] translate-y-0",
|
|
1281
|
-
showCloseButton: false,
|
|
1282
|
-
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
1283
|
-
children: [
|
|
1284
|
-
/* @__PURE__ */ jsx17(DialogTitle, { className: "sr-only", children: "Search Documentation" }),
|
|
1285
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border", children: [
|
|
1286
|
-
/* @__PURE__ */ jsx17(Search, { className: "h-5 w-5 text-muted-foreground shrink-0" }),
|
|
1287
|
-
/* @__PURE__ */ jsx17(
|
|
1288
|
-
"input",
|
|
1289
|
-
{
|
|
1290
|
-
type: "text",
|
|
1291
|
-
value: query,
|
|
1292
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1293
|
-
placeholder: searchConfig?.placeholder || "Search documentation...",
|
|
1294
|
-
className: "flex-1 bg-transparent border-none outline-none text-foreground placeholder:text-muted-foreground",
|
|
1295
|
-
autoFocus: true
|
|
1296
|
-
}
|
|
1297
|
-
),
|
|
1298
|
-
isLoading && /* @__PURE__ */ jsx17(Loader2, { className: "h-5 w-5 text-muted-foreground animate-spin" })
|
|
1299
|
-
] }),
|
|
1300
|
-
/* @__PURE__ */ jsxs12("div", { className: "max-h-[60vh] overflow-y-auto", children: [
|
|
1301
|
-
query.trim() && results.length === 0 && !isLoading && /* @__PURE__ */ jsxs12("div", { className: "px-4 py-8 text-center text-muted-foreground", children: [
|
|
1302
|
-
'No results found for "',
|
|
1303
|
-
query,
|
|
1304
|
-
'"'
|
|
1305
|
-
] }),
|
|
1306
|
-
results.length > 0 && /* @__PURE__ */ jsx17("div", { className: "py-2", children: results.map((result, index) => /* @__PURE__ */ jsx17(
|
|
1307
|
-
"button",
|
|
1308
|
-
{
|
|
1309
|
-
onClick: () => handleResultClick(result),
|
|
1310
|
-
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"}`,
|
|
1311
|
-
onMouseEnter: () => setSelectedIndex(index),
|
|
1312
|
-
children: /* @__PURE__ */ jsxs12("div", { className: "flex items-start gap-3", children: [
|
|
1313
|
-
/* @__PURE__ */ jsx17(FileText, { className: "h-5 w-5 text-muted-foreground shrink-0 mt-0.5" }),
|
|
1314
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex-1 min-w-0", children: [
|
|
1315
|
-
/* @__PURE__ */ jsx17("div", { className: "font-medium text-foreground mb-1", children: highlightText(result.title, query) }),
|
|
1316
|
-
result.content && /* @__PURE__ */ jsx17("div", { className: "text-sm text-muted-foreground line-clamp-2", children: highlightText(result.content, query) }),
|
|
1317
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 mt-1 text-xs text-muted-foreground", children: [
|
|
1318
|
-
/* @__PURE__ */ jsx17("span", { children: result.version }),
|
|
1319
|
-
result.category && /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
1320
|
-
/* @__PURE__ */ jsx17("span", { children: "\u2022" }),
|
|
1321
|
-
/* @__PURE__ */ jsx17("span", { children: result.category })
|
|
1322
|
-
] })
|
|
1323
|
-
] })
|
|
1324
|
-
] })
|
|
1325
|
-
] })
|
|
1326
|
-
},
|
|
1327
|
-
result.id
|
|
1328
|
-
)) }),
|
|
1329
|
-
!query.trim() && /* @__PURE__ */ jsxs12("div", { className: "px-4 py-8 text-center text-muted-foreground text-sm", children: [
|
|
1330
|
-
/* @__PURE__ */ jsx17("p", { children: "Start typing to search documentation..." }),
|
|
1331
|
-
/* @__PURE__ */ jsxs12("div", { className: "mt-4 flex items-center justify-center gap-4 text-xs", children: [
|
|
1332
|
-
/* @__PURE__ */ jsx17("kbd", { className: "px-2 py-1 bg-muted rounded border border-border", children: "\u2191\u2193" }),
|
|
1333
|
-
/* @__PURE__ */ jsx17("span", { children: "Navigate" }),
|
|
1334
|
-
/* @__PURE__ */ jsx17("kbd", { className: "px-2 py-1 bg-muted rounded border border-border", children: "Enter" }),
|
|
1335
|
-
/* @__PURE__ */ jsx17("span", { children: "Select" }),
|
|
1336
|
-
/* @__PURE__ */ jsx17("kbd", { className: "px-2 py-1 bg-muted rounded border border-border", children: "Esc" }),
|
|
1337
|
-
/* @__PURE__ */ jsx17("span", { children: "Close" })
|
|
1338
|
-
] })
|
|
1339
|
-
] })
|
|
1340
|
-
] })
|
|
1341
|
-
]
|
|
1342
|
-
}
|
|
1343
|
-
) });
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
// src/components/docs/header.tsx
|
|
1347
|
-
import { useState as useState12, useEffect as useEffect7 } from "react";
|
|
1348
|
-
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1349
|
-
function Header({ currentVersion, versions, onMenuClick, config: configProp }) {
|
|
1350
|
-
const contextConfig = useConfig();
|
|
1351
|
-
const config = configProp || contextConfig;
|
|
1352
|
-
const [searchOpen, setSearchOpen] = useState12(false);
|
|
1353
|
-
useEffect7(() => {
|
|
1354
|
-
const handleKeyDown = (e) => {
|
|
1355
|
-
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
1356
|
-
e.preventDefault();
|
|
1357
|
-
setSearchOpen(true);
|
|
1358
|
-
}
|
|
1359
|
-
};
|
|
1360
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1361
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1362
|
-
}, []);
|
|
1363
|
-
return /* @__PURE__ */ jsxs13("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: [
|
|
1364
|
-
/* @__PURE__ */ jsxs13("div", { className: "container flex h-16 items-center justify-between px-2 md:px-6 mx-auto", children: [
|
|
1365
|
-
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1", children: [
|
|
1366
|
-
/* @__PURE__ */ jsx18(
|
|
1367
|
-
"button",
|
|
1368
|
-
{
|
|
1369
|
-
onClick: onMenuClick,
|
|
1370
|
-
className: "lg:hidden hover:bg-muted p-2 rounded-md transition-colors",
|
|
1371
|
-
"aria-label": "Toggle menu",
|
|
1372
|
-
children: /* @__PURE__ */ jsx18(Menu, { className: "h-5 w-5" })
|
|
1373
|
-
}
|
|
1374
|
-
),
|
|
1375
|
-
/* @__PURE__ */ jsxs13(Link4, { href: "/", className: "flex items-center gap-2", children: [
|
|
1376
|
-
!config.site.hideLogo && (config.site.logo ? /* @__PURE__ */ jsx18(Logo, { logo: config.site.logo, alt: config.site.title, className: "h-12 w-auto object-contain" }) : /* @__PURE__ */ jsx18("div", { className: "h-8 w-8 rounded-xl bg-primary flex items-center justify-center", children: /* @__PURE__ */ jsx18("span", { className: "text-primary-foreground font-bold text-lg", children: config.site.title.charAt(0).toUpperCase() }) })),
|
|
1377
|
-
!config.site.hideTitle && /* @__PURE__ */ jsx18("span", { className: "font-semibold text-lg text-foreground", children: config.site.title ?? "Specra" })
|
|
1378
|
-
] })
|
|
1379
|
-
] }),
|
|
1380
|
-
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
|
|
1381
|
-
config.search?.enabled && /* @__PURE__ */ jsxs13(
|
|
1382
|
-
"button",
|
|
1383
|
-
{
|
|
1384
|
-
onClick: () => setSearchOpen(true),
|
|
1385
|
-
className: "flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground hover:text-foreground bg-muted rounded-md transition-colors",
|
|
1386
|
-
children: [
|
|
1387
|
-
/* @__PURE__ */ jsx18(Search2, { className: "h-4 w-4" }),
|
|
1388
|
-
/* @__PURE__ */ jsx18("span", { className: "hidden sm:inline", children: config.search.placeholder || "Search" }),
|
|
1389
|
-
/* @__PURE__ */ jsx18("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" })
|
|
1390
|
-
]
|
|
1391
|
-
}
|
|
1392
|
-
),
|
|
1393
|
-
config.features?.versioning && /* @__PURE__ */ jsx18(VersionSwitcher, { currentVersion, versions }),
|
|
1394
|
-
config.social?.github && /* @__PURE__ */ jsx18(
|
|
1395
|
-
"a",
|
|
1396
|
-
{
|
|
1397
|
-
href: config.social.github,
|
|
1398
|
-
target: "_blank",
|
|
1399
|
-
rel: "noopener noreferrer",
|
|
1400
|
-
className: "hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors",
|
|
1401
|
-
"aria-label": "GitHub",
|
|
1402
|
-
children: /* @__PURE__ */ jsx18(Github, { className: "h-4 w-4" })
|
|
1403
|
-
}
|
|
1404
|
-
),
|
|
1405
|
-
config.social?.twitter && /* @__PURE__ */ jsx18(
|
|
1406
|
-
"a",
|
|
1407
|
-
{
|
|
1408
|
-
href: config.social.twitter,
|
|
1409
|
-
target: "_blank",
|
|
1410
|
-
rel: "noopener noreferrer",
|
|
1411
|
-
className: "hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors",
|
|
1412
|
-
"aria-label": "Twitter",
|
|
1413
|
-
children: /* @__PURE__ */ jsx18(Twitter, { className: "h-4 w-4" })
|
|
1414
|
-
}
|
|
1415
|
-
),
|
|
1416
|
-
config.social?.discord && /* @__PURE__ */ jsx18(
|
|
1417
|
-
"a",
|
|
1418
|
-
{
|
|
1419
|
-
href: config.social.discord,
|
|
1420
|
-
target: "_blank",
|
|
1421
|
-
rel: "noopener noreferrer",
|
|
1422
|
-
className: "hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors",
|
|
1423
|
-
"aria-label": "Discord",
|
|
1424
|
-
children: /* @__PURE__ */ jsx18(MessageCircle, { className: "h-4 w-4" })
|
|
1425
|
-
}
|
|
1426
|
-
),
|
|
1427
|
-
/* @__PURE__ */ jsx18(ThemeToggle, {}),
|
|
1428
|
-
/* @__PURE__ */ jsx18(LanguageSwitcher, {})
|
|
1429
|
-
] })
|
|
1430
|
-
] }),
|
|
1431
|
-
/* @__PURE__ */ jsx18(SearchModal, { isOpen: searchOpen, onClose: () => setSearchOpen(false), config })
|
|
1432
|
-
] });
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
// src/components/docs/hot-reload-indicator.tsx
|
|
1436
|
-
import { useEffect as useEffect8, useState as useState13 } from "react";
|
|
1437
|
-
import { usePathname as usePathname3 } from "next/navigation";
|
|
1438
|
-
import { RefreshCw } from "lucide-react";
|
|
1439
|
-
import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1440
|
-
function HotReloadIndicator() {
|
|
1441
|
-
const [isReloading, setIsReloading] = useState13(false);
|
|
1442
|
-
const [lastReload, setLastReload] = useState13(null);
|
|
1443
|
-
const pathname = usePathname3();
|
|
1444
|
-
useEffect8(() => {
|
|
1445
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
1446
|
-
setIsReloading(true);
|
|
1447
|
-
const timer = setTimeout(() => {
|
|
1448
|
-
setIsReloading(false);
|
|
1449
|
-
setLastReload(/* @__PURE__ */ new Date());
|
|
1450
|
-
setTimeout(() => {
|
|
1451
|
-
setLastReload(null);
|
|
1452
|
-
}, 3e3);
|
|
1453
|
-
}, 500);
|
|
1454
|
-
return () => clearTimeout(timer);
|
|
1455
|
-
}, [pathname]);
|
|
1456
|
-
useEffect8(() => {
|
|
1457
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
1458
|
-
const handleBeforeRefresh = () => {
|
|
1459
|
-
setIsReloading(true);
|
|
1460
|
-
};
|
|
1461
|
-
const handleAfterRefresh = () => {
|
|
1462
|
-
setIsReloading(false);
|
|
1463
|
-
setLastReload(/* @__PURE__ */ new Date());
|
|
1464
|
-
setTimeout(() => setLastReload(null), 3e3);
|
|
1465
|
-
};
|
|
1466
|
-
if (typeof window !== "undefined" && window.__NEXT_DATA__) {
|
|
1467
|
-
window.addEventListener("beforeunload", handleBeforeRefresh);
|
|
1468
|
-
}
|
|
1469
|
-
return () => {
|
|
1470
|
-
window.removeEventListener("beforeunload", handleBeforeRefresh);
|
|
1471
|
-
};
|
|
1472
|
-
}, []);
|
|
1473
|
-
if (process.env.NODE_ENV !== "development") return null;
|
|
1474
|
-
return /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
1475
|
-
isReloading && /* @__PURE__ */ jsxs14("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: [
|
|
1476
|
-
/* @__PURE__ */ jsx19(RefreshCw, { className: "h-4 w-4 animate-spin" }),
|
|
1477
|
-
/* @__PURE__ */ jsx19("span", { className: "text-sm font-medium", children: "Reloading..." })
|
|
1478
|
-
] }),
|
|
1479
|
-
lastReload && !isReloading && /* @__PURE__ */ jsxs14("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: [
|
|
1480
|
-
/* @__PURE__ */ jsx19(RefreshCw, { className: "h-4 w-4" }),
|
|
1481
|
-
/* @__PURE__ */ jsxs14("span", { className: "text-sm font-medium", children: [
|
|
1482
|
-
"Updated at ",
|
|
1483
|
-
lastReload.toLocaleTimeString()
|
|
1484
|
-
] })
|
|
1485
|
-
] })
|
|
1486
|
-
] });
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
// src/components/docs/mdx-hot-reload.tsx
|
|
1490
|
-
import { useEffect as useEffect9 } from "react";
|
|
1491
|
-
import { useRouter as useRouter5 } from "next/navigation";
|
|
1492
|
-
function MdxHotReload() {
|
|
1493
|
-
const router = useRouter5();
|
|
1494
|
-
useEffect9(() => {
|
|
1495
|
-
if (process.env.NODE_ENV !== "development") return;
|
|
1496
|
-
const eventSource = new EventSource("/api/mdx-watch");
|
|
1497
|
-
eventSource.onmessage = (event) => {
|
|
1498
|
-
const data = JSON.parse(event.data);
|
|
1499
|
-
if (data.type === "change") {
|
|
1500
|
-
console.log("[MDX Hot Reload] File changed:", data.file);
|
|
1501
|
-
router.refresh();
|
|
1502
|
-
} else if (data.type === "connected") {
|
|
1503
|
-
console.log("[MDX Hot Reload] Watching for changes...");
|
|
1504
|
-
}
|
|
1505
|
-
};
|
|
1506
|
-
eventSource.onerror = (error) => {
|
|
1507
|
-
console.error("[MDX Hot Reload] Connection error:", error);
|
|
1508
|
-
eventSource.close();
|
|
1509
|
-
};
|
|
1510
|
-
return () => {
|
|
1511
|
-
eventSource.close();
|
|
1512
|
-
};
|
|
1513
|
-
}, [router]);
|
|
1514
|
-
return null;
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
// src/components/docs/not-found-content.tsx
|
|
1518
|
-
import Link5 from "next/link";
|
|
1519
|
-
import { AlertTriangle, Home, ArrowLeft } from "lucide-react";
|
|
1520
|
-
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1521
|
-
function NotFoundContent({ version }) {
|
|
1522
|
-
return /* @__PURE__ */ jsx20("div", { className: "flex min-h-[calc(100vh-12rem)] items-center justify-center px-4 py-12", children: /* @__PURE__ */ jsxs15("div", { className: "w-full max-w-2xl text-center", children: [
|
|
1523
|
-
/* @__PURE__ */ jsx20("div", { className: "mb-6 flex justify-center", children: /* @__PURE__ */ jsx20("div", { className: "rounded-full bg-yellow-500/10 p-4", children: /* @__PURE__ */ jsx20(AlertTriangle, { className: "h-16 w-16 text-yellow-500" }) }) }),
|
|
1524
|
-
/* @__PURE__ */ jsx20("h1", { className: "mb-3 text-5xl font-bold tracking-tight", children: "404" }),
|
|
1525
|
-
/* @__PURE__ */ jsx20("h2", { className: "mb-4 text-2xl font-semibold", children: "Page Not Found" }),
|
|
1526
|
-
/* @__PURE__ */ jsxs15("p", { className: "mb-8 text-base text-muted-foreground", children: [
|
|
1527
|
-
"The documentation page you're looking for doesn't exist or may have been moved.",
|
|
1528
|
-
/* @__PURE__ */ jsx20("br", {}),
|
|
1529
|
-
"Try using the sidebar to find what you're looking for, or return to the documentation home."
|
|
1530
|
-
] }),
|
|
1531
|
-
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-center justify-center gap-3 sm:flex-row", children: [
|
|
1532
|
-
/* @__PURE__ */ jsxs15(
|
|
1533
|
-
Link5,
|
|
1534
|
-
{
|
|
1535
|
-
href: `/docs/${version}`,
|
|
1536
|
-
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",
|
|
1537
|
-
children: [
|
|
1538
|
-
/* @__PURE__ */ jsx20(ArrowLeft, { className: "h-4 w-4" }),
|
|
1539
|
-
"Back to Documentation"
|
|
1540
|
-
]
|
|
1541
|
-
}
|
|
1542
|
-
),
|
|
1543
|
-
/* @__PURE__ */ jsxs15(
|
|
1544
|
-
Link5,
|
|
1545
|
-
{
|
|
1546
|
-
href: "/",
|
|
1547
|
-
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",
|
|
1548
|
-
children: [
|
|
1549
|
-
/* @__PURE__ */ jsx20(Home, { className: "h-4 w-4" }),
|
|
1550
|
-
"Go to Homepage"
|
|
1551
|
-
]
|
|
1552
|
-
}
|
|
1553
|
-
)
|
|
1554
|
-
] }),
|
|
1555
|
-
/* @__PURE__ */ jsx20("div", { className: "mt-12 rounded-lg border border-border bg-muted/30 p-6", children: /* @__PURE__ */ jsxs15("p", { className: "text-sm text-muted-foreground", children: [
|
|
1556
|
-
/* @__PURE__ */ jsx20("strong", { className: "font-medium text-foreground", children: "Tip:" }),
|
|
1557
|
-
" Use the sidebar navigation on the left to browse all available documentation pages."
|
|
1558
|
-
] }) })
|
|
1559
|
-
] }) });
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
// src/components/docs/search-highlight.tsx
|
|
1563
|
-
import { useEffect as useEffect10 } from "react";
|
|
1564
|
-
import { useSearchParams } from "next/navigation";
|
|
1565
|
-
function SearchHighlight() {
|
|
1566
|
-
const searchParams = useSearchParams();
|
|
1567
|
-
const query = searchParams.get("q");
|
|
1568
|
-
useEffect10(() => {
|
|
1569
|
-
if (!query) {
|
|
1570
|
-
document.querySelectorAll("mark.search-highlight").forEach((mark) => {
|
|
1571
|
-
const parent = mark.parentNode;
|
|
1572
|
-
if (parent) {
|
|
1573
|
-
parent.replaceChild(document.createTextNode(mark.textContent || ""), mark);
|
|
1574
|
-
parent.normalize();
|
|
1575
|
-
}
|
|
1576
|
-
});
|
|
1577
|
-
return;
|
|
1578
|
-
}
|
|
1579
|
-
const timeout = setTimeout(() => {
|
|
1580
|
-
highlightSearchTerm(query);
|
|
1581
|
-
}, 100);
|
|
1582
|
-
return () => {
|
|
1583
|
-
clearTimeout(timeout);
|
|
1584
|
-
document.querySelectorAll("mark.search-highlight").forEach((mark) => {
|
|
1585
|
-
const parent = mark.parentNode;
|
|
1586
|
-
if (parent) {
|
|
1587
|
-
parent.replaceChild(document.createTextNode(mark.textContent || ""), mark);
|
|
1588
|
-
parent.normalize();
|
|
1589
|
-
}
|
|
1590
|
-
});
|
|
1591
|
-
};
|
|
1592
|
-
}, [query]);
|
|
1593
|
-
return null;
|
|
1594
|
-
}
|
|
1595
|
-
function highlightSearchTerm(searchTerm) {
|
|
1596
|
-
document.querySelectorAll("mark.search-highlight").forEach((mark) => {
|
|
1597
|
-
const parent = mark.parentNode;
|
|
1598
|
-
if (parent) {
|
|
1599
|
-
parent.replaceChild(document.createTextNode(mark.textContent || ""), mark);
|
|
1600
|
-
parent.normalize();
|
|
1601
|
-
}
|
|
1602
|
-
});
|
|
1603
|
-
const contentArea = document.querySelector("main") || document.body;
|
|
1604
|
-
const walker = document.createTreeWalker(
|
|
1605
|
-
contentArea,
|
|
1606
|
-
NodeFilter.SHOW_TEXT,
|
|
1607
|
-
{
|
|
1608
|
-
acceptNode: (node) => {
|
|
1609
|
-
const parent = node.parentElement;
|
|
1610
|
-
if (!parent) return NodeFilter.FILTER_REJECT;
|
|
1611
|
-
const tagName = parent.tagName.toLowerCase();
|
|
1612
|
-
if (["mark", "script", "style", "code", "pre"].includes(tagName)) {
|
|
1613
|
-
return NodeFilter.FILTER_REJECT;
|
|
1614
|
-
}
|
|
1615
|
-
if (node.textContent && node.textContent.toLowerCase().includes(searchTerm.toLowerCase())) {
|
|
1616
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
1617
|
-
}
|
|
1618
|
-
return NodeFilter.FILTER_REJECT;
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
);
|
|
1622
|
-
const nodesToHighlight = [];
|
|
1623
|
-
let currentNode;
|
|
1624
|
-
while (currentNode = walker.nextNode()) {
|
|
1625
|
-
if (currentNode.textContent) {
|
|
1626
|
-
nodesToHighlight.push({
|
|
1627
|
-
node: currentNode,
|
|
1628
|
-
text: currentNode.textContent
|
|
1629
|
-
});
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
nodesToHighlight.forEach(({ node, text }) => {
|
|
1633
|
-
const regex = new RegExp(`(${escapeRegex(searchTerm)})`, "gi");
|
|
1634
|
-
const parts = text.split(regex);
|
|
1635
|
-
if (parts.length > 1) {
|
|
1636
|
-
const fragment = document.createDocumentFragment();
|
|
1637
|
-
parts.forEach((part) => {
|
|
1638
|
-
if (part.toLowerCase() === searchTerm.toLowerCase()) {
|
|
1639
|
-
const mark = document.createElement("mark");
|
|
1640
|
-
mark.className = "search-highlight bg-yellow-200 dark:bg-yellow-900/50 text-foreground px-1 rounded";
|
|
1641
|
-
mark.textContent = part;
|
|
1642
|
-
fragment.appendChild(mark);
|
|
1643
|
-
} else if (part) {
|
|
1644
|
-
fragment.appendChild(document.createTextNode(part));
|
|
1645
|
-
}
|
|
1646
|
-
});
|
|
1647
|
-
node.parentNode?.replaceChild(fragment, node);
|
|
1648
|
-
}
|
|
1649
|
-
});
|
|
1650
|
-
const firstHighlight = document.querySelector("mark.search-highlight");
|
|
1651
|
-
if (firstHighlight) {
|
|
1652
|
-
setTimeout(() => {
|
|
1653
|
-
firstHighlight.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
1654
|
-
}, 200);
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
function escapeRegex(string) {
|
|
1658
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
// src/components/docs/sidebar-skeleton.tsx
|
|
1662
|
-
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1663
|
-
function SidebarSkeleton() {
|
|
1664
|
-
return /* @__PURE__ */ jsx21("aside", { className: "w-64 pr-8 py-6", children: /* @__PURE__ */ jsxs16("div", { className: "space-y-6", children: [
|
|
1665
|
-
/* @__PURE__ */ jsx21("div", { className: "px-2", children: /* @__PURE__ */ jsx21("div", { className: "h-5 w-32 bg-muted/50 rounded animate-pulse" }) }),
|
|
1666
|
-
/* @__PURE__ */ jsx21("div", { className: "space-y-1", children: [...Array(8)].map((_, i) => /* @__PURE__ */ jsx21("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx21(
|
|
1667
|
-
"div",
|
|
1668
|
-
{
|
|
1669
|
-
className: "h-4 bg-muted/50 rounded animate-pulse",
|
|
1670
|
-
style: { width: `${60 + Math.random() * 40}%` }
|
|
1671
|
-
}
|
|
1672
|
-
) }, i)) }),
|
|
1673
|
-
/* @__PURE__ */ jsxs16("div", { className: "space-y-1", children: [
|
|
1674
|
-
/* @__PURE__ */ jsx21("div", { className: "px-2 mb-2", children: /* @__PURE__ */ jsx21("div", { className: "h-4 w-24 bg-muted/50 rounded animate-pulse" }) }),
|
|
1675
|
-
[...Array(5)].map((_, i) => /* @__PURE__ */ jsx21("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx21(
|
|
1676
|
-
"div",
|
|
1677
|
-
{
|
|
1678
|
-
className: "h-4 bg-muted/50 rounded animate-pulse",
|
|
1679
|
-
style: { width: `${50 + Math.random() * 50}%` }
|
|
1680
|
-
}
|
|
1681
|
-
) }, i))
|
|
1682
|
-
] })
|
|
1683
|
-
] }) });
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
// src/components/docs/table-of-contents.tsx
|
|
1687
|
-
import { useEffect as useEffect11, useState as useState14 } from "react";
|
|
1688
|
-
import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1689
|
-
function TableOfContents({ items, config }) {
|
|
1690
|
-
const [activeId, setActiveId] = useState14("");
|
|
1691
|
-
if (!config.navigation?.showTableOfContents) {
|
|
1692
|
-
return null;
|
|
1693
|
-
}
|
|
1694
|
-
const maxDepth = config.navigation?.tocMaxDepth || 3;
|
|
1695
|
-
const filteredItems = items.filter((item) => item.level <= maxDepth);
|
|
1696
|
-
const hasTabGroups = config.navigation?.tabGroups && config.navigation.tabGroups.length > 0;
|
|
1697
|
-
useEffect11(() => {
|
|
1698
|
-
const observer = new IntersectionObserver(
|
|
1699
|
-
(entries) => {
|
|
1700
|
-
entries.forEach((entry) => {
|
|
1701
|
-
if (entry.isIntersecting) {
|
|
1702
|
-
setActiveId(entry.target.id);
|
|
1703
|
-
}
|
|
1704
|
-
});
|
|
1705
|
-
},
|
|
1706
|
-
{ rootMargin: "-80px 0px -80% 0px" }
|
|
1707
|
-
);
|
|
1708
|
-
filteredItems.forEach((item) => {
|
|
1709
|
-
const element = document.getElementById(item.id);
|
|
1710
|
-
if (element) {
|
|
1711
|
-
observer.observe(element);
|
|
1712
|
-
}
|
|
1713
|
-
});
|
|
1714
|
-
return () => observer.disconnect();
|
|
1715
|
-
}, [filteredItems]);
|
|
1716
|
-
const handleClick = (e, id) => {
|
|
1717
|
-
e.preventDefault();
|
|
1718
|
-
const element = document.getElementById(id);
|
|
1719
|
-
if (element) {
|
|
1720
|
-
const offset = 100;
|
|
1721
|
-
const elementPosition = element.getBoundingClientRect().top;
|
|
1722
|
-
const offsetPosition = elementPosition + window.scrollY - offset;
|
|
1723
|
-
window.scrollTo({
|
|
1724
|
-
top: offsetPosition,
|
|
1725
|
-
behavior: "smooth"
|
|
1726
|
-
});
|
|
1727
|
-
window.history.replaceState(null, "", `#${id}`);
|
|
1728
|
-
setActiveId(id);
|
|
1729
|
-
}
|
|
1730
|
-
};
|
|
1731
|
-
const stickyTop = hasTabGroups ? "top-[7.5rem]" : "top-24";
|
|
1732
|
-
const maxHeight = hasTabGroups ? "max-h-[calc(100vh-10rem)]" : "max-h-[calc(100vh-7rem)]";
|
|
1733
|
-
return /* @__PURE__ */ jsx22("aside", { className: `w-64 hidden xl:block shrink-0 sticky ${stickyTop} self-start`, children: filteredItems.length > 0 && /* @__PURE__ */ jsxs17("div", { className: `${maxHeight} overflow-y-auto bg-muted/30 dark:bg-muted/10 rounded-2xl p-4 border border-border/50`, children: [
|
|
1734
|
-
/* @__PURE__ */ jsx22("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4 px-2", children: "On this page" }),
|
|
1735
|
-
/* @__PURE__ */ jsx22("nav", { className: "space-y-1", children: filteredItems.map((item, index) => /* @__PURE__ */ jsx22(
|
|
1736
|
-
"a",
|
|
1737
|
-
{
|
|
1738
|
-
href: `#${item.id}`,
|
|
1739
|
-
onClick: (e) => handleClick(e, item.id),
|
|
1740
|
-
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"}`,
|
|
1741
|
-
children: item.title
|
|
1742
|
-
},
|
|
1743
|
-
`${item.id}-${index}`
|
|
1744
|
-
)) })
|
|
1745
|
-
] }) });
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
// src/components/global/version-not-found.tsx
|
|
1749
|
-
import { AlertTriangle as AlertTriangle2 } from "lucide-react";
|
|
1750
|
-
import Link6 from "next/link";
|
|
1751
|
-
import { Fragment as Fragment6, jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1752
|
-
function VersionNotFound() {
|
|
1753
|
-
return /* @__PURE__ */ jsx23(Fragment6, { children: /* @__PURE__ */ jsx23("div", { className: "flex min-h-screen items-center justify-center px-4", children: /* @__PURE__ */ jsxs18("div", { className: "text-center", children: [
|
|
1754
|
-
/* @__PURE__ */ jsx23("div", { className: "mb-4 flex justify-center", children: /* @__PURE__ */ jsx23(AlertTriangle2, { className: "h-16 w-16 text-yellow-500" }) }),
|
|
1755
|
-
/* @__PURE__ */ jsx23("h1", { className: "mb-2 text-4xl font-bold", children: "Version Not Found" }),
|
|
1756
|
-
/* @__PURE__ */ jsx23("p", { className: "mb-6 text-muted-foreground", children: "The documentation version you're looking for doesn't exist." }),
|
|
1757
|
-
/* @__PURE__ */ jsx23(
|
|
1758
|
-
Link6,
|
|
1759
|
-
{
|
|
1760
|
-
href: "/docs/v1.0.0",
|
|
1761
|
-
className: "inline-flex items-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90",
|
|
1762
|
-
children: "Go to Latest Version"
|
|
1763
|
-
}
|
|
1764
|
-
)
|
|
1765
|
-
] }) }) });
|
|
1766
|
-
}
|
|
1767
|
-
export {
|
|
1768
|
-
Accordion,
|
|
1769
|
-
AccordionItem,
|
|
1770
|
-
ApiEndpoint,
|
|
1771
|
-
ApiParams,
|
|
1772
|
-
ApiPlayground,
|
|
1773
|
-
ApiReference,
|
|
1774
|
-
ApiResponse,
|
|
1775
|
-
ApiResponse as ApiResponseDisplay,
|
|
1776
|
-
Badge2 as Badge,
|
|
1777
|
-
Breadcrumb,
|
|
1778
|
-
Button,
|
|
1779
|
-
COMPONENT_TEXT_PROPS,
|
|
1780
|
-
CSP_DIRECTIVES,
|
|
1781
|
-
Callout,
|
|
1782
|
-
Card,
|
|
1783
|
-
CardGrid,
|
|
1784
|
-
CodeBlock,
|
|
1785
|
-
Column,
|
|
1786
|
-
Columns,
|
|
1787
|
-
ConfigProvider,
|
|
1788
|
-
DevModeBadge,
|
|
1789
|
-
Dialog,
|
|
1790
|
-
DialogClose,
|
|
1791
|
-
DialogContent,
|
|
1792
|
-
DialogDescription,
|
|
1793
|
-
DialogFooter,
|
|
1794
|
-
DialogHeader,
|
|
1795
|
-
DialogOverlay,
|
|
1796
|
-
DialogPortal,
|
|
1797
|
-
DialogTitle,
|
|
1798
|
-
DialogTrigger,
|
|
1799
|
-
Badge as DocBadge,
|
|
1800
|
-
DocLayoutWrapper,
|
|
1801
|
-
DocLoading,
|
|
1802
|
-
DocMetadata,
|
|
1803
|
-
DocNavigation,
|
|
1804
|
-
DocTags,
|
|
1805
|
-
DraftBadge,
|
|
1806
|
-
Footer,
|
|
1807
|
-
Frame,
|
|
1808
|
-
Header,
|
|
1809
|
-
HotReloadIndicator,
|
|
1810
|
-
Icon,
|
|
1811
|
-
Image,
|
|
1812
|
-
ImageCard,
|
|
1813
|
-
ImageCardGrid,
|
|
1814
|
-
Input,
|
|
1815
|
-
LanguageSwitcher,
|
|
1816
|
-
Logo,
|
|
1817
|
-
Math2 as Math,
|
|
1818
|
-
MdxHotReload,
|
|
1819
|
-
Mermaid,
|
|
1820
|
-
MobileDocLayout,
|
|
1821
|
-
NotFoundContent,
|
|
1822
|
-
OpenApiParser,
|
|
1823
|
-
PerfTimer,
|
|
1824
|
-
PostmanParser,
|
|
1825
|
-
SAFE_MDX_COMPONENTS,
|
|
1826
|
-
SearchHighlight,
|
|
1827
|
-
SearchModal,
|
|
1828
|
-
Sidebar,
|
|
1829
|
-
SidebarSkeleton,
|
|
1830
|
-
SiteBanner,
|
|
1831
|
-
SpecraParser,
|
|
1832
|
-
Step,
|
|
1833
|
-
Steps,
|
|
1834
|
-
Tab,
|
|
1835
|
-
TabGroups,
|
|
1836
|
-
TabProvider,
|
|
1837
|
-
TableOfContents,
|
|
1838
|
-
Tabs,
|
|
1839
|
-
Textarea,
|
|
1840
|
-
ThemeToggle,
|
|
1841
|
-
Tooltip,
|
|
1842
|
-
VersionNotFound,
|
|
1843
|
-
VersionSwitcher,
|
|
1844
|
-
Video,
|
|
1845
|
-
badgeVariants,
|
|
1846
|
-
buildRedirectMappings,
|
|
1847
|
-
buildSidebarStructure,
|
|
1848
|
-
buttonVariants,
|
|
1849
|
-
clearAllCaches,
|
|
1850
|
-
cn,
|
|
1851
|
-
debugLog,
|
|
1852
|
-
defaultConfig,
|
|
1853
|
-
detectParserType,
|
|
1854
|
-
extractComponentPropsText,
|
|
1855
|
-
extractHeadings,
|
|
1856
|
-
extractSearchText,
|
|
1857
|
-
extractTableOfContents,
|
|
1858
|
-
findRedirect,
|
|
1859
|
-
generateCSPHeader,
|
|
1860
|
-
getAdjacentDocs,
|
|
1861
|
-
getAllCategoryConfigs,
|
|
1862
|
-
getAllDocs,
|
|
1863
|
-
getAssetPath,
|
|
1864
|
-
getCacheStats,
|
|
1865
|
-
getCachedAllDocs,
|
|
1866
|
-
getCachedDocBySlug,
|
|
1867
|
-
getCachedVersions,
|
|
1868
|
-
getCategoryConfig,
|
|
1869
|
-
getConfig,
|
|
1870
|
-
getConfigValue,
|
|
1871
|
-
getDocBySlug,
|
|
1872
|
-
getI18nConfig,
|
|
1873
|
-
getVersions,
|
|
1874
|
-
initConfig,
|
|
1875
|
-
isCategoryPage,
|
|
1876
|
-
loadConfig,
|
|
1877
|
-
logCacheOperation,
|
|
1878
|
-
logFsOperation,
|
|
1879
|
-
logMemoryUsage,
|
|
1880
|
-
parseApiSpec,
|
|
1881
|
-
processContentWithEnv,
|
|
1882
|
-
reloadConfig,
|
|
1883
|
-
replaceEnvVariables,
|
|
1884
|
-
sanitizeMDXContent,
|
|
1885
|
-
sanitizePath,
|
|
1886
|
-
scanMDXForDangerousPatterns,
|
|
1887
|
-
sortSidebarGroups,
|
|
1888
|
-
sortSidebarItems,
|
|
1889
|
-
useConfig,
|
|
1890
|
-
useConfigValue,
|
|
1891
|
-
useTabContext,
|
|
1892
|
-
validateConfig,
|
|
1893
|
-
validateMDXComponents,
|
|
1894
|
-
validateMDXSecurity,
|
|
1895
|
-
validatePathWithinDirectory
|
|
1896
|
-
};
|
|
1897
|
-
//# sourceMappingURL=index.mjs.map
|