@movk/nuxt-docs 1.8.1 → 1.10.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/README.md +4 -0
- package/app/assets/css/main.css +40 -0
- package/app/composables/useToolCall.ts +3 -1
- package/app/pages/docs/[...slug].vue +1 -1
- package/app/pages/index.vue +1 -1
- package/app/templates/releases.vue +1 -1
- package/app/utils/shiki-transformer-icon-highlight.ts +0 -1
- package/content.config.ts +7 -8
- package/modules/ai-chat/runtime/server/utils/docs_agent.ts +1 -1
- package/modules/config.ts +14 -35
- package/modules/css.ts +16 -29
- package/modules/md-rewrite.ts +1 -1
- package/nuxt.config.ts +36 -28
- package/package.json +19 -14
- package/server/api/component-example.get.ts +2 -2
- package/server/api/github/commits.get.ts +4 -4
- package/server/api/github/last-commit.get.ts +4 -4
- package/server/mcp/tools/get-example.ts +19 -0
- package/server/mcp/tools/get-page.ts +75 -6
- package/server/mcp/tools/list-examples.ts +14 -0
- package/server/mcp/tools/list-pages.ts +1 -1
- package/server/plugins/llms.ts +12 -16
- package/server/routes/raw/[...slug].md.get.ts +28 -8
- package/server/utils/transformMDC.ts +559 -0
- package/utils/component-meta.ts +85 -0
- /package/app/components/content/prose/{ProsePre.vue → ProsePre.global.vue} +0 -0
package/README.md
CHANGED
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
|
|
21
21
|
### 🤖 AI 增强体验
|
|
22
22
|
|
|
23
|
+
<div style="padding: 40px 0; display: flex; justify-content: center;">
|
|
24
|
+
<img src="https://docs.mhaibaraai.cn/ai/AiChat.png" alt="AiChat" width="400">
|
|
25
|
+
</div>
|
|
26
|
+
|
|
23
27
|
- **AI 聊天助手** - 内置智能文档助手,基于 Vercel AI SDK 支持多种 LLM 模型(Mistral、Qwen、OpenRouter)
|
|
24
28
|
- **MCP Server 支持** - 集成 Model Context Protocol 服务器,为 AI 助手提供结构化的文档访问能力
|
|
25
29
|
- **LLM 优化** - 通过 `nuxt-llms` 模块自动生成 `llms.txt` 和 `llms-full.txt`,为 AI 工具提供优化的文档索引
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
@import "tailwindcss" theme(static) source("../../../..");
|
|
2
|
+
@import "@nuxt/ui";
|
|
3
|
+
|
|
4
|
+
@theme static {
|
|
5
|
+
--container-8xl: 90rem;
|
|
6
|
+
|
|
7
|
+
--font-sans: 'Public Sans', sans-serif;
|
|
8
|
+
|
|
9
|
+
--color-green-50: #EFFDF5;
|
|
10
|
+
--color-green-100: #D9FBE8;
|
|
11
|
+
--color-green-200: #B3F5D1;
|
|
12
|
+
--color-green-300: #75EDAE;
|
|
13
|
+
--color-green-400: #00DC82;
|
|
14
|
+
--color-green-500: #00C16A;
|
|
15
|
+
--color-green-600: #00A155;
|
|
16
|
+
--color-green-700: #007F45;
|
|
17
|
+
--color-green-800: #016538;
|
|
18
|
+
--color-green-900: #0A5331;
|
|
19
|
+
--color-green-950: #052E16;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
:root {
|
|
23
|
+
--ui-container: var(--container-8xl);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Shiki icon highlight transformer styles */
|
|
27
|
+
.shiki-icon-highlight {
|
|
28
|
+
display: inline-block;
|
|
29
|
+
width: 1.25em;
|
|
30
|
+
height: 1.25em;
|
|
31
|
+
vertical-align: -0.25em;
|
|
32
|
+
margin-right: 0.125em;
|
|
33
|
+
background-color: var(--ui-text-highlighted);
|
|
34
|
+
-webkit-mask-repeat: no-repeat;
|
|
35
|
+
mask-repeat: no-repeat;
|
|
36
|
+
-webkit-mask-size: 100% 100%;
|
|
37
|
+
mask-size: 100% 100%;
|
|
38
|
+
-webkit-mask-image: var(--shiki-icon-url);
|
|
39
|
+
mask-image: var(--shiki-icon-url);
|
|
40
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export function useToolCall() {
|
|
2
2
|
const tools: Record<string, string | ((args: any) => string)> = {
|
|
3
3
|
'list-pages': '列出所有文档页面',
|
|
4
|
-
'get-page': (args: any) => `检索 ${args?.path || '页面'}
|
|
4
|
+
'get-page': (args: any) => `检索 ${args?.path || '页面'}`,
|
|
5
|
+
'list-examples': '列出所有示例',
|
|
6
|
+
'get-example': (args: any) => `获取示例:${args?.exampleName || '示例'}`
|
|
5
7
|
}
|
|
6
8
|
return {
|
|
7
9
|
tools
|
|
@@ -14,7 +14,7 @@ const { toc, github } = useAppConfig()
|
|
|
14
14
|
const { data: page } = await useAsyncData(`docs-${kebabCase(route.path)}`, () => queryCollection('docs').path(route.path).first())
|
|
15
15
|
|
|
16
16
|
if (!page.value) {
|
|
17
|
-
throw createError({
|
|
17
|
+
throw createError({ status: 404, statusText: 'Page not found', fatal: true })
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
package/app/pages/index.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
const { data: page } = await useAsyncData('landing', () => queryCollection('landing').path('/').first())
|
|
3
3
|
if (!page.value) {
|
|
4
|
-
throw createError({
|
|
4
|
+
throw createError({ status: 404, statusText: 'Page not found', fatal: true })
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
const title = page.value.seo?.title || page.value.title
|
|
@@ -3,7 +3,7 @@ import type { ButtonProps } from '@nuxt/ui'
|
|
|
3
3
|
|
|
4
4
|
const { data: page } = await useAsyncData('releases', () => queryCollection('releases').first())
|
|
5
5
|
if (!page.value) {
|
|
6
|
-
throw createError({
|
|
6
|
+
throw createError({ status: 404, statusText: 'Page not found', fatal: true })
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const title = page.value.seo?.title || page.value.title
|
package/content.config.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { defineCollection, defineContentConfig } from '@nuxt/content'
|
|
3
3
|
import { useNuxt } from '@nuxt/kit'
|
|
4
|
-
import { asSeoCollection } from '@nuxtjs/seo/content'
|
|
5
4
|
import { joinURL } from 'ufo'
|
|
6
|
-
import { z } from 'zod
|
|
5
|
+
import { z } from 'zod'
|
|
7
6
|
|
|
8
7
|
const { options } = useNuxt()
|
|
9
8
|
const cwd = joinURL(options.rootDir, 'content')
|
|
@@ -38,14 +37,14 @@ const PageHero = z.object({
|
|
|
38
37
|
|
|
39
38
|
export default defineContentConfig({
|
|
40
39
|
collections: {
|
|
41
|
-
landing: defineCollection(
|
|
40
|
+
landing: defineCollection({
|
|
42
41
|
type: 'page',
|
|
43
42
|
source: {
|
|
44
43
|
cwd,
|
|
45
44
|
include: 'index.md'
|
|
46
45
|
}
|
|
47
|
-
})
|
|
48
|
-
docs: defineCollection(
|
|
46
|
+
}),
|
|
47
|
+
docs: defineCollection({
|
|
49
48
|
type: 'page',
|
|
50
49
|
source: {
|
|
51
50
|
cwd,
|
|
@@ -58,8 +57,8 @@ export default defineContentConfig({
|
|
|
58
57
|
title: z.string().optional()
|
|
59
58
|
})
|
|
60
59
|
})
|
|
61
|
-
})
|
|
62
|
-
releases: defineCollection(
|
|
60
|
+
}),
|
|
61
|
+
releases: defineCollection({
|
|
63
62
|
type: 'page',
|
|
64
63
|
source: {
|
|
65
64
|
cwd,
|
|
@@ -71,6 +70,6 @@ export default defineContentConfig({
|
|
|
71
70
|
releases: z.string(),
|
|
72
71
|
hero: PageHero
|
|
73
72
|
})
|
|
74
|
-
})
|
|
73
|
+
})
|
|
75
74
|
}
|
|
76
75
|
})
|
package/modules/config.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createResolver, defineNuxtModule } from '@nuxt/kit'
|
|
2
|
-
import { join } from 'pathe'
|
|
3
2
|
import { defu } from 'defu'
|
|
4
3
|
import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git'
|
|
5
4
|
import { getPackageJsonMetadata, inferSiteURL } from '../utils/meta'
|
|
5
|
+
import { createComponentMetaExcludeFilters } from '../utils/component-meta'
|
|
6
6
|
|
|
7
7
|
export default defineNuxtModule({
|
|
8
8
|
meta: {
|
|
@@ -17,28 +17,25 @@ export default defineNuxtModule({
|
|
|
17
17
|
const url = inferSiteURL()
|
|
18
18
|
const meta = await getPackageJsonMetadata(dir)
|
|
19
19
|
const gitInfo = await getLocalGitInfo(dir) || getGitEnv()
|
|
20
|
-
const siteName =
|
|
20
|
+
const siteName = meta.name || gitInfo?.name || ''
|
|
21
|
+
|
|
22
|
+
nuxt.options.site = defu(nuxt.options.site, {
|
|
23
|
+
url,
|
|
24
|
+
name: siteName,
|
|
25
|
+
debug: false
|
|
26
|
+
})
|
|
21
27
|
|
|
22
28
|
nuxt.options.llms = defu(nuxt.options.llms, {
|
|
23
29
|
domain: url || 'https://example.com',
|
|
24
30
|
title: siteName,
|
|
25
31
|
description: meta.description || '',
|
|
32
|
+
contentRawMarkdown: false as const,
|
|
26
33
|
full: {
|
|
27
34
|
title: siteName,
|
|
28
35
|
description: meta.description || ''
|
|
29
36
|
}
|
|
30
37
|
})
|
|
31
38
|
|
|
32
|
-
nuxt.options.site = defu(nuxt.options.site, {
|
|
33
|
-
url,
|
|
34
|
-
name: siteName,
|
|
35
|
-
debug: false
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
nuxt.options.robots = defu(nuxt.options.robots, {
|
|
39
|
-
sitemap: url ? `${url.replace(/\/$/, '')}/sitemap.xml` : undefined
|
|
40
|
-
})
|
|
41
|
-
|
|
42
39
|
nuxt.options.appConfig.header = defu(nuxt.options.appConfig.header, {
|
|
43
40
|
title: siteName
|
|
44
41
|
})
|
|
@@ -62,34 +59,16 @@ export default defineNuxtModule({
|
|
|
62
59
|
})
|
|
63
60
|
|
|
64
61
|
const layerPath = resolve('..')
|
|
65
|
-
const allowedComponents = [
|
|
66
|
-
resolve('../app/components/content/CommitChangelog.vue'),
|
|
67
|
-
resolve('../app/components/content/ComponentEmits.vue'),
|
|
68
|
-
resolve('../app/components/content/ComponentExample.vue'),
|
|
69
|
-
resolve('../app/components/content/ComponentProps.vue'),
|
|
70
|
-
resolve('../app/components/content/ComponentSlots.vue'),
|
|
71
|
-
resolve('../app/components/content/PageLastCommit.vue'),
|
|
72
|
-
resolve('../app/components/content/Mermaid.vue'),
|
|
73
|
-
resolve('./ai-chat/runtime/components/AiChatToolCall.vue'),
|
|
74
|
-
resolve('./ai-chat/runtime/components/AiChatReasoning.vue'),
|
|
75
|
-
resolve('./ai-chat/runtime/components/AiChatSlideoverFaq.vue'),
|
|
76
|
-
resolve('./ai-chat/runtime/components/AiChatPreStream.vue')
|
|
77
|
-
]
|
|
78
|
-
const userComponentPaths = [
|
|
79
|
-
join(dir, 'app/components'),
|
|
80
|
-
join(dir, 'components'),
|
|
81
|
-
join(dir, 'docs/app/components'),
|
|
82
|
-
join(dir, 'templates/*/app/components')
|
|
83
|
-
]
|
|
84
62
|
|
|
85
63
|
// @ts-ignore - component-meta is not typed
|
|
86
64
|
nuxt.hook('component-meta:extend', (options: any) => {
|
|
65
|
+
const userInclude = (nuxt.options.componentMeta && typeof nuxt.options.componentMeta === 'object')
|
|
66
|
+
? nuxt.options.componentMeta.include || []
|
|
67
|
+
: []
|
|
68
|
+
|
|
87
69
|
options.exclude = [
|
|
88
70
|
...(options.exclude || []),
|
|
89
|
-
(
|
|
90
|
-
filePath.startsWith(layerPath) && !allowedComponents.includes(filePath),
|
|
91
|
-
({ filePath }: { filePath: string }) =>
|
|
92
|
-
userComponentPaths.some(path => filePath.startsWith(path))
|
|
71
|
+
...createComponentMetaExcludeFilters(resolve, dir, layerPath, userInclude)
|
|
93
72
|
]
|
|
94
73
|
})
|
|
95
74
|
}
|
package/modules/css.ts
CHANGED
|
@@ -1,46 +1,33 @@
|
|
|
1
|
-
import { addTemplate,
|
|
1
|
+
import { addTemplate, defineNuxtModule } from '@nuxt/kit'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { dirname, join } from 'node:path'
|
|
2
4
|
import { joinURL } from 'ufo'
|
|
5
|
+
import { resolveModulePath } from 'exsolve'
|
|
3
6
|
|
|
4
7
|
export default defineNuxtModule({
|
|
5
8
|
meta: {
|
|
6
9
|
name: 'css'
|
|
7
10
|
},
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
+
setup(_options, nuxt) {
|
|
12
|
+
const currentDir = dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
const mainCssPath = join(currentDir, '../app/assets/css/main.css')
|
|
14
|
+
|
|
15
|
+
nuxt.options.css ||= []
|
|
16
|
+
nuxt.options.css.unshift(mainCssPath)
|
|
11
17
|
|
|
12
|
-
const
|
|
13
|
-
const aiChatDir = resolve('../modules/ai-chat')
|
|
18
|
+
const dir = nuxt.options.rootDir
|
|
14
19
|
|
|
15
20
|
const contentDir = joinURL(dir, 'content')
|
|
21
|
+
const uiPath = resolveModulePath('@nuxt/ui', { from: import.meta.url, conditions: ['style'] })
|
|
22
|
+
const tailwindPath = resolveModulePath('tailwindcss', { from: import.meta.url, conditions: ['style'] })
|
|
16
23
|
|
|
17
24
|
const cssTemplate = addTemplate({
|
|
18
25
|
filename: 'movk-nuxt-docs.css',
|
|
19
26
|
getContents: () => {
|
|
20
|
-
return `@import
|
|
21
|
-
@import
|
|
22
|
-
@import "@nuxt/ui";
|
|
23
|
-
|
|
24
|
-
@source "${contentDir.replace(/\\/g, '/')}/**/*";
|
|
25
|
-
@source "${layerDir.replace(/\\/g, '/')}/**/*";
|
|
26
|
-
@source "${aiChatDir.replace(/\\/g, '/')}/**/*";
|
|
27
|
-
@source "../../app.config.ts";
|
|
27
|
+
return `@import ${JSON.stringify(tailwindPath)};
|
|
28
|
+
@import ${JSON.stringify(uiPath)};
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
.shiki-icon-highlight {
|
|
31
|
-
display: inline-block;
|
|
32
|
-
width: 1.25em;
|
|
33
|
-
height: 1.25em;
|
|
34
|
-
vertical-align: -0.25em;
|
|
35
|
-
margin-right: 0.125em;
|
|
36
|
-
background-color: var(--ui-text-highlighted);
|
|
37
|
-
-webkit-mask-repeat: no-repeat;
|
|
38
|
-
mask-repeat: no-repeat;
|
|
39
|
-
-webkit-mask-size: 100% 100%;
|
|
40
|
-
mask-size: 100% 100%;
|
|
41
|
-
-webkit-mask-image: var(--shiki-icon-url);
|
|
42
|
-
mask-image: var(--shiki-icon-url);
|
|
43
|
-
}`
|
|
30
|
+
@source "${contentDir.replace(/\\/g, '/')}/**/*";`
|
|
44
31
|
}
|
|
45
32
|
})
|
|
46
33
|
|
package/modules/md-rewrite.ts
CHANGED
package/nuxt.config.ts
CHANGED
|
@@ -1,45 +1,27 @@
|
|
|
1
|
-
import { createResolver, extendViteConfig } from '@nuxt/kit'
|
|
2
1
|
import { defineNuxtConfig } from 'nuxt/config'
|
|
3
2
|
import pkg from './package.json'
|
|
4
3
|
|
|
5
|
-
const { resolve } = createResolver(import.meta.url)
|
|
6
|
-
|
|
7
4
|
export default defineNuxtConfig({
|
|
8
5
|
modules: [
|
|
9
|
-
resolve('./modules/config'),
|
|
10
6
|
'@nuxt/ui',
|
|
11
7
|
'@nuxt/content',
|
|
12
8
|
'@nuxt/image',
|
|
13
9
|
'@nuxt/a11y',
|
|
14
10
|
'@nuxtjs/mcp-toolkit',
|
|
15
|
-
'@nuxtjs/seo',
|
|
16
11
|
'@vueuse/nuxt',
|
|
17
12
|
'nuxt-component-meta',
|
|
18
13
|
'nuxt-llms',
|
|
19
|
-
'
|
|
20
|
-
|
|
21
|
-
extendViteConfig((config) => {
|
|
22
|
-
config.optimizeDeps ||= {}
|
|
23
|
-
config.optimizeDeps.include ||= []
|
|
24
|
-
config.optimizeDeps.include.push(
|
|
25
|
-
'@nuxt/content > slugify',
|
|
26
|
-
'extend',
|
|
27
|
-
'@ai-sdk/gateway > @vercel/oidc',
|
|
28
|
-
'mermaid',
|
|
29
|
-
'dompurify'
|
|
30
|
-
)
|
|
31
|
-
config.optimizeDeps.include = config.optimizeDeps.include
|
|
32
|
-
.map(id => id.replace(/^@nuxt\/content > /, '@movk/nuxt-docs > @nuxt/content > '))
|
|
33
|
-
})
|
|
34
|
-
}
|
|
14
|
+
'nuxt-og-image',
|
|
15
|
+
'motion-v/nuxt'
|
|
35
16
|
],
|
|
17
|
+
|
|
36
18
|
app: {
|
|
37
19
|
rootAttrs: {
|
|
38
20
|
'data-vaul-drawer-wrapper': '',
|
|
39
21
|
'class': 'bg-default'
|
|
40
22
|
}
|
|
41
23
|
},
|
|
42
|
-
|
|
24
|
+
|
|
43
25
|
content: {
|
|
44
26
|
build: {
|
|
45
27
|
markdown: {
|
|
@@ -56,22 +38,25 @@ export default defineNuxtConfig({
|
|
|
56
38
|
}
|
|
57
39
|
}
|
|
58
40
|
},
|
|
41
|
+
|
|
59
42
|
mdc: {
|
|
60
43
|
highlight: {
|
|
61
44
|
noApiRoute: false
|
|
62
45
|
}
|
|
63
46
|
},
|
|
47
|
+
|
|
64
48
|
runtimeConfig: {
|
|
65
49
|
public: {
|
|
66
50
|
version: pkg.version
|
|
67
51
|
}
|
|
68
52
|
},
|
|
53
|
+
|
|
69
54
|
routeRules: {
|
|
70
55
|
'/llms.txt': { isr: true },
|
|
71
56
|
'/llms-full.txt': { isr: true }
|
|
72
57
|
},
|
|
58
|
+
|
|
73
59
|
experimental: {
|
|
74
|
-
typescriptPlugin: true,
|
|
75
60
|
asyncContext: true,
|
|
76
61
|
defaults: {
|
|
77
62
|
nuxtLink: {
|
|
@@ -79,7 +64,9 @@ export default defineNuxtConfig({
|
|
|
79
64
|
}
|
|
80
65
|
}
|
|
81
66
|
},
|
|
67
|
+
|
|
82
68
|
compatibilityDate: 'latest',
|
|
69
|
+
|
|
83
70
|
nitro: {
|
|
84
71
|
prerender: {
|
|
85
72
|
crawlLinks: true,
|
|
@@ -87,15 +74,36 @@ export default defineNuxtConfig({
|
|
|
87
74
|
autoSubfolderIndex: false
|
|
88
75
|
}
|
|
89
76
|
},
|
|
77
|
+
|
|
78
|
+
hooks: {
|
|
79
|
+
// Rewrite optimizeDeps paths for layer architecture
|
|
80
|
+
'vite:extendConfig': (config) => {
|
|
81
|
+
const include = config.optimizeDeps?.include
|
|
82
|
+
if (!include) return
|
|
83
|
+
|
|
84
|
+
const layerPkgs = /^(?:@nuxt\/content|@nuxtjs\/mdc|@nuxt\/a11y) > /
|
|
85
|
+
include.forEach((id, i) => {
|
|
86
|
+
if (layerPkgs.test(id)) include[i] = `@movk/nuxt-docs > ${id}`
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// Layer dependencies that need pre-bundling
|
|
90
|
+
include.push(
|
|
91
|
+
'@movk/nuxt-docs > @nuxt/content > slugify',
|
|
92
|
+
'@movk/nuxt-docs > @ai-sdk/gateway > @vercel/oidc'
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
90
97
|
a11y: {
|
|
91
98
|
logIssues: false
|
|
92
99
|
},
|
|
100
|
+
|
|
93
101
|
componentMeta: {
|
|
94
102
|
metaFields: {
|
|
95
103
|
type: false,
|
|
96
104
|
props: true,
|
|
97
|
-
slots: 'no-schema'
|
|
98
|
-
events: 'no-schema'
|
|
105
|
+
slots: 'no-schema',
|
|
106
|
+
events: 'no-schema',
|
|
99
107
|
exposed: false
|
|
100
108
|
},
|
|
101
109
|
exclude: [
|
|
@@ -110,6 +118,7 @@ export default defineNuxtConfig({
|
|
|
110
118
|
'nuxt-og-image'
|
|
111
119
|
]
|
|
112
120
|
},
|
|
121
|
+
|
|
113
122
|
fonts: {
|
|
114
123
|
families: [
|
|
115
124
|
{ name: 'Public Sans', provider: 'google', global: true },
|
|
@@ -121,9 +130,11 @@ export default defineNuxtConfig({
|
|
|
121
130
|
{ name: 'Raleway', provider: 'google', global: true }
|
|
122
131
|
]
|
|
123
132
|
},
|
|
133
|
+
|
|
124
134
|
icon: {
|
|
125
135
|
provider: 'iconify'
|
|
126
136
|
},
|
|
137
|
+
|
|
127
138
|
ogImage: {
|
|
128
139
|
zeroRuntime: true,
|
|
129
140
|
googleFontMirror: 'fonts.loli.net',
|
|
@@ -134,8 +145,5 @@ export default defineNuxtConfig({
|
|
|
134
145
|
'Inter:400',
|
|
135
146
|
'Inter:700'
|
|
136
147
|
]
|
|
137
|
-
},
|
|
138
|
-
sitemap: {
|
|
139
|
-
zeroRuntime: true
|
|
140
148
|
}
|
|
141
149
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@movk/nuxt-docs",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.10.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Modern Nuxt 4 documentation theme with auto-generated component docs, AI chat assistant, MCP server, and complete developer experience optimization.",
|
|
7
7
|
"author": "YiXuan <mhaibaraai@gmail.com>",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"main": "./nuxt.config.ts",
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"better-sqlite3": "12.x",
|
|
17
|
-
"nuxt": "4.x"
|
|
17
|
+
"nuxt": "4.x",
|
|
18
|
+
"tailwindcss": "4.x"
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
|
20
21
|
"app",
|
|
@@ -28,38 +29,40 @@
|
|
|
28
29
|
"README.md"
|
|
29
30
|
],
|
|
30
31
|
"dependencies": {
|
|
31
|
-
"@ai-sdk/gateway": "^3.0.
|
|
32
|
-
"@ai-sdk/mcp": "^1.0.
|
|
33
|
-
"@ai-sdk/vue": "^3.0.
|
|
34
|
-
"@iconify-json/lucide": "^1.2.
|
|
32
|
+
"@ai-sdk/gateway": "^3.0.29",
|
|
33
|
+
"@ai-sdk/mcp": "^1.0.15",
|
|
34
|
+
"@ai-sdk/vue": "^3.0.62",
|
|
35
|
+
"@iconify-json/lucide": "^1.2.87",
|
|
35
36
|
"@iconify-json/ph": "^1.2.2",
|
|
36
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
37
|
+
"@iconify-json/simple-icons": "^1.2.68",
|
|
37
38
|
"@iconify-json/tabler": "^1.2.26",
|
|
38
39
|
"@iconify-json/vscode-icons": "^1.2.40",
|
|
39
40
|
"@movk/core": "^1.1.0",
|
|
40
41
|
"@nuxt/a11y": "^1.0.0-alpha.1",
|
|
41
42
|
"@nuxt/content": "^3.11.0",
|
|
42
43
|
"@nuxt/image": "^2.0.0",
|
|
43
|
-
"@nuxt/kit": "^4.
|
|
44
|
+
"@nuxt/kit": "^4.3.0",
|
|
44
45
|
"@nuxt/ui": "^4.4.0",
|
|
45
46
|
"@nuxtjs/mcp-toolkit": "^0.6.2",
|
|
46
|
-
"@nuxtjs/
|
|
47
|
+
"@nuxtjs/mdc": "^0.20.0",
|
|
47
48
|
"@octokit/rest": "^22.0.1",
|
|
48
|
-
"@openrouter/ai-sdk-provider": "^2.
|
|
49
|
+
"@openrouter/ai-sdk-provider": "^2.1.1",
|
|
49
50
|
"@vercel/analytics": "^1.6.1",
|
|
50
51
|
"@vercel/speed-insights": "^1.3.1",
|
|
51
52
|
"@vueuse/core": "^14.1.0",
|
|
52
53
|
"@vueuse/nuxt": "^14.1.0",
|
|
53
|
-
"ai": "^6.0.
|
|
54
|
+
"ai": "^6.0.62",
|
|
54
55
|
"defu": "^6.1.4",
|
|
55
56
|
"dompurify": "^3.3.1",
|
|
56
57
|
"exsolve": "^1.0.8",
|
|
57
58
|
"git-url-parse": "^16.1.0",
|
|
58
59
|
"mermaid": "^11.12.2",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
60
|
+
"minimark": "^0.2.0",
|
|
61
|
+
"motion-v": "^1.10.2",
|
|
62
|
+
"nuxt": "^4.3.0",
|
|
61
63
|
"nuxt-component-meta": "^0.17.1",
|
|
62
64
|
"nuxt-llms": "^0.2.0",
|
|
65
|
+
"nuxt-og-image": "^5.1.13",
|
|
63
66
|
"ohash": "^2.0.11",
|
|
64
67
|
"pathe": "^2.0.3",
|
|
65
68
|
"pkg-types": "^2.3.0",
|
|
@@ -69,7 +72,9 @@
|
|
|
69
72
|
"shiki-stream": "^0.1.4",
|
|
70
73
|
"shiki-transformer-color-highlight": "^1.0.0",
|
|
71
74
|
"tailwindcss": "^4.1.18",
|
|
75
|
+
"tailwind-merge": "^3.4.0",
|
|
72
76
|
"ufo": "^1.6.3",
|
|
73
|
-
"zod": "^4.3.
|
|
77
|
+
"zod": "^4.3.6",
|
|
78
|
+
"vue-component-meta": "^3.2.4"
|
|
74
79
|
}
|
|
75
80
|
}
|
|
@@ -10,8 +10,8 @@ export default defineEventHandler((event) => {
|
|
|
10
10
|
const component = components[pascalCase(componentName)]
|
|
11
11
|
if (!component) {
|
|
12
12
|
throw createError({
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
statusText: 'Example not found!',
|
|
14
|
+
status: 404
|
|
15
15
|
})
|
|
16
16
|
}
|
|
17
17
|
return component
|
|
@@ -10,8 +10,8 @@ export default defineCachedEventHandler(async (event) => {
|
|
|
10
10
|
|
|
11
11
|
if (!paths.length || !paths[0]) {
|
|
12
12
|
throw createError({
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
status: 400,
|
|
14
|
+
statusText: 'Path is required'
|
|
15
15
|
})
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -19,8 +19,8 @@ export default defineCachedEventHandler(async (event) => {
|
|
|
19
19
|
|
|
20
20
|
if (!github || typeof github === 'boolean') {
|
|
21
21
|
throw createError({
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
status: 500,
|
|
23
|
+
statusText: 'GitHub configuration is not available'
|
|
24
24
|
})
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -8,8 +8,8 @@ export default defineCachedEventHandler(async (event) => {
|
|
|
8
8
|
const { path } = getQuery(event) as { path: string }
|
|
9
9
|
if (!path) {
|
|
10
10
|
throw createError({
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
status: 400,
|
|
12
|
+
statusText: 'Path is required'
|
|
13
13
|
})
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -17,8 +17,8 @@ export default defineCachedEventHandler(async (event) => {
|
|
|
17
17
|
|
|
18
18
|
if (!github || typeof github === 'boolean') {
|
|
19
19
|
throw createError({
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
status: 500,
|
|
21
|
+
statusText: 'GitHub configuration is not available'
|
|
22
22
|
})
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export default defineMcpTool({
|
|
4
|
+
description: '检索特定的 UI 示例实现代码和详细信息',
|
|
5
|
+
inputSchema: {
|
|
6
|
+
exampleName: z.string().describe('示例名称(PascalCase)')
|
|
7
|
+
},
|
|
8
|
+
cache: '30m',
|
|
9
|
+
async handler({ exampleName }) {
|
|
10
|
+
try {
|
|
11
|
+
const result = await $fetch<{ code: string }>(`/api/component-example/${exampleName}.json`)
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text' as const, text: result.code }]
|
|
14
|
+
}
|
|
15
|
+
} catch {
|
|
16
|
+
return errorResult(`示例 '${exampleName}' 未找到。使用 list_examples 工具查看所有可用示例。`)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
})
|