feat: Implemented launching and downloading of roms

This is just an initial implementation lots of kings to iron out
This commit is contained in:
Simeon Radivoev 2026-02-19 16:10:29 +02:00
parent ef08fa6114
commit f15bf9a1e0
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
117 changed files with 37776 additions and 1073 deletions

View file

@ -16,23 +16,30 @@ export function GameCardSkeleton ()
);
}
export default function GameCard (data: {
export interface GameCardParams
{
title: string;
type?: string;
subtitle: string;
preview?: string | JSX.Element;
subtitle: string | JSX.Element;
preview?: string | JSX.Element | ((p: { focused: boolean; }) => JSX.Element);
focusKey: string;
index: number;
id: number;
badge?: JSX.Element;
onFocus?: (id: number) => void;
id: string;
badges?: JSX.Element[];
className?: string;
onFocus?: (id: string) => void;
onBlur?: (id: string) => void;
onAction?: () => void;
})
clickFocuses?: boolean;
}
export default function GameCard (data: GameCardParams)
{
const { ref, focused, focusSelf } = useFocusable({
focusKey: data.focusKey,
onFocus: () => data.onFocus?.(data.id),
onEnterPress: () => data.onAction?.(),
onBlur: () => data.onBlur?.(data.id)
});
useEffect(() =>
@ -59,33 +66,48 @@ export default function GameCard (data: {
}}
onFocus={focusSelf}
onDoubleClick={data.onAction}
onClick={focused ? data.onAction : focusSelf}
onClick={() =>
{
focusSelf();
data.onAction?.();
}}
className={twMerge(
`game-card game-card-height flex flex-col justify-end`,
`game-card game-card-height flex flex-col justify-end z-5`,
'max-h-(--game-card-height) min-w-(--game-card-width) w-(--game-card-width)',
"overflow-hidden transition-all duration-200 drop-shadow-lg cursor-pointer",
focused ?
`animate-wiggle ring-7 bg-base-content text-base-300 ring-primary drop-shadow-xl drop-shadow-base-300/60 scale-102 z-10` :
"bg-base-300 text-base-content",
`focused animate-wiggle ring-7 bg-base-content text-base-300 ring-primary drop-shadow-xl drop-shadow-black/30 scale-102 z-10` :
"bg-base-300 hover:bg-base-100 hover:scale-102 text-base-content",
classNames({
"h-(--game-card-height)": typeof data.preview === "string"
})
}),
data.className
)}
>
<div className={twMerge("overflow-hidden bg-base-400 h-full rounded-t-xl rounded-b-md transition-all", focused ? "mt-2 mx-2" : "mt-2 mx-2")}>
{typeof data.preview === "string" ? (
<img src={data.preview}></img>
<img width={5192} height={5192} className={classNames({ "animate-rotate-small": focused })} src={data.preview} ></img>
) : (
data.preview
typeof data.preview === 'function' ? data.preview({ focused }) : data.preview
)}</div>
<div className="h-0 flex pr-2 justify-end items-center">{data.badge}</div>
<div className="h-0 flex pr-2 justify-end items-center">
{data.badges?.map(b =>
<div
className={
twMerge("bg-base-100 text-base-content drop-shadow-lg overflow-hidden rounded-full p-1 mr-4 transition-colors",
classNames({ "bg-primary text-primary-content": focused }))}
>
{b}
</div>)
}
</div>
<div className="flex flex-col p-4">
<div className="text-xl font-bold text-nowrap text-ellipsis overflow-hidden">
{data.title}
</div>
<div className="text-s">{data.subtitle}</div>
</div>
</li>
</li >
);
}