@@ -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,37 @@ 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 ) {
327- updatedGroup .isExpanded = true
328- }
329- } catch (error ) {
330- // eslint-disable-next-line no-console
331- console .error (' Failed to load versions:' , error )
332- } finally {
333- group .isLoading = false
343+ group .isLoading = true
344+ try {
345+ const allVersions = await loadAllVersions ()
346+ processLoadedVersions (allVersions )
347+ showAllGroups .value = hasAdditionalGroups .value
348+
349+ // Find the group again after processing (it may have moved)
350+ const updatedGroup = versionGroups .value .find (g => g .id === groupId )
351+ if (updatedGroup && hasNestedVersions (updatedGroup )) {
352+ updatedGroup .isExpanded = true
334353 }
335- } else {
336- group .isExpanded = true
354+ } catch (error ) {
355+ // eslint-disable-next-line no-console
356+ console .error (' Failed to load versions:' , error )
357+ } finally {
358+ group .isLoading = false
337359 }
338360}
339361
@@ -345,7 +367,7 @@ async function toggleGroup(groupId: string) {
345367const flatItems = computed (() => {
346368 const items: Array <{ type: ' group' | ' version' ; groupId: string ; version? : VersionDisplay }> = []
347369
348- for (const group of versionGroups .value ) {
370+ for (const group of visibleVersionGroups .value ) {
349371 items .push ({ type: ' group' , groupId: group .id , version: group .primaryVersion })
350372
351373 if (group .isExpanded && group .versions .length > 1 ) {
@@ -401,7 +423,7 @@ function handleListboxKeydown(event: KeyboardEvent) {
401423 const item = items [focusedIndex .value ]
402424 if (item ?.type === ' group' ) {
403425 const group = versionGroups .value .find (g => g .id === item .groupId )
404- if (group && ! group . isExpanded && (group . versions . length > 1 || ! hasLoadedAll . value )) {
426+ if (group && ! isGroupOpen ( group ) && canToggleGroup (group )) {
405427 toggleGroup (item .groupId )
406428 }
407429 }
@@ -414,6 +436,8 @@ function handleListboxKeydown(event: KeyboardEvent) {
414436 const group = versionGroups .value .find (g => g .id === item .groupId )
415437 if (group ?.isExpanded ) {
416438 group .isExpanded = false
439+ } else if (group && controlsAdditionalGroups (group ) && showAllGroups .value ) {
440+ showAllGroups .value = false
417441 }
418442 } else if (item ?.type === ' version' ) {
419443 // Jump to parent group
@@ -450,6 +474,31 @@ function navigateToVersion(version: string) {
450474 navigateTo (getVersionUrl (version ))
451475}
452476
477+ function hasNestedVersions(group : VersionGroup ): boolean {
478+ return group .versions .length > 1
479+ }
480+
481+ function controlsAdditionalGroups(group : VersionGroup ): boolean {
482+ return (
483+ Boolean (group .primaryVersion .tags ?.length ) &&
484+ ! hasNestedVersions (group ) &&
485+ hasAdditionalGroups .value
486+ )
487+ }
488+
489+ function isGroupOpen(group : VersionGroup ): boolean {
490+ return group .isExpanded || (controlsAdditionalGroups (group ) && showAllGroups .value )
491+ }
492+
493+ function canToggleGroup(group : VersionGroup ): boolean {
494+ return (
495+ group .isLoading ||
496+ hasNestedVersions (group ) ||
497+ ! hasLoadedAll .value ||
498+ controlsAdditionalGroups (group )
499+ )
500+ }
501+
453502// Reset focused index when dropdown opens
454503watch (isOpen , open => {
455504 if (open ) {
@@ -463,6 +512,7 @@ watch(isOpen, open => {
463512watch (
464513 () => [props .distTags , props .versions , props .currentVersion ],
465514 () => {
515+ showAllGroups .value = false
466516 if (hasLoadedAll .value && allVersionsCache .value ) {
467517 processLoadedVersions (allVersionsCache .value )
468518 } else {
@@ -518,7 +568,7 @@ watch(
518568 @keydown =" handleListboxKeydown"
519569 >
520570 <!-- Version groups -->
521- <div v-for =" group in versionGroups " :key =" group.id" >
571+ <div v-for =" group in visibleVersionGroups " :key =" group.id" >
522572 <!-- Group header (primary version) -->
523573 <div
524574 :id =" `version-${group.primaryVersion.version}`"
@@ -539,11 +589,11 @@ watch(
539589 >
540590 <!-- Expand button -->
541591 <button
542- v-if =" group.isExpanded || group.versions.length > 1 || !hasLoadedAll "
592+ v-if =" canToggleGroup( group) "
543593 type =" button"
544594 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')"
595+ :aria-expanded =" isGroupOpen( group) "
596+ :aria-label =" isGroupOpen( group) ? $t('common.collapse') : $t('common.expand')"
547597 @click.stop =" toggleGroup(group.id)"
548598 >
549599 <span
@@ -554,11 +604,11 @@ watch(
554604 <span
555605 v-else
556606 class =" w-3 h-3 transition-transform duration-200 rtl-flip"
557- :class =" group.isExpanded ? 'i-lucide:chevron-down' : 'i-lucide:chevron-right'"
607+ :class =" isGroupOpen( group) ? 'i-lucide:chevron-down' : 'i-lucide:chevron-right'"
558608 aria-hidden =" true"
559609 />
560610 </button >
561- <span v-else class =" w-4" />
611+ <span v-else class =" w-4 h-4 shrink-0 " />
562612
563613 <!-- Version link -->
564614 <NuxtLink
0 commit comments