import { useFocusable } from "@noriginmedia/norigin-spatial-navigation"; import classNames from "classnames"; import { JSX } from "react"; import { twMerge } from "tailwind-merge"; import useActiveControl from "../scripts/gamepads"; import { oneShot } from "../scripts/audio/audio"; import ImageWithFallbacks from "./ImageWithFallbacks"; export function GameCardSkeleton () { return (
  • ); } export interface GameCardParams extends FocusParams { title: string; subtitle?: string | JSX.Element; preview?: string | JSX.Element | URL[] | ((p: { focused: boolean; }) => JSX.Element); srcset?: string; focusKey: string; index: number; id: string; badges?: JSX.Element[]; className?: string; onBlur?: (id: string) => void; clickFocuses?: boolean; previewClassName?: string; } export default function CardElement (data: GameCardParams & InteractParams) { const handleAction = (event?: Event) => { data.onAction?.({ event, focusKey }); oneShot('click'); }; const { ref, focused, focusSelf, focusKey } = useFocusable({ focusKey: data.focusKey, onFocus: (l, p, details) => data.onFocus?.(focusKey, ref.current as any, details), onEnterPress: handleAction, onBlur: () => data.onBlur?.(data.id), }); const { isPointer } = useActiveControl(); let preview: any = undefined; if (typeof data.preview === "string") { preview = ; } else if (Array.isArray(data.preview)) { preview = ; } else if (typeof data.preview === 'function') { preview = data.preview({ focused }); } else { preview = data.preview; } return (
  • { focusSelf(); handleAction(e.nativeEvent); }} className={twMerge( "relative game-card light:bg-base-100 dark:bg-base-300 flex flex-col z-5 overflow-hidden transition-all duration-200 not-mobile:drop-shadow-lg cursor-pointer focusable focusable-primary focusable-hover select-none focused focused:not-control-mouse:animate-wiggle focused:not-control-mouse:bg-base-content focused:not-control-mouse:text-base-300 focused:not-control-mouse:drop-shadow-lg focused:not-control-mouse:drop-shadow-black/30 focused:not-control-mouse:scale-102 focused:not-control-mouse:z-10 group control-mouse:hover:bg-base-200 h-full [--tw-border-style:inset] border-2 border-base-content/5 backdrop-opacity-0 active:bg-base-content! active:text-base-100 active:transition-none", data.className )} >
    {preview}
    {data.badges?.map((b, i) =>
    {b}
    ) }
    {data.title}
    {data.subtitle}
  • ); }