feat: Implemented link game importing

feat: Implemented download page for downloading roms from various sources using plugins. Added support for internet archive external plugin.
feat: Added tasks page to track running tasks/downloads
feat: Added tanstack caching
feat: Added quick play action Fixes #6
feat: Added quick emulator launch action
fix: Made task queue only support 1 task per group and task ID should now be unique
This commit is contained in:
Simeon Radivoev 2026-05-15 13:50:55 +03:00
parent 9a3e605625
commit 9141fb35d4
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
70 changed files with 1922 additions and 560 deletions

View file

@ -6,7 +6,7 @@ import
import CardElement, { GameCardParams } from "./CardElement";
import { JSX } from "react";
import { twMerge } from "tailwind-merge";
import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts";
import { GamePadButtonCode, Shortcut, useShortcuts } from "../scripts/shortcuts";
import { oneShot } from "../scripts/audio/audio";
export interface GameMetaExtra extends GameMeta
@ -16,7 +16,7 @@ export interface GameMetaExtra extends GameMeta
focusKey: string;
}
function LocalCardElement (data: { game: GameMetaExtra, i: number; } & FocusParams & InteractParams)
function LocalCardElement (data: { game: GameMetaExtra, i: number; onQuickAction?: (ctx: InteractParamsArgs) => void; } & FocusParams & InteractParams)
{
let preview: GameCardParams['preview'] = data.game.preview;
if (!preview && data.game.previewUrls)
@ -31,7 +31,28 @@ function LocalCardElement (data: { game: GameMetaExtra, i: number; } & FocusPara
oneShot('click');
};
useShortcuts(data.game.focusKey, () => [{ label: "Details", button: GamePadButtonCode.A, action: event => handleAction({ event, focusKey: data.game.focusKey }) }]);
const handleAltAction = (ctx: InteractParamsArgs) =>
{
data.game.onQuickAction?.();
data.onQuickAction?.({ event, focusKey: data.game.focusKey });
oneShot('click');
};
useShortcuts(data.game.focusKey, () =>
{
const options: Shortcut[] = [{
label: "Details",
button: GamePadButtonCode.A,
action: event => handleAction({ event, focusKey: data.game.focusKey })
}];
if (data.onQuickAction || data.game.onQuickAction)
{
options.push({ label: "Play", button: GamePadButtonCode.X, action: event => handleAltAction({ event, focusKey: data.game.focusKey }) });
}
return options;
}, [data.onQuickAction, data.game.onQuickAction, data.game.focusKey]);
return (
<CardElement
@ -91,7 +112,12 @@ export function CardList (data: {
>
<FocusContext.Provider value={focusKey}>
{data.games.map((g, i) => <LocalCardElement
key={g.id} onFocus={data.onFocus} game={g} onAction={() => data.onSelectGame?.(g.id)} i={i} />)}
key={g.id}
onFocus={data.onFocus}
game={g}
onAction={() => data.onSelectGame?.(g.id)}
i={i}
/>)}
{data.finalElement}
</FocusContext.Provider>
</ul>