From 82262de5c2927e802bf09bb5a79545873de532a6 Mon Sep 17 00:00:00 2001 From: Ivan Bochkarev Date: Wed, 11 Mar 2026 22:48:16 +0600 Subject: [PATCH 01/19] docs: render minimalVersion badge from layout - Add minimalVersion to docs collection schemas (docsv3, docsv4, docsv5) - Render version badge in docs page header when frontmatter has minimalVersion - Badge shows vX.Y (e.g. v3.12), info color, with aria-label for a11y Complements nuxt/nuxt#34485: API docs set minimalVersion in frontmatter; this repo displays the badge so global inline badges are not needed. --- app/pages/docs/[...slug].vue | 15 +++++++++++++++ content.config.ts | 9 ++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index 9209835fd..e033ec091 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -185,6 +185,21 @@ function refreshHeading(opened: boolean) { + + diff --git a/app/composables/useVersionBadge.ts b/app/composables/useVersionBadge.ts index 13ca29830..33c8e5db9 100644 --- a/app/composables/useVersionBadge.ts +++ b/app/composables/useVersionBadge.ts @@ -8,19 +8,22 @@ export interface UseVersionBadgeOptions { /** * Decides whether a minimum Nuxt version is worth surfacing as a badge for the docs * version currently being read — a requirement older than `tolerance` is not news anymore. + * + * `version` takes a version number or one of the {@link VERSION_KEYWORDS}, e.g. `nightly`. */ export const useVersionBadge = (version: MaybeRefOrGetter, options: UseVersionBadgeOptions = {}) => { + const { version: docsVersion } = useDocsVersion() const { latest } = useDocsLatestVersion() - const label = computed(() => { - const value = toValue(version)?.trim() - return value ? `v${value}` : undefined - }) + const labels = computed(() => versionBadgeLabels(toValue(version), docsVersion.value?.shortTag)) + const label = computed(() => labels.value?.label) + const ariaLabel = computed(() => labels.value?.ariaLabel) const show = computed(() => satisfiesVersionTolerance(toValue(version), latest.value, toValue(options.tolerance) ?? { major: 0 })) return { label, + ariaLabel, show, latest } diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index 9e5e571a4..d9cd50c84 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -40,12 +40,15 @@ const versionBadge = (item: ContentNavigationItem) => { const minimal = item.minimalVersion.trim() if (!satisfiesVersionTolerance(minimal, latest.value, navVersionTolerance)) return undefined + const labels = versionBadgeLabels(minimal, version.value?.shortTag) + if (!labels) return undefined + return { - 'label': `v${minimal}`, + 'label': labels.label, 'size': 'sm' as const, 'color': 'info' as const, 'variant': 'subtle' as const, - 'aria-label': `Minimum Nuxt Version: v${minimal}` + 'aria-label': labels.ariaLabel } } diff --git a/app/utils/version.ts b/app/utils/version.ts index f1cddb543..de0249e73 100644 --- a/app/utils/version.ts +++ b/app/utils/version.ts @@ -1,5 +1,34 @@ import { coerce, getMajor, getMinor, getPatch, isGreaterOrEqual } from 'verkit' +/** + * Shortcuts for a requirement that has no version number yet. They stand for something + * unreleased, so tolerance never filters them out and they render as-is instead of `v`. + */ +export const VERSION_KEYWORDS = ['nightly'] as const + +export type VersionKeyword = typeof VERSION_KEYWORDS[number] + +/** The keyword `version` stands for, if it is one. */ +export function versionKeyword(version: string | undefined | null): VersionKeyword | undefined { + const value = version?.trim().toLowerCase() + return VERSION_KEYWORDS.find(keyword => keyword === value) +} + +/** + * How a minimum version requirement reads as a badge — a version number as `v`, + * a keyword as-is, qualified by the major it applies to (`nightly v4`). + * Returns `undefined` when there is nothing to show. + */ +export function versionBadgeLabels(version: string | undefined | null, tag?: string): { label: string, ariaLabel: string } | undefined { + const value = version?.trim() + if (!value) return undefined + + const keyword = versionKeyword(value) + const label = keyword ? [keyword, tag].filter(Boolean).join(' ') : `v${value}` + + return { label, ariaLabel: `Minimum Nuxt Version: ${label}` } +} + /** * How far *behind* the latest release a version may be and still be worth surfacing. * Tolerance only ever looks backwards — versions newer than the latest release @@ -37,11 +66,14 @@ export function versionThreshold(latest: string | undefined | null, tolerance: V /** * Whether `version` is at or above the tolerated threshold, which means: + * - a keyword like `nightly` -> always `true`, it describes an unreleased version * - newer than `latest` -> always `true` * - older than `latest` -> `true` while it is within `tolerance` * - unparseable input -> `false` */ export function satisfiesVersionTolerance(version: string | undefined | null, latest: string | undefined | null, tolerance: VersionTolerance = {}): boolean { + if (versionKeyword(version)) return true + const target = coerce(version?.trim() ?? '') const threshold = versionThreshold(latest, tolerance) if (!target || !threshold) return false diff --git a/test/nuxt/index.spec.ts b/test/nuxt/index.spec.ts index a4240a1f0..8cd28635b 100644 --- a/test/nuxt/index.spec.ts +++ b/test/nuxt/index.spec.ts @@ -161,3 +161,55 @@ describe('utils/index', () => { }) }) }) + +describe('utils/version', () => { + describe('versionKeyword', () => { + it('should recognize keywords regardless of casing and padding', () => { + expect(versionKeyword('nightly')).toBe('nightly') + expect(versionKeyword(' Nightly ')).toBe('nightly') + }) + + it('should ignore version numbers and unknown words', () => { + expect(versionKeyword('4.2.0')).toBeUndefined() + expect(versionKeyword('later')).toBeUndefined() + expect(versionKeyword(undefined)).toBeUndefined() + }) + }) + + describe('versionBadgeLabels', () => { + it('should prefix version numbers with v', () => { + expect(versionBadgeLabels('4.2')).toEqual({ + label: 'v4.2', + ariaLabel: 'Minimum Nuxt Version: v4.2' + }) + }) + + it('should qualify keywords with the docs tag', () => { + expect(versionBadgeLabels('nightly', 'v4')).toEqual({ + label: 'nightly v4', + ariaLabel: 'Minimum Nuxt Version: nightly v4' + }) + }) + + it('should render keywords as-is without a docs tag', () => { + expect(versionBadgeLabels('nightly')?.label).toBe('nightly') + }) + + it('should return undefined for empty input', () => { + expect(versionBadgeLabels(' ')).toBeUndefined() + expect(versionBadgeLabels(undefined)).toBeUndefined() + }) + }) + + describe('satisfiesVersionTolerance', () => { + it('should always surface keywords', () => { + expect(satisfiesVersionTolerance('nightly', '4.5.2', { minor: 2 })).toBe(true) + }) + + it('should keep the tolerated range for version numbers', () => { + expect(satisfiesVersionTolerance('4.4.0', '4.5.2', { minor: 2 })).toBe(true) + expect(satisfiesVersionTolerance('4.2.0', '4.5.2', { minor: 2 })).toBe(false) + expect(satisfiesVersionTolerance('nope', '4.5.2')).toBe(false) + }) + }) +}) From 39ad20bff86d40cb6df2ddf2cf3b3fa90df0d10a Mon Sep 17 00:00:00 2001 From: OrbisK Date: Wed, 29 Jul 2026 11:36:38 +0200 Subject: [PATCH 15/19] fix: use unreleased as keyword and add short label --- app/components/content/VersionBadge.vue | 2 +- app/composables/useVersionBadge.ts | 5 ++++- app/pages/docs/[...slug].vue | 3 ++- app/utils/version.ts | 25 +++++++++++++++---------- test/nuxt/index.spec.ts | 18 ++++++++++-------- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/app/components/content/VersionBadge.vue b/app/components/content/VersionBadge.vue index eebe0d0bd..968e47614 100644 --- a/app/components/content/VersionBadge.vue +++ b/app/components/content/VersionBadge.vue @@ -2,7 +2,7 @@ import type { BadgeProps } from '@nuxt/ui' interface Props extends Omit { - /** A version number, or one of the {@link VERSION_KEYWORDS} like `nightly` for something unreleased. */ + /** A version number, or one of the {@link VERSION_KEYWORDS} like `unreleased` for something without a version yet. */ version: string | VersionKeyword /** How far behind the latest release the requirement may be. Defaults to the whole current major. */ tolerance?: VersionTolerance diff --git a/app/composables/useVersionBadge.ts b/app/composables/useVersionBadge.ts index 33c8e5db9..28da3978c 100644 --- a/app/composables/useVersionBadge.ts +++ b/app/composables/useVersionBadge.ts @@ -9,7 +9,7 @@ export interface UseVersionBadgeOptions { * Decides whether a minimum Nuxt version is worth surfacing as a badge for the docs * version currently being read — a requirement older than `tolerance` is not news anymore. * - * `version` takes a version number or one of the {@link VERSION_KEYWORDS}, e.g. `nightly`. + * `version` takes a version number or one of the {@link VERSION_KEYWORDS}, e.g. `unreleased`. */ export const useVersionBadge = (version: MaybeRefOrGetter, options: UseVersionBadgeOptions = {}) => { const { version: docsVersion } = useDocsVersion() @@ -17,12 +17,15 @@ export const useVersionBadge = (version: MaybeRefOrGetter, o const labels = computed(() => versionBadgeLabels(toValue(version), docsVersion.value?.shortTag)) const label = computed(() => labels.value?.label) + /** For tight spots like the sidebar — `soon` instead of `nightly v4` */ + const shortLabel = computed(() => labels.value?.shortLabel) const ariaLabel = computed(() => labels.value?.ariaLabel) const show = computed(() => satisfiesVersionTolerance(toValue(version), latest.value, toValue(options.tolerance) ?? { major: 0 })) return { label, + shortLabel, ariaLabel, show, latest diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index d9cd50c84..a74a341f4 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -44,7 +44,8 @@ const versionBadge = (item: ContentNavigationItem) => { if (!labels) return undefined return { - 'label': labels.label, + // The sidebar has no room for `nightly v4` + 'label': labels.shortLabel, 'size': 'sm' as const, 'color': 'info' as const, 'variant': 'subtle' as const, diff --git a/app/utils/version.ts b/app/utils/version.ts index de0249e73..ef935b17f 100644 --- a/app/utils/version.ts +++ b/app/utils/version.ts @@ -1,32 +1,37 @@ import { coerce, getMajor, getMinor, getPatch, isGreaterOrEqual } from 'verkit' /** - * Shortcuts for a requirement that has no version number yet. They stand for something - * unreleased, so tolerance never filters them out and they render as-is instead of `v`. + * Shortcuts for a requirement that has no version number yet, mapped to how they render: + * `label` where there is room, `short` in tight spots like the sidebar. + * They stand for something unreleased, so tolerance never filters them out. */ -export const VERSION_KEYWORDS = ['nightly'] as const +export const VERSION_KEYWORDS = { + unreleased: { label: 'nightly', short: 'soon' } +} as const -export type VersionKeyword = typeof VERSION_KEYWORDS[number] +export type VersionKeyword = keyof typeof VERSION_KEYWORDS /** The keyword `version` stands for, if it is one. */ export function versionKeyword(version: string | undefined | null): VersionKeyword | undefined { const value = version?.trim().toLowerCase() - return VERSION_KEYWORDS.find(keyword => keyword === value) + return value && value in VERSION_KEYWORDS ? value as VersionKeyword : undefined } /** * How a minimum version requirement reads as a badge — a version number as `v`, - * a keyword as-is, qualified by the major it applies to (`nightly v4`). + * a keyword as its label qualified by the major it applies to (`unreleased` -> `nightly v4`, + * `soon` where space is tight). The aria label always spells out the long form. * Returns `undefined` when there is nothing to show. */ -export function versionBadgeLabels(version: string | undefined | null, tag?: string): { label: string, ariaLabel: string } | undefined { +export function versionBadgeLabels(version: string | undefined | null, tag?: string): { label: string, shortLabel: string, ariaLabel: string } | undefined { const value = version?.trim() if (!value) return undefined const keyword = versionKeyword(value) - const label = keyword ? [keyword, tag].filter(Boolean).join(' ') : `v${value}` + const label = keyword ? [VERSION_KEYWORDS[keyword].label, tag].filter(Boolean).join(' ') : `v${value}` + const shortLabel = keyword ? VERSION_KEYWORDS[keyword].short : label - return { label, ariaLabel: `Minimum Nuxt Version: ${label}` } + return { label, shortLabel, ariaLabel: `Minimum Nuxt Version: ${label}` } } /** @@ -66,7 +71,7 @@ export function versionThreshold(latest: string | undefined | null, tolerance: V /** * Whether `version` is at or above the tolerated threshold, which means: - * - a keyword like `nightly` -> always `true`, it describes an unreleased version + * - a keyword like `unreleased` -> always `true`, it describes a version that has no number yet * - newer than `latest` -> always `true` * - older than `latest` -> `true` while it is within `tolerance` * - unparseable input -> `false` diff --git a/test/nuxt/index.spec.ts b/test/nuxt/index.spec.ts index 8cd28635b..f17b1e49d 100644 --- a/test/nuxt/index.spec.ts +++ b/test/nuxt/index.spec.ts @@ -165,13 +165,13 @@ describe('utils/index', () => { describe('utils/version', () => { describe('versionKeyword', () => { it('should recognize keywords regardless of casing and padding', () => { - expect(versionKeyword('nightly')).toBe('nightly') - expect(versionKeyword(' Nightly ')).toBe('nightly') + expect(versionKeyword('unreleased')).toBe('unreleased') + expect(versionKeyword(' Unreleased ')).toBe('unreleased') }) it('should ignore version numbers and unknown words', () => { expect(versionKeyword('4.2.0')).toBeUndefined() - expect(versionKeyword('later')).toBeUndefined() + expect(versionKeyword('nightly')).toBeUndefined() expect(versionKeyword(undefined)).toBeUndefined() }) }) @@ -180,19 +180,21 @@ describe('utils/version', () => { it('should prefix version numbers with v', () => { expect(versionBadgeLabels('4.2')).toEqual({ label: 'v4.2', + shortLabel: 'v4.2', ariaLabel: 'Minimum Nuxt Version: v4.2' }) }) - it('should qualify keywords with the docs tag', () => { - expect(versionBadgeLabels('nightly', 'v4')).toEqual({ + it('should render keywords as their label qualified with the docs tag', () => { + expect(versionBadgeLabels('unreleased', 'v4')).toEqual({ label: 'nightly v4', + shortLabel: 'soon', ariaLabel: 'Minimum Nuxt Version: nightly v4' }) }) - it('should render keywords as-is without a docs tag', () => { - expect(versionBadgeLabels('nightly')?.label).toBe('nightly') + it('should render the bare keyword label without a docs tag', () => { + expect(versionBadgeLabels('unreleased')?.label).toBe('nightly') }) it('should return undefined for empty input', () => { @@ -203,7 +205,7 @@ describe('utils/version', () => { describe('satisfiesVersionTolerance', () => { it('should always surface keywords', () => { - expect(satisfiesVersionTolerance('nightly', '4.5.2', { minor: 2 })).toBe(true) + expect(satisfiesVersionTolerance('unreleased', '4.5.2', { minor: 2 })).toBe(true) }) it('should keep the tolerated range for version numbers', () => { From 40dc8b596c1899dc720aadc9a47b90d44cd22faa Mon Sep 17 00:00:00 2001 From: OrbisK Date: Wed, 29 Jul 2026 12:04:05 +0200 Subject: [PATCH 16/19] feat: version badges shouldl link to blogs or nightly docs --- app/components/content/VersionBadge.vue | 12 +++++++++-- app/composables/useBlog.ts | 16 ++++++++++++++ app/composables/useVersionBadge.ts | 16 ++++++++++++++ app/utils/version.ts | 21 +++++++++++++++++++ test/nuxt/index.spec.ts | 28 +++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) diff --git a/app/components/content/VersionBadge.vue b/app/components/content/VersionBadge.vue index 968e47614..65ad69b90 100644 --- a/app/components/content/VersionBadge.vue +++ b/app/components/content/VersionBadge.vue @@ -1,4 +1,5 @@ @@ -28,8 +33,11 @@ const badgeProps = computed(() => { diff --git a/app/composables/useBlog.ts b/app/composables/useBlog.ts index 664bbdf7a..64307cbbf 100644 --- a/app/composables/useBlog.ts +++ b/app/composables/useBlog.ts @@ -1,5 +1,21 @@ import type { BlogArticle } from '~/types' +/** + * Paths of the release announcements, e.g. `/blog/v4-5`. Kept to paths only so version badges + * can check whether a release has a post to link to without pulling the whole blog. + */ +export const useReleaseArticlePaths = () => { + const { data: paths } = useAsyncData('release-article-paths', () => { + return queryCollection('blog') + .where('category', '=', 'Release') + .select('path') + .all() + .then(articles => articles.map(article => article.path)) + }, { default: () => [] }) + + return { paths } +} + export const useBlog = () => { const { data: articles, refresh } = useAsyncData('blog', async () => { return queryCollection('blog') diff --git a/app/composables/useVersionBadge.ts b/app/composables/useVersionBadge.ts index 28da3978c..6e0b47c14 100644 --- a/app/composables/useVersionBadge.ts +++ b/app/composables/useVersionBadge.ts @@ -23,10 +23,26 @@ export const useVersionBadge = (version: MaybeRefOrGetter, o const show = computed(() => satisfiesVersionTolerance(toValue(version), latest.value, toValue(options.tolerance) ?? { major: 0 })) + const { paths: releasePaths } = useReleaseArticlePaths() + + /** + * Where the badge points: the nightly channel guide for a keyword, the release announcement + * for a version number. `undefined` while a release has no post yet, so the badge stays plain + * text instead of linking into a 404. + */ + const to = computed(() => { + const value = toValue(version) + if (versionKeyword(value)) return nightlyChannelPath(docsVersion.value?.path) + + const path = versionBlogPath(value) + return path && releasePaths.value.includes(path) ? path : undefined + }) + return { label, shortLabel, ariaLabel, + to, show, latest } diff --git a/app/utils/version.ts b/app/utils/version.ts index ef935b17f..ad8318df0 100644 --- a/app/utils/version.ts +++ b/app/utils/version.ts @@ -34,6 +34,27 @@ export function versionBadgeLabels(version: string | undefined | null, tag?: str return { label, shortLabel, ariaLabel: `Minimum Nuxt Version: ${label}` } } +/** + * Where the release announcement for a version lives, e.g. `4.5.2` -> `/blog/v4-5`. + * A major release drops the minor (`4.0.0` -> `/blog/v4`), matching how the posts are named. + * The path is derived, not verified — check it against the blog collection before linking. + */ +export function versionBlogPath(version: string | undefined | null): string | undefined { + const target = coerce(version?.trim() ?? '') + if (!target) return undefined + + const minor = getMinor(target) + + return `/blog/v${getMajor(target)}${minor ? `-${minor}` : ''}` +} + +/** The nightly release channel guide for a docs version, e.g. `/docs/4.x` -> how to install nightly. */ +export function nightlyChannelPath(docsPath: string | undefined): string | undefined { + if (!docsPath?.startsWith('/docs')) return undefined + + return `${docsPath}/guide/going-further/nightly-release-channel` +} + /** * How far *behind* the latest release a version may be and still be worth surfacing. * Tolerance only ever looks backwards — versions newer than the latest release diff --git a/test/nuxt/index.spec.ts b/test/nuxt/index.spec.ts index f17b1e49d..3cdb4342c 100644 --- a/test/nuxt/index.spec.ts +++ b/test/nuxt/index.spec.ts @@ -203,6 +203,34 @@ describe('utils/version', () => { }) }) + describe('versionBlogPath', () => { + it('should point at the minor release announcement', () => { + expect(versionBlogPath('4.5.2')).toBe('/blog/v4-5') + expect(versionBlogPath('3.18')).toBe('/blog/v3-18') + }) + + it('should drop the minor for a major release', () => { + expect(versionBlogPath('4.0.0')).toBe('/blog/v4') + expect(versionBlogPath('4')).toBe('/blog/v4') + }) + + it('should return undefined for keywords and unparseable input', () => { + expect(versionBlogPath('unreleased')).toBeUndefined() + expect(versionBlogPath(undefined)).toBeUndefined() + }) + }) + + describe('nightlyChannelPath', () => { + it('should build the guide path for a docs version', () => { + expect(nightlyChannelPath('/docs/4.x')).toBe('/docs/4.x/guide/going-further/nightly-release-channel') + }) + + it('should ignore paths outside the docs', () => { + expect(nightlyChannelPath('https://v2.nuxt.com')).toBeUndefined() + expect(nightlyChannelPath(undefined)).toBeUndefined() + }) + }) + describe('satisfiesVersionTolerance', () => { it('should always surface keywords', () => { expect(satisfiesVersionTolerance('unreleased', '4.5.2', { minor: 2 })).toBe(true) From 350f84491997a3b442169bc1a927e17a45ad8d00 Mon Sep 17 00:00:00 2001 From: OrbisK Date: Wed, 29 Jul 2026 15:49:30 +0200 Subject: [PATCH 17/19] chore: capitalize navigation badges --- app/pages/docs/[...slug].vue | 1 + 1 file changed, 1 insertion(+) diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index 7967b23a1..dde569b9d 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -49,6 +49,7 @@ const versionBadge = (item: ContentNavigationItem) => { 'size': 'sm' as const, 'color': 'info' as const, 'variant': 'subtle' as const, + 'class': 'capitalize', 'aria-label': labels.ariaLabel } } From 108e5c3dfbfffc7d9604b4576aba3375bbb5ca60 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 29 Jul 2026 17:11:41 +0200 Subject: [PATCH 18/19] Apply suggestions from code review Co-authored-by: Robin --- app/pages/docs/[...slug].vue | 1 - app/utils/version.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index dde569b9d..7967b23a1 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -49,7 +49,6 @@ const versionBadge = (item: ContentNavigationItem) => { 'size': 'sm' as const, 'color': 'info' as const, 'variant': 'subtle' as const, - 'class': 'capitalize', 'aria-label': labels.ariaLabel } } diff --git a/app/utils/version.ts b/app/utils/version.ts index ad8318df0..f07394ac5 100644 --- a/app/utils/version.ts +++ b/app/utils/version.ts @@ -6,7 +6,7 @@ import { coerce, getMajor, getMinor, getPatch, isGreaterOrEqual } from 'verkit' * They stand for something unreleased, so tolerance never filters them out. */ export const VERSION_KEYWORDS = { - unreleased: { label: 'nightly', short: 'soon' } + unreleased: { label: 'nightly', short: 'Soon' } } as const export type VersionKeyword = keyof typeof VERSION_KEYWORDS From 9f970e45162219870ab86e06276b9ee83e9543cb Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 29 Jul 2026 17:42:01 +0200 Subject: [PATCH 19/19] Apply suggestions from code review Co-authored-by: Robin --- test/nuxt/index.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nuxt/index.spec.ts b/test/nuxt/index.spec.ts index 3cdb4342c..99c930936 100644 --- a/test/nuxt/index.spec.ts +++ b/test/nuxt/index.spec.ts @@ -188,7 +188,7 @@ describe('utils/version', () => { it('should render keywords as their label qualified with the docs tag', () => { expect(versionBadgeLabels('unreleased', 'v4')).toEqual({ label: 'nightly v4', - shortLabel: 'soon', + shortLabel: 'Soon', ariaLabel: 'Minimum Nuxt Version: nightly v4' }) })