@movk/nuxt-docs 1.12.2 → 1.12.4

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/content.config.ts CHANGED
@@ -1,13 +1,15 @@
1
- import { existsSync } from 'node:fs'
1
+ import type { DefinedCollection } from '@nuxt/content'
2
2
  import { defineCollection, defineContentConfig } from '@nuxt/content'
3
3
  import { useNuxt } from '@nuxt/kit'
4
4
  import { joinURL } from 'ufo'
5
5
  import { z } from 'zod'
6
+ import { docsFolderExists, landingPageExists } from './utils/pages'
6
7
 
7
8
  const { options } = useNuxt()
8
9
  const cwd = joinURL(options.rootDir, 'content')
9
10
 
10
- const hasReleasesMd = existsSync(joinURL(cwd, 'releases.md'))
11
+ const hasLandingPage = landingPageExists(options.rootDir)
12
+ const hasDocsFolder = docsFolderExists(options.rootDir)
11
13
 
12
14
  const Avatar = z.object({
13
15
  src: z.string(),
@@ -35,41 +37,46 @@ const PageHero = z.object({
35
37
  links: z.array(Button).optional()
36
38
  })
37
39
 
38
- export default defineContentConfig({
39
- collections: {
40
- landing: defineCollection({
41
- type: 'page',
42
- source: {
43
- cwd,
44
- include: 'index.md'
45
- }
46
- }),
47
- docs: defineCollection({
48
- type: 'page',
49
- source: {
50
- cwd,
51
- include: 'docs/**/*'
52
- },
53
- schema: z.object({
54
- links: z.array(Button),
55
- category: z.string().optional(),
56
- navigation: z.object({
57
- title: z.string().optional()
58
- })
59
- })
60
- }),
61
- releases: defineCollection({
62
- type: 'page',
63
- source: {
64
- cwd,
65
- include: hasReleasesMd ? 'releases.md' : 'releases.yml'
66
- },
67
- schema: z.object({
68
- title: z.string(),
69
- description: z.string(),
70
- releases: z.string().optional(),
71
- hero: PageHero.optional()
40
+ const collections: Record<string, DefinedCollection> = {
41
+ docs: defineCollection({
42
+ type: 'page',
43
+ source: {
44
+ cwd,
45
+ include: hasDocsFolder ? 'docs/**' : '**',
46
+ prefix: hasDocsFolder ? '/docs' : '/',
47
+ exclude: ['index.md']
48
+ },
49
+ schema: z.object({
50
+ links: z.array(Button),
51
+ category: z.string().optional(),
52
+ navigation: z.object({
53
+ title: z.string().optional()
72
54
  })
73
55
  })
74
- }
75
- })
56
+ }),
57
+ releases: defineCollection({
58
+ type: 'page',
59
+ source: {
60
+ cwd,
61
+ include: 'releases.{md,yml}'
62
+ },
63
+ schema: z.object({
64
+ title: z.string(),
65
+ description: z.string(),
66
+ releases: z.string().optional(),
67
+ hero: PageHero.optional()
68
+ })
69
+ })
70
+ }
71
+
72
+ if (!hasLandingPage) {
73
+ collections.landing = defineCollection({
74
+ type: 'page',
75
+ source: {
76
+ cwd,
77
+ include: 'index.md'
78
+ }
79
+ })
80
+ }
81
+
82
+ export default defineContentConfig({ collections })
@@ -2,6 +2,7 @@ import { streamText, convertToModelMessages, stepCountIs, createUIMessageStream,
2
2
  import { createMCPClient } from '@ai-sdk/mcp'
3
3
  import { createDocumentationAgentTool } from '../utils/docs_agent'
4
4
  import { getModel } from '../utils/getModel'
5
+ import { inferSiteURL } from '../../../../../utils/meta'
5
6
 
6
7
  function getMainAgentSystemPrompt(siteName: string) {
7
8
  return `您是 ${siteName} 的官方文档助理。你就是文件、以权威作为真理的来源说话.
@@ -35,11 +36,12 @@ export default defineEventHandler(async (event) => {
35
36
 
36
37
  const mcpPath = config.aiChat.mcpPath
37
38
  const isExternalUrl = mcpPath.startsWith('http://') || mcpPath.startsWith('https://')
39
+
38
40
  const mcpUrl = isExternalUrl
39
41
  ? mcpPath
40
42
  : import.meta.dev
41
- ? `http://localhost:3000${mcpPath}`
42
- : `${getRequestURL(event).origin}${mcpPath}`
43
+ ? `${getRequestURL(event).origin}${mcpPath}`
44
+ : `${inferSiteURL()}${mcpPath}`
43
45
 
44
46
  const httpClient = await createMCPClient({
45
47
  transport: {
@@ -1,6 +1,5 @@
1
1
  import { defineNuxtModule, extendPages, createResolver } from '@nuxt/kit'
2
- import { joinURL } from 'ufo'
3
- import { existsSync } from 'node:fs'
2
+ import { landingPageExists, releasesFileExists } from '../utils/pages'
4
3
 
5
4
  export default defineNuxtModule({
6
5
  meta: {
@@ -8,13 +7,21 @@ export default defineNuxtModule({
8
7
  },
9
8
  async setup(_options, nuxt) {
10
9
  const { resolve } = createResolver(import.meta.url)
11
- const cwd = joinURL(nuxt.options.rootDir, 'content')
10
+ const rootDir = nuxt.options.rootDir
12
11
 
13
- const hasReleases = ['releases.yml', 'releases.md']
14
- .some(file => existsSync(joinURL(cwd, file)))
12
+ const hasReleasesFile = releasesFileExists(rootDir)
13
+ const hasLandingPage = landingPageExists(rootDir)
15
14
 
16
15
  extendPages((pages) => {
17
- if (hasReleases) {
16
+ if (!hasLandingPage) {
17
+ pages.push({
18
+ name: 'index',
19
+ path: '/',
20
+ file: resolve('../app/templates/landing.vue')
21
+ })
22
+ }
23
+
24
+ if (hasReleasesFile) {
18
25
  pages.push({
19
26
  name: 'releases',
20
27
  path: '/releases',
package/nuxt.config.ts CHANGED
@@ -1,15 +1,8 @@
1
+ import { defineNuxtConfig } from 'nuxt/config'
1
2
  import pkg from './package.json'
2
- import { createResolver } from '@nuxt/kit'
3
-
4
- const { resolve } = createResolver(import.meta.url)
5
3
 
6
4
  export default defineNuxtConfig({
7
5
  modules: [
8
- resolve('./modules/config'),
9
- resolve('./modules/routing'),
10
- resolve('./modules/md-rewrite'),
11
- resolve('./modules/component-example'),
12
- resolve('./modules/css'),
13
6
  '@nuxt/ui',
14
7
  '@nuxt/content',
15
8
  '@nuxt/image',
@@ -49,8 +42,7 @@ export default defineNuxtConfig({
49
42
 
50
43
  mdc: {
51
44
  highlight: {
52
- noApiRoute: false,
53
- shikiEngine: 'javascript'
45
+ noApiRoute: false
54
46
  }
55
47
  },
56
48
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@movk/nuxt-docs",
3
3
  "type": "module",
4
- "version": "1.12.2",
4
+ "version": "1.12.4",
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>",
@@ -29,39 +29,39 @@
29
29
  "README.md"
30
30
  ],
31
31
  "dependencies": {
32
- "@ai-sdk/gateway": "^3.0.39",
33
- "@ai-sdk/mcp": "^1.0.19",
34
- "@ai-sdk/vue": "^3.0.78",
35
- "@iconify-json/lucide": "^1.2.89",
36
- "@iconify-json/simple-icons": "^1.2.70",
37
- "@iconify-json/vscode-icons": "^1.2.40",
32
+ "@ai-sdk/gateway": "^3.0.55",
33
+ "@ai-sdk/mcp": "^1.0.21",
34
+ "@ai-sdk/vue": "^3.0.99",
35
+ "@iconify-json/lucide": "^1.2.94",
36
+ "@iconify-json/simple-icons": "^1.2.71",
37
+ "@iconify-json/vscode-icons": "^1.2.44",
38
38
  "@movk/core": "^1.1.0",
39
39
  "@nuxt/a11y": "^1.0.0-alpha.1",
40
40
  "@nuxt/content": "^3.11.2",
41
41
  "@nuxt/image": "^2.0.0",
42
42
  "@nuxt/kit": "^4.3.1",
43
- "@nuxt/ui": "^4.4.0",
44
- "@nuxtjs/mcp-toolkit": "^0.6.3",
43
+ "@nuxt/ui": "^4.5.0",
44
+ "@nuxtjs/mcp-toolkit": "^0.7.0",
45
45
  "@nuxtjs/mdc": "^0.20.1",
46
46
  "@nuxtjs/robots": "^5.7.0",
47
47
  "@octokit/rest": "^22.0.1",
48
- "@openrouter/ai-sdk-provider": "^2.2.1",
49
- "@shikijs/core": "^3.22.0",
50
- "@shikijs/engine-javascript": "^3.22.0",
51
- "@shikijs/langs": "^3.22.0",
52
- "@shikijs/themes": "^3.22.0",
48
+ "@openrouter/ai-sdk-provider": "^2.2.3",
49
+ "@shikijs/core": "^3.23.0",
50
+ "@shikijs/engine-javascript": "^3.23.0",
51
+ "@shikijs/langs": "^3.23.0",
52
+ "@shikijs/themes": "^3.23.0",
53
53
  "@vercel/analytics": "^1.6.1",
54
54
  "@vercel/speed-insights": "^1.3.1",
55
- "@vueuse/core": "^14.2.0",
56
- "@vueuse/nuxt": "^14.2.0",
57
- "ai": "^6.0.78",
55
+ "@vueuse/core": "^14.2.1",
56
+ "@vueuse/nuxt": "^14.2.1",
57
+ "ai": "^6.0.99",
58
58
  "defu": "^6.1.4",
59
59
  "dompurify": "^3.3.1",
60
60
  "exsolve": "^1.0.8",
61
61
  "git-url-parse": "^16.1.0",
62
- "mermaid": "^11.12.2",
63
- "minimark": "^0.2.0",
64
- "motion-v": "^1.10.2",
62
+ "mermaid": "^11.12.3",
63
+ "minimark": "^1.0.0",
64
+ "motion-v": "^2.0.0",
65
65
  "nuxt": "^4.3.1",
66
66
  "nuxt-component-meta": "^0.17.2",
67
67
  "nuxt-llms": "^0.2.0",
@@ -72,11 +72,11 @@
72
72
  "prettier": "^3.8.1",
73
73
  "scule": "^1.3.0",
74
74
  "shiki-stream": "^0.1.4",
75
- "tailwind-merge": "^3.4.0",
76
- "tailwindcss": "^4.1.18",
75
+ "tailwind-merge": "^3.5.0",
76
+ "tailwindcss": "^4.2.1",
77
77
  "ufo": "^1.6.3",
78
78
  "unist-util-visit": "^5.1.0",
79
- "vue-component-meta": "^3.2.4",
79
+ "vue-component-meta": "^3.2.5",
80
80
  "zod": "^4.3.6",
81
81
  "zod-to-json-schema": "^3.25.1"
82
82
  }
@@ -21,7 +21,9 @@ export default defineMcpTool({
21
21
  cache: '30m',
22
22
  handler: async ({ path, sections }) => {
23
23
  const event = useEvent()
24
- const siteUrl = import.meta.dev ? 'http://localhost:3000' : inferSiteURL()
24
+ const siteUrl = import.meta.dev
25
+ ? getRequestURL(event).origin
26
+ : inferSiteURL()
25
27
 
26
28
  try {
27
29
  const page = await queryCollection(event, 'docs')
@@ -1,4 +1,5 @@
1
1
  import { queryCollection } from '@nuxt/content/server'
2
+ import { inferSiteURL } from '../../../utils/meta'
2
3
 
3
4
  export default defineMcpTool({
4
5
  description: `列出所有可用的文档页面及其分类和基本信息。
@@ -22,7 +23,9 @@ export default defineMcpTool({
22
23
  cache: '30m',
23
24
  handler: async () => {
24
25
  const event = useEvent()
25
- const siteUrl = import.meta.dev ? 'http://localhost:3000' : getRequestURL(event).origin
26
+ const siteUrl = import.meta.dev
27
+ ? getRequestURL(event).origin
28
+ : inferSiteURL()
26
29
 
27
30
  try {
28
31
  const pages = await queryCollection(event, 'docs')
@@ -1,5 +1,6 @@
1
1
  import type { H3Event } from 'h3'
2
2
  import type { PageCollectionItemBase } from '@nuxt/content'
3
+ import type { LLMsSection } from 'nuxt-llms'
3
4
 
4
5
  export default defineNitroPlugin((nitroApp) => {
5
6
  nitroApp.hooks.hook('content:llms:generate:document', async (event: H3Event, doc: PageCollectionItemBase) => {
@@ -8,7 +9,7 @@ export default defineNitroPlugin((nitroApp) => {
8
9
 
9
10
  nitroApp.hooks.hook('llms:generate', (_, { sections, domain }) => {
10
11
  // Transform links except for "Documentation Sets"
11
- sections.forEach((section) => {
12
+ sections.forEach((section: LLMsSection) => {
12
13
  if (section.title !== 'Documentation Sets') {
13
14
  section.links = section.links?.map(link => ({
14
15
  ...link,
package/utils/pages.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { joinURL } from 'ufo'
3
+
4
+ /**
5
+ * 检查是否存在 landing page,即 app/pages/index.vue 文件
6
+ */
7
+ export function landingPageExists(rootDir: string): boolean {
8
+ const vueLandingPath = joinURL(rootDir, 'app', 'pages', 'index.vue')
9
+ return existsSync(vueLandingPath)
10
+ }
11
+
12
+ /**
13
+ * 检查是否存在 docs 文件夹,即 content/docs
14
+ */
15
+ export function docsFolderExists(rootDir: string): boolean {
16
+ const docsPath = joinURL(rootDir, 'content', 'docs')
17
+ return existsSync(docsPath)
18
+ }
19
+
20
+ /**
21
+ * 检查是否存在 releases 文件,即 content/releases.md 或 content/releases.yml
22
+ */
23
+ export function releasesFileExists(rootDir: string): boolean {
24
+ return ['releases.md', 'releases.yml'].some(file =>
25
+ existsSync(joinURL(rootDir, 'content', file))
26
+ )
27
+ }
File without changes