@@ -3,6 +3,9 @@ import type { NpmSearchResult } from '#shared/types'
33import type { WindowVirtualizerHandle } from ' ~/composables/useVirtualInfiniteScroll'
44import { WindowVirtualizer } from ' virtua/vue'
55
6+ /** Number of items to render statically during SSR */
7+ const SSR_COUNT = 20
8+
69const props = defineProps <{
710 /** List of search results to display */
811 results: NpmSearchResult []
@@ -96,31 +99,52 @@ defineExpose({
9699
97100<template >
98101 <div >
99- <WindowVirtualizer
100- ref =" listRef"
101- :data =" results"
102- :item-size =" 140"
103- as =" ol"
104- item =" li"
105- class =" list-none m-0 p-0"
106- @scroll =" handleScroll"
107- >
108- <template #default =" { item , index } " >
109- <div class =" pb-4" >
110- <PackageCard
111- :result =" item as NpmSearchResult"
112- :heading-level =" headingLevel"
113- :show-publisher =" showPublisher"
114- :selected =" index === (selectedIndex ?? -1)"
115- :index =" index"
116- :search-query =" searchQuery"
117- class =" motion-safe:animate-fade-in motion-safe:animate-fill-both"
118- :style =" { animationDelay: `${Math.min(index * 0.02, 0.3)}s` }"
119- @focus =" emit('select', $event)"
120- />
121- </div >
102+ <!-- SSR: Render static list for first page, replaced by virtual list on client -->
103+ <ClientOnly >
104+ <WindowVirtualizer
105+ ref =" listRef"
106+ :data =" results"
107+ :item-size =" 140"
108+ as =" ol"
109+ item =" li"
110+ class =" list-none m-0 p-0"
111+ @scroll =" handleScroll"
112+ >
113+ <template #default =" { item , index } " >
114+ <div class =" pb-4" >
115+ <PackageCard
116+ :result =" item as NpmSearchResult"
117+ :heading-level =" headingLevel"
118+ :show-publisher =" showPublisher"
119+ :selected =" index === (selectedIndex ?? -1)"
120+ :index =" index"
121+ :search-query =" searchQuery"
122+ class =" motion-safe:animate-fade-in motion-safe:animate-fill-both"
123+ :style =" { animationDelay: `${Math.min(index * 0.02, 0.3)}s` }"
124+ @focus =" emit('select', $event)"
125+ />
126+ </div >
127+ </template >
128+ </WindowVirtualizer >
129+
130+ <!-- SSR fallback: static list of first page results -->
131+ <template #fallback >
132+ <ol class =" list-none m-0 p-0" >
133+ <li v-for =" (item, index) in results.slice(0, SSR_COUNT)" :key =" item.package.name" >
134+ <div class =" pb-4" >
135+ <PackageCard
136+ :result =" item"
137+ :heading-level =" headingLevel"
138+ :show-publisher =" showPublisher"
139+ :selected =" index === (selectedIndex ?? -1)"
140+ :index =" index"
141+ :search-query =" searchQuery"
142+ />
143+ </div >
144+ </li >
145+ </ol >
122146 </template >
123- </WindowVirtualizer >
147+ </ClientOnly >
124148
125149 <!-- Loading indicator -->
126150 <div v-if =" isLoading" class =" py-4 flex items-center justify-center" >
0 commit comments