@movk/nuxt-docs 1.8.0 → 1.8.1

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 CHANGED
@@ -108,8 +108,7 @@ export default defineAppConfig({
108
108
  streaming: 'i-lucide-chevron-down',
109
109
  providers: {
110
110
  mistral: 'i-simple-icons-mistralai',
111
- kwaipilot: 'i-lucide-wand',
112
- zai: 'i-lucide-wand'
111
+ kwaipilot: 'i-lucide-wand'
113
112
  }
114
113
  }
115
114
  }
@@ -81,10 +81,11 @@ const diagramRef = ref<HTMLElement | null>(null)
81
81
  const isRendered = ref(false)
82
82
  const hasError = ref(false)
83
83
  const errorMessage = ref('')
84
+ const hasBeenVisible = ref(false)
84
85
 
85
86
  const [isFullscreen, toggleFullscreen] = useToggle(false)
86
87
  const { copy, copied } = useClipboard({ source: () => props.code })
87
- const isVisible = useElementVisibility(containerRef)
88
+ const isVisible = useElementVisibility(containerRef, { threshold: 0.1 })
88
89
 
89
90
  async function renderMermaid() {
90
91
  if (!props.code || isRendered.value || !diagramRef.value) return
@@ -127,7 +128,11 @@ async function reRender() {
127
128
  watch(
128
129
  [isVisible, diagramRef],
129
130
  ([visible, el]) => {
130
- if (visible && el && !isRendered.value) {
131
+ // 记录曾经可见状态,避免快速滚动时错过渲染
132
+ if (visible) {
133
+ hasBeenVisible.value = true
134
+ }
135
+ if (hasBeenVisible.value && el && !isRendered.value) {
131
136
  renderMermaid()
132
137
  }
133
138
  },
@@ -22,7 +22,7 @@ export interface AiChatModuleOptions {
22
22
  */
23
23
  mcpPath?: string
24
24
  /**
25
- * 通过 AI SDK Gateway 、OpenRouter 使用的 AI 模型
25
+ * 使用的 AI 模型
26
26
  */
27
27
  model?: string
28
28
  /**
@@ -46,7 +46,7 @@ export default defineNuxtModule<AiChatModuleOptions>({
46
46
  models: []
47
47
  },
48
48
  setup(options, nuxt) {
49
- const hasApiKey = !!(process.env.AI_GATEWAY_API_KEY || process.env.OPENROUTER_API_KEY)
49
+ const hasApiKey = !!(process.env.AI_GATEWAY_API_KEY || process.env.OPENROUTER_API_KEY || process.env.ZHIPU_API_KEY)
50
50
 
51
51
  const { resolve } = createResolver(import.meta.url)
52
52
 
@@ -77,7 +77,7 @@ export default defineNuxtModule<AiChatModuleOptions>({
77
77
  }
78
78
 
79
79
  if (!hasApiKey) {
80
- log.warn('[ai-chat] Module disabled: no AI_GATEWAY_API_KEY or OPENROUTER_API_KEY found')
80
+ log.warn('[ai-chat] Module disabled: no API key found in environment variables.')
81
81
  return
82
82
  }
83
83
 
@@ -1,23 +1,29 @@
1
1
  import { createGateway } from '@ai-sdk/gateway'
2
2
  import { createOpenRouter } from '@openrouter/ai-sdk-provider'
3
+ import { modelProviderRegistry } from './modelProviders'
4
+
5
+ modelProviderRegistry.register('openrouter', ({ config, modelId }) => {
6
+ const openRouter = createOpenRouter({
7
+ apiKey: config.openRouterApiKey as string | undefined
8
+ })
9
+ return openRouter.chat(modelId)
10
+ })
3
11
 
4
12
  /**
5
13
  * 获取 AI 模型实例
6
- * @param modelId - 模型标识符,格式为 "provider/model" 或 "model"
7
- * @returns AI SDK 模型实例
14
+ * 优先使用注册的提供商,否则回退到 AI Gateway
8
15
  */
9
16
  export function getModel(modelId: string) {
10
17
  const config = useRuntimeConfig()
18
+ const parsed = modelProviderRegistry.parseModelId(modelId)
11
19
 
12
- // OpenRouter 模型:以 "openrouter/" 开头
13
- if (modelId.startsWith('openrouter/')) {
14
- const openRouter = createOpenRouter({
15
- apiKey: config.openRouterApiKey as string | undefined
16
- })
17
- return openRouter.chat(modelId.replace('openrouter/', ''))
20
+ if (parsed) {
21
+ const factory = modelProviderRegistry.get(parsed.prefix)
22
+ if (factory) {
23
+ return factory({ config, modelId: parsed.modelId })
24
+ }
18
25
  }
19
26
 
20
- // AI Gateway 模型(默认)
21
27
  const gateway = createGateway({
22
28
  apiKey: config.aiGatewayApiKey as string | undefined
23
29
  })
@@ -0,0 +1,34 @@
1
+ import type { LanguageModel } from 'ai'
2
+
3
+ export interface ModelProviderContext {
4
+ config: ReturnType<typeof useRuntimeConfig>
5
+ modelId: string
6
+ }
7
+
8
+ export type ModelProviderFactory = (context: ModelProviderContext) => LanguageModel
9
+
10
+ /**
11
+ * 模型提供商注册表
12
+ */
13
+ class ModelProviderRegistry {
14
+ private providers = new Map<string, ModelProviderFactory>()
15
+
16
+ register(prefix: string, factory: ModelProviderFactory): void {
17
+ this.providers.set(prefix, factory)
18
+ }
19
+
20
+ get(prefix: string): ModelProviderFactory | undefined {
21
+ return this.providers.get(prefix)
22
+ }
23
+
24
+ parseModelId(modelId: string): { prefix: string, modelId: string } | null {
25
+ const separatorIndex = modelId.indexOf('/')
26
+ if (separatorIndex === -1) return null
27
+ return {
28
+ prefix: modelId.slice(0, separatorIndex),
29
+ modelId: modelId.slice(separatorIndex + 1)
30
+ }
31
+ }
32
+ }
33
+
34
+ export const modelProviderRegistry = new ModelProviderRegistry()
package/modules/config.ts CHANGED
@@ -10,6 +10,9 @@ export default defineNuxtModule({
10
10
  },
11
11
  async setup(_options, nuxt) {
12
12
  const { resolve } = createResolver(import.meta.url)
13
+
14
+ nuxt.options.alias['#ai-chat'] = resolve('./ai-chat/runtime')
15
+
13
16
  const dir = nuxt.options.rootDir
14
17
  const url = inferSiteURL()
15
18
  const meta = await getPackageJsonMetadata(dir)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@movk/nuxt-docs",
3
3
  "type": "module",
4
- "version": "1.8.0",
4
+ "version": "1.8.1",
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>",
@@ -28,9 +28,9 @@
28
28
  "README.md"
29
29
  ],
30
30
  "dependencies": {
31
- "@ai-sdk/gateway": "^3.0.17",
31
+ "@ai-sdk/gateway": "^3.0.19",
32
32
  "@ai-sdk/mcp": "^1.0.11",
33
- "@ai-sdk/vue": "^3.0.42",
33
+ "@ai-sdk/vue": "^3.0.45",
34
34
  "@iconify-json/lucide": "^1.2.86",
35
35
  "@iconify-json/ph": "^1.2.2",
36
36
  "@iconify-json/simple-icons": "^1.2.67",
@@ -41,7 +41,7 @@
41
41
  "@nuxt/content": "^3.11.0",
42
42
  "@nuxt/image": "^2.0.0",
43
43
  "@nuxt/kit": "^4.2.2",
44
- "@nuxt/ui": "^4.3.0",
44
+ "@nuxt/ui": "^4.4.0",
45
45
  "@nuxtjs/mcp-toolkit": "^0.6.2",
46
46
  "@nuxtjs/seo": "^3.3.0",
47
47
  "@octokit/rest": "^22.0.1",
@@ -50,9 +50,9 @@
50
50
  "@vercel/speed-insights": "^1.3.1",
51
51
  "@vueuse/core": "^14.1.0",
52
52
  "@vueuse/nuxt": "^14.1.0",
53
- "ai": "^6.0.42",
53
+ "ai": "^6.0.45",
54
54
  "defu": "^6.1.4",
55
- "dompurify": "^3.2.6",
55
+ "dompurify": "^3.3.1",
56
56
  "exsolve": "^1.0.8",
57
57
  "git-url-parse": "^16.1.0",
58
58
  "mermaid": "^11.12.2",
@@ -63,7 +63,7 @@
63
63
  "ohash": "^2.0.11",
64
64
  "pathe": "^2.0.3",
65
65
  "pkg-types": "^2.3.0",
66
- "prettier": "^3.8.0",
66
+ "prettier": "^3.8.1",
67
67
  "scule": "^1.3.0",
68
68
  "shiki": "^3.21.0",
69
69
  "shiki-stream": "^0.1.4",