@@ -5,6 +5,7 @@ import type {
55 TimelineResponse ,
66 TimelineVersion ,
77} from ' ~~/server/api/registry/timeline/[...pkg].get'
8+ import type { TimelineSizeResponse } from ' ~~/server/api/registry/timeline/sizes/[...pkg].get'
89
910definePageMeta ({
1011 name: ' timeline' ,
@@ -81,13 +82,15 @@ watch(
8182)
8283
8384async function loadMore() {
84- if (loadingMore .value || sizesLoading . value ) return
85+ if (loadingMore .value ) return
8586 loadingMore .value = true
8687 loadError .value = false
8788 try {
88- const data = await fetchTimeline (timelineEntries .value .length )
89+ const offset = timelineEntries .value .length
90+ const data = await fetchTimeline (offset )
8991 timelineEntries .value = [... timelineEntries .value , ... data .versions ]
9092 totalVersions .value = data .total
93+ fetchSizes (offset )
9194 } catch {
9295 loadError .value = true
9396 } finally {
@@ -99,39 +102,40 @@ const SIZE_INCREASE_THRESHOLD = 0.25
99102const DEP_INCREASE_THRESHOLD = 5
100103const NO_LICENSE_VALUES = new Set ([' ' , ' UNLICENSED' ])
101104
102- const sizeCache = shallowReactive (new Map <string , InstallSizeResult >())
103- const fetchingVersions = shallowReactive (new Set <string >())
104-
105- const sizesLoading = computed (() => fetchingVersions .size > 0 )
105+ const sizeCache = shallowReactive (new Map <string , { totalSize: number ; dependencyCount: number }>())
106+ const sizeFetchesInFlight = ref (0 )
107+ const sizesLoading = computed (() => sizeFetchesInFlight .value > 0 )
106108
107109function sizeKey(ver : string ) {
108110 return ` ${packageName .value }@${ver } `
109111}
110112
111- async function fetchSize(ver : string ) {
112- const key = sizeKey (ver )
113- if (sizeCache .has (key ) || fetchingVersions .has (key )) return
114- fetchingVersions .add (key )
113+ async function fetchSizes(offset : number ) {
114+ sizeFetchesInFlight .value ++
115115 try {
116- const data = await $fetch <InstallSizeResult >(
117- ` /api/registry/install-size/${packageName .value }/v/${ver } ` ,
116+ const data = await $fetch <TimelineSizeResponse >(
117+ ` /api/registry/timeline/sizes/${packageName .value } ` ,
118+ { query: { offset , limit: PAGE_SIZE } },
118119 )
119- sizeCache .set (key , data )
120+ for (const entry of data .sizes ) {
121+ sizeCache .set (sizeKey (entry .version ), {
122+ totalSize: entry .totalSize ,
123+ dependencyCount: entry .dependencyCount ,
124+ })
125+ }
120126 } catch {
121127 // silently skip - size data is best-effort
122128 } finally {
123- fetchingVersions . delete ( key )
129+ sizeFetchesInFlight . value --
124130 }
125131}
126132
127- // Fetch sizes for visible versions
133+ // Fetch sizes for the initial page
128134if (import .meta .client ) {
129135 watch (
130- timelineEntries ,
131- entries => {
132- for (const entry of entries ) {
133- fetchSize (entry .version )
134- }
136+ initialTimeline ,
137+ () => {
138+ fetchSizes (0 )
135139 },
136140 { immediate: true },
137141 )
@@ -322,6 +326,11 @@ useSeoMeta({
322326 />
323327
324328 <div class =" container w-full py-8" >
329+ <!-- Sizes loading indicator -->
330+ <div v-if =" sizesLoading" class =" h-0.5 mb-4 rounded-full bg-bg-muted overflow-hidden" >
331+ <div class =" h-full w-1/3 bg-accent rounded-full animate-indeterminate" />
332+ </div >
333+
325334 <!-- Timeline -->
326335 <ol v-if =" timelineEntries.length" class =" relative border-s border-border ms-4" >
327336 <li v-for =" entry in timelineEntries" :key =" entry.version" class =" mb-6 ms-6" >
@@ -394,7 +403,7 @@ useSeoMeta({
394403 <button
395404 type =" button"
396405 class =" text-sm text-accent hover:text-accent/80 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
397- :disabled =" loadingMore || sizesLoading "
406+ :disabled =" loadingMore"
398407 @click =" loadMore"
399408 >
400409 {{ $t('package.timeline.load_more') }}
@@ -418,3 +427,18 @@ useSeoMeta({
418427 </div >
419428 </main >
420429</template >
430+
431+ <style scoped>
432+ @keyframes indeterminate {
433+ 0% {
434+ translate : -100% ;
435+ }
436+ 100% {
437+ translate : 400% ;
438+ }
439+ }
440+
441+ .animate-indeterminate {
442+ animation : indeterminate 1.5s ease-in-out infinite ;
443+ }
444+ </style >
0 commit comments