@@ -70,6 +70,9 @@ const isLoadingAll = shallowRef(false)
7070/** Cached full version list */
7171const allVersionsCache = shallowRef <PackageVersionInfo [] | null >(null )
7272
73+ /** Whether non-tagged version groups are visible */
74+ const showAllGroups = shallowRef (false )
75+
7376// ============================================================================
7477// Computed
7578// ============================================================================
@@ -78,6 +81,18 @@ const latestVersion = computed(() => props.distTags.latest)
7881
7982const versionToTags = computed (() => buildVersionToTagsMap (props .distTags ))
8083
84+ const visibleVersionGroups = computed (() => {
85+ if (! hasLoadedAll .value || showAllGroups .value ) {
86+ return versionGroups .value
87+ }
88+
89+ return versionGroups .value .filter (group => group .primaryVersion .tags ?.length )
90+ })
91+
92+ const hasAdditionalGroups = computed (() =>
93+ versionGroups .value .some (group => ! group .primaryVersion .tags ?.length ),
94+ )
95+
8196/** Get URL for a specific version */
8297function getVersionUrl(version : string ): string {
8398 return props .urlPattern .replace (' {version}' , version )
@@ -310,30 +325,40 @@ async function toggleGroup(groupId: string) {
310325 const group = versionGroups .value .find (g => g .id === groupId )
311326 if (! group ) return
312327
313- if (group .isExpanded ) {
314- group .isExpanded = false
328+ if (group .isLoading ) return
329+
330+ if (hasLoadedAll .value ) {
331+ if (hasNestedVersions (group )) {
332+ group .isExpanded = ! group .isExpanded
333+ return
334+ }
335+
336+ if (controlsAdditionalGroups (group )) {
337+ showAllGroups .value = ! showAllGroups .value
338+ }
339+
315340 return
316341 }
317342
318- // Load all versions if not yet loaded
319- if ( ! hasLoadedAll . value ) {
320- group . isLoading = true
321- try {
322- const allVersions = await loadAllVersions ()
323- processLoadedVersions ( allVersions )
324- // Find the group again after processing (it may have moved )
325- const updatedGroup = versionGroups . value . find ( g => g . id === groupId )
326- if (updatedGroup ) {
343+ group . isLoading = true
344+ try {
345+ const allVersions = await loadAllVersions ()
346+ processLoadedVersions ( allVersions )
347+
348+ // Find the group again after processing (it may have moved )
349+ const updatedGroup = versionGroups . value . find ( g => g . id === groupId )
350+ if ( updatedGroup ) {
351+ if (hasNestedVersions ( updatedGroup ) ) {
327352 updatedGroup .isExpanded = true
353+ } else if (controlsAdditionalGroups (updatedGroup )) {
354+ showAllGroups .value = true
328355 }
329- } catch (error ) {
330- // eslint-disable-next-line no-console
331- console .error (' Failed to load versions:' , error )
332- } finally {
333- group .isLoading = false
334356 }
335- } else {
336- group .isExpanded = true
357+ } catch (error ) {
358+ // eslint-disable-next-line no-console
359+ console .error (' Failed to load versions:' , error )
360+ } finally {
361+ group .isLoading = false
337362 }
338363}
339364
@@ -345,7 +370,7 @@ async function toggleGroup(groupId: string) {
345370const flatItems = computed (() => {
346371 const items: Array <{ type: ' group' | ' version' ; groupId: string ; version? : VersionDisplay }> = []
347372
348- for (const group of versionGroups .value ) {
373+ for (const group of visibleVersionGroups .value ) {
349374 items .push ({ type: ' group' , groupId: group .id , version: group .primaryVersion })
350375
351376 if (group .isExpanded && group .versions .length > 1 ) {
@@ -401,7 +426,7 @@ function handleListboxKeydown(event: KeyboardEvent) {
401426 const item = items [focusedIndex .value ]
402427 if (item ?.type === ' group' ) {
403428 const group = versionGroups .value .find (g => g .id === item .groupId )
404- if (group && ! group . isExpanded && group . versions . length > 1 ) {
429+ if (group && ! isGroupOpen ( group ) && canToggleGroup ( group ) ) {
405430 toggleGroup (item .groupId )
406431 }
407432 }
@@ -414,6 +439,8 @@ function handleListboxKeydown(event: KeyboardEvent) {
414439 const group = versionGroups .value .find (g => g .id === item .groupId )
415440 if (group ?.isExpanded ) {
416441 group .isExpanded = false
442+ } else if (group && controlsAdditionalGroups (group ) && showAllGroups .value ) {
443+ showAllGroups .value = false
417444 }
418445 } else if (item ?.type === ' version' ) {
419446 // Jump to parent group
@@ -450,6 +477,31 @@ function navigateToVersion(version: string) {
450477 navigateTo (getVersionUrl (version ))
451478}
452479
480+ function hasNestedVersions(group : VersionGroup ): boolean {
481+ return group .versions .length > 1
482+ }
483+
484+ function controlsAdditionalGroups(group : VersionGroup ): boolean {
485+ return (
486+ Boolean (group .primaryVersion .tags ?.length ) &&
487+ ! hasNestedVersions (group ) &&
488+ hasAdditionalGroups .value
489+ )
490+ }
491+
492+ function isGroupOpen(group : VersionGroup ): boolean {
493+ return group .isExpanded || (controlsAdditionalGroups (group ) && showAllGroups .value )
494+ }
495+
496+ function canToggleGroup(group : VersionGroup ): boolean {
497+ return (
498+ group .isLoading ||
499+ hasNestedVersions (group ) ||
500+ ! hasLoadedAll .value ||
501+ controlsAdditionalGroups (group )
502+ )
503+ }
504+
453505// Reset focused index when dropdown opens
454506watch (isOpen , open => {
455507 if (open ) {
@@ -463,6 +515,7 @@ watch(isOpen, open => {
463515watch (
464516 () => [props .distTags , props .versions , props .currentVersion ],
465517 () => {
518+ showAllGroups .value = false
466519 if (hasLoadedAll .value && allVersionsCache .value ) {
467520 processLoadedVersions (allVersionsCache .value )
468521 } else {
@@ -518,7 +571,7 @@ watch(
518571 @keydown =" handleListboxKeydown"
519572 >
520573 <!-- Version groups -->
521- <div v-for =" group in versionGroups " :key =" group.id" >
574+ <div v-for =" group in visibleVersionGroups " :key =" group.id" >
522575 <!-- Group header (primary version) -->
523576 <div
524577 :id =" `version-${group.primaryVersion.version}`"
@@ -539,11 +592,11 @@ watch(
539592 >
540593 <!-- Expand button -->
541594 <button
542- v-if =" group.versions.length > 1 || !hasLoadedAll "
595+ v-if =" canToggleGroup( group) "
543596 type =" button"
544597 class =" w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg transition-colors shrink-0"
545- :aria-expanded =" group.isExpanded "
546- :aria-label =" group.isExpanded ? $t('common.collapse') : $t('common.expand')"
598+ :aria-expanded =" isGroupOpen( group) "
599+ :aria-label =" isGroupOpen( group) ? $t('common.collapse') : $t('common.expand')"
547600 @click.stop =" toggleGroup(group.id)"
548601 >
549602 <span
@@ -554,11 +607,11 @@ watch(
554607 <span
555608 v-else
556609 class =" w-3 h-3 transition-transform duration-200 rtl-flip"
557- :class =" group.isExpanded ? 'i-lucide:chevron-down' : 'i-lucide:chevron-right'"
610+ :class =" isGroupOpen( group) ? 'i-lucide:chevron-down' : 'i-lucide:chevron-right'"
558611 aria-hidden =" true"
559612 />
560613 </button >
561- <span v-else class =" w-4" />
614+ <span v-else class =" w-4 h-4 shrink-0 " />
562615
563616 <!-- Version link -->
564617 <NuxtLink
@@ -626,7 +679,7 @@ watch(
626679 <!-- Link to package page for full version list -->
627680 <div class =" border-t border-border mt-1 pt-1 px-3 py-2" >
628681 <NuxtLink
629- :to =" packageRoute (packageName)"
682+ :to =" packageVersionsRoute (packageName)"
630683 class =" text-xs text-fg-subtle hover:text-fg transition-[color] focus-visible:outline-none focus-visible:text-fg"
631684 @click =" isOpen = false"
632685 >
0 commit comments