@movk/nuxt-docs 1.6.2 → 1.7.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/app/app.config.ts +37 -0
- package/app/app.vue +8 -3
- package/app/components/DocsAsideRightBottom.vue +17 -22
- package/app/components/PageHeaderLinks.vue +6 -1
- package/app/components/content/PageLastCommit.vue +5 -5
- package/app/components/header/Header.vue +1 -1
- package/app/components/header/HeaderBody.vue +12 -2
- package/app/components/header/HeaderBottom.vue +1 -0
- package/app/components/header/HeaderCTA.vue +2 -2
- package/app/components/header/HeaderCenter.vue +1 -1
- package/app/components/header/HeaderLogo.vue +1 -1
- package/app/layouts/default.vue +3 -1
- package/app/layouts/docs.vue +1 -1
- package/app/pages/docs/[...slug].vue +3 -2
- package/app/templates/releases.vue +98 -0
- package/app/types/index.d.ts +149 -0
- package/content.config.ts +24 -2
- package/modules/ai-chat/index.ts +53 -21
- package/modules/ai-chat/runtime/components/AiChat.vue +4 -10
- package/modules/ai-chat/runtime/components/AiChatDisabled.vue +3 -0
- package/modules/ai-chat/runtime/components/AiChatFloatingInput.vue +24 -9
- package/modules/ai-chat/runtime/components/AiChatModelSelect.vue +2 -0
- package/modules/ai-chat/runtime/components/AiChatPanel.vue +318 -0
- package/modules/ai-chat/runtime/components/AiChatPreStream.vue +1 -0
- package/modules/ai-chat/runtime/components/AiChatReasoning.vue +3 -3
- package/modules/ai-chat/runtime/components/AiChatSlideoverFaq.vue +2 -5
- package/modules/ai-chat/runtime/composables/useAIChat.ts +48 -0
- package/modules/ai-chat/runtime/composables/useModels.ts +3 -6
- package/modules/ai-chat/runtime/server/api/ai-chat.ts +40 -32
- package/modules/ai-chat/runtime/server/utils/docs_agent.ts +23 -15
- package/modules/ai-chat/runtime/types.ts +6 -0
- package/modules/css.ts +3 -2
- package/modules/routing.ts +26 -0
- package/nuxt.config.ts +2 -0
- package/nuxt.schema.ts +493 -0
- package/package.json +11 -9
- package/app/composables/useFaq.ts +0 -21
- package/modules/ai-chat/runtime/components/AiChatSlideover.vue +0 -255
- /package/{app → modules/ai-chat/runtime}/composables/useHighlighter.ts +0 -0
package/app/app.config.ts
CHANGED
|
@@ -70,5 +70,42 @@ export default defineAppConfig({
|
|
|
70
70
|
timeZone: 'Asia/Shanghai'
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
},
|
|
74
|
+
aiChat: {
|
|
75
|
+
floatingInput: true,
|
|
76
|
+
explainWithAi: true,
|
|
77
|
+
shortcuts: {
|
|
78
|
+
focusInput: 'meta_i'
|
|
79
|
+
},
|
|
80
|
+
texts: {
|
|
81
|
+
title: 'AI 助手',
|
|
82
|
+
collapse: '折叠',
|
|
83
|
+
expand: '展开',
|
|
84
|
+
clearChat: '清除聊天记录',
|
|
85
|
+
close: '关闭',
|
|
86
|
+
loading: 'Loading...',
|
|
87
|
+
askAnything: '问我任何事情...',
|
|
88
|
+
askMeAnythingDescription: '我可以帮助您浏览文档、解释概念并回答您的问题。',
|
|
89
|
+
faq: 'FAQ 建议',
|
|
90
|
+
placeholder: '输入你的问题...',
|
|
91
|
+
lineBreak: '换行',
|
|
92
|
+
trigger: '与 AI 聊天',
|
|
93
|
+
streaming: '思考中...',
|
|
94
|
+
streamed: '思考过程',
|
|
95
|
+
explainWithAi: '用 AI 解释此页面'
|
|
96
|
+
},
|
|
97
|
+
icons: {
|
|
98
|
+
loading: 'i-lucide-loader',
|
|
99
|
+
trigger: 'i-lucide-sparkles',
|
|
100
|
+
explain: 'i-lucide-brain',
|
|
101
|
+
close: 'i-lucide-x',
|
|
102
|
+
clearChat: 'i-lucide-trash-2',
|
|
103
|
+
streaming: 'i-lucide-chevron-down',
|
|
104
|
+
providers: {
|
|
105
|
+
mistral: 'i-simple-icons-mistralai',
|
|
106
|
+
kwaipilot: 'i-lucide-wand',
|
|
107
|
+
zai: 'i-lucide-wand'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
73
110
|
}
|
|
74
111
|
})
|
package/app/app.vue
CHANGED
|
@@ -7,6 +7,7 @@ const site = useSiteConfig()
|
|
|
7
7
|
const appConfig = useAppConfig()
|
|
8
8
|
const colorMode = useColorMode()
|
|
9
9
|
const route = useRoute()
|
|
10
|
+
const { isEnabled: isAiChatEnabled, panelWidth: aiChatPanelWidth, shouldPushContent } = useAIChat()
|
|
10
11
|
|
|
11
12
|
const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('docs', ['category', 'description']))
|
|
12
13
|
const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSections('docs'), {
|
|
@@ -48,9 +49,9 @@ provide('navigation', rootNavigation)
|
|
|
48
49
|
<Analytics v-if="appConfig.vercelAnalytics" :debug="appConfig.vercelAnalytics?.debug" />
|
|
49
50
|
<SpeedInsights v-if="appConfig.vercelAnalytics" :debug="appConfig.vercelAnalytics?.debug" />
|
|
50
51
|
|
|
51
|
-
<div :class="{ root: route.path.startsWith('/docs/') }">
|
|
52
|
+
<div :class="{ root: route.path.startsWith('/docs/') }" :style="{ marginRight: shouldPushContent ? `${aiChatPanelWidth}px` : '0' }">
|
|
52
53
|
<template v-if="!route.path.startsWith('/examples')">
|
|
53
|
-
<Header />
|
|
54
|
+
<Header v-if="$route.meta.header !== false" />
|
|
54
55
|
</template>
|
|
55
56
|
|
|
56
57
|
<NuxtLayout>
|
|
@@ -58,10 +59,14 @@ provide('navigation', rootNavigation)
|
|
|
58
59
|
</NuxtLayout>
|
|
59
60
|
|
|
60
61
|
<template v-if="!route.path.startsWith('/examples')">
|
|
61
|
-
<Footer />
|
|
62
|
+
<Footer v-if="$route.meta.footer !== false" />
|
|
62
63
|
|
|
63
64
|
<ClientOnly>
|
|
64
65
|
<LazyUContentSearch :files="files" :navigation="rootNavigation" :fuse="{ resultLimit: 1000 }" />
|
|
66
|
+
<template v-if="isAiChatEnabled">
|
|
67
|
+
<LazyAiChatFloatingInput />
|
|
68
|
+
<LazyAiChatPanel />
|
|
69
|
+
</template>
|
|
65
70
|
</ClientOnly>
|
|
66
71
|
</template>
|
|
67
72
|
</div>
|
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
const { aiChat } = useRuntimeConfig().public
|
|
3
2
|
const route = useRoute()
|
|
4
|
-
|
|
5
3
|
const pageUrl = route.path
|
|
6
|
-
|
|
7
|
-
const {
|
|
4
|
+
|
|
5
|
+
const { aiChat } = useAppConfig()
|
|
6
|
+
const { isEnabled, open } = useAIChat()
|
|
7
|
+
|
|
8
|
+
const showExplainWithAi = computed(() => {
|
|
9
|
+
return isEnabled.value && aiChat.explainWithAi !== false
|
|
10
|
+
})
|
|
8
11
|
</script>
|
|
9
12
|
|
|
10
13
|
<template>
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<AiChatSlideover :faq-questions="faqQuestions" />
|
|
22
|
-
|
|
23
|
-
<Teleport to="body">
|
|
24
|
-
<ClientOnly>
|
|
25
|
-
<LazyAiChatFloatingInput />
|
|
26
|
-
</ClientOnly>
|
|
27
|
-
</Teleport>
|
|
28
|
-
</div>
|
|
14
|
+
<UButton
|
|
15
|
+
v-if="showExplainWithAi"
|
|
16
|
+
:icon="aiChat.icons.explain"
|
|
17
|
+
target="_blank"
|
|
18
|
+
:label="aiChat.texts.explainWithAi"
|
|
19
|
+
size="sm"
|
|
20
|
+
variant="ghost"
|
|
21
|
+
color="neutral"
|
|
22
|
+
@click="open(`解释此页面 ${pageUrl}`, true)"
|
|
23
|
+
/>
|
|
29
24
|
</template>
|
|
@@ -106,7 +106,12 @@ async function copyPage() {
|
|
|
106
106
|
content: 'w-48'
|
|
107
107
|
}"
|
|
108
108
|
>
|
|
109
|
-
<UButton
|
|
109
|
+
<UButton
|
|
110
|
+
:icon="ui.icons.chevronDown"
|
|
111
|
+
color="neutral"
|
|
112
|
+
variant="outline"
|
|
113
|
+
aria-label="Toggle Dropdown"
|
|
114
|
+
/>
|
|
110
115
|
</UDropdownMenu>
|
|
111
116
|
</UFieldGroup>
|
|
112
117
|
</template>
|
|
@@ -67,9 +67,9 @@ const authorUrl = computed(() => {
|
|
|
67
67
|
|
|
68
68
|
<template>
|
|
69
69
|
<div v-if="commit" class="flex items-center flex-wrap gap-1.5 text-sm text-muted mt-2">
|
|
70
|
-
<span class="text-
|
|
70
|
+
<span class="text-muted">最后更新于</span>
|
|
71
71
|
<time class="font-medium text-default" :datetime="commit.date">{{ commit.dateFormatted }}</time>
|
|
72
|
-
<span class="text-
|
|
72
|
+
<span class="text-muted">由</span>
|
|
73
73
|
<ULink
|
|
74
74
|
v-if="authorUrl"
|
|
75
75
|
:to="authorUrl"
|
|
@@ -79,7 +79,7 @@ const authorUrl = computed(() => {
|
|
|
79
79
|
<UAvatar
|
|
80
80
|
v-if="showAvatar && commit.author.avatar"
|
|
81
81
|
:src="commit.author.avatar"
|
|
82
|
-
|
|
82
|
+
alt="Author Avatar"
|
|
83
83
|
size="2xs"
|
|
84
84
|
/>
|
|
85
85
|
<UBadge color="neutral" variant="outline" size="sm">
|
|
@@ -90,7 +90,7 @@ const authorUrl = computed(() => {
|
|
|
90
90
|
<UAvatar
|
|
91
91
|
v-if="showAvatar && commit.author.avatar"
|
|
92
92
|
:src="commit.author.avatar"
|
|
93
|
-
|
|
93
|
+
alt="Author Avatar"
|
|
94
94
|
size="2xs"
|
|
95
95
|
/>
|
|
96
96
|
<UBadge color="neutral" variant="outline" size="sm">
|
|
@@ -98,7 +98,7 @@ const authorUrl = computed(() => {
|
|
|
98
98
|
</UBadge>
|
|
99
99
|
</span>
|
|
100
100
|
<template v-if="showMessage && commit.message">
|
|
101
|
-
<span class="text-
|
|
101
|
+
<span class="text-muted">提交</span>
|
|
102
102
|
<ULink
|
|
103
103
|
v-if="commitUrl"
|
|
104
104
|
:to="commitUrl"
|
|
@@ -18,7 +18,7 @@ const links = computed<ButtonProps[]>(() => github && github.url
|
|
|
18
18
|
</script>
|
|
19
19
|
|
|
20
20
|
<template>
|
|
21
|
-
<UHeader :ui="{ left: 'min-w-0' }" class="flex flex-col">
|
|
21
|
+
<UHeader :ui="{ left: 'min-w-0' }" class="flex flex-col" aria-label="Site Header">
|
|
22
22
|
<template #left>
|
|
23
23
|
<HeaderLogo />
|
|
24
24
|
</template>
|
|
@@ -9,11 +9,21 @@ const { navigationByCategory } = useNavigation(navigation!)
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
|
-
<UNavigationMenu
|
|
12
|
+
<UNavigationMenu
|
|
13
|
+
orientation="vertical"
|
|
14
|
+
:items="mobileLinks"
|
|
15
|
+
class="-mx-2.5"
|
|
16
|
+
aria-label="Mobile Navigation"
|
|
17
|
+
/>
|
|
13
18
|
|
|
14
19
|
<template v-if="route.path.startsWith('/docs/')">
|
|
15
20
|
<USeparator type="dashed" class="mt-4 mb-6" />
|
|
16
21
|
|
|
17
|
-
<UContentNavigation
|
|
22
|
+
<UContentNavigation
|
|
23
|
+
:navigation="navigationByCategory"
|
|
24
|
+
highlight
|
|
25
|
+
:ui="{ linkTrailingBadge: 'font-semibold uppercase' }"
|
|
26
|
+
aria-label="Documentation Navigation"
|
|
27
|
+
/>
|
|
18
28
|
</template>
|
|
19
29
|
</template>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
const { aiChat } = useRuntimeConfig().public
|
|
3
2
|
const route = useRoute()
|
|
3
|
+
const { isEnabled: isAiChatEnabled } = useAIChat()
|
|
4
4
|
</script>
|
|
5
5
|
|
|
6
6
|
<template>
|
|
7
|
-
<div v-if="
|
|
7
|
+
<div v-if="isAiChatEnabled" class="hidden md:block">
|
|
8
8
|
<UButton
|
|
9
9
|
v-if="route.path === '/'"
|
|
10
10
|
to="/docs"
|
package/app/layouts/default.vue
CHANGED
package/app/layouts/docs.vue
CHANGED
|
@@ -17,6 +17,7 @@ if (!page.value) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
|
20
|
+
const { shouldPushContent: shouldHideToc } = useAIChat()
|
|
20
21
|
|
|
21
22
|
const { data: surround } = await useAsyncData(`surround-${(kebabCase(route.path))}`, () => {
|
|
22
23
|
return queryCollectionItemSurroundings('docs', route.path, {
|
|
@@ -93,7 +94,7 @@ defineOgImageComponent('Nuxt', {
|
|
|
93
94
|
</script>
|
|
94
95
|
|
|
95
96
|
<template>
|
|
96
|
-
<UPage v-if="page">
|
|
97
|
+
<UPage v-if="page" :key="`page-${shouldHideToc}`">
|
|
97
98
|
<UPageHeader :title="title">
|
|
98
99
|
<template #headline>
|
|
99
100
|
<UBreadcrumb :items="breadcrumb" />
|
|
@@ -136,7 +137,7 @@ defineOgImageComponent('Nuxt', {
|
|
|
136
137
|
<UContentSurround :surround="surround" />
|
|
137
138
|
</UPageBody>
|
|
138
139
|
|
|
139
|
-
<template v-if="page?.body?.toc?.links?.length" #right>
|
|
140
|
+
<template v-if="page?.body?.toc?.links?.length && !shouldHideToc" #right>
|
|
140
141
|
<UContentToc
|
|
141
142
|
:title="toc?.title"
|
|
142
143
|
:links="page.body?.toc?.links"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ButtonProps } from '@nuxt/ui'
|
|
3
|
+
|
|
4
|
+
const { data: page } = await useAsyncData('releases', () => queryCollection('releases').first())
|
|
5
|
+
if (!page.value) {
|
|
6
|
+
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const title = page.value.seo?.title || page.value.title
|
|
10
|
+
const description = page.value.seo?.description || page.value.description
|
|
11
|
+
|
|
12
|
+
useSeoMeta({
|
|
13
|
+
title,
|
|
14
|
+
description,
|
|
15
|
+
ogTitle: title,
|
|
16
|
+
ogDescription: description
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
defineOgImageComponent('Nuxt', {
|
|
20
|
+
title,
|
|
21
|
+
description
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const { data: versions } = await useFetch(page.value.releases || '', {
|
|
25
|
+
server: false,
|
|
26
|
+
transform: (data: {
|
|
27
|
+
releases: {
|
|
28
|
+
name?: string
|
|
29
|
+
tag: string
|
|
30
|
+
publishedAt: string
|
|
31
|
+
markdown: string
|
|
32
|
+
}[]
|
|
33
|
+
}) => {
|
|
34
|
+
return data.releases.map(release => ({
|
|
35
|
+
tag: release.tag,
|
|
36
|
+
title: release.name || release.tag,
|
|
37
|
+
date: release.publishedAt,
|
|
38
|
+
markdown: release.markdown
|
|
39
|
+
}))
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<main v-if="page">
|
|
46
|
+
<UPageHero
|
|
47
|
+
:title="page.hero.title"
|
|
48
|
+
:description="page.hero.description"
|
|
49
|
+
:links="(page.hero.links as ButtonProps[]) || []"
|
|
50
|
+
class="md:border-b border-default"
|
|
51
|
+
:ui="{ container: 'relative py-10 sm:py-16 lg:py-24' }"
|
|
52
|
+
>
|
|
53
|
+
<template #top>
|
|
54
|
+
<div class="absolute z-[-1] rounded-full bg-primary blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<LazyStarsBg />
|
|
58
|
+
|
|
59
|
+
<div aria-hidden="true" class="hidden md:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
|
60
|
+
</UPageHero>
|
|
61
|
+
|
|
62
|
+
<UPageSection :ui="{ container: 'py-0!' }">
|
|
63
|
+
<div class="py-4 md:py-8 lg:py-16 md:border-x border-default">
|
|
64
|
+
<UContainer class="max-w-5xl">
|
|
65
|
+
<UChangelogVersions
|
|
66
|
+
as="main"
|
|
67
|
+
:indicator-motion="false"
|
|
68
|
+
:ui="{
|
|
69
|
+
root: 'py-16 sm:py-24 lg:py-32',
|
|
70
|
+
indicator: 'inset-y-0'
|
|
71
|
+
}"
|
|
72
|
+
>
|
|
73
|
+
<UChangelogVersion
|
|
74
|
+
v-for="version in versions"
|
|
75
|
+
:key="version.tag"
|
|
76
|
+
v-bind="version"
|
|
77
|
+
:ui="{
|
|
78
|
+
root: 'flex items-start',
|
|
79
|
+
container: 'max-w-xl',
|
|
80
|
+
header: 'border-b border-default pb-4',
|
|
81
|
+
title: 'text-3xl',
|
|
82
|
+
date: 'text-xs/9 text-highlighted font-mono',
|
|
83
|
+
indicator: 'sticky top-0 pt-16 -mt-16 sm:pt-24 sm:-mt-24 lg:pt-32 lg:-mt-32'
|
|
84
|
+
}"
|
|
85
|
+
>
|
|
86
|
+
<template #body>
|
|
87
|
+
<MDC
|
|
88
|
+
v-if="version.markdown"
|
|
89
|
+
:value="version.markdown"
|
|
90
|
+
/>
|
|
91
|
+
</template>
|
|
92
|
+
</UChangelogVersion>
|
|
93
|
+
</UChangelogVersions>
|
|
94
|
+
</UContainer>
|
|
95
|
+
</div>
|
|
96
|
+
</UPageSection>
|
|
97
|
+
</main>
|
|
98
|
+
</template>
|
package/app/types/index.d.ts
CHANGED
|
@@ -61,6 +61,155 @@ declare module 'nuxt/schema' {
|
|
|
61
61
|
options?: Intl.DateTimeFormatOptions
|
|
62
62
|
}
|
|
63
63
|
} | false
|
|
64
|
+
aiChat: {
|
|
65
|
+
/**
|
|
66
|
+
* 在文档页面底部显示浮动输入。
|
|
67
|
+
* @default true
|
|
68
|
+
*/
|
|
69
|
+
floatingInput: boolean
|
|
70
|
+
/**
|
|
71
|
+
* 在文档侧边栏中显示“使用 AI 进行解释”按钮。
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
74
|
+
explainWithAi?: boolean
|
|
75
|
+
/**
|
|
76
|
+
* 显示的常见问题解答问题。
|
|
77
|
+
* @example 简单格式: ['如何安装?', '如何配置?']
|
|
78
|
+
* @example 分类格式: [{ category: '入门', items: ['如何安装?'] }]
|
|
79
|
+
*/
|
|
80
|
+
faqQuestions?: FaqQuestions
|
|
81
|
+
/**
|
|
82
|
+
* 键盘快捷键配置。
|
|
83
|
+
*/
|
|
84
|
+
shortcuts: {
|
|
85
|
+
/**
|
|
86
|
+
* 快捷键,用于聚焦浮动输入框。
|
|
87
|
+
* @default 'meta_i'
|
|
88
|
+
*/
|
|
89
|
+
focusInput: string
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 文本配置。
|
|
93
|
+
*/
|
|
94
|
+
texts: {
|
|
95
|
+
/**
|
|
96
|
+
* AI 聊天面板的标题文本。
|
|
97
|
+
* @default 'AI 助手'
|
|
98
|
+
*/
|
|
99
|
+
title: string
|
|
100
|
+
/**
|
|
101
|
+
* 折叠按钮的文本。
|
|
102
|
+
* @default '折叠‘
|
|
103
|
+
*/
|
|
104
|
+
collapse: string
|
|
105
|
+
/**
|
|
106
|
+
* 展开按钮的文本。
|
|
107
|
+
* @default '展开'
|
|
108
|
+
*/
|
|
109
|
+
expand: string
|
|
110
|
+
/**
|
|
111
|
+
* 清除聊天记录按钮的文本。
|
|
112
|
+
* @default '清除聊天记录'
|
|
113
|
+
*/
|
|
114
|
+
clearChat: string
|
|
115
|
+
/**
|
|
116
|
+
* 关闭按钮的文本。
|
|
117
|
+
* @default '关闭'
|
|
118
|
+
*/
|
|
119
|
+
close: string
|
|
120
|
+
/**
|
|
121
|
+
* 加载时的提示文本。
|
|
122
|
+
* @default 'Loading...'
|
|
123
|
+
*/
|
|
124
|
+
loading: string
|
|
125
|
+
/**
|
|
126
|
+
* 询问任何事情文本
|
|
127
|
+
* @default '问我任何事情...'
|
|
128
|
+
*/
|
|
129
|
+
askAnything: string
|
|
130
|
+
/**
|
|
131
|
+
* 询问任何事情描述文本
|
|
132
|
+
* @default '我可以帮助您浏览文档、解释概念并回答您的问题。'
|
|
133
|
+
*/
|
|
134
|
+
askMeAnythingDescription: string
|
|
135
|
+
/**
|
|
136
|
+
* FAQ 建议标题文本。
|
|
137
|
+
* @default 'FAQ 建议'
|
|
138
|
+
*/
|
|
139
|
+
faq: string
|
|
140
|
+
/**
|
|
141
|
+
* 浮动输入框的占位符文本。
|
|
142
|
+
* @default '输入你的问题...'
|
|
143
|
+
*/
|
|
144
|
+
placeholder: string
|
|
145
|
+
/**
|
|
146
|
+
* 换行的提示文本。
|
|
147
|
+
* @default '换行'
|
|
148
|
+
*/
|
|
149
|
+
lineBreak: string
|
|
150
|
+
/**
|
|
151
|
+
* AI 聊天面板触发按钮的提示文本。
|
|
152
|
+
* @default '与 AI 聊天'
|
|
153
|
+
*/
|
|
154
|
+
trigger: string
|
|
155
|
+
/**
|
|
156
|
+
* 思考时的提示文本。
|
|
157
|
+
* @default '思考中...'
|
|
158
|
+
*/
|
|
159
|
+
streaming: string
|
|
160
|
+
/**
|
|
161
|
+
* 思考后的提示文本。
|
|
162
|
+
* @default '思考过程'
|
|
163
|
+
*/
|
|
164
|
+
streamed: string
|
|
165
|
+
/**
|
|
166
|
+
* 使用 AI 进行解释按钮的文本。
|
|
167
|
+
* @default '用 AI 解释此页面
|
|
168
|
+
*/
|
|
169
|
+
explainWithAi: string
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* 图标配置。
|
|
173
|
+
*/
|
|
174
|
+
icons: {
|
|
175
|
+
/**
|
|
176
|
+
* 加载时的图标。
|
|
177
|
+
* @default i-lucide-loader
|
|
178
|
+
*/
|
|
179
|
+
loading: string
|
|
180
|
+
/**
|
|
181
|
+
* AI 聊天触发按钮和滑出层头部的图标。
|
|
182
|
+
* @default 'i-lucide-sparkles'
|
|
183
|
+
*/
|
|
184
|
+
trigger: string
|
|
185
|
+
/**
|
|
186
|
+
* "使用 AI 进行解释" 按钮的图标。
|
|
187
|
+
* @default 'i-lucide-brain'
|
|
188
|
+
*/
|
|
189
|
+
explain: string
|
|
190
|
+
/**
|
|
191
|
+
* 思考时的图标。
|
|
192
|
+
* @default ui.icons.chevronDown
|
|
193
|
+
*/
|
|
194
|
+
streaming: string
|
|
195
|
+
/**
|
|
196
|
+
* 清除聊天记录按钮的图标。
|
|
197
|
+
* @default 'i-lucide-trash-2'
|
|
198
|
+
*/
|
|
199
|
+
clearChat: string
|
|
200
|
+
/**
|
|
201
|
+
* 关闭按钮的图标。
|
|
202
|
+
* @default 'i-lucide-x'
|
|
203
|
+
*/
|
|
204
|
+
close: string
|
|
205
|
+
/**
|
|
206
|
+
* 用于映射不同 AI 提供商的图标。
|
|
207
|
+
* @example { mistral: 'i-simple-icons-mistralai' }
|
|
208
|
+
* @default { xxx: 'i-simple-xxx', mistral: 'i-simple-icons-mistralai', kwaipilot: 'i-lucide-wand', zai: 'i-lucide-wand' }
|
|
209
|
+
*/
|
|
210
|
+
providers: Record<string, string>
|
|
211
|
+
}
|
|
212
|
+
}
|
|
64
213
|
}
|
|
65
214
|
}
|
|
66
215
|
|
package/content.config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
1
2
|
import { defineCollection, defineContentConfig } from '@nuxt/content'
|
|
2
3
|
import { useNuxt } from '@nuxt/kit'
|
|
3
4
|
import { asSeoCollection } from '@nuxtjs/seo/content'
|
|
@@ -7,6 +8,8 @@ import { z } from 'zod/v4'
|
|
|
7
8
|
const { options } = useNuxt()
|
|
8
9
|
const cwd = joinURL(options.rootDir, 'content')
|
|
9
10
|
|
|
11
|
+
const hasReleasesMd = existsSync(joinURL(cwd, 'releases.md'))
|
|
12
|
+
|
|
10
13
|
const Avatar = z.object({
|
|
11
14
|
src: z.string(),
|
|
12
15
|
alt: z.string().optional()
|
|
@@ -27,6 +30,12 @@ const Button = z.object({
|
|
|
27
30
|
class: z.string().optional()
|
|
28
31
|
})
|
|
29
32
|
|
|
33
|
+
const PageHero = z.object({
|
|
34
|
+
title: z.string(),
|
|
35
|
+
description: z.string(),
|
|
36
|
+
links: z.array(Button).optional()
|
|
37
|
+
})
|
|
38
|
+
|
|
30
39
|
export default defineContentConfig({
|
|
31
40
|
collections: {
|
|
32
41
|
landing: defineCollection(asSeoCollection({
|
|
@@ -38,10 +47,10 @@ export default defineContentConfig({
|
|
|
38
47
|
})),
|
|
39
48
|
docs: defineCollection(asSeoCollection({
|
|
40
49
|
type: 'page',
|
|
41
|
-
source:
|
|
50
|
+
source: {
|
|
42
51
|
cwd,
|
|
43
52
|
include: 'docs/**/*'
|
|
44
|
-
}
|
|
53
|
+
},
|
|
45
54
|
schema: z.object({
|
|
46
55
|
links: z.array(Button),
|
|
47
56
|
category: z.string().optional(),
|
|
@@ -49,6 +58,19 @@ export default defineContentConfig({
|
|
|
49
58
|
title: z.string().optional()
|
|
50
59
|
})
|
|
51
60
|
})
|
|
61
|
+
})),
|
|
62
|
+
releases: defineCollection(asSeoCollection({
|
|
63
|
+
type: 'page',
|
|
64
|
+
source: {
|
|
65
|
+
cwd,
|
|
66
|
+
include: hasReleasesMd ? 'releases.md' : 'releases.yml'
|
|
67
|
+
},
|
|
68
|
+
schema: z.object({
|
|
69
|
+
title: z.string(),
|
|
70
|
+
description: z.string(),
|
|
71
|
+
releases: z.string(),
|
|
72
|
+
hero: PageHero
|
|
73
|
+
})
|
|
52
74
|
}))
|
|
53
75
|
}
|
|
54
76
|
})
|