fix: Fixed tests
feat: Added RClone integration feat: Implemented plugin settings feat: Updated minimal store version test: Fixed tests feat: Moved store and igdb and es-de to their own plugins
This commit is contained in:
parent
444d8c4c27
commit
c09fbd3dc8
115 changed files with 4139 additions and 1502 deletions
|
|
@ -387,10 +387,11 @@ export function RouteComponent ()
|
|||
More Emulators
|
||||
</h2></>}
|
||||
onFocus={scrollIntoViewHandler({ block: 'center' })}
|
||||
onSelect={(id, focus) =>
|
||||
onSelect={(em, focus) =>
|
||||
{
|
||||
if (em.source === 'local') return;
|
||||
router.navigate({
|
||||
to: '/store/details/emulator/$id', params: { id }
|
||||
to: '/store/details/emulator/$id', params: { id: em.name }
|
||||
});
|
||||
}}
|
||||
emulators={recommendedEmulators} />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { FocusContext, getCurrentFocusKey, useFocusable } from '@noriginmedia/no
|
|||
import { createFileRoute, useNavigate, useSearch } from '@tanstack/react-router';
|
||||
import { Gamepad2, HardDrive } from 'lucide-react';
|
||||
import { JSX, useContext, useEffect, useState } from 'react';
|
||||
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useInfiniteQuery, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import FrontEndGameCard from '@/mainview/components/FrontEndGameCard';
|
||||
import { GetFocusedElement } from '@/mainview/scripts/spatialNavigation';
|
||||
import LoadMoreButton from '@/mainview/components/LoadMoreButton';
|
||||
|
|
@ -15,6 +15,7 @@ import { useSessionStorage } from 'usehooks-ts';
|
|||
import { zodValidator } from '@tanstack/zod-adapter';
|
||||
import z from 'zod';
|
||||
import SideFilters from '@/mainview/components/SideFilters';
|
||||
import { gameFiltersQuery } from '@/mainview/scripts/queries/romm';
|
||||
|
||||
export const Route = createFileRoute('/store/tab/games')({
|
||||
component: RouteComponent,
|
||||
|
|
@ -32,7 +33,7 @@ function RouteComponent ()
|
|||
const { ref, focusKey, focusSelf } = useFocusable({ focusKey: "main-area", preferredChildFocusKey: focus });
|
||||
const [filter, setFilter] = useSessionStorage<GameListFilterType>('store-games-filters', {});
|
||||
const { data, fetchNextPage, isFetchingNextPage, isFetching } = useInfiniteQuery(storeGamesInfiniteQuery(filter));
|
||||
const [filterValues, setFilterValues] = useState<FrontEndFilterLists>();
|
||||
const { data: gameFilters } = useQuery(gameFiltersQuery({ source: 'store' }));
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
|
|
@ -86,23 +87,32 @@ function RouteComponent ()
|
|||
badges.push(<HardDrive className="sm:size-4 md:size-8 md:p-1 m-1" />);
|
||||
}
|
||||
|
||||
const previewUrl = new URL(`${RPC_URL(__HOST__)}${g.path_cover}`);
|
||||
previewUrl.searchParams.delete('ts');
|
||||
const previewUrls = g.path_covers.map(c =>
|
||||
{
|
||||
const url = new URL(`${RPC_URL(__HOST__)}${c}`);
|
||||
url.searchParams.delete('ts');
|
||||
return url;
|
||||
});
|
||||
|
||||
|
||||
let subtitle: string | JSX.Element | undefined = undefined;
|
||||
if (g.path_platform_cover)
|
||||
{
|
||||
const platformUrl = new URL(`${RPC_URL(__HOST__)}${g.path_platform_cover}`);
|
||||
platformUrl.searchParams.set('width', "64");
|
||||
subtitle = <div className="flex gap-1 items-center">
|
||||
{!!g.path_platform_cover && <img className="sm:hidden md:inline size-4" src={platformUrl.href} />}
|
||||
<p className="opacity-80">{g.platform_display_name}</p>
|
||||
</div>;
|
||||
}
|
||||
|
||||
const platformUrl = new URL(`${RPC_URL(__HOST__)}${g.path_platform_cover}`);
|
||||
platformUrl.searchParams.set('width', "64");
|
||||
|
||||
return {
|
||||
id: `${g.id.source}@${g.id.id}`,
|
||||
focusKey: `${g.id.source}@${g.id.id}`,
|
||||
title: g.name ?? "",
|
||||
subtitle: (
|
||||
<div className="flex gap-1 items-center">
|
||||
{!!g.path_platform_cover && <img className="sm:hidden md:inline size-4" src={platformUrl.href} />}
|
||||
<p className="opacity-80">{g.platform_display_name}</p>
|
||||
</div>
|
||||
),
|
||||
previewUrl: previewUrl.href,
|
||||
subtitle,
|
||||
previewUrls,
|
||||
badges: badges,
|
||||
onSelect: () => handleDefaultSelect(g),
|
||||
onFocus: (k, n, d) => handleFocus(k, n, d)
|
||||
|
|
@ -111,7 +121,7 @@ function RouteComponent ()
|
|||
) ?? []} id={'store-games'} />
|
||||
</div>
|
||||
<div className='fixed left-2 top-52 bottom-0 sm:w-10 md:w-14 z-10'>
|
||||
<SideFilters id='filter-btns' localFilter={filter} setLocalFilter={setFilter} filterValues={filterValues} filters={{ source: 'store' }} />
|
||||
<SideFilters id='filter-btns' localFilter={filter} setLocalFilter={setFilter} filterValues={gameFilters} filters={{ source: 'store' }} />
|
||||
</div>
|
||||
</FocusContext>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -50,8 +50,13 @@ function Main (data: { games?: FrontEndGameTypeDetailed[]; })
|
|||
}, 10);
|
||||
|
||||
const storeContext = useContext(StoreContext);
|
||||
const previewUrl = data.games ? new URL(`${RPC_URL(__HOST__)}${data.games[selectedGame].path_cover}`) : undefined;
|
||||
previewUrl?.searchParams.set('blur', '16');
|
||||
const previewUrls = data.games?.[selectedGame] ? data.games[selectedGame].path_covers.map(c =>
|
||||
{
|
||||
const url = new URL(`${RPC_URL(__HOST__)}${c}`);
|
||||
url.searchParams.set('blur', '16');
|
||||
return url;
|
||||
}) : undefined;
|
||||
|
||||
|
||||
return <div ref={ref} className='flex sm:flex-wrap md:flex-nowrap group-focusable md:px-12 p-4 mt-4 gap-6'>
|
||||
|
||||
|
|
@ -59,22 +64,23 @@ function Main (data: { games?: FrontEndGameTypeDetailed[]; })
|
|||
{game ? <div key={selectedGame} className="flex transition-all duration-500 flex-col rounded-3xl overflow-hidden shadow-black/5 shadow-md w-full ring-6 ring-base-200 border-6 border-base-200">
|
||||
<div className='flex relative h-full overflow-hidden'>
|
||||
<div className='absolute w-full h-full z-0 bg-base-200'>
|
||||
<img key={selectedGame}
|
||||
<picture key={selectedGame}
|
||||
className='w-full h-full object-cover transition-all duration-500 ease-out scale-110 opacity-0 light:data-loaded:opacity-40 dark:data-loaded:opacity-80 z-0'
|
||||
src={previewUrl?.href}
|
||||
onLoad={(e) =>
|
||||
{
|
||||
e.currentTarget.dataset.loaded = "true";
|
||||
e.currentTarget.classList.toggle('scale-110', false);
|
||||
}}
|
||||
/>
|
||||
>
|
||||
{previewUrls?.map((u, i) => <source key={i} src={u.href} />)}
|
||||
</picture>
|
||||
</div>
|
||||
<div key={selectedGame} className='flex sm:flex-wrap md:flex-nowrap grow z-1 p-8 opacity-0 animate-fade-in h-full items-end gap-4 sm:justify-end md:justify-between'>
|
||||
<div className='flex gap-4 max-h-full z-1 grow md:h-full'>
|
||||
<div className='flex sm:portrait:flex-wrap sm:portrait:grow gap-4 max-h-full justify-center'>
|
||||
<div className='relative rounded-3xl max-w-xs h-48 overflow-hidden shadow-lg'>
|
||||
<div className='flex absolute bottom-4 left-4 size-8 bg-base-content text-base-100 rounded-full items-center justify-center shadow-lg '><HardDrive /></div>
|
||||
{!!data.games && <img className='object-cover w-full h-full ' src={`${RPC_URL(__HOST__)}${data.games[selectedGame].path_cover}`} />}
|
||||
{!!data.games && <img className='object-cover w-full h-full ' src={`${RPC_URL(__HOST__)}${data.games[selectedGame].path_covers[0]}`} />}
|
||||
</div>
|
||||
<div className='flex flex-col gap-2 py-3 max-w-md'>
|
||||
<h1 className='font-semibold text-3xl text-shadow-md'>{game.name}</h1>
|
||||
|
|
@ -133,7 +139,7 @@ export function RouteComponent ()
|
|||
<div className='pt-4'>
|
||||
<EmulatorsSection
|
||||
id="recommended-emulators"
|
||||
onSelect={(id, focus) => storeContext.showDetails('emulator', 'store', id, focus)}
|
||||
onSelect={(em, focus) => storeContext.showDetails('emulator', em.source, em.name, focus)}
|
||||
onFocus={scrollIntoViewHandler({ block: 'end' })}
|
||||
emulators={recommendedEmulators} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ function RouteComponent ()
|
|||
{
|
||||
if (type === 'emulator')
|
||||
{
|
||||
if (source === 'local') return;
|
||||
router.navigate({ to: '/store/details/emulator/$id', params: { id } });
|
||||
}
|
||||
else if (type === 'game')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue