zudoku 0.3.0-dev.82 → 0.3.0-dev.84
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/cli.js +5 -1
- package/dist/app/demo.js +5 -4
- package/dist/app/demo.js.map +1 -1
- package/dist/app/main.js +3 -1
- package/dist/app/main.js.map +1 -1
- package/dist/app/standalone.js +5 -4
- package/dist/app/standalone.js.map +1 -1
- package/dist/config/validators/ResolvedSidebarSchema.d.ts +18 -0
- package/dist/config/validators/ResolvedSidebarSchema.js +76 -0
- package/dist/config/validators/ResolvedSidebarSchema.js.map +1 -0
- package/dist/config/validators/SidebarSchema.d.ts +177 -0
- package/dist/config/validators/SidebarSchema.js +71 -0
- package/dist/config/validators/SidebarSchema.js.map +1 -0
- package/dist/config/validators/validate.d.ts +411 -59
- package/dist/config/validators/validate.js +22 -4
- package/dist/config/validators/validate.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/lib/components/DevPortal.js +1 -1
- package/dist/lib/components/DevPortal.js.map +1 -1
- package/dist/lib/components/Header.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/Layout.js +2 -2
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/TopNavigation.js +5 -5
- package/dist/lib/components/TopNavigation.js.map +1 -1
- package/dist/lib/components/context/DevPortalProvider.d.ts +9 -3
- package/dist/lib/components/context/DevPortalProvider.js +11 -23
- package/dist/lib/components/context/DevPortalProvider.js.map +1 -1
- package/dist/lib/components/context/ThemeContext.d.ts +1 -4
- package/dist/lib/components/context/ThemeContext.js +3 -29
- package/dist/lib/components/context/ThemeContext.js.map +1 -1
- package/dist/lib/components/context/ThemeProvider.d.ts +4 -0
- package/dist/lib/components/context/ThemeProvider.js +23 -0
- package/dist/lib/components/context/ThemeProvider.js.map +1 -0
- package/dist/lib/components/navigation/Sidebar.d.ts +1 -0
- package/dist/lib/components/navigation/Sidebar.js +12 -0
- package/dist/lib/components/navigation/Sidebar.js.map +1 -0
- package/dist/lib/components/navigation/SidebarBadge.d.ts +22 -0
- package/dist/lib/components/navigation/SidebarBadge.js +24 -0
- package/dist/lib/components/navigation/SidebarBadge.js.map +1 -0
- package/dist/lib/components/navigation/SidebarCategory.d.ts +5 -0
- package/dist/lib/components/navigation/SidebarCategory.js +33 -0
- package/dist/lib/components/navigation/SidebarCategory.js.map +1 -0
- package/dist/lib/components/navigation/SidebarItem.d.ts +12 -0
- package/dist/lib/components/navigation/SidebarItem.js +42 -0
- package/dist/lib/components/navigation/SidebarItem.js.map +1 -0
- package/dist/lib/components/navigation/{SideNavigationWrapper.d.ts → SidebarWrapper.d.ts} +1 -1
- package/dist/lib/components/navigation/{SideNavigationWrapper.js → SidebarWrapper.js} +2 -2
- package/dist/lib/components/navigation/SidebarWrapper.js.map +1 -0
- package/dist/lib/components/navigation/utils.d.ts +16 -0
- package/dist/lib/components/navigation/utils.js +85 -0
- package/dist/lib/components/navigation/utils.js.map +1 -0
- package/dist/lib/core/DevPortalContext.d.ts +9 -32
- package/dist/lib/core/DevPortalContext.js +8 -5
- package/dist/lib/core/DevPortalContext.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +6 -8
- package/dist/lib/core/plugins.js.map +1 -1
- package/dist/lib/plugins/api-keys/SettingsApiKeys.js +16 -2
- package/dist/lib/plugins/api-keys/SettingsApiKeys.js.map +1 -1
- package/dist/lib/plugins/api-keys/index.js +6 -0
- package/dist/lib/plugins/api-keys/index.js.map +1 -1
- package/dist/lib/plugins/markdown/MdxPage.js +5 -36
- package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
- package/dist/lib/plugins/markdown/generateRoutes.js +20 -43
- package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +12 -2
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/index.js +14 -11
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/interfaces.d.ts +1 -1
- package/dist/lib/util/useScrollToAnchor.js +31 -17
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/plugin-sidebar.d.ts +3 -0
- package/dist/vite/plugin-sidebar.js +23 -0
- package/dist/vite/plugin-sidebar.js.map +1 -0
- package/dist/vite/plugin.js +2 -0
- package/dist/vite/plugin.js.map +1 -1
- package/lib/{AuthenticationPlugin-XS0DoAhE.js → AuthenticationPlugin-DgwV0hVu.js} +7 -7
- package/lib/{AuthenticationPlugin-XS0DoAhE.js.map → AuthenticationPlugin-DgwV0hVu.js.map} +1 -1
- package/lib/{CategoryHeading-DCmchnA1.js → CategoryHeading-BWq12Bfa.js} +3 -3
- package/lib/{CategoryHeading-DCmchnA1.js.map → CategoryHeading-BWq12Bfa.js.map} +1 -1
- package/lib/{Combination-C442XfGG.js → Combination-DkycFHkm.js} +4 -4
- package/lib/{Combination-C442XfGG.js.map → Combination-DkycFHkm.js.map} +1 -1
- package/lib/{DevPortalProvider-BWeAysxF.js → DevPortalProvider-CTxoCHIT.js} +375 -417
- package/lib/DevPortalProvider-CTxoCHIT.js.map +1 -0
- package/lib/DeveloperHint-BQSFXH01.js +10 -0
- package/lib/{DeveloperHint-DQVwIery.js.map → DeveloperHint-BQSFXH01.js.map} +1 -1
- package/lib/{Input-3IEt27jb.js → Input-BclXSY0g.js} +5 -5
- package/lib/{Input-3IEt27jb.js.map → Input-BclXSY0g.js.map} +1 -1
- package/lib/{Markdown-QsZ-PHET.js → Markdown-B_Gax7at.js} +1136 -1152
- package/lib/{Markdown-QsZ-PHET.js.map → Markdown-B_Gax7at.js.map} +1 -1
- package/lib/{MdxPage-CA1WmW14.js → MdxPage-Crlr0GmN.js} +67 -81
- package/lib/MdxPage-Crlr0GmN.js.map +1 -0
- package/lib/{OperationList-CHK_erYP.js → OperationList-nQ0bd8TU.js} +8 -8
- package/lib/{OperationList-CHK_erYP.js.map → OperationList-nQ0bd8TU.js.map} +1 -1
- package/lib/Route-CNvxEBnR.js +14 -0
- package/lib/{Route-D70pGn9n.js.map → Route-CNvxEBnR.js.map} +1 -1
- package/lib/{SlotletProvider-B71hNEUL.js → SlotletProvider-CzMAO73_.js} +12 -12
- package/lib/{SlotletProvider-B71hNEUL.js.map → SlotletProvider-CzMAO73_.js.map} +1 -1
- package/lib/Spinner-fF-Xv-gw.js +274 -0
- package/lib/Spinner-fF-Xv-gw.js.map +1 -0
- package/lib/index-7kcHaXD6.js +1771 -0
- package/lib/index-7kcHaXD6.js.map +1 -0
- package/lib/{index-Bl6YeerK.js → index-CgCPw6Jn.js} +1026 -1043
- package/lib/index-CgCPw6Jn.js.map +1 -0
- package/lib/{index-BH-Ub36F.js → index-DkuZvRNP.js} +4 -4
- package/lib/{index-BH-Ub36F.js.map → index-DkuZvRNP.js.map} +1 -1
- package/lib/joinPath-VeNuJa7y.js +8 -0
- package/lib/joinPath-VeNuJa7y.js.map +1 -0
- package/lib/jsx-runtime-B6kdoens.js +635 -0
- package/lib/jsx-runtime-B6kdoens.js.map +1 -0
- package/lib/{AnchorLink-BZcpTwOs.js → utils-CzT_9Tsn.js} +258 -214
- package/lib/utils-CzT_9Tsn.js.map +1 -0
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +2 -2
- package/lib/zudoku.components.js +1229 -1227
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-api-keys.js +129 -107
- package/lib/zudoku.plugin-api-keys.js.map +1 -1
- package/lib/zudoku.plugin-custom-page.js +2 -2
- package/lib/zudoku.plugin-markdown.js +21 -38
- package/lib/zudoku.plugin-markdown.js.map +1 -1
- package/lib/zudoku.plugin-openapi.js +8 -6
- package/lib/zudoku.plugin-openapi.js.map +1 -1
- package/package.json +4 -1
- package/src/app/demo.tsx +5 -4
- package/src/app/main.css +2 -2
- package/src/app/main.tsx +3 -1
- package/src/app/standalone.tsx +5 -4
- package/src/lib/components/DevPortal.tsx +1 -1
- package/src/lib/components/Header.tsx +2 -2
- package/src/lib/components/Layout.tsx +2 -2
- package/src/lib/components/TopNavigation.tsx +5 -5
- package/src/lib/components/context/DevPortalProvider.ts +11 -28
- package/src/lib/components/context/ThemeContext.tsx +3 -41
- package/src/lib/components/context/ThemeProvider.tsx +27 -0
- package/src/lib/components/navigation/{SideNavigation.tsx → Sidebar.tsx} +7 -7
- package/src/lib/components/navigation/SidebarBadge.tsx +40 -0
- package/src/lib/components/navigation/SidebarCategory.tsx +105 -0
- package/src/lib/components/navigation/SidebarItem.tsx +96 -0
- package/src/lib/components/navigation/{SideNavigationWrapper.tsx → SidebarWrapper.tsx} +1 -1
- package/src/lib/components/navigation/utils.ts +120 -0
- package/src/lib/core/DevPortalContext.ts +12 -44
- package/src/lib/core/plugins.ts +6 -13
- package/src/lib/plugins/api-keys/SettingsApiKeys.tsx +31 -10
- package/src/lib/plugins/api-keys/index.tsx +10 -0
- package/src/lib/plugins/markdown/MdxPage.tsx +14 -50
- package/src/lib/plugins/markdown/generateRoutes.tsx +29 -57
- package/src/lib/plugins/openapi/Sidecar.tsx +15 -2
- package/src/lib/plugins/openapi/index.tsx +17 -23
- package/src/lib/plugins/openapi/interfaces.ts +1 -1
- package/src/lib/util/useScrollToAnchor.ts +39 -18
- package/dist/lib/components/navigation/SideNavigation.d.ts +0 -1
- package/dist/lib/components/navigation/SideNavigation.js +0 -12
- package/dist/lib/components/navigation/SideNavigation.js.map +0 -1
- package/dist/lib/components/navigation/SideNavigationCategory.d.ts +0 -4
- package/dist/lib/components/navigation/SideNavigationCategory.js +0 -26
- package/dist/lib/components/navigation/SideNavigationCategory.js.map +0 -1
- package/dist/lib/components/navigation/SideNavigationItem.d.ts +0 -9
- package/dist/lib/components/navigation/SideNavigationItem.js +0 -44
- package/dist/lib/components/navigation/SideNavigationItem.js.map +0 -1
- package/dist/lib/components/navigation/SideNavigationWrapper.js.map +0 -1
- package/dist/lib/components/navigation/useNavigationCollapsibleState.d.ts +0 -9
- package/dist/lib/components/navigation/useNavigationCollapsibleState.js +0 -28
- package/dist/lib/components/navigation/useNavigationCollapsibleState.js.map +0 -1
- package/dist/lib/components/navigation/util.d.ts +0 -8
- package/dist/lib/components/navigation/util.js +0 -15
- package/dist/lib/components/navigation/util.js.map +0 -1
- package/dist/lib/plugins/openapi/MethodBadge.d.ts +0 -13
- package/dist/lib/plugins/openapi/MethodBadge.js +0 -26
- package/dist/lib/plugins/openapi/MethodBadge.js.map +0 -1
- package/dist/lib/util/traverseNavigation.d.ts +0 -6
- package/dist/lib/util/traverseNavigation.js +0 -30
- package/dist/lib/util/traverseNavigation.js.map +0 -1
- package/lib/AnchorLink-BZcpTwOs.js.map +0 -1
- package/lib/DevPortalProvider-BWeAysxF.js.map +0 -1
- package/lib/DeveloperHint-DQVwIery.js +0 -10
- package/lib/MdxPage-CA1WmW14.js.map +0 -1
- package/lib/Route-D70pGn9n.js +0 -13
- package/lib/Spinner-Coi7ORUV.js +0 -244
- package/lib/Spinner-Coi7ORUV.js.map +0 -1
- package/lib/index-Bl6YeerK.js.map +0 -1
- package/lib/index-Dt-pU7Vu.js +0 -916
- package/lib/index-Dt-pU7Vu.js.map +0 -1
- package/lib/jsx-runtime-CJBdjYYx.js +0 -1526
- package/lib/jsx-runtime-CJBdjYYx.js.map +0 -1
- package/src/lib/components/navigation/SideNavigationCategory.tsx +0 -72
- package/src/lib/components/navigation/SideNavigationItem.tsx +0 -148
- package/src/lib/components/navigation/useNavigationCollapsibleState.ts +0 -42
- package/src/lib/components/navigation/util.ts +0 -38
- package/src/lib/plugins/openapi/MethodBadge.tsx +0 -36
- package/src/lib/util/traverseNavigation.ts +0 -55
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zudoku.plugin-markdown.js","sources":["../src/lib/plugins/markdown/generateRoutes.tsx","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"zudoku.plugin-markdown.js","sources":["../src/lib/plugins/markdown/generateRoutes.tsx","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import { type RouteObject } from \"react-router-dom\";\n\nimport {\n MarkdownPluginDefaultOptions,\n MarkdownPluginOptions,\n} from \"./index.js\";\n\nexport const generateRoutes = (\n markdownFiles: MarkdownPluginOptions[\"markdownFiles\"],\n defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] =>\n Object.entries(markdownFiles).flatMap(([file, importPromise]) => {\n // @todo we can pass in the folder name and then filter the markdown files based on that path\n const match = file.match(/pages\\/(.*).mdx?$/);\n const path = match?.at(1);\n\n if (!path) return [];\n\n const pathSegments = path.split(\"/\");\n const isIndexFile = pathSegments.at(-1) === \"index\";\n const routePath = isIndexFile ? pathSegments.slice(0, -1).join(\"/\") : path;\n\n return {\n path: routePath,\n lazy: async () => {\n const { MdxPage } = await import(\"./MdxPage.js\");\n const { default: Component, ...props } = await importPromise();\n return {\n element: (\n <MdxPage\n mdxComponent={Component}\n {...props}\n defaultOptions={defaultOptions}\n />\n ),\n };\n },\n } satisfies RouteObject;\n });\n","import type { Toc } from \"@stefanprobst/rehype-extract-toc\";\nimport type { MDXProps } from \"mdx/types.js\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\nimport { generateRoutes } from \"./generateRoutes.js\";\n\nexport type MarkdownPluginOptions = {\n markdownFiles: Record<string, () => Promise<MDXImport>>;\n defaultOptions?: MarkdownPluginDefaultOptions;\n};\nexport type MarkdownPluginDefaultOptions = Pick<\n Frontmatter,\n \"toc\" | \"disablePager\"\n>;\n\nexport type Frontmatter = {\n title?: string;\n description?: string;\n category?: string;\n toc?: boolean;\n disablePager?: boolean;\n};\n\nexport type MDXImport = {\n tableOfContents: Toc;\n frontmatter: Frontmatter;\n default: (props: MDXProps) => JSX.Element;\n};\n\nexport const markdownPlugin = ({\n markdownFiles,\n defaultOptions,\n}: MarkdownPluginOptions): DevPortalPlugin => ({\n getRoutes: () => generateRoutes(markdownFiles, defaultOptions),\n});\n"],"names":["generateRoutes","markdownFiles","defaultOptions","file","importPromise","match","path","pathSegments","MdxPage","Component","props","jsx","markdownPlugin"],"mappings":";AAOO,MAAMA,IAAiB,CAC5BC,GACAC,MAEA,OAAO,QAAQD,CAAa,EAAE,QAAQ,CAAC,CAACE,GAAMC,CAAa,MAAM;AAEzD,QAAAC,IAAQF,EAAK,MAAM,mBAAmB,GACtCG,IAAOD,KAAA,gBAAAA,EAAO,GAAG;AAEnB,MAAA,CAACC,EAAM,QAAO;AAEZ,QAAAC,IAAeD,EAAK,MAAM,GAAG;AAI5B,SAAA;AAAA,IACL,MAJkBC,EAAa,GAAG,EAAE,MAAM,UACZA,EAAa,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAAID;AAAA,IAIpE,MAAM,YAAY;AAChB,YAAM,EAAE,SAAAE,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAMN;AACxC,aAAA;AAAA,QACL,SACEO,gBAAAA,EAAA;AAAA,UAACH;AAAA,UAAA;AAAA,YACC,cAAcC;AAAA,YACb,GAAGC;AAAA,YACJ,gBAAAR;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAGN;AAAA,EAAA;AAEJ,CAAC,GCVUU,IAAiB,CAAC;AAAA,EAC7B,eAAAX;AAAA,EACA,gBAAAC;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,CAAc;AAC/D;"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import "./jsx-runtime-
|
|
2
|
-
import { o as
|
|
1
|
+
import "./jsx-runtime-B6kdoens.js";
|
|
2
|
+
import { o as l } from "./index-CgCPw6Jn.js";
|
|
3
3
|
import "./urql-DrBfkb92.js";
|
|
4
|
-
import "./DevPortalProvider-
|
|
4
|
+
import "./DevPortalProvider-CTxoCHIT.js";
|
|
5
5
|
import "zudoku/openapi-worker";
|
|
6
|
-
import "./Combination-
|
|
7
|
-
import "./Markdown-
|
|
6
|
+
import "./Combination-DkycFHkm.js";
|
|
7
|
+
import "./Markdown-B_Gax7at.js";
|
|
8
|
+
import "./joinPath-VeNuJa7y.js";
|
|
8
9
|
import "./router-BiRCp01d.js";
|
|
10
|
+
import "./index-7kcHaXD6.js";
|
|
9
11
|
export {
|
|
10
|
-
|
|
12
|
+
l as openApiPlugin
|
|
11
13
|
};
|
|
12
14
|
//# sourceMappingURL=zudoku.plugin-openapi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.84",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -102,9 +102,11 @@
|
|
|
102
102
|
"class-variance-authority": "0.7.0",
|
|
103
103
|
"dotenv": "16.4.5",
|
|
104
104
|
"express": "4.19.2",
|
|
105
|
+
"glob": "^11.0.0",
|
|
105
106
|
"graphql": "16.9.0",
|
|
106
107
|
"graphql-type-json": "0.3.2",
|
|
107
108
|
"graphql-yoga": "5.2.0",
|
|
109
|
+
"gray-matter": "^4.0.3",
|
|
108
110
|
"loglevel": "^1.9.1",
|
|
109
111
|
"lru-cache": "10.2.0",
|
|
110
112
|
"mdx": "0.3.1",
|
|
@@ -170,6 +172,7 @@
|
|
|
170
172
|
"react-markdown": "9.0.1",
|
|
171
173
|
"react-router-dom": "6.25.1",
|
|
172
174
|
"rollup-plugin-visualizer": "^5.12.0",
|
|
175
|
+
"tsx": "4.16.5",
|
|
173
176
|
"typescript": "5.5.3"
|
|
174
177
|
},
|
|
175
178
|
"peerDependencies": {
|
package/src/app/demo.tsx
CHANGED
|
@@ -32,14 +32,15 @@ createRoot(document.getElementById("root")!).render(
|
|
|
32
32
|
},
|
|
33
33
|
pageTitle: "Developer Portal",
|
|
34
34
|
}}
|
|
35
|
-
|
|
35
|
+
topNavigation={[
|
|
36
36
|
{
|
|
37
|
+
id: "demo",
|
|
37
38
|
label: "API Reference",
|
|
38
|
-
path: "/demo",
|
|
39
|
-
categories: [],
|
|
40
39
|
},
|
|
41
40
|
]}
|
|
42
|
-
plugins={[
|
|
41
|
+
plugins={[
|
|
42
|
+
openApiPlugin({ type: "url", input: apiUrl!, navigationId: "demo" }),
|
|
43
|
+
]}
|
|
43
44
|
/>
|
|
44
45
|
</StrictMode>,
|
|
45
46
|
);
|
package/src/app/main.css
CHANGED
|
@@ -137,10 +137,10 @@
|
|
|
137
137
|
--slide-offset: -0.75rem;
|
|
138
138
|
@apply overflow-hidden;
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
.CollapsibleContent[data-state="open"] {
|
|
141
141
|
animation: slideDown 300ms var(--easing);
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
.CollapsibleContent[data-state="closed"] {
|
|
144
144
|
animation: slideUp 300ms var(--easing);
|
|
145
145
|
}
|
|
146
146
|
|
package/src/app/main.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
|
|
|
4
4
|
import { configuredAuthProvider } from "virtual:zudoku-auth";
|
|
5
5
|
import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
|
|
6
6
|
import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
|
|
7
|
+
import { configuredSidebar } from "virtual:zudoku-sidebar";
|
|
7
8
|
import "virtual:zudoku-theme.css";
|
|
8
9
|
import { DevPortal, Layout, RouterError } from "zudoku/components";
|
|
9
10
|
import { isNavigationPlugin } from "zudoku/internal";
|
|
@@ -35,8 +36,9 @@ export const convertZudokuConfigToOptions = (
|
|
|
35
36
|
title: "%s | Developer Portal",
|
|
36
37
|
...config.metadata,
|
|
37
38
|
},
|
|
39
|
+
sidebars: configuredSidebar,
|
|
40
|
+
topNavigation: config.topNavigation,
|
|
38
41
|
mdx: config.mdx,
|
|
39
|
-
navigation: config.navigation ?? [],
|
|
40
42
|
authentication: configuredAuthProvider,
|
|
41
43
|
plugins: [
|
|
42
44
|
...configuredDocsPlugins,
|
package/src/app/standalone.tsx
CHANGED
|
@@ -38,14 +38,15 @@ createRoot(root).render(
|
|
|
38
38
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
39
39
|
pageTitle: pageTitle ?? "Developer Portal",
|
|
40
40
|
}}
|
|
41
|
-
|
|
41
|
+
topNavigation={[
|
|
42
42
|
{
|
|
43
|
+
id: "demo",
|
|
43
44
|
label: "API Reference",
|
|
44
|
-
path: "/",
|
|
45
|
-
categories: [],
|
|
46
45
|
},
|
|
47
46
|
]}
|
|
48
|
-
plugins={[
|
|
47
|
+
plugins={[
|
|
48
|
+
openApiPlugin({ type: "url", input: apiUrl!, navigationId: "/" }),
|
|
49
|
+
]}
|
|
49
50
|
/>
|
|
50
51
|
</StrictMode>,
|
|
51
52
|
);
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
DEFAULT_COMPONENTS,
|
|
29
29
|
} from "./context/ComponentsContext.js";
|
|
30
30
|
import { DevPortalProvider } from "./context/DevPortalProvider.js";
|
|
31
|
-
import { ThemeProvider } from "./context/
|
|
31
|
+
import { ThemeProvider } from "./context/ThemeProvider.js";
|
|
32
32
|
import { ViewportAnchorProvider } from "./context/ViewportAnchorContext.js";
|
|
33
33
|
import { SlotletProvider } from "./SlotletProvider.js";
|
|
34
34
|
|
|
@@ -3,7 +3,7 @@ import { memo } from "react";
|
|
|
3
3
|
|
|
4
4
|
import { Link, useLocation } from "react-router-dom";
|
|
5
5
|
import { useAuth } from "../authentication/hook.js";
|
|
6
|
-
import { isProfileMenuPlugin,
|
|
6
|
+
import { isProfileMenuPlugin, ProfileNavigationItem } from "../core/plugins.js";
|
|
7
7
|
import { Button } from "../ui/Button.js";
|
|
8
8
|
import {
|
|
9
9
|
DropdownMenu,
|
|
@@ -22,7 +22,7 @@ import { TopNavigation } from "./TopNavigation.js";
|
|
|
22
22
|
import { useDevPortal } from "./context/DevPortalProvider.js";
|
|
23
23
|
import { useTheme } from "./context/ThemeContext.js";
|
|
24
24
|
|
|
25
|
-
const RecursiveMenu = ({ item }: { item:
|
|
25
|
+
const RecursiveMenu = ({ item }: { item: ProfileNavigationItem }) => {
|
|
26
26
|
return item.children ? (
|
|
27
27
|
<DropdownMenuSub key={item.label}>
|
|
28
28
|
<DropdownMenuSubTrigger>{item.label}</DropdownMenuSubTrigger>
|
|
@@ -7,7 +7,7 @@ import { useScrollToTop } from "../util/useScrollToTop.js";
|
|
|
7
7
|
import { useDevPortal } from "./context/DevPortalProvider.js";
|
|
8
8
|
import { useViewportAnchor } from "./context/ViewportAnchorContext.js";
|
|
9
9
|
import { Header } from "./Header.js";
|
|
10
|
-
import {
|
|
10
|
+
import { Sidebar } from "./navigation/Sidebar.js";
|
|
11
11
|
import { Slotlet } from "./SlotletProvider.js";
|
|
12
12
|
import { Spinner } from "./Spinner.js";
|
|
13
13
|
|
|
@@ -47,7 +47,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
|
47
47
|
</div>
|
|
48
48
|
}
|
|
49
49
|
>
|
|
50
|
-
<
|
|
50
|
+
<Sidebar />
|
|
51
51
|
<main
|
|
52
52
|
className={cn(
|
|
53
53
|
"dark:border-white/10 translate-x-0 h-full",
|
|
@@ -4,17 +4,17 @@ import { NavLink } from "react-router-dom";
|
|
|
4
4
|
import { useDevPortal } from "./context/DevPortalProvider.js";
|
|
5
5
|
|
|
6
6
|
export const TopNavigation = () => {
|
|
7
|
-
const {
|
|
7
|
+
const { topNavigation } = useDevPortal();
|
|
8
8
|
|
|
9
|
-
// Hide
|
|
10
|
-
if (
|
|
9
|
+
// Hide top nav if there is only one item
|
|
10
|
+
if (topNavigation.length <= 1) {
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
return (
|
|
15
15
|
<nav className="border-b text-sm px-12 h-[--top-nav-height]">
|
|
16
16
|
<ul className="flex flex-row items-center gap-8">
|
|
17
|
-
{
|
|
17
|
+
{topNavigation.map((item) => (
|
|
18
18
|
<li key={item.label}>
|
|
19
19
|
<NavLink
|
|
20
20
|
className={({ isActive }) =>
|
|
@@ -25,7 +25,7 @@ export const TopNavigation = () => {
|
|
|
25
25
|
: "border-transparent text-foreground/75 hover:text-foreground hover:border-accent-foreground/25",
|
|
26
26
|
)
|
|
27
27
|
}
|
|
28
|
-
to={item.
|
|
28
|
+
to={item.id}
|
|
29
29
|
>
|
|
30
30
|
{item.label}
|
|
31
31
|
</NavLink>
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { useLocation } from "react-router-dom";
|
|
4
4
|
import { DevPortalContext } from "../../core/DevPortalContext.js";
|
|
5
|
-
import { traverseNavigation } from "../../util/traverseNavigation.js";
|
|
6
5
|
|
|
7
6
|
const DevPortalReactContext = createContext<DevPortalContext | undefined>(
|
|
8
7
|
undefined,
|
|
@@ -29,43 +28,27 @@ export const useApiIdentities = () => {
|
|
|
29
28
|
};
|
|
30
29
|
|
|
31
30
|
export const useTopNavigationItem = () => {
|
|
32
|
-
const {
|
|
31
|
+
const { topNavigation } = useDevPortal();
|
|
33
32
|
const location = useLocation();
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for (const item of navigation) {
|
|
38
|
-
const foundNavItem = traverseNavigation(item, (_node, fullPath) => {
|
|
39
|
-
if (location.pathname === fullPath) {
|
|
40
|
-
return item;
|
|
41
|
-
}
|
|
42
|
-
});
|
|
34
|
+
const firstPart = location.pathname.split("/").at(1);
|
|
35
|
+
if (!firstPart) return;
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
return foundNavItem;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (location.pathname === "/") {
|
|
49
|
-
return navigation.find((item) => item.path === "/");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return navigation.find(
|
|
53
|
-
(item) =>
|
|
54
|
-
item.path !== "/" &&
|
|
55
|
-
matchPath({ path: item.path, end: false }, location.pathname),
|
|
56
|
-
);
|
|
37
|
+
return topNavigation.find((item) => item.id === firstPart);
|
|
57
38
|
};
|
|
58
39
|
|
|
59
40
|
export const useNavigation = () => {
|
|
60
|
-
const {
|
|
41
|
+
const { getPluginNavigation, sidebars } = useDevPortal();
|
|
61
42
|
const navItem = useTopNavigationItem();
|
|
62
|
-
|
|
63
|
-
const
|
|
43
|
+
const path = navItem?.id;
|
|
44
|
+
const currentSidebar = path ? sidebars[path] ?? [] : [];
|
|
64
45
|
|
|
65
46
|
return useSuspenseQuery({
|
|
66
47
|
queryFn: async () => {
|
|
48
|
+
const pluginSidebar = path ? await getPluginNavigation(path) : [];
|
|
49
|
+
|
|
67
50
|
return {
|
|
68
|
-
items: [...
|
|
51
|
+
items: [...currentSidebar, ...pluginSidebar],
|
|
69
52
|
currentTopNavItem: navItem,
|
|
70
53
|
};
|
|
71
54
|
},
|
|
@@ -1,46 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext,
|
|
3
|
-
type ReactNode,
|
|
4
|
-
useCallback,
|
|
5
|
-
useContext,
|
|
6
|
-
useEffect,
|
|
7
|
-
useState,
|
|
8
|
-
} from "react";
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
9
2
|
|
|
10
|
-
const ThemeContext = createContext<readonly [boolean, () => void]>([
|
|
3
|
+
export const ThemeContext = createContext<readonly [boolean, () => void]>([
|
|
11
4
|
false,
|
|
12
5
|
() => {},
|
|
13
6
|
]);
|
|
14
7
|
|
|
15
|
-
export const useTheme = () =>
|
|
16
|
-
const context = useContext(ThemeContext);
|
|
17
|
-
if (!context) {
|
|
18
|
-
throw new Error("useTheme must be used within a ThemeProvider");
|
|
19
|
-
}
|
|
20
|
-
return context;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const ThemeProvider = (props: { children: ReactNode }) => {
|
|
24
|
-
const [dark, setDark] = useState(false);
|
|
25
|
-
|
|
26
|
-
// On mount, read the preferred theme from the persistence
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
const theme = localStorage.getItem("theme");
|
|
29
|
-
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
|
|
30
|
-
const isDark = theme === "dark" || (!theme && prefersDark.matches);
|
|
31
|
-
|
|
32
|
-
setDark(isDark);
|
|
33
|
-
}, [dark]);
|
|
34
|
-
|
|
35
|
-
// To toggle between dark and light modes
|
|
36
|
-
const toggle = useCallback(() => {
|
|
37
|
-
const toggled = !dark;
|
|
38
|
-
document.documentElement.classList.toggle("dark", toggled);
|
|
39
|
-
localStorage.setItem("theme", toggled ? "dark" : "light");
|
|
40
|
-
setDark(toggled);
|
|
41
|
-
}, [dark]);
|
|
42
|
-
|
|
43
|
-
const value = [dark, toggle] as const;
|
|
44
|
-
|
|
45
|
-
return <ThemeContext.Provider value={value} {...props} />;
|
|
46
|
-
};
|
|
8
|
+
export const useTheme = () => useContext(ThemeContext);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactNode, useCallback, useEffect, useState } from "react";
|
|
2
|
+
import { ThemeContext } from "./ThemeContext.js";
|
|
3
|
+
|
|
4
|
+
export const ThemeProvider = (props: { children: ReactNode }) => {
|
|
5
|
+
const [dark, setDark] = useState(false);
|
|
6
|
+
|
|
7
|
+
// On mount, read the preferred theme from the persistence
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const theme = localStorage.getItem("theme");
|
|
10
|
+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
|
|
11
|
+
const isDark = theme === "dark" || (!theme && prefersDark.matches);
|
|
12
|
+
|
|
13
|
+
setDark(isDark);
|
|
14
|
+
}, [dark]);
|
|
15
|
+
|
|
16
|
+
// To toggle between dark and light modes
|
|
17
|
+
const toggle = useCallback(() => {
|
|
18
|
+
const toggled = !dark;
|
|
19
|
+
document.documentElement.classList.toggle("dark", toggled);
|
|
20
|
+
localStorage.setItem("theme", toggled ? "dark" : "light");
|
|
21
|
+
setDark(toggled);
|
|
22
|
+
}, [dark]);
|
|
23
|
+
|
|
24
|
+
const value = [dark, toggle] as const;
|
|
25
|
+
|
|
26
|
+
return <ThemeContext.Provider value={value} {...props} />;
|
|
27
|
+
};
|
|
@@ -2,23 +2,23 @@ import { useRef } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { useNavigation } from "../context/DevPortalProvider.js";
|
|
4
4
|
import { Slotlet } from "../SlotletProvider.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SidebarItem } from "./SidebarItem.js";
|
|
6
|
+
import { SidebarWrapper } from "./SidebarWrapper.js";
|
|
7
7
|
|
|
8
|
-
export const
|
|
8
|
+
export const Sidebar = () => {
|
|
9
9
|
const navRef = useRef<HTMLDivElement | null>(null);
|
|
10
10
|
const navigation = useNavigation();
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<
|
|
13
|
+
<SidebarWrapper
|
|
14
14
|
ref={navRef}
|
|
15
15
|
pushMainContent={navigation.data.items.length > 0}
|
|
16
16
|
>
|
|
17
17
|
<Slotlet name="zudoku-before-navigation" />
|
|
18
|
-
{navigation.data.items.map((
|
|
19
|
-
<
|
|
18
|
+
{navigation.data.items.map((item) => (
|
|
19
|
+
<SidebarItem key={item.label} item={item} />
|
|
20
20
|
))}
|
|
21
21
|
<Slotlet name="zudoku-after-navigation" />
|
|
22
|
-
</
|
|
22
|
+
</SidebarWrapper>
|
|
23
23
|
);
|
|
24
24
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cn } from "../../util/cn.js";
|
|
2
|
+
|
|
3
|
+
export const TextColorMap = {
|
|
4
|
+
green: "text-green-600",
|
|
5
|
+
blue: "text-sky-600",
|
|
6
|
+
yellow: "text-yellow-600",
|
|
7
|
+
red: "text-red-600",
|
|
8
|
+
purple: "text-purple-600",
|
|
9
|
+
indigo: "text-indigo-600",
|
|
10
|
+
gray: "text-gray-600",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const ColorMap = {
|
|
14
|
+
green: "bg-green-400 dark:bg-green-800",
|
|
15
|
+
blue: "bg-sky-400 dark:bg-sky-800",
|
|
16
|
+
yellow: "bg-yellow-400 dark:bg-yellow-800",
|
|
17
|
+
red: "bg-red-400 dark:bg-red-800",
|
|
18
|
+
purple: "bg-purple-400 dark:bg-purple-600",
|
|
19
|
+
indigo: "bg-indigo-400 dark:bg-indigo-600",
|
|
20
|
+
gray: "bg-gray-400 dark:bg-gray-600",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const SidebarBadge = ({
|
|
24
|
+
color,
|
|
25
|
+
label,
|
|
26
|
+
}: {
|
|
27
|
+
color: keyof typeof ColorMap;
|
|
28
|
+
label: string;
|
|
29
|
+
}) => {
|
|
30
|
+
return (
|
|
31
|
+
<span
|
|
32
|
+
className={cn(
|
|
33
|
+
"mt-0.5 flex items-center duration-200 transition-opacity text-center uppercase font-mono text-[0.65rem] font-bold rounded text-background dark:text-zinc-50 h-4 px-1",
|
|
34
|
+
ColorMap[color],
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
{label}
|
|
38
|
+
</span>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
|
+
import { ChevronRightIcon } from "lucide-react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { NavLink } from "react-router-dom";
|
|
5
|
+
import type { ResolvedSidebarItemCategory } from "../../../config/validators/ResolvedSidebarSchema.js";
|
|
6
|
+
import { cn } from "../../util/cn.js";
|
|
7
|
+
import { joinPath } from "../../util/joinPath.js";
|
|
8
|
+
import { useTopNavigationItem } from "../context/DevPortalProvider.js";
|
|
9
|
+
import { navigationListItem, SidebarItem } from "./SidebarItem.js";
|
|
10
|
+
import { useIsCategoryOpen } from "./utils.js";
|
|
11
|
+
|
|
12
|
+
export const SidebarCategory = ({
|
|
13
|
+
category,
|
|
14
|
+
level,
|
|
15
|
+
}: {
|
|
16
|
+
category: ResolvedSidebarItemCategory;
|
|
17
|
+
level: number;
|
|
18
|
+
}) => {
|
|
19
|
+
const topNavItem = useTopNavigationItem();
|
|
20
|
+
const isCategoryOpen = useIsCategoryOpen(category);
|
|
21
|
+
|
|
22
|
+
const isCollapsible = category.collapsible ?? true;
|
|
23
|
+
const isCollapsed = category.collapsed ?? true;
|
|
24
|
+
const isDefaultOpen = Boolean(
|
|
25
|
+
!isCollapsible || !isCollapsed || isCategoryOpen,
|
|
26
|
+
);
|
|
27
|
+
const [open, setOpen] = useState(isDefaultOpen);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
// this is triggered when an item from the sidebar is clicked
|
|
31
|
+
// and the sidebar, enclosing this item, is not opened
|
|
32
|
+
if (isCategoryOpen) {
|
|
33
|
+
setOpen(true);
|
|
34
|
+
}
|
|
35
|
+
}, [isCategoryOpen]);
|
|
36
|
+
|
|
37
|
+
const ToggleButton = isCollapsible && (
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
onClick={(e) => {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
setOpen((prev) => !prev);
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
<ChevronRightIcon
|
|
46
|
+
size={16}
|
|
47
|
+
className="transition shrink-0 group-data-[state=open]:rotate-90"
|
|
48
|
+
/>
|
|
49
|
+
</button>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Collapsible.Root
|
|
54
|
+
className={cn("flex flex-col", level === 0 && "-mx-[--padding-nav-item]")}
|
|
55
|
+
defaultOpen={isDefaultOpen}
|
|
56
|
+
open={open}
|
|
57
|
+
onOpenChange={() => setOpen(true)}
|
|
58
|
+
>
|
|
59
|
+
<Collapsible.Trigger
|
|
60
|
+
className={cn(
|
|
61
|
+
"group text-start",
|
|
62
|
+
navigationListItem({ isActive: false, isTopLevel: level === 0 }),
|
|
63
|
+
isCollapsible
|
|
64
|
+
? "cursor-pointer"
|
|
65
|
+
: "cursor-default hover:bg-transparent",
|
|
66
|
+
)}
|
|
67
|
+
asChild
|
|
68
|
+
disabled={!isCollapsible}
|
|
69
|
+
>
|
|
70
|
+
{category.link?.type === "doc" ? (
|
|
71
|
+
<NavLink to={joinPath(topNavItem?.id, category.link.id)}>
|
|
72
|
+
{({ isActive }) => (
|
|
73
|
+
<div
|
|
74
|
+
className={cn(
|
|
75
|
+
"flex items-center gap-2 justify-between w-full",
|
|
76
|
+
isActive ? "text-primary font-medium" : "text-foreground/80",
|
|
77
|
+
)}
|
|
78
|
+
>
|
|
79
|
+
<div className="truncate">{category.label}</div>
|
|
80
|
+
{ToggleButton}
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
</NavLink>
|
|
84
|
+
) : (
|
|
85
|
+
<div className="flex items-center justify-between w-full">
|
|
86
|
+
<div className="flex gap-2 truncate w-full">{category.label}</div>
|
|
87
|
+
{ToggleButton}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
</Collapsible.Trigger>
|
|
91
|
+
<Collapsible.Content className="CollapsibleContent ms-[calc(var(--padding-nav-item)*1.125)]">
|
|
92
|
+
<ul className="mt-1 border-l ps-2">
|
|
93
|
+
{category.items.map((item) => (
|
|
94
|
+
<SidebarItem
|
|
95
|
+
key={item.label}
|
|
96
|
+
level={level + 1}
|
|
97
|
+
item={item}
|
|
98
|
+
// activeAnchor={activeAnchor}
|
|
99
|
+
/>
|
|
100
|
+
))}
|
|
101
|
+
</ul>
|
|
102
|
+
</Collapsible.Content>
|
|
103
|
+
</Collapsible.Root>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
import { ExternalLinkIcon } from "lucide-react";
|
|
3
|
+
import { NavLink } from "react-router-dom";
|
|
4
|
+
|
|
5
|
+
import type { ResolvedSidebarItem } from "../../../config/validators/ResolvedSidebarSchema.js";
|
|
6
|
+
import { cn } from "../../util/cn.js";
|
|
7
|
+
import { joinPath } from "../../util/joinPath.js";
|
|
8
|
+
import { AnchorLink } from "../AnchorLink.js";
|
|
9
|
+
import { useTopNavigationItem } from "../context/DevPortalProvider.js";
|
|
10
|
+
import { useViewportAnchor } from "../context/ViewportAnchorContext.js";
|
|
11
|
+
import { SidebarBadge } from "./SidebarBadge.js";
|
|
12
|
+
import { SidebarCategory } from "./SidebarCategory.js";
|
|
13
|
+
|
|
14
|
+
export const navigationListItem = cva(
|
|
15
|
+
"flex px-[--padding-nav-item] py-1.5 rounded-lg hover:bg-accent transition-colors duration-300",
|
|
16
|
+
{
|
|
17
|
+
variants: {
|
|
18
|
+
isTopLevel: {
|
|
19
|
+
true: "font-semibold",
|
|
20
|
+
},
|
|
21
|
+
isActive: {
|
|
22
|
+
true: "text-primary font-medium",
|
|
23
|
+
false: "text-foreground/80",
|
|
24
|
+
},
|
|
25
|
+
isMuted: {
|
|
26
|
+
true: "text-foreground/30",
|
|
27
|
+
false: "",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const DATA_ANCHOR_ATTR = "data-anchor";
|
|
34
|
+
|
|
35
|
+
export const SidebarItem = ({
|
|
36
|
+
item,
|
|
37
|
+
level = 0,
|
|
38
|
+
}: {
|
|
39
|
+
item: ResolvedSidebarItem;
|
|
40
|
+
basePath?: string;
|
|
41
|
+
level?: number;
|
|
42
|
+
}) => {
|
|
43
|
+
const topNavItem = useTopNavigationItem();
|
|
44
|
+
const { activeAnchor } = useViewportAnchor();
|
|
45
|
+
|
|
46
|
+
switch (item.type) {
|
|
47
|
+
case "category":
|
|
48
|
+
return <SidebarCategory category={item} level={level} />;
|
|
49
|
+
case "doc":
|
|
50
|
+
return (
|
|
51
|
+
<NavLink
|
|
52
|
+
className={({ isActive }) =>
|
|
53
|
+
navigationListItem({ isActive, isTopLevel: level === 0 })
|
|
54
|
+
}
|
|
55
|
+
to={joinPath(topNavItem?.id, item.id)}
|
|
56
|
+
>
|
|
57
|
+
{item.label}
|
|
58
|
+
{item.badge && <SidebarBadge {...item.badge} />}
|
|
59
|
+
</NavLink>
|
|
60
|
+
);
|
|
61
|
+
case "link":
|
|
62
|
+
return item.href.startsWith("#") ? (
|
|
63
|
+
<AnchorLink
|
|
64
|
+
to={item.href}
|
|
65
|
+
{...{ [DATA_ANCHOR_ATTR]: item.href.slice(1) }}
|
|
66
|
+
className={cn(
|
|
67
|
+
"flex gap-2.5 justify-between",
|
|
68
|
+
level === 0 && "-mx-[--padding-nav-item]",
|
|
69
|
+
navigationListItem({
|
|
70
|
+
isActive: item.href.slice(1) === activeAnchor,
|
|
71
|
+
}),
|
|
72
|
+
)}
|
|
73
|
+
>
|
|
74
|
+
{item.label}
|
|
75
|
+
{item.badge && <SidebarBadge {...item.badge} />}
|
|
76
|
+
</AnchorLink>
|
|
77
|
+
) : (
|
|
78
|
+
<a
|
|
79
|
+
className={cn(
|
|
80
|
+
navigationListItem({ isTopLevel: level === 0 }),
|
|
81
|
+
"block",
|
|
82
|
+
)}
|
|
83
|
+
href={item.href}
|
|
84
|
+
target="_blank"
|
|
85
|
+
rel="noopener noreferrer"
|
|
86
|
+
>
|
|
87
|
+
<span className="whitespace-normal">{item.label}</span>
|
|
88
|
+
{/* This prevents that the icon would be positioned in its own line if the text fills an line entirely */}
|
|
89
|
+
<span className="whitespace-nowrap">
|
|
90
|
+
|
|
91
|
+
<ExternalLinkIcon className="inline ml-1" size={12} />
|
|
92
|
+
</span>
|
|
93
|
+
</a>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { forwardRef, type PropsWithChildren } from "react";
|
|
2
2
|
import { cn } from "../../util/cn.js";
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const SidebarWrapper = forwardRef<
|
|
5
5
|
HTMLDivElement,
|
|
6
6
|
PropsWithChildren<{ pushMainContent?: boolean; className?: string }>
|
|
7
7
|
>(function SideNavigation({ children, className, pushMainContent }, ref) {
|