11import type { Provider , SearchResult } from '@/bindings.gen' ;
2- import { abbreviateNumber , LOADERS } from '@/utils' ;
3- import { Show } from '@onelauncher/common/components' ;
4- import { useNavigate } from '@tanstack/react-router' ;
2+ import { abbreviateNumber , LOADERS , upperFirst } from '@/utils' ;
3+ import { Show , Tooltip } from '@onelauncher/common/components' ;
4+ import { Link , useNavigate } from '@tanstack/react-router' ;
55import { Download01Icon } from '@untitled-theme/icons-react' ;
6+ import { useMemo } from 'react' ;
7+ import { Focusable } from 'react-aria-components' ;
68import LoaderIcon from '../launcher/LoaderIcon' ;
79
810function includes < T , TArray extends T > ( list : { includes : ( arg0 : TArray ) => boolean } , element : T ) : element is TArray {
@@ -20,16 +22,14 @@ export function PackageGrid({ items, provider }: { items: Array<SearchResult>; p
2022}
2123
2224export function PackageItem ( { provider, ...item } : SearchResult & { provider : Provider } ) {
23- const navigate = useNavigate ( ) ;
24- function redirect ( ) {
25- navigate ( { to : '/app/browser/package/$provider/$slug' , params : { provider, slug : item . slug } } ) ;
26- }
25+ const loaders = useMemo ( ( ) => item . categories . filter ( cat => includes ( LOADERS , cat ) ) , [ ] ) ;
2726
2827 return (
29- < div
28+ < Link
3029 className = "h-full min-w-50 flex overflow-hidden rounded-lg bg-component-bg hover:bg-component-bg-hover flex-col max-h-74 min-h-74"
31- onClick = { redirect }
30+ params = { { provider , slug : item . slug } }
3231 tabIndex = { 0 }
32+ to = "/app/browser/package/$provider/$slug"
3333 >
3434 < div
3535 className = "relative flex items-center justify-center overflow-hidden w-full h-28"
@@ -49,9 +49,21 @@ export function PackageItem({ provider, ...item }: SearchResult & { provider: Pr
4949 src = { item . icon_url }
5050 />
5151 </ Show >
52- < div className = "flex flex-col rounded-full bg-component-bg/70 border-component-border/70 border gap-2 p-2 absolute top-0 right-0 m-2" >
53- { item . categories . filter ( cat => includes ( LOADERS , cat ) ) . map ( loader => < LoaderIcon className = "w-5" key = { loader } loader = { loader } /> ) }
54- </ div >
52+ < Tooltip text = { loaders . map ( upperFirst ) . join ( ', ' ) } >
53+ < Focusable >
54+ < div className = "flex flex-col rounded-full bg-component-bg/70 border-component-border/70 border p-1 absolute top-0 right-0 m-2" >
55+ { loaders . toSpliced ( loaders . length > 3 ? 2 : 3 ) . map ( loader => < LoaderIcon className = "w-5 m-1" key = { loader } loader = { loader } /> ) }
56+ { loaders . length > 3 && (
57+ < div className = "bg-component-bg/50 rounded-full w-7 h-7 flex items-center justify-center" >
58+ < span className = "tracking-tight -ml-0.5 mt-0.5" >
59+ +
60+ { loaders . length - 2 }
61+ </ span >
62+ </ div >
63+ ) }
64+ </ div >
65+ </ Focusable >
66+ </ Tooltip >
5567 </ div >
5668 < div className = "flex flex-1 flex-col gap-2 p-3" >
5769 < div className = "flex flex-col gap-2" >
@@ -78,6 +90,6 @@ export function PackageItem({ provider, ...item }: SearchResult & { provider: Pr
7890 </ Show >
7991 </ div >
8092 </ div >
81- </ div >
93+ </ Link >
8294 ) ;
8395}
0 commit comments