Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/components/ClaimPackageModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ const connectorModalOpen = shallowRef(false)

<div class="flex gap-3">
<NuxtLink
:to="`/package/${packageName}`"
:to="getPackageRoute(packageName)"
class="flex-1 px-4 py-2 font-mono text-sm text-center text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
@click="open = false"
>
Expand Down Expand Up @@ -299,7 +299,7 @@ const connectorModalOpen = shallowRef(false)
<span v-else class="w-4 h-4 shrink-0" />
<div class="min-w-0">
<NuxtLink
:to="`/package/${pkg.name}`"
:to="getPackageRoute(pkg.name)"
class="font-mono text-sm text-fg hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded"
target="_blank"
>
Expand Down
2 changes: 1 addition & 1 deletion app/components/HeaderPackagesDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function handleKeydown(event: KeyboardEvent) {
<ul v-else-if="packages.length > 0" class="py-1 max-h-80 overflow-y-auto">
<li v-for="pkg in packages" :key="pkg">
<NuxtLink
:to="`/${pkg}`"
:to="getPackageRoute(pkg)"
class="block px-3 py-2 font-mono text-sm text-fg hover:bg-bg-subtle transition-colors truncate"
>
{{ pkg }}
Expand Down
2 changes: 1 addition & 1 deletion app/components/PackageCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const emit = defineEmits<{
class="font-mono text-sm sm:text-base font-medium text-fg group-hover:text-fg transition-colors duration-200 min-w-0 break-all"
>
<NuxtLink
:to="{ name: 'package', params: { package: result.package.name.split('/') } }"
:to="getPackageRoute(result.package.name, result.package.version)"
:prefetch-on="prefetch ? 'visibility' : 'interaction'"
class="decoration-none scroll-mt-48 scroll-mb-6 after:content-[''] after:absolute after:inset-0"
:data-result-index="index"
Expand Down
20 changes: 7 additions & 13 deletions app/components/PackageDependencies.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const sortedOptionalDependencies = computed(() => {
class="flex items-center justify-between py-1 text-sm gap-2"
>
<NuxtLink
:to="{ name: 'package', params: { package: dep.split('/') } }"
:to="getPackageRoute(dep)"
class="font-mono text-fg-muted hover:text-fg transition-colors duration-200 truncate min-w-0"
>
{{ dep }}
Expand All @@ -109,10 +109,7 @@ const sortedOptionalDependencies = computed(() => {
</span>
<NuxtLink
v-if="getVulnerableDepInfo(dep)"
:to="{
name: 'package',
params: { package: [...dep.split('/'), 'v', getVulnerableDepInfo(dep)!.version] },
}"
:to="getPackageRoute(dep, getVulnerableDepInfo(dep)!.version)"
class="shrink-0"
:class="SEVERITY_TEXT_COLORS[getHighestSeverity(getVulnerableDepInfo(dep)!.counts)]"
:title="`${getVulnerableDepInfo(dep)!.counts.total} vulnerabilities`"
Expand All @@ -121,7 +118,7 @@ const sortedOptionalDependencies = computed(() => {
<span class="sr-only">{{ $t('package.dependencies.view_vulnerabilities') }}</span>
</NuxtLink>
<NuxtLink
:to="{ name: 'package', params: { package: [...dep.split('/'), 'v', version] } }"
:to="getPackageRoute(dep, version)"
class="font-mono text-xs text-right truncate"
:class="getVersionClass(outdatedDeps[dep])"
:title="outdatedDeps[dep] ? getOutdatedTooltip(outdatedDeps[dep]) : version"
Expand Down Expand Up @@ -180,7 +177,7 @@ const sortedOptionalDependencies = computed(() => {
>
<div class="flex items-center gap-2 min-w-0">
<NuxtLink
:to="{ name: 'package', params: { package: peer.name.split('/') } }"
:to="getPackageRoute(peer.name)"
class="font-mono text-fg-muted hover:text-fg transition-colors duration-200 truncate"
>
{{ peer.name }}
Expand All @@ -194,10 +191,7 @@ const sortedOptionalDependencies = computed(() => {
</span>
</div>
<NuxtLink
:to="{
name: 'package',
params: { package: [...peer.name.split('/'), 'v', peer.version] },
}"
:to="getPackageRoute(peer.name, peer.version)"
class="font-mono text-xs text-fg-subtle max-w-[40%] text-right truncate"
:title="peer.version"
>
Expand Down Expand Up @@ -252,13 +246,13 @@ const sortedOptionalDependencies = computed(() => {
class="flex items-center justify-between py-1 text-sm gap-2"
>
<NuxtLink
:to="{ name: 'package', params: { package: dep.split('/') } }"
:to="getPackageRoute(dep)"
class="font-mono text-fg-muted hover:text-fg transition-colors duration-200 truncate min-w-0"
>
{{ dep }}
</NuxtLink>
<NuxtLink
:to="{ name: 'package', params: { package: [...dep.split('/'), 'v', version] } }"
:to="getPackageRoute(dep, version)"
class="font-mono text-xs text-fg-subtle max-w-[50%] text-right truncate"
:title="version"
>
Expand Down
2 changes: 1 addition & 1 deletion app/components/PackageInstallScripts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const isExpanded = shallowRef(false)
class="flex items-center justify-between py-0.5 text-sm gap-2"
>
<NuxtLink
:to="{ name: 'package', params: { package: dep.split('/') } }"
:to="getPackageRoute(dep)"
class="font-mono text-fg-muted hover:text-fg transition-colors duration-200 truncate min-w-0"
>
{{ dep }}
Expand Down
5 changes: 1 addition & 4 deletions app/components/PackageVersions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ function hasProvenance(version: PackumentVersion | undefined): boolean {

// Build route object for package version link
function versionRoute(version: string): RouteLocationRaw {
return {
name: 'package',
params: { package: [...props.packageName.split('/'), 'v', version] },
}
return getPackageRoute(props.packageName, version)
}

// Version to tags lookup (supports multiple tags per version)
Expand Down
2 changes: 1 addition & 1 deletion app/components/VersionSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ watch(
<!-- Link to package page for full version list -->
<div class="border-t border-border mt-1 pt-1 px-3 py-2">
<NuxtLink
:to="`/${packageName}`"
:to="getPackageRoute(packageName)"
class="text-xs text-fg-subtle hover:text-fg transition-[color] focus-visible:outline-none focus-visible:text-fg"
@click="isOpen = false"
>
Expand Down
37 changes: 22 additions & 15 deletions app/composables/usePackageRoute.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/**
* Generate a route object for navigating to a package page.
*
* @param pkg - Package name (e.g., "nuxt" or "@nuxt/kit")
* @param version - Optional version string
* @returns Route object with name and params
* @public
*/
export function getPackageRoute(pkg: string, version: string | null = null) {
return {
name: 'package',
params: {
package: [...pkg.split('/'), version ? 'v' : null, version].filter(
(a): a is NonNullable<typeof a> => !!a,
),
},
} as const
}

/**
* Parse package name and optional version from the route URL.
*
Expand All @@ -13,7 +32,7 @@
export function usePackageRoute() {
const route = useRoute('package')

const parsedRoute = computed(() => {
const data = computed(() => {
const segments = route.params.package || []

// Find the /v/ separator for version
Expand Down Expand Up @@ -42,20 +61,8 @@ export function usePackageRoute() {
}
})

const packageName = computed(() => parsedRoute.value.packageName)
const requestedVersion = computed(() => parsedRoute.value.requestedVersion)

// Extract org name from scoped package (e.g., "@nuxt/kit" -> "nuxt")
const orgName = computed(() => {
const name = packageName.value
if (!name.startsWith('@')) return null
const match = name.match(/^@([^/]+)\//)
return match ? match[1] : null
})

return {
packageName,
requestedVersion,
orgName,
packageName: computed(() => data.value.packageName),
requestedVersion: computed(() => data.value.requestedVersion),
}
}
16 changes: 12 additions & 4 deletions app/pages/[...package].vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ definePageMeta({

const router = useRouter()

const { packageName, requestedVersion, orgName } = usePackageRoute()
const { packageName, requestedVersion } = usePackageRoute()

const orgName = computed(() => {
const name = packageName.value
if (!name.startsWith('@')) return null

const match = name.match(/^@([^/]+)\//)
return match ? match[1] : null
})

if (import.meta.server) {
assertValidPackageName(packageName.value)
Expand Down Expand Up @@ -472,7 +480,7 @@ defineOgImageComponent('Package', {

<NuxtLink
v-if="resolvedVersion !== requestedVersion"
:to="`/${pkg.name}/v/${displayVersion.version}`"
:to="getPackageRoute(pkg.name, displayVersion.version)"
:title="$t('package.view_permalink')"
>{{ displayVersion.version }}</NuxtLink
>
Expand Down Expand Up @@ -993,7 +1001,7 @@ defineOgImageComponent('Package', {
>
<NuxtLink
v-if="typesPackageName"
:to="`/${typesPackageName}`"
:to="getPackageRoute(typesPackageName)"
class="text-fg-subtle hover:text-fg-muted text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded"
:title="$t('package.get_started.view_types', { package: typesPackageName })"
>
Expand Down Expand Up @@ -1077,7 +1085,7 @@ defineOgImageComponent('Package', {
}}</span>
</button>
<NuxtLink
:to="`/${createPackageInfo.packageName}`"
:to="getPackageRoute(createPackageInfo.packageName)"
class="text-fg-subtle hover:text-fg-muted text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded"
:title="`View ${createPackageInfo.packageName}`"
>
Expand Down
6 changes: 1 addition & 5 deletions app/pages/code/[...path].vue
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,7 @@ const orgName = computed(() => {
// Build route object for package link (with optional version)
function packageRoute(ver?: string | null) {
const segments = packageName.value.split('/')
if (ver) {
segments.push('v', ver)
}
return { name: 'package' as const, params: { package: segments } }
return getPackageRoute(packageName.value, ver)
}
// Format file size
Expand Down
2 changes: 1 addition & 1 deletion app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ defineOgImageComponent('Default')
:key="pkg"
>
<NuxtLink
:to="{ name: 'package', params: { package: [pkg] } }"
:to="getPackageRoute(pkg)"
class="link-subtle font-mono text-sm inline-flex items-center gap-2 group"
>
<span
Expand Down
Loading