@@ -96,6 +96,17 @@ const AgentStorePage = () => {
9696 }
9797 return await response . json ( )
9898 } ,
99+ select : ( data ) => {
100+ // Normalize data once to prevent reference changes and precompute expensive operations
101+ return data . map ( ( agent ) => ( {
102+ ...agent ,
103+ // Precompute expensive operations
104+ createdAtMs : new Date ( agent . created_at ) . getTime ( ) ,
105+ nameLower : agent . name . toLowerCase ( ) ,
106+ descriptionLower : agent . description ?. toLowerCase ( ) || '' ,
107+ tagsLower : agent . tags ?. map ( ( tag ) => tag . toLowerCase ( ) ) || [ ] ,
108+ } ) )
109+ } ,
99110 } )
100111
101112 // Fetch user's publishers if signed in
@@ -158,22 +169,17 @@ const AgentStorePage = () => {
158169 } )
159170 } , [ editorsChoice , searchQuery ] )
160171
161- // Helper function to get agents for a specific row
172+ // Get agents for a specific row without pre-building all rows
162173 const getAgentsForRow = useCallback (
163- ( agents : AgentData [ ] , rowIndex : number , cols : number ) => {
164- const startIndex = rowIndex * cols
165- return agents . slice ( startIndex , startIndex + cols )
174+ ( rowIndex : number ) => {
175+ const startIndex = rowIndex * columns
176+ return filteredAndSortedAgents . slice ( startIndex , startIndex + columns )
166177 } ,
167- [ ]
178+ [ filteredAndSortedAgents , columns ]
168179 )
169180
170- // Create virtualized rows for All Agents only
171- const allAgentsRows = useMemo ( ( ) => {
172- const rowCount = Math . ceil ( filteredAndSortedAgents . length / columns )
173- return Array . from ( { length : rowCount } , ( _ , i ) =>
174- getAgentsForRow ( filteredAndSortedAgents , i , columns )
175- )
176- } , [ filteredAndSortedAgents , columns , getAgentsForRow ] )
181+ // Calculate total rows needed
182+ const totalRows = Math . ceil ( filteredAndSortedAgents . length / columns )
177183
178184 // Only create virtualizer when we have data and the component is mounted
179185 const [ isMounted , setIsMounted ] = useState ( false )
@@ -184,14 +190,13 @@ const AgentStorePage = () => {
184190
185191 // Virtualizer for All Agents section only
186192 const allAgentsVirtualizer = useWindowVirtualizer ( {
187- count : isMounted ? allAgentsRows . length : 0 ,
193+ count : isMounted ? totalRows : 0 ,
188194 estimateSize : ( ) => 270 , // Height for agent rows (card + gap)
189195 overscan : 6 ,
190- useAnimationFrameWithResizeObserver : true ,
191196 } )
192197
193198 // Determine if we should use virtualization for All Agents section
194- const shouldVirtualizeAllAgents = isMounted && allAgentsRows . length > 6
199+ const shouldVirtualizeAllAgents = isMounted && totalRows > 6
195200
196201 // Publisher button logic
197202 const renderPublisherButton = ( ) => {
@@ -235,7 +240,6 @@ const AgentStorePage = () => {
235240 return count . toString ( )
236241 }
237242
238- // Memoized AgentCard component to prevent unnecessary re-renders
239243 const AgentCard = memo (
240244 ( {
241245 agent,
@@ -251,10 +255,14 @@ const AgentStorePage = () => {
251255 >
252256 < Card
253257 className = { cn (
254- 'relative h-full transition-all duration-200 cursor-pointer border bg-card/50 backdrop-blur-sm ' ,
258+ 'relative h-full transition-all duration-200 cursor-pointer border bg-card/50' ,
255259 'hover:border-accent/50 hover:bg-card/80' ,
256260 isEditorsChoice && 'ring-2 ring-amber-400/50 border-amber-400/30'
257261 ) }
262+ style = { {
263+ // Use CSS transforms for hover effects instead of Framer Motion
264+ transition : 'all 0.2s ease' ,
265+ } }
258266 >
259267 { /* Editor's Choice Badge - Positioned absolutely for better visual hierarchy */ }
260268 { isEditorsChoice && (
@@ -285,12 +293,9 @@ const AgentStorePage = () => {
285293 v{ agent . version }
286294 </ Badge >
287295 </ div >
288- { /* Action buttons */ }
289296 < div className = "flex items-center gap-1" >
290297 < div onClick = { ( e ) => e . preventDefault ( ) } >
291- < motion . button
292- whileHover = { { scale : 1.1 } }
293- whileTap = { { scale : 0.95 } }
298+ < button
294299 onClick = { ( ) => {
295300 navigator . clipboard . writeText (
296301 `codebuff --agent ${ agent . publisher . id } /${ agent . id } @${ agent . version } `
@@ -299,11 +304,11 @@ const AgentStorePage = () => {
299304 description : `Agent run command copied to clipboard!` ,
300305 } )
301306 } }
302- className = "p-2 hover:bg-muted/50 rounded-lg transition-all duration-200 opacity-60 group-hover:opacity-100"
307+ className = "p-2 hover:bg-muted/50 rounded-lg transition-all duration-200 opacity-60 group-hover:opacity-100 hover:scale-110 active:scale-95 "
303308 title = { `Copy: codebuff --agent ${ agent . publisher . id } /${ agent . id } @${ agent . version } ` }
304309 >
305310 < Copy className = "h-4 w-4 text-muted-foreground hover:text-foreground" />
306- </ motion . button >
311+ </ button >
307312 </ div >
308313 < ChevronRight className = "h-5 w-5 text-muted-foreground transition-all duration-300 group-hover:text-primary group-hover:translate-x-1" />
309314 </ div >
@@ -511,9 +516,9 @@ const AgentStorePage = () => {
511516 </ p >
512517 </ div >
513518
514- { /* Non-virtualized Editor's Choice */ }
515519 < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" >
516520 { filteredEditorsChoice . map ( ( agent ) => (
521+ // Only use motion for small, non-virtualized sections
517522 < motion . div
518523 key = { agent . id }
519524 whileHover = { { y : - 4 , transition : { duration : 0.2 } } }
@@ -547,7 +552,7 @@ const AgentStorePage = () => {
547552 { allAgentsVirtualizer
548553 . getVirtualItems ( )
549554 . map ( ( virtualItem ) => {
550- const agents = allAgentsRows [ virtualItem . index ]
555+ const agents = getAgentsForRow ( virtualItem . index )
551556 return (
552557 < div
553558 key = { virtualItem . key }
@@ -562,20 +567,18 @@ const AgentStorePage = () => {
562567 >
563568 < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-6" >
564569 { agents ?. map ( ( agent ) => (
565- < motion . div
570+ // No motion for virtualized items - use CSS transitions instead
571+ < div
566572 key = { agent . id }
567- whileHover = { {
568- y : - 4 ,
569- transition : { duration : 0.2 } ,
570- } }
573+ className = "hover:-translate-y-1 transition-transform duration-200"
571574 >
572575 < AgentCard
573576 agent = { agent }
574577 isEditorsChoice = { EDITORS_CHOICE_AGENTS . includes (
575578 agent . id
576579 ) }
577580 />
578- </ motion . div >
581+ </ div >
579582 ) ) }
580583 </ div >
581584 </ div >
@@ -586,17 +589,17 @@ const AgentStorePage = () => {
586589 // Non-virtualized All Agents
587590 < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" >
588591 { filteredAndSortedAgents . map ( ( agent ) => (
589- < motion . div
592+ < div
590593 key = { agent . id }
591- whileHover = { { y : - 4 , transition : { duration : 0.2 } } }
594+ className = "hover:-translate-y-1 transition-transform duration-200"
592595 >
593596 < AgentCard
594597 agent = { agent }
595598 isEditorsChoice = { EDITORS_CHOICE_AGENTS . includes (
596599 agent . id
597600 ) }
598601 />
599- </ motion . div >
602+ </ div >
600603 ) ) }
601604 </ div >
602605 ) }
0 commit comments