@farming-labs/nuxt-theme 0.0.2-beta.21 → 0.0.2-beta.23
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/package.json +17 -17
- package/src/components/Breadcrumb.vue +4 -4
- package/src/components/DocsContent.vue +14 -17
- package/src/components/DocsLayout.vue +229 -151
- package/src/components/DocsPage.vue +50 -10
- package/src/components/FloatingAIChat.vue +326 -234
- package/src/components/SearchDialog.vue +9 -7
- package/src/components/TableOfContents.vue +34 -18
- package/src/components/ThemeToggle.vue +18 -2
- package/src/lib/renderMarkdown.js +21 -11
- package/src/themes/colorful.d.ts +3 -1
- package/styles/colorful.css +3 -1
- package/styles/docs.css +262 -69
- package/styles/pixel-border.css +3 -4
package/package.json
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/nuxt-theme",
|
|
3
|
-
"version": "0.0.2-beta.
|
|
3
|
+
"version": "0.0.2-beta.23",
|
|
4
4
|
"description": "Nuxt/Vue UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"docs",
|
|
7
|
+
"documentation",
|
|
8
|
+
"nuxt",
|
|
9
|
+
"theme",
|
|
10
|
+
"vue"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "Farming Labs",
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"styles"
|
|
17
|
+
],
|
|
5
18
|
"type": "module",
|
|
6
19
|
"exports": {
|
|
7
20
|
".": {
|
|
@@ -38,26 +51,13 @@
|
|
|
38
51
|
"./styles/colorful.css": "./styles/colorful.css",
|
|
39
52
|
"./colorful/css": "./styles/colorful-bundle.css"
|
|
40
53
|
},
|
|
41
|
-
"files": [
|
|
42
|
-
"src",
|
|
43
|
-
"styles"
|
|
44
|
-
],
|
|
45
|
-
"keywords": [
|
|
46
|
-
"docs",
|
|
47
|
-
"nuxt",
|
|
48
|
-
"vue",
|
|
49
|
-
"theme",
|
|
50
|
-
"documentation"
|
|
51
|
-
],
|
|
52
|
-
"author": "Farming Labs",
|
|
53
|
-
"license": "MIT",
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"sugar-high": "^0.9.5",
|
|
56
|
-
"@farming-labs/docs": "0.0.2-beta.
|
|
56
|
+
"@farming-labs/docs": "0.0.2-beta.23"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"
|
|
60
|
-
"
|
|
59
|
+
"nuxt": ">=3.0.0",
|
|
60
|
+
"vue": ">=3.0.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"nuxt": {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from "vue";
|
|
3
3
|
|
|
4
|
-
const props = withDefaults(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
);
|
|
4
|
+
const props = withDefaults(defineProps<{ pathname?: string; entry?: string }>(), {
|
|
5
|
+
pathname: "",
|
|
6
|
+
entry: "docs",
|
|
7
|
+
});
|
|
8
8
|
|
|
9
9
|
const segments = computed(() => {
|
|
10
10
|
return props.pathname.split("/").filter(Boolean);
|
|
@@ -18,16 +18,12 @@ const props = defineProps<{
|
|
|
18
18
|
const titleSuffix = computed(() =>
|
|
19
19
|
props.config?.metadata?.titleTemplate
|
|
20
20
|
? String(props.config.metadata.titleTemplate).replace("%s", "")
|
|
21
|
-
: " – Docs"
|
|
21
|
+
: " – Docs",
|
|
22
22
|
);
|
|
23
23
|
|
|
24
|
-
const tocEnabled = computed(
|
|
25
|
-
() => (props.config?.theme as any)?.ui?.layout?.toc?.enabled ?? true
|
|
26
|
-
);
|
|
24
|
+
const tocEnabled = computed(() => (props.config?.theme as any)?.ui?.layout?.toc?.enabled ?? true);
|
|
27
25
|
|
|
28
|
-
const tocStyle = computed(
|
|
29
|
-
() => (props.config?.theme as any)?.ui?.layout?.toc?.style ?? "default"
|
|
30
|
-
);
|
|
26
|
+
const tocStyle = computed(() => (props.config?.theme as any)?.ui?.layout?.toc?.style ?? "default");
|
|
31
27
|
|
|
32
28
|
const breadcrumbEnabled = computed(() => {
|
|
33
29
|
const bc = props.config?.breadcrumb;
|
|
@@ -37,26 +33,26 @@ const breadcrumbEnabled = computed(() => {
|
|
|
37
33
|
return true;
|
|
38
34
|
});
|
|
39
35
|
|
|
40
|
-
const showEditOnGithub = computed(
|
|
41
|
-
() => !!props.config?.github && !!props.data.editOnGithub
|
|
42
|
-
);
|
|
36
|
+
const showEditOnGithub = computed(() => !!props.config?.github && !!props.data.editOnGithub);
|
|
43
37
|
const showLastModified = computed(() => !!props.data.lastModified);
|
|
44
38
|
|
|
39
|
+
const llmsTxtEnabled = computed(() => {
|
|
40
|
+
const cfg = props.config?.llmsTxt;
|
|
41
|
+
if (cfg === true) return true;
|
|
42
|
+
if (typeof cfg === "object" && cfg !== null) return (cfg as { enabled?: boolean }).enabled !== false;
|
|
43
|
+
return false;
|
|
44
|
+
});
|
|
45
|
+
|
|
45
46
|
const entry = computed(() => (props.config?.entry as string) ?? "docs");
|
|
46
47
|
|
|
47
48
|
const metaDescription = computed(
|
|
48
|
-
() =>
|
|
49
|
-
props.data.description ??
|
|
50
|
-
(props.config?.metadata as any)?.description ??
|
|
51
|
-
undefined
|
|
49
|
+
() => props.data.description ?? (props.config?.metadata as any)?.description ?? undefined,
|
|
52
50
|
);
|
|
53
51
|
|
|
54
52
|
useHead({
|
|
55
53
|
title: () => `${props.data.title}${titleSuffix.value}`,
|
|
56
54
|
meta: () =>
|
|
57
|
-
metaDescription.value
|
|
58
|
-
? [{ name: "description", content: metaDescription.value }]
|
|
59
|
-
: [],
|
|
55
|
+
metaDescription.value ? [{ name: "description", content: metaDescription.value }] : [],
|
|
60
56
|
});
|
|
61
57
|
</script>
|
|
62
58
|
|
|
@@ -70,6 +66,7 @@ useHead({
|
|
|
70
66
|
:next-page="data.nextPage ?? null"
|
|
71
67
|
:edit-on-github="showEditOnGithub ? data.editOnGithub : null"
|
|
72
68
|
:last-modified="showLastModified ? data.lastModified : null"
|
|
69
|
+
:llms-txt-enabled="llmsTxtEnabled"
|
|
73
70
|
>
|
|
74
71
|
<p v-if="data.description" class="fd-page-description">{{ data.description }}</p>
|
|
75
72
|
<div class="fd-docs-content" v-html="data.html" />
|
|
@@ -21,17 +21,13 @@ const props = withDefaults(
|
|
|
21
21
|
titleUrl?: string;
|
|
22
22
|
triggerComponent?: object | null;
|
|
23
23
|
}>(),
|
|
24
|
-
{ config: null, title: undefined, titleUrl: undefined, triggerComponent: null }
|
|
24
|
+
{ config: null, title: undefined, titleUrl: undefined, triggerComponent: null },
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
const route = useRoute();
|
|
28
28
|
|
|
29
|
-
const resolvedTitle = computed(
|
|
30
|
-
|
|
31
|
-
);
|
|
32
|
-
const resolvedTitleUrl = computed(
|
|
33
|
-
() => props.titleUrl ?? props.config?.nav?.url ?? "/docs"
|
|
34
|
-
);
|
|
29
|
+
const resolvedTitle = computed(() => props.title ?? props.config?.nav?.title ?? "Docs");
|
|
30
|
+
const resolvedTitleUrl = computed(() => props.titleUrl ?? props.config?.nav?.url ?? "/docs");
|
|
35
31
|
|
|
36
32
|
const showThemeToggle = computed(() => {
|
|
37
33
|
const toggle = props.config?.themeToggle;
|
|
@@ -62,7 +58,9 @@ const themeInitScript = computed(() => {
|
|
|
62
58
|
return `document.documentElement.classList.remove('light','dark');document.documentElement.classList.add('${forcedTheme.value}')`;
|
|
63
59
|
}
|
|
64
60
|
const def = defaultTheme.value;
|
|
65
|
-
const fallback = def
|
|
61
|
+
const fallback = def
|
|
62
|
+
? `'${def}'`
|
|
63
|
+
: `(window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light')`;
|
|
66
64
|
return [
|
|
67
65
|
"(function(){",
|
|
68
66
|
"var m=document.cookie.match(/(?:^|;\\s*)theme=(\\w+)/);",
|
|
@@ -142,25 +140,26 @@ function buildLayoutCSS(layout: Record<string, any> | undefined): string {
|
|
|
142
140
|
if (rootVars.length === 0 && desktopVars.length === 0) return "";
|
|
143
141
|
const parts: string[] = [];
|
|
144
142
|
if (rootVars.length > 0) parts.push(`:root {\n ${rootVars.join("\n ")}\n}`);
|
|
145
|
-
if (desktopVars.length > 0)
|
|
143
|
+
if (desktopVars.length > 0)
|
|
144
|
+
parts.push(
|
|
145
|
+
`@media (min-width: 1024px) {\n :root {\n ${desktopVars.join("\n ")}\n }\n}`,
|
|
146
|
+
);
|
|
146
147
|
return parts.join("\n");
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
const overrideCSS = computed(() => {
|
|
150
|
-
const colorOverrides =
|
|
151
|
-
?? (props.config?.theme as any)?.ui?.colors;
|
|
151
|
+
const colorOverrides =
|
|
152
|
+
(props.config?.theme as any)?._userColorOverrides ?? (props.config?.theme as any)?.ui?.colors;
|
|
152
153
|
const typography = (props.config?.theme as any)?.ui?.typography;
|
|
153
154
|
const layout = (props.config?.theme as any)?.ui?.layout;
|
|
154
|
-
return [buildColorsCSS(colorOverrides), buildTypographyCSS(typography), buildLayoutCSS(layout)]
|
|
155
|
+
return [buildColorsCSS(colorOverrides), buildTypographyCSS(typography), buildLayoutCSS(layout)]
|
|
156
|
+
.filter(Boolean)
|
|
157
|
+
.join("\n");
|
|
155
158
|
});
|
|
156
159
|
|
|
157
160
|
useHead(() => ({
|
|
158
|
-
script: [
|
|
159
|
-
|
|
160
|
-
],
|
|
161
|
-
style: overrideCSS.value
|
|
162
|
-
? [{ innerHTML: overrideCSS.value }]
|
|
163
|
-
: [],
|
|
161
|
+
script: [{ innerHTML: themeInitScript.value, tagPosition: "head" }],
|
|
162
|
+
style: overrideCSS.value ? [{ innerHTML: overrideCSS.value }] : [],
|
|
164
163
|
}));
|
|
165
164
|
|
|
166
165
|
// ─── Sidebar / search / keyboard ─────────────────────────────
|
|
@@ -189,12 +188,16 @@ function isActive(url: string) {
|
|
|
189
188
|
|
|
190
189
|
const ICON_MAP: Record<string, string> = {
|
|
191
190
|
book: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>',
|
|
192
|
-
terminal:
|
|
191
|
+
terminal:
|
|
192
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>',
|
|
193
193
|
code: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>',
|
|
194
194
|
file: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>',
|
|
195
|
-
folder:
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
folder:
|
|
196
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>',
|
|
197
|
+
rocket:
|
|
198
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>',
|
|
199
|
+
settings:
|
|
200
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',
|
|
198
201
|
};
|
|
199
202
|
|
|
200
203
|
function getIcon(iconKey?: string) {
|
|
@@ -214,156 +217,231 @@ function handleKeydown(e: KeyboardEvent) {
|
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
const showFloatingAI = computed(
|
|
217
|
-
() =>
|
|
218
|
-
props.config?.ai?.enabled &&
|
|
219
|
-
props.config?.ai?.mode === "floating"
|
|
220
|
+
() => props.config?.ai?.enabled && props.config?.ai?.mode === "floating",
|
|
220
221
|
);
|
|
221
222
|
</script>
|
|
222
223
|
|
|
223
224
|
<template>
|
|
224
225
|
<div class="fd-layout-root">
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<aside class="fd-sidebar" :class="{ 'fd-sidebar-open': sidebarOpen }">
|
|
246
|
-
<div class="fd-sidebar-header">
|
|
247
|
-
<NuxtLink :to="resolvedTitleUrl" class="fd-sidebar-title" @click="closeSidebar">
|
|
248
|
-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
249
|
-
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
|
|
250
|
-
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
|
|
226
|
+
<div class="fd-layout" @keydown="handleKeydown">
|
|
227
|
+
<header class="fd-header">
|
|
228
|
+
<button
|
|
229
|
+
class="fd-menu-btn"
|
|
230
|
+
type="button"
|
|
231
|
+
aria-label="Toggle sidebar"
|
|
232
|
+
@click="toggleSidebar"
|
|
233
|
+
>
|
|
234
|
+
<svg
|
|
235
|
+
width="20"
|
|
236
|
+
height="20"
|
|
237
|
+
viewBox="0 0 24 24"
|
|
238
|
+
fill="none"
|
|
239
|
+
stroke="currentColor"
|
|
240
|
+
stroke-width="2"
|
|
241
|
+
>
|
|
242
|
+
<line x1="3" y1="6" x2="21" y2="6" />
|
|
243
|
+
<line x1="3" y1="12" x2="21" y2="12" />
|
|
244
|
+
<line x1="3" y1="18" x2="21" y2="18" />
|
|
251
245
|
</svg>
|
|
252
|
-
|
|
253
|
-
</NuxtLink>
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
246
|
+
</button>
|
|
247
|
+
<NuxtLink :to="resolvedTitleUrl" class="fd-header-title">{{ resolvedTitle }}</NuxtLink>
|
|
248
|
+
<button
|
|
249
|
+
class="fd-search-trigger-mobile"
|
|
250
|
+
type="button"
|
|
251
|
+
aria-label="Search"
|
|
252
|
+
@click="openSearch"
|
|
253
|
+
>
|
|
254
|
+
<svg
|
|
255
|
+
width="18"
|
|
256
|
+
height="18"
|
|
257
|
+
viewBox="0 0 24 24"
|
|
258
|
+
fill="none"
|
|
259
|
+
stroke="currentColor"
|
|
260
|
+
stroke-width="2"
|
|
261
|
+
>
|
|
259
262
|
<circle cx="11" cy="11" r="8" />
|
|
260
263
|
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
261
264
|
</svg>
|
|
262
|
-
<span>Search</span>
|
|
263
|
-
<kbd>⌘</kbd><kbd>K</kbd>
|
|
264
265
|
</button>
|
|
265
|
-
</
|
|
266
|
+
</header>
|
|
267
|
+
|
|
268
|
+
<div v-if="sidebarOpen" class="fd-sidebar-overlay" aria-hidden="true" @click="closeSidebar" />
|
|
266
269
|
|
|
267
|
-
<
|
|
268
|
-
<
|
|
269
|
-
<
|
|
270
|
-
<
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
<aside class="fd-sidebar" :class="{ 'fd-sidebar-open': sidebarOpen }">
|
|
271
|
+
<div class="fd-sidebar-header">
|
|
272
|
+
<NuxtLink :to="resolvedTitleUrl" class="fd-sidebar-title" @click="closeSidebar">
|
|
273
|
+
<svg
|
|
274
|
+
width="18"
|
|
275
|
+
height="18"
|
|
276
|
+
viewBox="0 0 24 24"
|
|
277
|
+
fill="none"
|
|
278
|
+
stroke="currentColor"
|
|
279
|
+
stroke-width="2"
|
|
276
280
|
>
|
|
277
|
-
<
|
|
278
|
-
|
|
279
|
-
</
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
281
|
+
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
|
|
282
|
+
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
|
|
283
|
+
</svg>
|
|
284
|
+
{{ resolvedTitle }}
|
|
285
|
+
</NuxtLink>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
<div class="fd-sidebar-search">
|
|
289
|
+
<button type="button" class="fd-sidebar-search-btn" @click="openSearch">
|
|
290
|
+
<svg
|
|
291
|
+
width="15"
|
|
292
|
+
height="15"
|
|
293
|
+
viewBox="0 0 24 24"
|
|
294
|
+
fill="none"
|
|
295
|
+
stroke="currentColor"
|
|
296
|
+
stroke-width="2"
|
|
297
|
+
>
|
|
298
|
+
<circle cx="11" cy="11" r="8" />
|
|
299
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
300
|
+
</svg>
|
|
301
|
+
<span>Search</span>
|
|
302
|
+
<kbd>⌘</kbd><kbd>K</kbd>
|
|
303
|
+
</button>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
<nav class="fd-sidebar-nav">
|
|
307
|
+
<template v-if="tree?.children">
|
|
308
|
+
<template v-for="(node, i) in tree.children" :key="node.name + (node.url ?? '')">
|
|
309
|
+
<NuxtLink
|
|
310
|
+
v-if="node.type === 'page'"
|
|
311
|
+
:to="node.url!"
|
|
312
|
+
class="fd-sidebar-link fd-sidebar-top-link"
|
|
313
|
+
:class="{
|
|
314
|
+
'fd-sidebar-link-active': isActive(node.url ?? ''),
|
|
315
|
+
'fd-sidebar-first-item': i === 0,
|
|
316
|
+
}"
|
|
317
|
+
@click="closeSidebar"
|
|
318
|
+
>
|
|
319
|
+
<span
|
|
320
|
+
v-if="getIcon(node.icon)"
|
|
321
|
+
class="fd-sidebar-icon"
|
|
322
|
+
v-html="getIcon(node.icon)"
|
|
323
|
+
/>
|
|
324
|
+
{{ node.name }}
|
|
325
|
+
</NuxtLink>
|
|
326
|
+
<details
|
|
327
|
+
v-else-if="node.type === 'folder'"
|
|
328
|
+
class="fd-sidebar-folder"
|
|
329
|
+
:class="{ 'fd-sidebar-first-item': i === 0 }"
|
|
330
|
+
open
|
|
331
|
+
>
|
|
332
|
+
<summary class="fd-sidebar-folder-trigger">
|
|
333
|
+
<span class="fd-sidebar-folder-label">
|
|
334
|
+
<span
|
|
335
|
+
v-if="getIcon(node.icon)"
|
|
336
|
+
class="fd-sidebar-icon"
|
|
337
|
+
v-html="getIcon(node.icon)"
|
|
338
|
+
/>
|
|
339
|
+
{{ node.name }}
|
|
340
|
+
</span>
|
|
341
|
+
<svg
|
|
342
|
+
class="fd-sidebar-chevron"
|
|
343
|
+
width="14"
|
|
344
|
+
height="14"
|
|
345
|
+
viewBox="0 0 24 24"
|
|
346
|
+
fill="none"
|
|
347
|
+
stroke="currentColor"
|
|
348
|
+
stroke-width="2"
|
|
349
|
+
>
|
|
350
|
+
<polyline points="6 9 12 15 18 9" />
|
|
351
|
+
</svg>
|
|
352
|
+
</summary>
|
|
353
|
+
<div class="fd-sidebar-folder-content">
|
|
301
354
|
<NuxtLink
|
|
302
|
-
v-if="
|
|
303
|
-
:to="
|
|
355
|
+
v-if="node.index"
|
|
356
|
+
:to="node.index.url"
|
|
304
357
|
class="fd-sidebar-link fd-sidebar-child-link"
|
|
305
|
-
:class="{ 'fd-sidebar-link-active': isActive(
|
|
358
|
+
:class="{ 'fd-sidebar-link-active': isActive(node.index.url) }"
|
|
306
359
|
@click="closeSidebar"
|
|
307
360
|
>
|
|
308
|
-
{{
|
|
361
|
+
{{ node.index.name }}
|
|
309
362
|
</NuxtLink>
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
363
|
+
<template
|
|
364
|
+
v-for="child in node.children"
|
|
365
|
+
:key="child.name + ((child as any).url ?? '')"
|
|
366
|
+
>
|
|
367
|
+
<NuxtLink
|
|
368
|
+
v-if="child.type === 'page'"
|
|
369
|
+
:to="(child as any).url"
|
|
370
|
+
class="fd-sidebar-link fd-sidebar-child-link"
|
|
371
|
+
:class="{ 'fd-sidebar-link-active': isActive((child as any).url) }"
|
|
372
|
+
@click="closeSidebar"
|
|
373
|
+
>
|
|
374
|
+
{{ child.name }}
|
|
375
|
+
</NuxtLink>
|
|
376
|
+
<details
|
|
377
|
+
v-else-if="child.type === 'folder'"
|
|
378
|
+
class="fd-sidebar-folder fd-sidebar-nested-folder"
|
|
379
|
+
open
|
|
380
|
+
>
|
|
381
|
+
<summary class="fd-sidebar-folder-trigger">
|
|
382
|
+
<span class="fd-sidebar-folder-label">{{ child.name }}</span>
|
|
383
|
+
<svg
|
|
384
|
+
class="fd-sidebar-chevron"
|
|
385
|
+
width="14"
|
|
386
|
+
height="14"
|
|
387
|
+
viewBox="0 0 24 24"
|
|
388
|
+
fill="none"
|
|
389
|
+
stroke="currentColor"
|
|
390
|
+
stroke-width="2"
|
|
391
|
+
>
|
|
392
|
+
<polyline points="6 9 12 15 18 9" />
|
|
393
|
+
</svg>
|
|
394
|
+
</summary>
|
|
395
|
+
<div class="fd-sidebar-folder-content">
|
|
396
|
+
<NuxtLink
|
|
397
|
+
v-if="(child as any).index"
|
|
398
|
+
:to="(child as any).index.url"
|
|
399
|
+
class="fd-sidebar-link fd-sidebar-child-link"
|
|
400
|
+
:class="{ 'fd-sidebar-link-active': isActive((child as any).index.url) }"
|
|
401
|
+
@click="closeSidebar"
|
|
402
|
+
>
|
|
403
|
+
{{ (child as any).index.name }}
|
|
404
|
+
</NuxtLink>
|
|
405
|
+
<NuxtLink
|
|
406
|
+
v-for="grandchild in (child as any).children"
|
|
407
|
+
v-if="grandchild.type === 'page'"
|
|
408
|
+
:key="grandchild.url"
|
|
409
|
+
:to="grandchild.url"
|
|
410
|
+
class="fd-sidebar-link fd-sidebar-child-link"
|
|
411
|
+
:class="{ 'fd-sidebar-link-active': isActive(grandchild.url) }"
|
|
412
|
+
@click="closeSidebar"
|
|
413
|
+
>
|
|
414
|
+
{{ grandchild.name }}
|
|
415
|
+
</NuxtLink>
|
|
416
|
+
</div>
|
|
417
|
+
</details>
|
|
418
|
+
</template>
|
|
419
|
+
</div>
|
|
420
|
+
</details>
|
|
421
|
+
</template>
|
|
343
422
|
</template>
|
|
344
|
-
</
|
|
345
|
-
</nav>
|
|
423
|
+
</nav>
|
|
346
424
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
425
|
+
<div v-if="showThemeToggle" class="fd-sidebar-footer">
|
|
426
|
+
<ThemeToggle />
|
|
427
|
+
</div>
|
|
428
|
+
</aside>
|
|
351
429
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
430
|
+
<main class="fd-main">
|
|
431
|
+
<slot />
|
|
432
|
+
</main>
|
|
433
|
+
</div>
|
|
356
434
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
435
|
+
<FloatingAIChat
|
|
436
|
+
v-if="showFloatingAI"
|
|
437
|
+
api="/api/docs"
|
|
438
|
+
:suggested-questions="config?.ai?.suggestedQuestions ?? []"
|
|
439
|
+
:ai-label="config?.ai?.aiLabel ?? 'AI'"
|
|
440
|
+
:position="config?.ai?.position ?? 'bottom-right'"
|
|
441
|
+
:floating-style="config?.ai?.floatingStyle ?? 'panel'"
|
|
442
|
+
:trigger-component="triggerComponent"
|
|
443
|
+
/>
|
|
366
444
|
|
|
367
|
-
|
|
445
|
+
<SearchDialog v-if="searchOpen" @close="closeSearch" />
|
|
368
446
|
</div>
|
|
369
447
|
</template>
|