Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
50ff9f9
feat: add basic version page with mock data
ShroXd Mar 13, 2026
8cafc0d
feat: update page layout
ShroXd Mar 11, 2026
165c233
feat: tweaks layout
ShroXd Mar 11, 2026
5bf81b1
refactor: tweaks the layout
ShroXd Mar 11, 2026
899e632
refactor: tweaks layout
ShroXd Mar 11, 2026
6b52875
feat: use sticky card
ShroXd Mar 11, 2026
778f4e4
chore: clean up mock changelog
ShroXd Mar 12, 2026
4bddb37
feat: fetch versions data
ShroXd Mar 12, 2026
e5c0760
feat: grouped versions
ShroXd Mar 12, 2026
483a5ca
feat: use map to avoid O(n) searching
ShroXd Mar 13, 2026
d54e400
perf: init loading for basic data, and lazy full loading when expanding
ShroXd Mar 13, 2026
6cb427f
feat: use virtual rendering
ShroXd Mar 13, 2026
bbd67a9
perf: use shallowRef for deep data structure
ShroXd Mar 13, 2026
76019ad
feat: fallback for ssr
ShroXd Mar 13, 2026
16c8e7f
feat: support filtering
ShroXd Mar 13, 2026
249d066
feat: tweaks versions' order
ShroXd Mar 13, 2026
cf177cd
chore: clean up
ShroXd Mar 13, 2026
8c6084b
test: fix test of PackageVersions
ShroXd Mar 13, 2026
215c9b4
fix: fix virtual window rendering issue
ShroXd Mar 14, 2026
bd2ab8d
fix: fix hltml lint errors
ShroXd Mar 14, 2026
ad1eab9
refactor: optimize type and css
ShroXd Mar 14, 2026
e4d9ee4
feat: searching animation and transition
ShroXd Mar 14, 2026
9433311
test: add tests for package version page
ShroXd Mar 14, 2026
6a56258
chore: move hard coded text to i18n file
ShroXd Mar 14, 2026
e62e236
feat: use debounce for filtering
ShroXd Mar 14, 2026
978ecec
test: use data-testid
ShroXd Mar 14, 2026
891573b
chore: remove all changelog related code
ShroXd Mar 14, 2026
59ef007
chore: explain why we cant disable fething in package/[name].vue page
ShroXd Mar 15, 2026
9a72c6b
fix: remove unnecessary aria-label
ShroXd Mar 15, 2026
1466e8b
test: encapsute similar filter lambda logic
ShroXd Mar 16, 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"
>
<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
8 changes: 6 additions & 2 deletions app/pages/package/[[org]]/[name].vue
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ 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.
// immediate is set once at mount β€” skipped requests won't re-fire on navigation, leaving data permanently missing.
const isVersionsRoute = computed(() => route.name === 'package-versions')
const hasEmptyPayload =
import.meta.client &&
nuxtApp.payload.serverRendered &&
Expand Down Expand Up @@ -479,7 +482,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 @@ -491,7 +495,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