docus 5.5.1 → 5.6.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.vue +2 -5
- package/app/error.vue +2 -5
- package/app/utils/navigation.ts +19 -0
- package/content.config.ts +28 -16
- package/modules/assistant/runtime/components/AssistantFloatingInput.vue +4 -4
- package/modules/routing.ts +21 -17
- package/nuxt.config.ts +9 -6
- package/package.json +9 -9
- package/utils/pages.ts +22 -0
package/app/app.vue
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ContentNavigationItem, PageCollections } from '@nuxt/content'
|
|
3
3
|
import * as nuxtUiLocales from '@nuxt/ui/locale'
|
|
4
|
+
import { transformNavigation } from './utils/navigation'
|
|
4
5
|
|
|
5
6
|
const { seo } = useAppConfig()
|
|
6
7
|
const site = useSiteConfig()
|
|
@@ -45,11 +46,7 @@ if (isEnabled.value) {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
const { data: navigation } = await useAsyncData(() => `navigation_${collectionName.value}`, () => queryCollectionNavigation(collectionName.value as keyof PageCollections), {
|
|
48
|
-
transform: (data: ContentNavigationItem[]) =>
|
|
49
|
-
const rootResult = data.find(item => item.path === '/docs')?.children || data || []
|
|
50
|
-
|
|
51
|
-
return rootResult.find((item: ContentNavigationItem) => item.path === `/${locale.value}`)?.children || rootResult
|
|
52
|
-
},
|
|
49
|
+
transform: (data: ContentNavigationItem[]) => transformNavigation(data, isEnabled.value, locale.value),
|
|
53
50
|
watch: [locale],
|
|
54
51
|
})
|
|
55
52
|
const { data: files } = useLazyAsyncData(`search_${collectionName.value}`, () => queryCollectionSearchSections(collectionName.value as keyof PageCollections), {
|
package/app/error.vue
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { NuxtError } from '#app'
|
|
3
3
|
import type { ContentNavigationItem, PageCollections } from '@nuxt/content'
|
|
4
4
|
import * as nuxtUiLocales from '@nuxt/ui/locale'
|
|
5
|
+
import { transformNavigation } from './utils/navigation'
|
|
5
6
|
|
|
6
7
|
const props = defineProps<{
|
|
7
8
|
error: NuxtError
|
|
@@ -47,11 +48,7 @@ if (isEnabled.value) {
|
|
|
47
48
|
const collectionName = computed(() => isEnabled.value ? `docs_${locale.value}` : 'docs')
|
|
48
49
|
|
|
49
50
|
const { data: navigation } = await useAsyncData(`navigation_${collectionName.value}`, () => queryCollectionNavigation(collectionName.value as keyof PageCollections), {
|
|
50
|
-
transform: (data: ContentNavigationItem[]) =>
|
|
51
|
-
const rootResult = data.find(item => item.path === '/docs')?.children || data || []
|
|
52
|
-
|
|
53
|
-
return rootResult.find(item => item.path === `/${locale.value}`)?.children || rootResult
|
|
54
|
-
},
|
|
51
|
+
transform: (data: ContentNavigationItem[]) => transformNavigation(data, isEnabled.value, locale.value),
|
|
55
52
|
watch: [locale],
|
|
56
53
|
})
|
|
57
54
|
const { data: files } = useLazyAsyncData(`search_${collectionName.value}`, () => queryCollectionSearchSections(collectionName.value as keyof PageCollections), {
|
package/app/utils/navigation.ts
CHANGED
|
@@ -6,6 +6,25 @@ export const flattenNavigation = (items?: ContentNavigationItem[]): ContentNavig
|
|
|
6
6
|
: [item],
|
|
7
7
|
) || []
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Transform navigation data by stripping locale and docs levels
|
|
11
|
+
*/
|
|
12
|
+
export function transformNavigation(
|
|
13
|
+
data: ContentNavigationItem[],
|
|
14
|
+
isI18nEnabled: boolean,
|
|
15
|
+
locale?: string,
|
|
16
|
+
): ContentNavigationItem[] {
|
|
17
|
+
if (isI18nEnabled && locale) {
|
|
18
|
+
// i18n: first strip locale level, then check for docs level
|
|
19
|
+
const localeResult = data.find(item => item.path === `/${locale}`)?.children || data
|
|
20
|
+
return localeResult.find(item => item.path === `/${locale}/docs`)?.children || localeResult
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// non-i18n: strip docs level if exists
|
|
24
|
+
return data.find(item => item.path === '/docs')?.children || data
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
export interface BreadcrumbItem {
|
|
10
29
|
title: string
|
|
11
30
|
path: string
|
package/content.config.ts
CHANGED
|
@@ -2,11 +2,15 @@ import type { DefinedCollection } from '@nuxt/content'
|
|
|
2
2
|
import { defineContentConfig, defineCollection, z } from '@nuxt/content'
|
|
3
3
|
import { useNuxt } from '@nuxt/kit'
|
|
4
4
|
import { joinURL } from 'ufo'
|
|
5
|
+
import { landingPageExists, docsFolderExists } from './utils/pages'
|
|
5
6
|
|
|
6
7
|
const { options } = useNuxt()
|
|
7
8
|
const cwd = joinURL(options.rootDir, 'content')
|
|
8
9
|
const locales = options.i18n?.locales
|
|
9
10
|
|
|
11
|
+
const hasLandingPage = landingPageExists(options.rootDir)
|
|
12
|
+
const hasDocsFolder = docsFolderExists(options.rootDir)
|
|
13
|
+
|
|
10
14
|
const createDocsSchema = () => z.object({
|
|
11
15
|
links: z.array(z.object({
|
|
12
16
|
label: z.string(),
|
|
@@ -22,21 +26,24 @@ if (locales && Array.isArray(locales)) {
|
|
|
22
26
|
collections = {}
|
|
23
27
|
for (const locale of locales) {
|
|
24
28
|
const code = (typeof locale === 'string' ? locale : locale.code).replace('-', '_')
|
|
29
|
+
const hasLocaleDocs = docsFolderExists(options.rootDir, code)
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
if (!hasLandingPage) {
|
|
32
|
+
collections[`landing_${code}`] = defineCollection({
|
|
33
|
+
type: 'page',
|
|
34
|
+
source: {
|
|
35
|
+
cwd,
|
|
36
|
+
include: `${code}/index.md`,
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
}
|
|
33
40
|
|
|
34
41
|
collections[`docs_${code}`] = defineCollection({
|
|
35
42
|
type: 'page',
|
|
36
43
|
source: {
|
|
37
44
|
cwd,
|
|
38
|
-
include: `${code}/**/*`,
|
|
39
|
-
prefix: `/${code}`,
|
|
45
|
+
include: hasLocaleDocs ? `${code}/docs/**` : `${code}/**/*`,
|
|
46
|
+
prefix: hasLocaleDocs ? `/${code}/docs` : `/${code}`,
|
|
40
47
|
exclude: [`${code}/index.md`],
|
|
41
48
|
},
|
|
42
49
|
schema: createDocsSchema(),
|
|
@@ -45,22 +52,27 @@ if (locales && Array.isArray(locales)) {
|
|
|
45
52
|
}
|
|
46
53
|
else {
|
|
47
54
|
collections = {
|
|
48
|
-
|
|
55
|
+
docs: defineCollection({
|
|
49
56
|
type: 'page',
|
|
50
57
|
source: {
|
|
51
58
|
cwd,
|
|
52
|
-
include: '
|
|
59
|
+
include: hasDocsFolder ? 'docs/**' : '**',
|
|
60
|
+
prefix: hasDocsFolder ? '/docs' : undefined,
|
|
61
|
+
exclude: ['index.md'],
|
|
53
62
|
},
|
|
63
|
+
schema: createDocsSchema(),
|
|
54
64
|
}),
|
|
55
|
-
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Only define landing collection if user doesn't have their own index.vue
|
|
68
|
+
if (!hasLandingPage) {
|
|
69
|
+
collections.landing = defineCollection({
|
|
56
70
|
type: 'page',
|
|
57
71
|
source: {
|
|
58
72
|
cwd,
|
|
59
|
-
include: '
|
|
60
|
-
exclude: ['index.md'],
|
|
73
|
+
include: 'index.md',
|
|
61
74
|
},
|
|
62
|
-
|
|
63
|
-
}),
|
|
75
|
+
})
|
|
64
76
|
}
|
|
65
77
|
}
|
|
66
78
|
|
|
@@ -18,7 +18,7 @@ const placeholder = computed(() => t('assistant.placeholder'))
|
|
|
18
18
|
const shortcutDisplayKeys = computed(() => {
|
|
19
19
|
const shortcut = focusInputShortcut.value
|
|
20
20
|
const parts = shortcut.split('_')
|
|
21
|
-
return parts.map(part => part === 'meta' ? 'meta' : part.toUpperCase())
|
|
21
|
+
return parts.map((part: string) => part === 'meta' ? 'meta' : part.toUpperCase())
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
function handleSubmit() {
|
|
@@ -62,14 +62,14 @@ defineShortcuts(shortcuts)
|
|
|
62
62
|
:animate="{ y: 0, opacity: 1 }"
|
|
63
63
|
:exit="{ y: 100, opacity: 0 }"
|
|
64
64
|
:transition="{ duration: 0.2, ease: 'easeOut' }"
|
|
65
|
-
class="fixed inset-x-0 z-10
|
|
65
|
+
class="pointer-events-none fixed inset-x-0 z-10 bottom-[max(1.5rem,env(safe-area-inset-bottom))] px-4 sm:px-80"
|
|
66
66
|
style="will-change: transform"
|
|
67
67
|
>
|
|
68
68
|
<form
|
|
69
|
-
class="flex w-full justify-center"
|
|
69
|
+
class="pointer-events-none flex w-full justify-center"
|
|
70
70
|
@submit.prevent="handleSubmit"
|
|
71
71
|
>
|
|
72
|
-
<div class="w-full max-w-96">
|
|
72
|
+
<div class="pointer-events-auto w-full max-w-96">
|
|
73
73
|
<UInput
|
|
74
74
|
ref="inputRef"
|
|
75
75
|
v-model="input"
|
package/modules/routing.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineNuxtModule, extendPages, createResolver } from '@nuxt/kit'
|
|
2
|
+
import { landingPageExists } from '../utils/pages'
|
|
2
3
|
|
|
3
4
|
export default defineNuxtModule({
|
|
4
5
|
meta: {
|
|
@@ -19,23 +20,26 @@ export default defineNuxtModule({
|
|
|
19
20
|
})
|
|
20
21
|
})
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
// Only add landing if index.vue is not already defined
|
|
24
|
+
if (!landingPageExists(nuxt.options.rootDir)) {
|
|
25
|
+
extendPages((pages) => {
|
|
26
|
+
const landingTemplate = resolve('../app/templates/landing.vue')
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
if (isI18nEnabled) {
|
|
29
|
+
pages.push({
|
|
30
|
+
name: 'lang-index',
|
|
31
|
+
path: '/:lang?',
|
|
32
|
+
file: landingTemplate,
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
pages.push({
|
|
37
|
+
name: 'index',
|
|
38
|
+
path: '/',
|
|
39
|
+
file: landingTemplate,
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
40
44
|
},
|
|
41
45
|
})
|
package/nuxt.config.ts
CHANGED
|
@@ -20,14 +20,16 @@ export default defineNuxtConfig({
|
|
|
20
20
|
extendViteConfig((config) => {
|
|
21
21
|
config.optimizeDeps ||= {}
|
|
22
22
|
config.optimizeDeps.include ||= []
|
|
23
|
-
config.optimizeDeps.include.push(
|
|
24
|
-
'@nuxt/content > slugify',
|
|
25
|
-
// Fix @vercel/oidc ESM export issue (transitive dep of @ai-sdk/gateway)
|
|
26
|
-
'@vercel/oidc',
|
|
27
|
-
)
|
|
23
|
+
config.optimizeDeps.include.push('@nuxt/content > slugify')
|
|
28
24
|
config.optimizeDeps.include = config.optimizeDeps.include
|
|
29
25
|
.map(id => id.replace(/^@nuxt\/content > /, 'docus > @nuxt/content > '))
|
|
30
|
-
|
|
26
|
+
|
|
27
|
+
// Fix @vercel/oidc ESM export issue (transitive dep of @ai-sdk/gateway)
|
|
28
|
+
// Only needed when AI assistant is enabled.
|
|
29
|
+
if (process.env.AI_GATEWAY_API_KEY) {
|
|
30
|
+
config.optimizeDeps.include.push('@vercel/oidc')
|
|
31
|
+
config.optimizeDeps.include.map(id => id.replace(/^@vercel\/oidc$/, 'docus > @vercel/oidc'))
|
|
32
|
+
}
|
|
31
33
|
})
|
|
32
34
|
},
|
|
33
35
|
],
|
|
@@ -35,6 +37,7 @@ export default defineNuxtConfig({
|
|
|
35
37
|
enabled: true,
|
|
36
38
|
},
|
|
37
39
|
content: {
|
|
40
|
+
experimental: { sqliteConnector: 'native' },
|
|
38
41
|
build: {
|
|
39
42
|
markdown: {
|
|
40
43
|
highlight: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docus",
|
|
3
3
|
"description": "Nuxt layer for Docus documentation theme",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.6.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -22,22 +22,22 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@ai-sdk/gateway": "^3.0.
|
|
26
|
-
"@ai-sdk/mcp": "^1.0.
|
|
27
|
-
"@ai-sdk/vue": "3.0.
|
|
28
|
-
"@iconify-json/lucide": "^1.2.
|
|
29
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
30
|
-
"@iconify-json/vscode-icons": "^1.2.
|
|
25
|
+
"@ai-sdk/gateway": "^3.0.46",
|
|
26
|
+
"@ai-sdk/mcp": "^1.0.21",
|
|
27
|
+
"@ai-sdk/vue": "3.0.86",
|
|
28
|
+
"@iconify-json/lucide": "^1.2.91",
|
|
29
|
+
"@iconify-json/simple-icons": "^1.2.71",
|
|
30
|
+
"@iconify-json/vscode-icons": "^1.2.43",
|
|
31
31
|
"@nuxt/content": "^3.11.2",
|
|
32
32
|
"@nuxt/image": "^2.0.0",
|
|
33
33
|
"@nuxt/kit": "^4.3.1",
|
|
34
34
|
"@nuxt/ui": "^4.4.0",
|
|
35
35
|
"@nuxtjs/i18n": "^10.2.3",
|
|
36
|
-
"@nuxtjs/mcp-toolkit": "^0.
|
|
36
|
+
"@nuxtjs/mcp-toolkit": "^0.7.0",
|
|
37
37
|
"@nuxtjs/mdc": "^0.20.1",
|
|
38
38
|
"@nuxtjs/robots": "^5.7.0",
|
|
39
39
|
"@vueuse/core": "^14.2.1",
|
|
40
|
-
"ai": "6.0.
|
|
40
|
+
"ai": "6.0.86",
|
|
41
41
|
"defu": "^6.1.4",
|
|
42
42
|
"exsolve": "^1.0.8",
|
|
43
43
|
"git-url-parse": "^16.1.0",
|
package/utils/pages.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { joinURL } from 'ufo'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks if the user has their own index.vue file in the pages folder.
|
|
6
|
+
* When true, the layer should not define the landing collection and / route.
|
|
7
|
+
*/
|
|
8
|
+
export function landingPageExists(rootDir: string): boolean {
|
|
9
|
+
const vueLandingPath = joinURL(rootDir, 'app', 'pages', 'index.vue')
|
|
10
|
+
return existsSync(vueLandingPath)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Checks if a docs folder exists in the content directory.
|
|
15
|
+
* When true, docs should be prefixed with /docs and only include files from the docs folder.
|
|
16
|
+
*/
|
|
17
|
+
export function docsFolderExists(rootDir: string, locale?: string): boolean {
|
|
18
|
+
const docsPath = locale
|
|
19
|
+
? joinURL(rootDir, 'content', locale, 'docs')
|
|
20
|
+
: joinURL(rootDir, 'content', 'docs')
|
|
21
|
+
return existsSync(docsPath)
|
|
22
|
+
}
|