undocs 0.4.10 → 0.4.12

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
@@ -4,6 +4,8 @@ export default defineAppConfig({
4
4
  logo: '/icon.svg',
5
5
  github: undefined,
6
6
  socials: {},
7
+ banner: {},
8
+ versions: [],
7
9
  },
8
10
  ui: {
9
11
  colors: {
package/app/app.vue CHANGED
@@ -1,4 +1,6 @@
1
1
  <script setup lang="ts">
2
+ import type { BannerProps } from '@nuxt/ui'
3
+
2
4
  const appConfig = useAppConfig()
3
5
 
4
6
  const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('content'))
@@ -52,6 +54,7 @@ provide('navigation', navigation)
52
54
  <template>
53
55
  <UApp>
54
56
  <NuxtLoadingIndicator color="var(--ui-primary)" />
57
+ <UBanner v-if="appConfig.docs.banner?.title" v-bind="appConfig.docs.banner as BannerProps" />
55
58
  <AppHeader />
56
59
 
57
60
  <UMain>
@@ -41,11 +41,18 @@ const mobileLinks = computed(() => {
41
41
 
42
42
  <template>
43
43
  <UHeader to="/">
44
- <template #title>
45
- <img :src="appConfig.docs.logo" :alt="`${appConfig.site.name} logo`" class="h-7 w-7" />
46
- <span>
47
- {{ appConfig.site.name }}
48
- </span>
44
+ <template #left>
45
+ <NuxtLink
46
+ to="/"
47
+ class="focus-visible:outline-primary shrink-0 font-bold text-xl text-highlighted flex items-end gap-1.5"
48
+ :aria-label="appConfig.site.name"
49
+ >
50
+ <img :src="appConfig.docs.logo" :alt="`${appConfig.site.name} logo`" class="h-7 w-7" />
51
+ <span>
52
+ {{ appConfig.site.name }}
53
+ </span>
54
+ </NuxtLink>
55
+ <AppHeaderVersionsMenu v-if="appConfig.docs.versions?.length" />
49
56
  </template>
50
57
 
51
58
  <UNavigationMenu v-if="headerLinks.length > 1" :items="headerLinks" variant="link" />
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ const appConfig = useAppConfig()
3
+
4
+ const activeVersion = computed(() => {
5
+ return appConfig.docs.versions.find((version) => version.active) || appConfig.docs.versions[0]
6
+ })
7
+ const items = computed(() => {
8
+ return appConfig.docs.versions.map((version) => {
9
+ if (activeVersion.value === version) {
10
+ return {
11
+ label: version.label,
12
+ type: 'checkbox' as const,
13
+ color: 'primary' as const,
14
+ checked: true,
15
+ }
16
+ }
17
+ return {
18
+ label: version.label,
19
+ to: version.to,
20
+ }
21
+ })
22
+ })
23
+ </script>
24
+
25
+ <template>
26
+ <UDropdownMenu
27
+ v-slot="{ open }"
28
+ :modal="false"
29
+ :items="items"
30
+ :content="{ align: 'start' }"
31
+ :ui="{ content: 'min-w-fit' }"
32
+ size="xs"
33
+ class="ml-1"
34
+ >
35
+ <UButton
36
+ :label="activeVersion?.label"
37
+ variant="subtle"
38
+ trailing-icon="i-lucide-chevron-down"
39
+ size="xs"
40
+ class="-mb-[6px] font-semibold rounded-full truncate"
41
+ :class="[open && 'bg-primary/15']"
42
+ :ui="{
43
+ trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' '),
44
+ }"
45
+ />
46
+ </UDropdownMenu>
47
+ </template>
@@ -0,0 +1,70 @@
1
+ <script setup lang="ts">
2
+ import { useClipboard } from '@vueuse/core'
3
+ import { useRuntimeConfig } from '#imports'
4
+
5
+ const route = useRoute()
6
+ const appBaseURL = useRuntimeConfig().app?.baseURL || '/'
7
+
8
+ const { copy, copied } = useClipboard()
9
+
10
+ const markdownLink = computed(() => `${window?.location?.origin}${appBaseURL}raw${route.path}.md`)
11
+ const items = [
12
+ {
13
+ label: 'Copy Markdown Link',
14
+ icon: 'i-lucide-link',
15
+ onSelect() {
16
+ copy(markdownLink.value)
17
+ },
18
+ },
19
+ {
20
+ label: 'View as Markdown',
21
+ icon: 'i-simple-icons:markdown',
22
+ target: '_blank',
23
+ to: markdownLink.value,
24
+ },
25
+ {
26
+ label: 'Open in ChatGPT',
27
+ icon: 'i-simple-icons:openai',
28
+ target: '_blank',
29
+ to: `https://chatgpt.com/?hints=search&q=${encodeURIComponent(`Read ${markdownLink.value} so I can ask questions about it.`)}`,
30
+ },
31
+ {
32
+ label: 'Open in Claude',
33
+ icon: 'i-simple-icons:anthropic',
34
+ target: '_blank',
35
+ to: `https://claude.ai/new?q=${encodeURIComponent(`Read ${markdownLink.value} so I can ask questions about it.`)}`,
36
+ },
37
+ ]
38
+
39
+ async function copyPage() {
40
+ const page = await $fetch<string>(`/raw${route.path}.md`)
41
+ copy(page)
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <UFieldGroup size="sm">
47
+ <UButton
48
+ label="Copy Page"
49
+ :icon="copied ? 'i-lucide-check' : 'i-lucide-copy'"
50
+ color="neutral"
51
+ variant="soft"
52
+ :ui="{
53
+ leadingIcon: 'text-neutral size-3.5',
54
+ }"
55
+ @click="copyPage"
56
+ />
57
+
58
+ <UDropdownMenu
59
+ size="sm"
60
+ :items="items"
61
+ :content="{
62
+ align: 'end',
63
+ side: 'bottom',
64
+ sideOffset: 8,
65
+ }"
66
+ >
67
+ <UButton icon="i-lucide-chevron-down" color="neutral" variant="soft" class="border-l border-muted" />
68
+ </UDropdownMenu>
69
+ </UFieldGroup>
70
+ </template>
@@ -116,8 +116,8 @@ function transformMermaid(node: MinimarkNode) {
116
116
  node[0] = 'mermaid'
117
117
  // @ts-expect-error
118
118
  node[1] = { code: node[1].code || '' }
119
- // @ts-expect-error
120
- node[2] = []
119
+ // Remove all children (splice instead of node[2] = [] which would create an invalid empty array child)
120
+ node.splice(2)
121
121
  }
122
122
  }
123
123
 
@@ -0,0 +1,32 @@
1
+ import type { NitroModule } from 'nitropack'
2
+ import { resolve } from 'node:path'
3
+ import { readFile, writeFile } from 'node:fs/promises'
4
+
5
+ import { defineNuxtModule } from 'nuxt/kit'
6
+
7
+ export default defineNuxtModule((_options, nuxt) => {
8
+ nuxt.options.nitro.modules ??= []
9
+ nuxt.options.nitro.modules.push(mdRewrite())
10
+ })
11
+
12
+ function mdRewrite(): NitroModule {
13
+ return {
14
+ name: 'markdown-rewrite',
15
+ setup(nitro) {
16
+ if (nitro.options.dev || !nitro.options.preset.includes('vercel')) {
17
+ return
18
+ }
19
+ nitro.hooks.hook('compiled', async () => {
20
+ const vcJSON = resolve(nitro.options.output.dir, 'config.json')
21
+ const vcConfig = JSON.parse(await readFile(vcJSON, 'utf8'))
22
+ vcConfig.routes.unshift({
23
+ src: '^/(.*)$',
24
+ dest: '/raw/$1.md',
25
+ has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
26
+ check: true,
27
+ })
28
+ await writeFile(vcJSON, JSON.stringify(vcConfig, null, 2), 'utf8')
29
+ })
30
+ },
31
+ }
32
+ }
@@ -16,7 +16,7 @@ export default defineNuxtConfig({
16
16
  name: 'undocs',
17
17
  },
18
18
  ssr,
19
- modules: ['@nuxt/ui', '@nuxt/content', isProd && '@nuxtjs/plausible'],
19
+ modules: ['@nuxt/ui', '@nuxt/content', isProd && '@nuxtjs/plausible', 'nuxt-llms'],
20
20
  css: [resolve('./assets/main.css')],
21
21
  ui: {
22
22
  theme: {
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { joinURL } from 'ufo'
2
3
  import { kebabCase } from 'scule'
3
4
  import type { ContentNavigationItem } from '@nuxt/content'
4
5
 
@@ -56,14 +57,37 @@ usePageSEO({
56
57
  ogTitle: page.value?.title,
57
58
  description: page.value?.description,
58
59
  })
60
+
61
+ const path = computed(() => route.path.replace(/\/$/, ''))
62
+ prerenderRoutes([joinURL('/raw', `${path.value}.md`)])
63
+ useHead({
64
+ link: [
65
+ {
66
+ rel: 'alternate',
67
+ href: joinURL(appConfig.site.url, 'raw', `${path.value}.md`),
68
+ type: 'text/markdown',
69
+ },
70
+ ],
71
+ })
59
72
  </script>
60
73
 
61
74
  <template>
62
75
  <UPage v-if="page">
63
- <UPageHeader :title="page.title" :description="page.description" :links="page.links">
76
+ <UPageHeader
77
+ :title="page.title"
78
+ :description="page.description"
79
+ :ui="{
80
+ wrapper: 'flex-row items-center flex-wrap justify-between',
81
+ }"
82
+ >
64
83
  <template #headline>
65
84
  <UBreadcrumb :items="breadcrumb" />
66
85
  </template>
86
+ <template #links>
87
+ <UButton v-for="(link, index) in page.links" :key="index" size="sm" v-bind="link" />
88
+
89
+ <PageHeaderLinks />
90
+ </template>
67
91
  </UPageHeader>
68
92
 
69
93
  <template v-if="page.body?.toc?.links?.length" #right>
@@ -0,0 +1,26 @@
1
+ import { queryCollection } from '@nuxt/content/server'
2
+ import { stringify } from 'minimark/stringify'
3
+ import { withLeadingSlash } from 'ufo'
4
+
5
+ export default eventHandler(async (event) => {
6
+ const slug = getRouterParams(event)['slug.md']
7
+ if (!slug?.endsWith('.md')) {
8
+ throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
9
+ }
10
+
11
+ const path = withLeadingSlash(slug.replace('.md', ''))
12
+
13
+ const page = await queryCollection(event, 'content').path(path).first()
14
+ if (!page) {
15
+ throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
16
+ }
17
+
18
+ // Add title and description to the top of the page if missing
19
+ if (page.body.value[0]?.[0] !== 'h1') {
20
+ page.body.value.unshift(['blockquote', {}, page.description])
21
+ page.body.value.unshift(['h1', {}, page.title])
22
+ }
23
+
24
+ setHeader(event, 'Content-Type', 'text/markdown; charset=utf-8')
25
+ return stringify({ ...page.body, type: 'minimark' }, { format: 'markdown/html' })
26
+ })
package/cli/cli.mjs CHANGED
@@ -58,8 +58,11 @@ export function createCLI(opts) {
58
58
  process.chdir(appDir)
59
59
  process.on('exit', () => unwatch())
60
60
 
61
- const { runCommand } = await import('nuxi')
62
- await runCommand('dev', [appDir, '--no-fork', '--port', process.env.PORT || '4000'], { overrides: nuxtConfig })
61
+ const { runCommand, main } = await import('nuxi')
62
+ const cmd = await main.subCommands.dev()
63
+ await runCommand(cmd, [appDir, '--no-fork', '--port', process.env.PORT || '4000'], {
64
+ overrides: nuxtConfig,
65
+ })
63
66
  },
64
67
  })
65
68
 
@@ -74,8 +77,9 @@ export function createCLI(opts) {
74
77
 
75
78
  process.chdir(appDir)
76
79
 
77
- const { runCommand } = await import('nuxi')
78
- await runCommand('generate', [appDir], { overrides: nuxtConfig })
80
+ const { runCommand, main } = await import('nuxi')
81
+ const cmd = await main.subCommands.generate()
82
+ await runCommand(cmd, [appDir], { overrides: nuxtConfig })
79
83
  },
80
84
  })
81
85
 
package/cli/setup.mjs CHANGED
@@ -3,6 +3,7 @@ import { resolve } from 'node:path'
3
3
  import { existsSync } from 'node:fs'
4
4
  import { execSync } from 'node:child_process'
5
5
  import { loadConfig, watchConfig } from 'c12'
6
+ import { defu } from 'defu'
6
7
 
7
8
  const appDir = fileURLToPath(new URL('../app', import.meta.url))
8
9
 
@@ -80,6 +81,16 @@ export async function setupDocs(docsDir, opts = {}) {
80
81
  }
81
82
 
82
83
  // Prepare loadNuxt overrides
84
+ const llmsConfig = defu(docsconfig.llms, {
85
+ domain: docsconfig.url,
86
+ title: docsconfig.name || '',
87
+ description: docsconfig.description || '',
88
+ full: {
89
+ title: docsconfig.name || '',
90
+ description: docsconfig.description || '',
91
+ },
92
+ })
93
+
83
94
  const nuxtConfig = {
84
95
  compatibilityDate: 'latest',
85
96
  rootDir: docsSrcDir,
@@ -95,6 +106,8 @@ export async function setupDocs(docsDir, opts = {}) {
95
106
  description: docsconfig.description || '',
96
107
  url: docsconfig.url,
97
108
  },
109
+ // @ts-ignore
110
+ llms: llmsConfig,
98
111
  appConfig: {
99
112
  site: {
100
113
  name: docsconfig.name || '',
@@ -120,6 +133,9 @@ export async function setupDocs(docsDir, opts = {}) {
120
133
  dir: resolve(docsDir, '.docs/public'),
121
134
  },
122
135
  ],
136
+ prerender: {
137
+ routes: ['/llms.txt', '/llms-full.txt'],
138
+ },
123
139
  },
124
140
  routeRules: {
125
141
  ...Object.fromEntries(Object.entries(docsconfig.redirects || {}).map(([from, to]) => [from, { redirect: to }])),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undocs",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "repository": "unjs/undocs",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,47 +31,47 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@headlessui/vue": "^1.7.23",
34
- "@iconify-json/logos": "^1.2.9",
35
- "@iconify-json/simple-icons": "^1.2.52",
36
- "@nuxt/content": "^3.7.1",
37
- "@nuxt/fonts": "^0.11.4",
38
- "@nuxt/ui": "4.0.0-alpha.2",
34
+ "@iconify-json/logos": "^1.2.10",
35
+ "@iconify-json/simple-icons": "^1.2.66",
36
+ "@nuxt/content": "^3.10.0",
37
+ "@nuxt/fonts": "^0.12.1",
38
+ "@nuxt/ui": "4.2.0",
39
39
  "@nuxtjs/plausible": "^2.0.1",
40
40
  "@resvg/resvg-wasm": "^2.6.2",
41
41
  "automd": "^0.4.2",
42
- "c12": "^3.3.0",
42
+ "c12": "^3.3.3",
43
43
  "citty": "^0.1.6",
44
44
  "consola": "^3.4.2",
45
45
  "defu": "^6.1.4",
46
46
  "is-buffer": "^2.0.5",
47
47
  "md4w": "^0.2.7",
48
- "mermaid": "^11.12.0",
49
- "motion-v": "^1.7.1",
50
- "nitropack": "^2.12.6",
51
- "nuxi": "^3.28.0",
52
- "nuxt": "^4.1.2",
48
+ "mermaid": "^11.12.2",
49
+ "motion-v": "^1.9.0",
50
+ "nitropack": "^2.13.1",
51
+ "nuxi": "^3.32.0",
52
+ "nuxt": "^4.2.2",
53
53
  "nuxt-build-cache": "^0.1.1",
54
54
  "nuxt-llms": "^0.1.3",
55
55
  "pkg-types": "^2.3.0",
56
56
  "scule": "^1.3.0",
57
- "shiki": "^3.12.2",
58
- "tailwindcss": "^4.1.13",
59
- "unctx": "^2.4.1",
60
- "unstorage": "^1.17.1",
61
- "vue": "^3.5.21",
62
- "vue-router": "^4.5.1"
57
+ "shiki": "^3.21.0",
58
+ "tailwindcss": "^4.1.18",
59
+ "unctx": "^2.5.0",
60
+ "unstorage": "^1.17.4",
61
+ "vue": "^3.5.26",
62
+ "vue-router": "^4.6.4"
63
63
  },
64
64
  "devDependencies": {
65
- "@nuxt/eslint-config": "^1.9.0",
66
- "@nuxt/image": "^1.11.0",
67
- "@types/node": "^24.5.2",
65
+ "@nuxt/eslint-config": "^1.12.1",
66
+ "@nuxt/image": "^2.0.0",
67
+ "@types/node": "^25.0.8",
68
68
  "changelogen": "^0.6.2",
69
- "eslint": "^9.35.0",
70
- "eslint-config-unjs": "^0.5.0",
71
- "jiti": "^2.5.1",
72
- "prettier": "^3.6.2",
73
- "typescript": "^5.9.2",
74
- "vue-tsc": "^3.0.7"
69
+ "eslint": "^9.39.2",
70
+ "eslint-config-unjs": "^0.6.2",
71
+ "jiti": "^2.6.1",
72
+ "prettier": "^3.8.0",
73
+ "typescript": "^5.9.3",
74
+ "vue-tsc": "^3.2.2"
75
75
  },
76
- "packageManager": "pnpm@10.17.0"
76
+ "packageManager": "pnpm@10.28.0"
77
77
  }
@@ -1,3 +1,5 @@
1
+ import type { BannerProps } from '@nuxt/ui'
2
+
1
3
  export interface DocsConfig {
2
4
  dir?: string
3
5
  name?: string
@@ -6,7 +8,15 @@ export interface DocsConfig {
6
8
  url?: string
7
9
  github?: string
8
10
  socials?: Record<string, string>
11
+ llms?: {
12
+ full?: {
13
+ title?: string
14
+ description?: string
15
+ }
16
+ }
9
17
  branch?: string
18
+ banner?: BannerProps
19
+ versions?: { label: string; to: string; active?: boolean }[]
10
20
  themeColor?: string
11
21
  redirects?: Record<string, string>
12
22
  automd?: unknown
@@ -35,6 +35,40 @@
35
35
  "type": "string",
36
36
  "description": "The GitHub repository for the documentation site."
37
37
  },
38
+ "llms": {
39
+ "type": "object",
40
+ "description": "Configuration for `nuxt-llms` generation (`/llms.txt` and `/llms-full.txt`).",
41
+ "additionalProperties": false,
42
+ "properties": {
43
+ "domain": {
44
+ "type": "string",
45
+ "description": "Public site domain (e.g. https://example.com)."
46
+ },
47
+ "title": {
48
+ "type": "string",
49
+ "description": "Title used in `/llms.txt`."
50
+ },
51
+ "description": {
52
+ "type": "string",
53
+ "description": "Description used in `/llms.txt`."
54
+ },
55
+ "full": {
56
+ "type": "object",
57
+ "description": "Metadata for `/llms-full.txt`.",
58
+ "additionalProperties": false,
59
+ "properties": {
60
+ "title": {
61
+ "type": "string",
62
+ "description": "Title used in `/llms-full.txt`."
63
+ },
64
+ "description": {
65
+ "type": "string",
66
+ "description": "Description used in `/llms-full.txt`."
67
+ }
68
+ }
69
+ }
70
+ }
71
+ },
38
72
  "socials": {
39
73
  "type": "object",
40
74
  "description": "Social media links for the documentation site.",
@@ -55,6 +89,169 @@
55
89
  "type": "string",
56
90
  "description": "The branch of the GitHub repository for the documentation site."
57
91
  },
92
+ "banner": {
93
+ "type": "object",
94
+ "description": "Banner configuration",
95
+ "additionalProperties": false,
96
+ "properties": {
97
+ "id": {
98
+ "type": "string",
99
+ "description": "A unique id saved to local storage to remember if the banner has been dismissed. Change this value to show the banner again."
100
+ },
101
+ "icon": {
102
+ "type": "string",
103
+ "description": "The icon displayed next to the title (e.g., 'i-lucide-info')."
104
+ },
105
+ "title": {
106
+ "type": "string",
107
+ "description": "The banner title text."
108
+ },
109
+ "actions": {
110
+ "type": "array",
111
+ "description": "Display a list of action buttons next to the title.",
112
+ "items": {
113
+ "type": "object",
114
+ "properties": {
115
+ "label": {
116
+ "type": "string",
117
+ "description": "Button label text"
118
+ },
119
+ "icon": {
120
+ "type": "string",
121
+ "description": "Button icon"
122
+ },
123
+ "to": {
124
+ "type": "string",
125
+ "description": "Button link destination"
126
+ },
127
+ "target": {
128
+ "type": "string",
129
+ "enum": ["_blank", "_parent", "_self", "_top"],
130
+ "description": "Link target attribute"
131
+ },
132
+ "color": {
133
+ "type": "string",
134
+ "enum": ["primary", "secondary", "success", "info", "warning", "error", "neutral"],
135
+ "description": "Button color"
136
+ },
137
+ "size": {
138
+ "type": "string",
139
+ "enum": ["xs", "sm", "md", "lg", "xl"],
140
+ "description": "Button size"
141
+ },
142
+ "variant": {
143
+ "type": "string",
144
+ "enum": ["solid", "outline", "soft", "subtle", "ghost", "link"],
145
+ "description": "Button variant"
146
+ }
147
+ }
148
+ }
149
+ },
150
+ "to": {
151
+ "type": "string",
152
+ "description": "Link destination URL or route path."
153
+ },
154
+ "target": {
155
+ "type": "string",
156
+ "enum": ["_blank", "_parent", "_self", "_top"],
157
+ "description": "Link target attribute."
158
+ },
159
+ "color": {
160
+ "type": "string",
161
+ "enum": ["primary", "secondary", "success", "info", "warning", "error", "neutral"],
162
+ "description": "Banner color theme.",
163
+ "default": "primary"
164
+ },
165
+ "close": {
166
+ "oneOf": [
167
+ {
168
+ "type": "boolean",
169
+ "description": "Display a close button to dismiss the banner."
170
+ },
171
+ {
172
+ "type": "object",
173
+ "description": "Close button configuration.",
174
+ "properties": {
175
+ "size": {
176
+ "type": "string",
177
+ "enum": ["xs", "sm", "md", "lg", "xl"],
178
+ "description": "Close button size"
179
+ },
180
+ "color": {
181
+ "type": "string",
182
+ "enum": ["primary", "secondary", "success", "info", "warning", "error", "neutral"],
183
+ "description": "Close button color"
184
+ },
185
+ "variant": {
186
+ "type": "string",
187
+ "enum": ["solid", "outline", "soft", "subtle", "ghost", "link"],
188
+ "description": "Close button variant"
189
+ }
190
+ }
191
+ }
192
+ ]
193
+ },
194
+ "closeIcon": {
195
+ "type": "string",
196
+ "description": "The icon displayed in the close button (e.g., 'i-lucide-x').",
197
+ "default": "i-lucide-x"
198
+ },
199
+ "ui": {
200
+ "type": "object",
201
+ "description": "UI customization classes for banner components.",
202
+ "properties": {
203
+ "root": {
204
+ "description": "Root element classes"
205
+ },
206
+ "container": {
207
+ "description": "Container element classes"
208
+ },
209
+ "left": {
210
+ "description": "Left section classes"
211
+ },
212
+ "center": {
213
+ "description": "Center section classes"
214
+ },
215
+ "right": {
216
+ "description": "Right section classes"
217
+ },
218
+ "icon": {
219
+ "description": "Icon element classes"
220
+ },
221
+ "title": {
222
+ "description": "Title element classes"
223
+ },
224
+ "actions": {
225
+ "description": "Actions container classes"
226
+ },
227
+ "close": {
228
+ "description": "Close button classes"
229
+ }
230
+ }
231
+ }
232
+ }
233
+ },
234
+ "versions": {
235
+ "type": "array",
236
+ "description": "The versions of the documentation site.",
237
+ "items": {
238
+ "type": "object",
239
+ "properties": {
240
+ "label": {
241
+ "type": "string",
242
+ "description": "The label of the version."
243
+ },
244
+ "to": {
245
+ "type": "string",
246
+ "description": "The URL to the version."
247
+ },
248
+ "active": {
249
+ "type": "boolean",
250
+ "description": "Whether the version is active on this documentation site."
251
+ }
252
+ }
253
+ }
254
+ },
58
255
  "themeColor": {
59
256
  "type": "string",
60
257
  "description": "The theme color of the documentation site.\nIt will be used as the `theme-color` meta tag and a full palette of colors will be generated from it."