From b35577330eab8d117dfc32906fa08a0d20c44808 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 11 Feb 2026 13:59:45 +0900 Subject: [PATCH 1/7] feat: link to releases --- app/components/Package/Versions.vue | 313 +++++++++++++++++---------- app/composables/useRepoMeta.ts | 239 ++++++++++++++++++++ app/pages/package/[[org]]/[name].vue | 39 +++- app/utils/releases.ts | 38 ++++ i18n/locales/en.json | 9 +- i18n/schema.json | 21 ++ lunaria/files/en-GB.json | 9 +- lunaria/files/en-US.json | 9 +- 8 files changed, 562 insertions(+), 115 deletions(-) create mode 100644 app/utils/releases.ts diff --git a/app/components/Package/Versions.vue b/app/components/Package/Versions.vue index 77ae6dc7f..56e9fc0e2 100644 --- a/app/components/Package/Versions.vue +++ b/app/components/Package/Versions.vue @@ -11,6 +11,8 @@ import { getVersionGroupLabel, isSameVersionGroup, } from '~/utils/versions' +import { getMatchedRelease } from '~/utils/releases' +import type { Release } from '~/composables/useRepoMeta' const props = defineProps<{ packageName: string @@ -18,6 +20,7 @@ const props = defineProps<{ distTags: Record time: Record selectedVersion?: string + releases?: Release[] }>() const chartModal = useModal('chart-modal') @@ -458,28 +461,41 @@ function majorGroupContainsCurrent(group: (typeof otherMajorGroups.value)[0]): b
- - - {{ row.primaryVersion.version }} - - +
+ + + {{ row.primaryVersion.version }} + + + +
- - - {{ v.version }} - - +
+ + + {{ v.version }} + + + + +
- - - {{ row.primaryVersion.version }} - - +
+ + + {{ row.primaryVersion.version }} + + + + +
-
+
+
- - - {{ v.version }} - - +
+ + + {{ v.version }} + + + + +
| null } /** GitLab API response for project details */ @@ -85,6 +98,30 @@ type RadicleProjectResponse = { issues?: { open: number; closed: number } } +/** GitLab releases API response */ +type GitLabReleaseResponse = Array<{ + tag_name: string + name: string + released_at: string +}> + +/** Gitea/Forgejo releases API response */ +type GiteaReleaseResponse = Array<{ + tag_name: string + name: string + html_url: string + published_at: string + draft: boolean + prerelease: boolean +}> + +/** Bitbucket tags API response (used as releases) */ +type BitbucketTagResponse = { + values: Array<{ + name: string + }> +} + type ProviderAdapter = { id: ProviderId parse(url: URL): RepoRef | null @@ -95,6 +132,11 @@ type ProviderAdapter = { links: RepoMetaLinks, options?: Parameters[1], ): Promise + fetchReleases( + cachedFetch: CachedFetchFunction, + ref: RepoRef, + options?: Parameters[1], + ): Promise } const githubAdapter: ProviderAdapter = { @@ -124,6 +166,7 @@ const githubAdapter: ProviderAdapter = { stars: `${base}/stargazers`, forks: `${base}/forks`, watchers: `${base}/watchers`, + releases: `${base}/releases`, } }, @@ -155,6 +198,29 @@ const githubAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + // Using UNGH to avoid API limitations of the Github API + try { + const { data } = await cachedFetch( + `https://ungh.cc/repos/${ref.owner}/${ref.repo}/releases`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + const releases = data.releases + if (!releases) return [] + + return releases.map(release => ({ + tag: release.tag, + url: `https://github.com/${ref.owner}/${ref.repo}/releases/tag/${release.tag}`, + name: release.name, + publishedAt: release.publishedAt, + })) + } catch { + return [] + } + }, } const gitlabAdapter: ProviderAdapter = { @@ -189,6 +255,7 @@ const gitlabAdapter: ProviderAdapter = { repo: base, stars: `${base}/-/starrers`, forks: `${base}/-/forks`, + releases: `${base}/-/releases`, } }, @@ -219,6 +286,27 @@ const gitlabAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + const baseHost = ref.host ?? 'gitlab.com' + const projectPath = encodeURIComponent(`${ref.owner}/${ref.repo}`) + try { + const { data } = await cachedFetch( + `https://${baseHost}/api/v4/projects/${projectPath}/releases?per_page=30`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + return data.map(release => ({ + tag: release.tag_name, + url: `https://${baseHost}/${ref.owner}/${ref.repo}/-/releases/${release.tag_name}`, + name: release.name, + publishedAt: release.released_at, + })) + } catch { + return [] + } + }, } const bitbucketAdapter: ProviderAdapter = { @@ -247,6 +335,7 @@ const bitbucketAdapter: ProviderAdapter = { repo: base, stars: base, // Bitbucket doesn't have public stars forks: `${base}/forks`, + releases: `${base}/downloads`, } }, @@ -276,6 +365,23 @@ const bitbucketAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + try { + const { data } = await cachedFetch( + `https://api.bitbucket.org/2.0/repositories/${ref.owner}/${ref.repo}/refs/tags?pagelen=30`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + return data.values.map(tag => ({ + tag: tag.name, + url: `https://bitbucket.org/${ref.owner}/${ref.repo}/src/${tag.name}`, + })) + } catch { + return [] + } + }, } const codebergAdapter: ProviderAdapter = { @@ -305,6 +411,7 @@ const codebergAdapter: ProviderAdapter = { stars: base, // Codeberg doesn't have a separate stargazers page forks: `${base}/forks`, watchers: base, + releases: `${base}/releases`, } }, @@ -334,6 +441,25 @@ const codebergAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + try { + const { data } = await cachedFetch( + `https://codeberg.org/api/v1/repos/${ref.owner}/${ref.repo}/releases?limit=30`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + return data.map(release => ({ + tag: release.tag_name, + url: release.html_url, + name: release.name, + publishedAt: release.published_at, + })) + } catch { + return [] + } + }, } const giteeAdapter: ProviderAdapter = { @@ -363,6 +489,7 @@ const giteeAdapter: ProviderAdapter = { stars: `${base}/stargazers`, forks: `${base}/members`, watchers: `${base}/watchers`, + releases: `${base}/releases`, } }, @@ -392,6 +519,25 @@ const giteeAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + try { + const { data } = await cachedFetch( + `https://gitee.com/api/v5/repos/${ref.owner}/${ref.repo}/releases?per_page=30`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + return data.map(release => ({ + tag: release.tag_name, + url: release.html_url, + name: release.name, + publishedAt: release.published_at, + })) + } catch { + return [] + } + }, } /** @@ -450,6 +596,7 @@ const giteaAdapter: ProviderAdapter = { stars: base, forks: `${base}/forks`, watchers: base, + releases: `${base}/releases`, } }, @@ -483,6 +630,27 @@ const giteaAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + if (!ref.host) return [] + + try { + const { data } = await cachedFetch( + `https://${ref.host}/api/v1/repos/${ref.owner}/${ref.repo}/releases?limit=30`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + return data.map(release => ({ + tag: release.tag_name, + url: release.html_url, + name: release.name, + publishedAt: release.published_at, + })) + } catch { + return [] + } + }, } const sourcehutAdapter: ProviderAdapter = { @@ -512,6 +680,7 @@ const sourcehutAdapter: ProviderAdapter = { repo: base, stars: base, // Sourcehut doesn't have stars forks: base, + releases: `${base}/refs`, } }, @@ -526,6 +695,11 @@ const sourcehutAdapter: ProviderAdapter = { links, } }, + + async fetchReleases() { + // Sourcehut doesn't have a public API for releases + return [] + }, } const tangledAdapter: ProviderAdapter = { @@ -562,6 +736,7 @@ const tangledAdapter: ProviderAdapter = { repo: base, stars: base, // Tangled shows stars on the repo page forks: `${base}/fork`, + releases: `${base}/releases`, } }, @@ -590,6 +765,11 @@ const tangledAdapter: ProviderAdapter = { } } }, + + async fetchReleases() { + // Tangled doesn't have a public API for releases + return [] + }, } const radicleAdapter: ProviderAdapter = { @@ -616,6 +796,7 @@ const radicleAdapter: ProviderAdapter = { repo: base, stars: base, // Radicle doesn't have stars, shows seeding count forks: base, + releases: `${base}/patches`, } }, @@ -645,6 +826,11 @@ const radicleAdapter: ProviderAdapter = { links, } }, + + async fetchReleases() { + // Radicle doesn't have a public API for releases + return [] + }, } const forgejoAdapter: ProviderAdapter = { @@ -680,6 +866,7 @@ const forgejoAdapter: ProviderAdapter = { stars: base, forks: `${base}/forks`, watchers: base, + releases: `${base}/releases`, } }, @@ -711,6 +898,27 @@ const forgejoAdapter: ProviderAdapter = { links, } }, + + async fetchReleases(cachedFetch, ref, options = {}) { + if (!ref.host) return [] + + try { + const { data } = await cachedFetch( + `https://${ref.host}/api/v1/repos/${ref.owner}/${ref.repo}/releases?limit=30`, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, + REPO_META_TTL, + ) + + return data.map(release => ({ + tag: release.tag_name, + url: release.html_url, + name: release.name, + publishedAt: release.published_at, + })) + } catch { + return [] + } + }, } // Order matters: more specific adapters should come before generic ones @@ -758,6 +966,30 @@ export function useRepoMeta(repositoryUrl: MaybeRefOrGetter(() => data.value ?? null) + // Separate releases fetch + const { + data: releasesData, + pending: releasesPending, + error: releasesError, + refresh: refreshReleases, + } = useLazyAsyncData( + () => + repoRef.value + ? `repo-releases:${repoRef.value.provider}:${repoRef.value.owner}/${repoRef.value.repo}` + : 'repo-releases:none', + async (_nuxtApp, { signal }) => { + const ref = repoRef.value + if (!ref) return [] + + const adapter = providers.find(provider => provider.id === ref.provider) + if (!adapter) return [] + + return await adapter.fetchReleases(cachedFetch, ref, { signal }) + }, + ) + + const releases = computed(() => releasesData.value ?? []) + return { repoRef, meta, @@ -772,6 +1004,13 @@ export function useRepoMeta(repositoryUrl: MaybeRefOrGetter meta.value?.links.forks ?? null), watchersLink: computed(() => meta.value?.links.watchers ?? null), repoLink: computed(() => meta.value?.links.repo ?? null), + releasesLink: computed(() => meta.value?.links.releases ?? null), + + // Releases data and loading state + releases, + releasesPending, + releasesError, + refreshReleases, pending, error, diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index 002326d73..a4758bd77 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -17,6 +17,7 @@ import { detectPublishSecurityDowngradeForVersion } from '~/utils/publish-securi import { useModal } from '~/composables/useModal' import { useAtproto } from '~/composables/atproto/useAtproto' import { togglePackageLike } from '~/utils/atproto/likes' +import { getMatchedRelease } from '~/utils/releases' defineOgImageComponent('Package', { name: () => packageName.value, @@ -358,7 +359,23 @@ const repositoryUrl = computed(() => { return url }) -const { meta: repoMeta, repoRef, stars, starsLink, forks, forksLink } = useRepoMeta(repositoryUrl) +const { + meta: repoMeta, + repoRef, + stars, + starsLink, + forks, + forksLink, + releases, + releasesLink, + releasesPending, +} = useRepoMeta(repositoryUrl) + +const currentVersionRelease = computed(() => { + const version = resolvedVersion.value ?? displayVersion.value?.version + if (!version || !releases.value.length) return null + return getMatchedRelease(version, releases.value) +}) const PROVIDER_ICONS: Record = { github: 'i-carbon:logo-github', @@ -591,6 +608,16 @@ onKeyStroke( }, ) +onKeyStroke( + e => isKeyWithoutModifiers(e, 'r') && !isEditableElement(e.target), + e => { + if (!currentVersionRelease.value) return + e.preventDefault() + navigateTo(currentVersionRelease.value.url) + }, + { dedupe: true }, +) + const showSkeleton = shallowRef(false) @@ -734,6 +761,15 @@ const showSkeleton = shallowRef(false) > {{ $t('package.links.compare') }} + + {{ $t('package.links.release') }} + @@ -1334,6 +1370,7 @@ const showSkeleton = shallowRef(false) :dist-tags="pkg['dist-tags'] ?? {}" :time="pkg.time" :selected-version="resolvedVersion ?? pkg['dist-tags']?.['latest']" + :releases="releases" /> diff --git a/app/utils/releases.ts b/app/utils/releases.ts new file mode 100644 index 000000000..95d6425c9 --- /dev/null +++ b/app/utils/releases.ts @@ -0,0 +1,38 @@ +import type { Release } from '~/composables/useRepoMeta' + +/** + * Match an npm version string to a repository release. + * Handles various tag formats: "v1.0.0", "1.0.0", "release-1.0.0", etc. + * + * @param version - npm version string (e.g., "1.2.3", "0.9.0-beta.1") + * @param releases - Array of releases from repository + * @returns Matched release or null + */ +export function getMatchedRelease(version: string, releases: Release[]): Release | null { + if (!version || !releases.length) return null + + // Normalize version for comparison (remove any existing 'v' prefix) + const normalizedVersion = version.replace(/^v/, '').toLowerCase() + + // Try exact matches with common tag formats + const tagVariants = [ + `v${normalizedVersion}`, // Most common: v1.0.0 + normalizedVersion, // Without prefix: 1.0.0 + `release-${normalizedVersion}`, // Some projects: release-1.0.0 + `${normalizedVersion}-release`, // Alternative: 1.0.0-release + ] + + for (const release of releases) { + if (!release.url) continue + const releaseTag = release.tag.toLowerCase() + + // Check each variant (case-insensitive) + for (const variant of tagVariants) { + if (releaseTag === variant) { + return release + } + } + } + + return null +} diff --git a/i18n/locales/en.json b/i18n/locales/en.json index c103fc7c1..5f6231269 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -206,7 +206,14 @@ "code": "code", "docs": "docs", "fund": "fund", - "compare": "compare" + "compare": "compare", + "release": "release" + }, + "releases": { + "title": "Releases", + "view_all": "View all {count} releases", + "view_release": "View release", + "view_release_for_version": "View release for {version}" }, "likes": { "like": "Like this package", diff --git a/i18n/schema.json b/i18n/schema.json index 84cbbd10c..0f2828f84 100644 --- a/i18n/schema.json +++ b/i18n/schema.json @@ -624,6 +624,27 @@ }, "compare": { "type": "string" + }, + "release": { + "type": "string" + } + }, + "additionalProperties": false + }, + "releases": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "view_all": { + "type": "string" + }, + "view_release": { + "type": "string" + }, + "view_release_for_version": { + "type": "string" } }, "additionalProperties": false diff --git a/lunaria/files/en-GB.json b/lunaria/files/en-GB.json index 0bc7b6d46..7ecfccf89 100644 --- a/lunaria/files/en-GB.json +++ b/lunaria/files/en-GB.json @@ -205,7 +205,14 @@ "code": "code", "docs": "docs", "fund": "fund", - "compare": "compare" + "compare": "compare", + "release": "release" + }, + "releases": { + "title": "Releases", + "view_all": "View all {count} releases", + "view_release": "View release", + "view_release_for_version": "View release for {version}" }, "likes": { "like": "Like this package", diff --git a/lunaria/files/en-US.json b/lunaria/files/en-US.json index 5df67f00f..fc284479c 100644 --- a/lunaria/files/en-US.json +++ b/lunaria/files/en-US.json @@ -205,7 +205,14 @@ "code": "code", "docs": "docs", "fund": "fund", - "compare": "compare" + "compare": "compare", + "release": "release" + }, + "releases": { + "title": "Releases", + "view_all": "View all {count} releases", + "view_release": "View release", + "view_release_for_version": "View release for {version}" }, "likes": { "like": "Like this package", From 36eb589c36107d4f562ba7aae3c08ecaf1cf9cf0 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 11 Feb 2026 14:14:34 +0900 Subject: [PATCH 2/7] chore: update ui --- app/components/Package/Versions.vue | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/components/Package/Versions.vue b/app/components/Package/Versions.vue index 56e9fc0e2..66b020d5d 100644 --- a/app/components/Package/Versions.vue +++ b/app/components/Package/Versions.vue @@ -494,7 +494,7 @@ function majorGroupContainsCurrent(group: (typeof otherMajorGroups.value)[0]): b }) " class="inline-flex items-center text-fg-muted hover:text-fg transition-colors shrink-0" - > + />
-
Date: Wed, 11 Feb 2026 14:35:44 +0900 Subject: [PATCH 3/7] chore: cleanup --- app/components/Package/Versions.vue | 6 ++---- app/pages/package/[[org]]/[name].vue | 2 -- lunaria/files/en-GB.json | 3 --- lunaria/files/en-US.json | 3 --- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/app/components/Package/Versions.vue b/app/components/Package/Versions.vue index 66b020d5d..0b8406fc1 100644 --- a/app/components/Package/Versions.vue +++ b/app/components/Package/Versions.vue @@ -869,11 +869,9 @@ function majorGroupContainsCurrent(group: (typeof otherMajorGroups.value)[0]): b version: group.versions[0]?.version, }) " + classicon="i-carbon-catalog size-3" class="inline-flex items-center text-fg-muted hover:text-fg transition-colors shrink-0" - > -
{ diff --git a/lunaria/files/en-GB.json b/lunaria/files/en-GB.json index 7ecfccf89..637c14ceb 100644 --- a/lunaria/files/en-GB.json +++ b/lunaria/files/en-GB.json @@ -209,9 +209,6 @@ "release": "release" }, "releases": { - "title": "Releases", - "view_all": "View all {count} releases", - "view_release": "View release", "view_release_for_version": "View release for {version}" }, "likes": { diff --git a/lunaria/files/en-US.json b/lunaria/files/en-US.json index fc284479c..8206602a7 100644 --- a/lunaria/files/en-US.json +++ b/lunaria/files/en-US.json @@ -209,9 +209,6 @@ "release": "release" }, "releases": { - "title": "Releases", - "view_all": "View all {count} releases", - "view_release": "View release", "view_release_for_version": "View release for {version}" }, "likes": { From 717d38c2824346f69f3d395d7b2f507381a9fc37 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:37:20 +0000 Subject: [PATCH 4/7] [autofix.ci] apply automated fixes --- lunaria/files/en-GB.json | 3 +++ lunaria/files/en-US.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lunaria/files/en-GB.json b/lunaria/files/en-GB.json index 637c14ceb..7ecfccf89 100644 --- a/lunaria/files/en-GB.json +++ b/lunaria/files/en-GB.json @@ -209,6 +209,9 @@ "release": "release" }, "releases": { + "title": "Releases", + "view_all": "View all {count} releases", + "view_release": "View release", "view_release_for_version": "View release for {version}" }, "likes": { diff --git a/lunaria/files/en-US.json b/lunaria/files/en-US.json index 8206602a7..fc284479c 100644 --- a/lunaria/files/en-US.json +++ b/lunaria/files/en-US.json @@ -209,6 +209,9 @@ "release": "release" }, "releases": { + "title": "Releases", + "view_all": "View all {count} releases", + "view_release": "View release", "view_release_for_version": "View release for {version}" }, "likes": { From 963e6de50cb3708c7db4d515cc1b6906a7d6e457 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 11 Feb 2026 14:43:00 +0900 Subject: [PATCH 5/7] chore: cleanup --- app/components/Package/Versions.vue | 18 ++++++------------ i18n/locales/en.json | 3 --- i18n/schema.json | 9 --------- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/app/components/Package/Versions.vue b/app/components/Package/Versions.vue index 0b8406fc1..526bd629b 100644 --- a/app/components/Package/Versions.vue +++ b/app/components/Package/Versions.vue @@ -686,11 +686,9 @@ function majorGroupContainsCurrent(group: (typeof otherMajorGroups.value)[0]): b version: row.primaryVersion.version, }) " + classicon="i-carbon-catalog size-3" class="inline-flex items-center text-fg-muted hover:text-fg transition-colors shrink-0" - > -
-
@@ -942,11 +938,9 @@ function majorGroupContainsCurrent(group: (typeof otherMajorGroups.value)[0]): b :title=" $t('package.releases.view_release_for_version', { version: v.version }) " + classicon="i-carbon-catalog size-3" class="inline-flex items-center text-fg-muted hover:text-fg transition-colors shrink-0" - > -
Date: Wed, 11 Feb 2026 05:44:19 +0000 Subject: [PATCH 6/7] [autofix.ci] apply automated fixes --- lunaria/files/en-GB.json | 3 --- lunaria/files/en-US.json | 3 --- 2 files changed, 6 deletions(-) diff --git a/lunaria/files/en-GB.json b/lunaria/files/en-GB.json index 7ecfccf89..637c14ceb 100644 --- a/lunaria/files/en-GB.json +++ b/lunaria/files/en-GB.json @@ -209,9 +209,6 @@ "release": "release" }, "releases": { - "title": "Releases", - "view_all": "View all {count} releases", - "view_release": "View release", "view_release_for_version": "View release for {version}" }, "likes": { diff --git a/lunaria/files/en-US.json b/lunaria/files/en-US.json index fc284479c..8206602a7 100644 --- a/lunaria/files/en-US.json +++ b/lunaria/files/en-US.json @@ -209,9 +209,6 @@ "release": "release" }, "releases": { - "title": "Releases", - "view_all": "View all {count} releases", - "view_release": "View release", "view_release_for_version": "View release for {version}" }, "likes": { From f1559a564255b5777671e1c13d27973a0ebfdca4 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 11 Feb 2026 14:46:00 +0900 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- app/pages/package/[[org]]/[name].vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index 3c664a46f..2338ebeff 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -611,7 +611,7 @@ onKeyStroke( e => { if (!currentVersionRelease.value) return e.preventDefault() - navigateTo(currentVersionRelease.value.url) + navigateTo(currentVersionRelease.value.url, { external: true }) }, { dedupe: true }, ) @@ -764,7 +764,7 @@ const showSkeleton = shallowRef(false) variant="button-secondary" :to="currentVersionRelease.url" aria-keyshortcuts="r" - classicon="i-carbon-catalog" + classicon="i-carbon:catalog" > {{ $t('package.links.release') }}