@movk/nuxt-docs 1.15.0 → 1.16.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 CHANGED
@@ -189,7 +189,10 @@ pnpm add mermaid dompurify
189
189
  ```ts [nuxt.config.ts]
190
190
  export default defineNuxtConfig({
191
191
  extends: ['@movk/nuxt-docs'],
192
- mermaid: { enabled: true }
192
+
193
+ movkNuxtDocs: {
194
+ mermaid: true
195
+ }
193
196
  })
194
197
  ```
195
198
 
@@ -225,6 +228,20 @@ graph TD
225
228
  - **Git 图**(`gitGraph`):用于展示分支历史
226
229
  - 以及更多 [Mermaid 支持的图表类型](https://mermaid.js.org/intro())
227
230
 
231
+ ### 无障碍支持(A11y)
232
+
233
+ Movk Nuxt Docs 默认启用 `@nuxt/a11y`。如需关闭,可在 `movkNuxtDocs` 中设置:
234
+
235
+ ```ts [nuxt.config.ts]
236
+ export default defineNuxtConfig({
237
+ extends: ['@movk/nuxt-docs'],
238
+
239
+ movkNuxtDocs: {
240
+ a11y: false
241
+ }
242
+ })
243
+ ```
244
+
228
245
  ## 🛠️ 开发
229
246
 
230
247
  ### 本地开发
@@ -11,10 +11,7 @@ withDefaults(defineProps<{
11
11
  </script>
12
12
 
13
13
  <template>
14
- <div
15
- style="font-family: 'Public Sans', 'Noto Sans SC', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;"
16
- class="w-full h-full flex flex-col justify-center items-center relative p-10 lg:p-15 bg-white text-neutral-900 dark:bg-neutral-900 dark:text-neutral-50"
17
- >
14
+ <div style="font-family: 'Noto Sans SC', sans-serif;" class="w-full h-full flex flex-col justify-center items-center relative p-10 lg:p-15 bg-white text-neutral-900 dark:bg-neutral-900 dark:text-neutral-50">
18
15
  <div
19
16
  class="absolute top-0 left-0 right-0 bottom-0"
20
17
  :style="{
@@ -82,7 +79,10 @@ withDefaults(defineProps<{
82
79
  </h1>
83
80
  </div>
84
81
 
85
- <p v-if="description" class="text-slate-500 text-[24px] lg:text-[32px] opacity-70 max-w-162.5 lg:max-w-225 leading-normal">
82
+ <p
83
+ v-if="description"
84
+ class="text-slate-500 text-[24px] lg:text-[32px] opacity-70 max-w-162.5 lg:max-w-225 leading-normal"
85
+ >
86
86
  {{ description }}
87
87
  </p>
88
88
  </div>
package/modules/config.ts CHANGED
@@ -1,27 +1,9 @@
1
- import { existsSync } from 'node:fs'
2
1
  import { createResolver, defineNuxtModule } from '@nuxt/kit'
3
2
  import { defu } from 'defu'
4
- import { join } from 'pathe'
5
3
  import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git'
6
4
  import { getPackageJsonMetadata, inferSiteURL } from '../utils/meta'
7
5
  import { createComponentMetaExcludeFilters } from '../utils/component-meta'
8
6
 
9
- function getMdcConfigSources(nuxt: any): string[] {
10
- return nuxt.options._layers.flatMap((layer: any) => {
11
- const tsConfigPath = join(layer.config.srcDir, 'mdc.config.ts')
12
- if (existsSync(tsConfigPath)) {
13
- return [tsConfigPath]
14
- }
15
-
16
- const jsConfigPath = join(layer.config.srcDir, 'mdc.config.js')
17
- if (existsSync(jsConfigPath)) {
18
- return [jsConfigPath]
19
- }
20
-
21
- return []
22
- })
23
- }
24
-
25
7
  export default defineNuxtModule({
26
8
  meta: {
27
9
  name: 'config'
@@ -91,10 +73,12 @@ export default defineNuxtModule({
91
73
  ]
92
74
  })
93
75
 
94
- // Load mdc.config from all layers
95
- const mdcConfigSources = getMdcConfigSources(nuxt)
96
- if (mdcConfigSources.length > 0) {
97
- await nuxt.callHook('mdc:configSources', mdcConfigSources)
98
- }
76
+ nuxt.hook('nitro:config', (nitroConfig) => {
77
+ nitroConfig.publicAssets ||= []
78
+ nitroConfig.publicAssets.push({
79
+ dir: resolve('./runtime/public'),
80
+ maxAge: 60 * 60 * 24 * 30
81
+ })
82
+ })
99
83
  }
100
84
  })
@@ -0,0 +1,103 @@
1
+ import { addComponentsDir, createResolver, defineNuxtModule, logger } from '@nuxt/kit'
2
+ import type { ModuleDependencies } from 'nuxt/schema'
3
+
4
+ export interface ModuleOptions {
5
+ /**
6
+ * 是否启用 @nuxt/a11y 无障碍支持
7
+ * @defaultValue true
8
+ * @see https://a11y.nuxtjs.org/
9
+ */
10
+ a11y?: boolean
11
+ /**
12
+ * 是否启用 Mermaid 图表支持
13
+ * - 启用前需安装依赖: `pnpm add mermaid dompurify`
14
+ * @defaultValue false
15
+ */
16
+ mermaid?: boolean
17
+ }
18
+
19
+ const log = logger.withTag('movk-nuxt-docs')
20
+
21
+ export default defineNuxtModule<ModuleOptions>({
22
+ meta: {
23
+ name: 'movk-nuxt-docs',
24
+ configKey: 'movkNuxtDocs'
25
+ },
26
+ defaults: {
27
+ a11y: true,
28
+ mermaid: false
29
+ },
30
+ moduleDependencies(nuxt): ModuleDependencies {
31
+ const userOptions = nuxt.options.movkNuxtDocs || {}
32
+ return {
33
+ ...userOptions.a11y !== false && {
34
+ '@nuxt/a11y': {
35
+ version: '^1.0.0-alpha.1'
36
+ }
37
+ }
38
+ }
39
+ },
40
+ setup(options, nuxt) {
41
+ const { resolve } = createResolver(import.meta.url)
42
+
43
+ if (options.mermaid) {
44
+ let mermaidAvailable = true
45
+ try {
46
+ import.meta.resolve('mermaid')
47
+ } catch {
48
+ log.warn('mermaid package not found. install it with: pnpm add mermaid dompurify')
49
+ mermaidAvailable = false
50
+ }
51
+
52
+ if (mermaidAvailable) {
53
+ addComponentsDir({
54
+ path: resolve('./runtime/components/prose'),
55
+ pathPrefix: false,
56
+ prefix: 'Prose',
57
+ global: true
58
+ })
59
+
60
+ // 添加 mermaid 语言高亮
61
+ const contentOptions = nuxt.options.content as Record<string, any> | false
62
+ if (contentOptions) {
63
+ const build = contentOptions.build ??= {}
64
+ const markdown = build.markdown ??= {}
65
+ const highlight = markdown.highlight ??= {}
66
+ const langs = highlight.langs ??= [] as string[]
67
+ if (!langs.includes('mermaid')) {
68
+ langs.push('mermaid')
69
+ }
70
+ }
71
+
72
+ // 为 mermaid ESM 兼容性配置 optimizeDeps
73
+ nuxt.hooks.hook('vite:extendConfig', (config) => {
74
+ const cfg = config as { optimizeDeps?: { include?: string[] } }
75
+ cfg.optimizeDeps ??= {}
76
+ cfg.optimizeDeps.include ??= []
77
+ cfg.optimizeDeps.include.push(
78
+ '@movk/nuxt-docs > mermaid',
79
+ '@movk/nuxt-docs > mermaid > dayjs',
80
+ '@movk/nuxt-docs > mermaid > @braintree/sanitize-url',
81
+ '@movk/nuxt-docs > mermaid > d3',
82
+ '@movk/nuxt-docs > mermaid > dompurify'
83
+ )
84
+ })
85
+
86
+ // 注入 mermaid 代码图标配置到 appConfig
87
+ const appConfig = nuxt.options.appConfig as Record<string, any>
88
+ appConfig.ui ??= {}
89
+ appConfig.ui.prose ??= {}
90
+ appConfig.ui.prose.codeIcon ??= {}
91
+ appConfig.ui.prose.codeIcon.mmd ??= 'i-vscode-icons-file-type-mermaid'
92
+
93
+ log.info('mermaid diagram support enabled')
94
+ }
95
+ }
96
+ }
97
+ })
98
+
99
+ declare module 'nuxt/schema' {
100
+ interface NuxtConfig {
101
+ movkNuxtDocs?: ModuleOptions
102
+ }
103
+ }
@@ -1,16 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  import type { ProsePreProps } from '@nuxt/ui'
3
- // @ts-ignore
3
+ // @ts-ignore - #build alias only available at Nuxt build time
4
4
  import NuxtUIProsePre from '@nuxt/ui/components/prose/Pre.vue'
5
5
 
6
6
  const props = defineProps<ProsePreProps>()
7
7
 
8
- const isMermaid = computed(() => props.language === 'mermaid')
9
-
10
- // 动态解析 Mermaid 组件(仅在 mermaid 模块启用时可用)
11
8
  const MermaidComponent = computed(() => {
12
- if (!isMermaid.value) return null
13
- const resolved = resolveComponent('Mermaid')
9
+ if (props.language !== 'mermaid') return null
10
+ const resolved = resolveComponent('ProseMermaid')
14
11
  return typeof resolved === 'string' ? null : resolved
15
12
  })
16
13
  </script>
@@ -18,11 +15,12 @@ const MermaidComponent = computed(() => {
18
15
  <template>
19
16
  <component
20
17
  :is="MermaidComponent"
21
- v-if="isMermaid && MermaidComponent"
18
+ v-if="MermaidComponent"
22
19
  :code="props.code || ''"
23
20
  :filename="props.filename"
24
21
  :icon="props.icon"
25
22
  />
23
+
26
24
  <NuxtUIProsePre v-else v-bind="props">
27
25
  <slot />
28
26
  </NuxtUIProsePre>
package/nuxt.config.ts CHANGED
@@ -20,7 +20,6 @@ export default defineNuxtConfig({
20
20
  '@nuxt/fonts',
21
21
  '@nuxt/content',
22
22
  '@nuxt/image',
23
- '@nuxt/a11y',
24
23
  '@nuxtjs/robots',
25
24
  '@nuxtjs/mcp-toolkit',
26
25
  '@vueuse/nuxt',
@@ -172,10 +171,9 @@ export default defineNuxtConfig({
172
171
  },
173
172
 
174
173
  fonts: {
175
- provider: 'bunny',
176
174
  families: [
177
- { name: 'Public Sans', global: true, fallbacks: ['Noto Sans SC', 'sans-serif'] },
178
- { name: 'Noto Sans SC', global: true }
175
+ { name: 'Public Sans', global: true, provider: 'bunny' },
176
+ { name: 'Noto Sans SC', global: true, provider: 'local' }
179
177
  ]
180
178
  },
181
179
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@movk/nuxt-docs",
3
3
  "type": "module",
4
- "version": "1.15.0",
4
+ "version": "1.16.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>",
@@ -39,10 +39,10 @@
39
39
  "README.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@ai-sdk/gateway": "^3.0.79",
42
+ "@ai-sdk/gateway": "^3.0.83",
43
43
  "@ai-sdk/mcp": "^1.0.30",
44
- "@ai-sdk/vue": "^3.0.137",
45
- "@iconify-json/lucide": "^1.2.98",
44
+ "@ai-sdk/vue": "^3.0.140",
45
+ "@iconify-json/lucide": "^1.2.100",
46
46
  "@iconify-json/simple-icons": "^1.2.75",
47
47
  "@iconify-json/vscode-icons": "^1.2.45",
48
48
  "@movk/core": "^1.2.2",
@@ -52,8 +52,8 @@
52
52
  "@nuxt/kit": "^4.4.2",
53
53
  "@nuxt/ui": "^4.6.0",
54
54
  "@nuxtjs/mcp-toolkit": "^0.12.0",
55
- "@nuxtjs/mdc": "^0.20.2",
56
- "@nuxtjs/robots": "^5.7.1",
55
+ "@nuxtjs/mdc": "^0.21.0",
56
+ "@nuxtjs/robots": "^6.0.6",
57
57
  "@octokit/rest": "^22.0.1",
58
58
  "@shikijs/core": "^4.0.2",
59
59
  "@shikijs/engine-javascript": "^4.0.2",
@@ -63,14 +63,14 @@
63
63
  "@takumi-rs/wasm": "^0.73.1",
64
64
  "@vueuse/core": "^14.2.1",
65
65
  "@vueuse/nuxt": "^14.2.1",
66
- "ai": "^6.0.137",
66
+ "ai": "^6.0.141",
67
67
  "defu": "^6.1.4",
68
68
  "exsolve": "^1.0.8",
69
69
  "git-url-parse": "^16.1.0",
70
70
  "motion-v": "^2.2.0",
71
71
  "nuxt-component-meta": "^0.17.2",
72
72
  "nuxt-llms": "^0.2.0",
73
- "nuxt-og-image": "^6.1.2",
73
+ "nuxt-og-image": "^6.2.6",
74
74
  "ohash": "^2.0.11",
75
75
  "pathe": "^2.0.3",
76
76
  "pkg-types": "^2.3.0",
@@ -52,11 +52,7 @@ export function createComponentMetaExcludeFilters(
52
52
  resolve('../app/components/content/ComponentProps.vue'),
53
53
  resolve('../app/components/content/ComponentSlots.vue'),
54
54
  resolve('../app/components/content/PageLastCommit.vue'),
55
- resolve('../app/components/content/Mermaid.vue'),
56
- resolve('./ai-chat/runtime/components/AiChatToolCall.vue'),
57
- resolve('./ai-chat/runtime/components/AiChatReasoning.vue'),
58
- resolve('./ai-chat/runtime/components/AiChatSlideoverFaq.vue'),
59
- resolve('./ai-chat/runtime/components/AiChatPreStream.vue')
55
+ resolve('./runtime/components/prose/Mermaid.vue')
60
56
  ]
61
57
 
62
58
  const userComponentPaths = [
@@ -1,93 +0,0 @@
1
- import { createResolver, defineNuxtModule, logger } from '@nuxt/kit'
2
-
3
- export interface MermaidModuleOptions {
4
- /**
5
- * 是否启用 Mermaid 图表支持
6
- *
7
- * 启用前需安装依赖: `pnpm add mermaid dompurify`
8
- * @default false
9
- */
10
- enabled?: boolean
11
- }
12
-
13
- const log = logger.withTag('movk-nuxt-docs')
14
-
15
- export default defineNuxtModule<MermaidModuleOptions>({
16
- meta: {
17
- name: 'mermaid',
18
- configKey: 'mermaid'
19
- },
20
- defaults: {
21
- enabled: false
22
- },
23
- setup(options, nuxt) {
24
- const { resolve } = createResolver(import.meta.url)
25
- const mermaidFilePath = resolve('../app/components/content/Mermaid.vue')
26
-
27
- // Layer 自动扫描会注册 Mermaid.vue,通过 components:extend 统一管理:
28
- // - 禁用时:从列表移除,resolveComponent('Mermaid') 返回字符串,ProsePre fallback 到普通代码块
29
- // - 启用时:将 mode 改为 'client',避免 SSR 阶段执行
30
- nuxt.hooks.hook('components:extend', (components) => {
31
- const idx = components.findIndex(c => c.filePath === mermaidFilePath)
32
- if (idx === -1) return
33
-
34
- if (!options.enabled) {
35
- components.splice(idx, 1)
36
- return
37
- }
38
-
39
- components[idx]!.mode = 'client'
40
- })
41
-
42
- if (!options.enabled) return
43
-
44
- // 验证 mermaid 依赖是否已安装
45
- try {
46
- import.meta.resolve('mermaid')
47
- } catch {
48
- log.warn('[mermaid] `mermaid` package not found. Install it with: pnpm add mermaid dompurify')
49
- return
50
- }
51
-
52
- // 添加 mermaid 语言高亮
53
- const contentOptions = nuxt.options.content as Record<string, any> | false
54
- if (contentOptions) {
55
- const build = contentOptions.build ??= {}
56
- const markdown = build.markdown ??= {}
57
- const highlight = markdown.highlight ??= {}
58
- const langs = highlight.langs ??= [] as string[]
59
- if (!langs.includes('mermaid')) {
60
- langs.push('mermaid')
61
- }
62
- }
63
-
64
- // 为 mermaid ESM 兼容性配置 optimizeDeps
65
- nuxt.hooks.hook('vite:extendConfig', (config) => {
66
- const cfg = config as { optimizeDeps?: { include?: string[] } }
67
- cfg.optimizeDeps ??= {}
68
- cfg.optimizeDeps.include ??= []
69
- cfg.optimizeDeps.include.push(
70
- '@movk/nuxt-docs > mermaid',
71
- '@movk/nuxt-docs > mermaid > dayjs',
72
- '@movk/nuxt-docs > mermaid > @braintree/sanitize-url',
73
- '@movk/nuxt-docs > mermaid > d3',
74
- '@movk/nuxt-docs > mermaid > dompurify'
75
- )
76
- })
77
-
78
- // 注入 mermaid 代码图标配置到 appConfig
79
- const appConfig = nuxt.options.appConfig as Record<string, any>
80
- appConfig.ui ??= {}
81
- appConfig.ui.prose ??= {}
82
- appConfig.ui.prose.codeIcon ??= {}
83
- appConfig.ui.prose.codeIcon.mmd ??= 'i-vscode-icons-file-type-mermaid'
84
-
85
- log.info('[mermaid] Mermaid diagram support enabled')
86
- }
87
- })
88
-
89
- declare module 'nuxt/schema' {
90
- interface NuxtConfig {
91
- mermaid?: MermaidModuleOptions
92
- }
93
- }