Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3bf1ff1
feat: add basic version page with mock data
ShroXd Mar 13, 2026
1373fdf
feat: update page layout
ShroXd Mar 11, 2026
ff2c7a8
feat: tweaks layout
ShroXd Mar 11, 2026
55c8117
refactor: tweaks the layout
ShroXd Mar 11, 2026
16833e0
refactor: tweaks layout
ShroXd Mar 11, 2026
cdc2b3e
feat: use sticky card
ShroXd Mar 11, 2026
2a4a4e8
chore: clean up mock changelog
ShroXd Mar 12, 2026
793ee16
feat: fetch versions data
ShroXd Mar 12, 2026
71a566c
feat: grouped versions
ShroXd Mar 12, 2026
5343fac
feat: use map to avoid O(n) searching
ShroXd Mar 13, 2026
5d305d1
perf: init loading for basic data, and lazy full loading when expanding
ShroXd Mar 13, 2026
016f47b
feat: use virtual rendering
ShroXd Mar 13, 2026
0361273
perf: use shallowRef for deep data structure
ShroXd Mar 13, 2026
bdffaf3
feat: fallback for ssr
ShroXd Mar 13, 2026
879a7d4
feat: support filtering
ShroXd Mar 13, 2026
7589471
feat: tweaks versions' order
ShroXd Mar 13, 2026
fede892
chore: clean up
ShroXd Mar 13, 2026
7aa08d5
test: fix test of PackageVersions
ShroXd Mar 13, 2026
4a816e7
fix: fix virtual window rendering issue
ShroXd Mar 14, 2026
a233df6
fix: fix hltml lint errors
ShroXd Mar 14, 2026
c39d591
refactor: optimize type and css
ShroXd Mar 14, 2026
9b7412c
feat: searching animation and transition
ShroXd Mar 14, 2026
35919a0
test: add tests for package version page
ShroXd Mar 14, 2026
cba049c
chore: move hard coded text to i18n file
ShroXd Mar 14, 2026
f069028
feat: use debounce for filtering
ShroXd Mar 14, 2026
6f5c1b8
test: use data-testid
ShroXd Mar 14, 2026
bba4380
chore: remove all changelog related code
ShroXd Mar 14, 2026
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
38 changes: 29 additions & 9 deletions app/components/Package/Versions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ function versionRoute(version: string): RouteLocationRaw {
return packageRoute(props.packageName, version)
}
// Route to the full versions history page
const versionsPageRoute = computed((): RouteLocationRaw => {
const [org, name = ''] = props.packageName.startsWith('@')
? props.packageName.split('/')
: ['', props.packageName]
return { name: 'package-versions', params: { org, name } }
})
// Version to tags lookup (supports multiple tags per version)
const versionToTags = computed(() => buildVersionToTagsMap(props.distTags))
Expand Down Expand Up @@ -521,15 +529,27 @@ function majorGroupContainsCurrent(group: (typeof otherMajorGroups.value)[0]): b
id="versions"
>
<template #actions>
<ButtonBase
variant="secondary"
class="text-fg-subtle hover:text-fg transition-colors min-w-6 min-h-6 -m-1 p-1 rounded"
:title="$t('package.downloads.community_distribution')"
classicon="i-lucide:file-stack"
@click="openDistributionModal"
>
<span class="sr-only">{{ $t('package.downloads.community_distribution') }}</span>
</ButtonBase>
<div class="flex items-center gap-3">
<LinkBase
:to="versionsPageRoute"
variant="button-secondary"
class="text-fg-subtle hover:text-fg transition-colors min-w-6 min-h-6 p-1 rounded"
:title="$t('package.versions.view_all_versions')"
classicon="i-lucide:history"
data-testid="view-all-versions-link"
>
Comment on lines +533 to +540
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate LinkBase implementation"
fd -p 'Base.vue' app/components/Link

LINK_BASE_FILE="$(fd -p 'Base.vue' app/components/Link | head -n 1)"
echo "Inspecting: ${LINK_BASE_FILE}"

echo
echo "=== defineProps / attrs forwarding signals ==="
rg -n "defineProps|\\$attrs|inheritAttrs|v-bind=|data-testid|title" "$LINK_BASE_FILE"

echo
echo "=== file excerpt ==="
sed -n '1,260p' "$LINK_BASE_FILE"

Repository: npmx-dev/npmx.dev

Length of output: 270


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Inspecting LinkBase implementation ==="
cat -n app/components/Link/Base.vue

Repository: npmx-dev/npmx.dev

Length of output: 5803


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Versions.vue lines 530-545 ==="
sed -n '530,545p' app/components/Package/Versions.vue

echo
echo "=== Search for data-testid usage in Versions.vue ==="
rg -n 'data-testid' app/components/Package/Versions.vue | head -20

echo
echo "=== Search for tests using view-all-versions-link ==="
rg -r 'view-all-versions-link' --type ts --type tsx --type js --type jsx --type vue

Repository: npmx-dev/npmx.dev

Length of output: 1543


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for test files referencing view-all-versions-link ==="
fd -e spec -e test | xargs grep -l 'view-all-versions-link' 2>/dev/null || echo "No test files found with this selector"

echo
echo "=== Check for any __tests__ or test directories ==="
fd -type d -name '__tests__' -o -name 'tests' -o -name 'test' | head -10

echo
echo "=== Search all files for view-all-versions-link ==="
rg 'view-all-versions-link' --type-list | head -5
rg 'view-all-versions-link' 2>/dev/null || echo "Pattern not found in other files"

Repository: npmx-dev/npmx.dev

Length of output: 405


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Verify if LinkBase ever renders disabled state in practice ==="
rg -c 'disabled' app/components/Link/Base.vue

echo
echo "=== Check Versions.vue to see if disabled is ever passed ==="
rg -n 'LinkBase' app/components/Package/Versions.vue | grep -i disabled || echo "No disabled prop passed"

echo
echo "=== Verify title is also not declared (from learnings) ==="
rg -n "title" app/components/Link/Base.vue || echo "title not found in LinkBase"

Repository: npmx-dev/npmx.dev

Length of output: 303


data-testid and title attributes are not forwarded by LinkBase.

LinkBase does not declare data-testid or title as props. The component uses a v-if/v-else fragment where the non-disabled branch renders <NuxtLink v-bind="props">. Since v-bind="props" only forwards declared props, these HTML attributes are silently dropped and will not appear on the rendered DOM element, making the test selector ineffective and the title attribute unavailable to assistive technologies.

To fix this, add both data-testid and title to LinkBase's defineProps, and forward them explicitly to the <NuxtLink> (the <span> branch can also receive them if needed for consistency).

<span class="sr-only">{{ $t('package.versions.view_all_versions') }}</span>
</LinkBase>
<ButtonBase
variant="secondary"
class="text-fg-subtle hover:text-fg transition-colors min-w-6 min-h-6 -m-1 p-1 rounded"
:title="$t('package.downloads.community_distribution')"
classicon="i-lucide:file-stack"
@click="openDistributionModal"
>
<span class="sr-only">{{ $t('package.downloads.community_distribution') }}</span>
</ButtonBase>
</div>
</template>
<div class="space-y-0.5 min-w-0">
<!-- Semver range filter -->
Expand Down
7 changes: 5 additions & 2 deletions app/pages/package/[[org]]/[name].vue
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ const { diff: sizeDiff } = useInstallSizeDiff(packageName, resolvedVersion, pkg,
// β†’ Preserve the server-rendered DOM, don't flash to skeleton.
const nuxtApp = useNuxtApp()
const route = useRoute()
// Gates template rendering only β€” data fetches intentionally still run.
const isVersionsRoute = computed(() => route.name === 'package-versions')
Comment on lines +210 to +211
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Versions route still triggers the full package data pipeline.
This gates rendering only, but all heavyweight fetch/composable initialisation still runs on /versions. That adds avoidable load and weakens the intended versions-page optimisation. Please gate expensive package-detail data hooks for this route, or move the versions page into a sibling route shell that does not initialise main-page data.

Also applies to: 521-535

const hasEmptyPayload =
import.meta.client &&
nuxtApp.payload.serverRendered &&
Expand Down Expand Up @@ -516,7 +518,8 @@ const showSkeleton = shallowRef(false)
</script>

<template>
<DevOnly>
<NuxtPage v-if="isVersionsRoute" />
<DevOnly v-else>
<ButtonBase
class="fixed bottom-4 inset-is-4 z-50 shadow-lg rounded-full! px-3! py-2!"
classicon="i-simple-icons:skeleton"
Expand All @@ -528,7 +531,7 @@ const showSkeleton = shallowRef(false)
<span class="text-xs">Skeleton</span>
</ButtonBase>
</DevOnly>
<main class="flex-1 pb-8">
<main v-if="!isVersionsRoute" class="flex-1 pb-8">
<!-- Scenario 1: SPA fallback β€” show skeleton (no real content to preserve) -->
<!-- Scenario 2: SSR with missing payload β€” preserve server DOM, skip skeleton -->
<PackageSkeleton
Expand Down
Loading
Loading