feat: Implemented filtering and searching

This commit is contained in:
Simeon Radivoev 2026-04-12 22:19:24 +03:00
parent 4806f3487a
commit 444d8c4c27
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
49 changed files with 841 additions and 290 deletions

View file

@ -13,11 +13,10 @@ export default function ActionButton (data: {
onFocus?: () => void;
tooltip?: string,
tooltip_type?: 'accent' | 'error';
onAction?: () => void;
disabled?: boolean;
})
} & InteractParams)
{
const { ref } = useFocusable({ focusKey: data.id, onFocus: data.onFocus, onEnterPress: data.onAction, focusable: data.disabled !== true });
const { ref, focusKey } = useFocusable({ focusKey: data.id, onFocus: data.onFocus, onEnterPress: () => data.onAction?.({ focusKey }), focusable: data.disabled !== true });
const styles = {
primary: "bg-primary text-primary-content focused:bg-base-content focused:text-base-300 focusable focusable-primary",
base: " text-base-content border-dashed border-base-content/20 border-2 focused:bg-base-content focused:text-base-300 focusable focusable-primary",
@ -29,7 +28,7 @@ export default function ActionButton (data: {
<button
disabled={data.disabled}
ref={ref}
onClick={data.onAction}
onClick={e => data.onAction?.({ event: e.nativeEvent, focusKey })}
data-tooltip={data.tooltip}
data-tooltip-type={data.tooltip_type}
className={twMerge("header-icon flex flex-col gap-2 md:px-5 md:py-4 rounded-3xl md:text-2xl justify-center items-center cursor-pointer disabled:opacity-30 active:bg-base-100 active:transition-none active:text-base-content",

View file

@ -9,6 +9,7 @@ import ActionButtons from "./ActionButtons";
import prettyMilliseconds from 'pretty-ms';
import { useQuery } from "@tanstack/react-query";
import { validateSourceQuery } from "@/mainview/scripts/queries/romm";
import { sourceIconMap } from "../Constants";
export function DetailElement (data: { icon: JSX.Element; tooltip?: string | null, children?: any | any[]; })
{
@ -20,12 +21,6 @@ export function DetailElement (data: { icon: JSX.Element; tooltip?: string | nul
);
}
const sourceIconMap: Record<string, any> = {
store: <Store />,
local: <HardDrive />,
romm: <Gamepad2 />
};
export default function Details (data: {
game?: FrontEndGameTypeDetailed,
source: string,
@ -81,7 +76,7 @@ export default function Details (data: {
<DetailElement icon={platformCoverImg ? <img className="size-6" src={platformCoverImg.href}></img> : <div className="skeleton size-6 rounded-full shrink-0"></div>} >{data.game?.platform_display_name ?? <div className="skeleton h-4 w-32"></div>}</DetailElement>
{data.game?.emulators?.some(e => e.integrations.some(i => i.capabilities?.includes('saves'))) && <DetailElement tooltip={"Save Backup"} icon={<CloudUpload />} />}
<DetailElement tooltip={validation?.reason} icon={
validation ? validation.valid ? sourceIconMap[data.game?.source ?? ''] : <TriangleAlert className="text-error" /> : <span className="loading loading-spinner loading-lg"></span>
validation ? validation.valid ? sourceIconMap[data.game?.source ?? data.game?.id.source ?? ''] : <TriangleAlert className="text-error" /> : <span className="loading loading-spinner loading-lg"></span>
} >
{data.game?.source ?? data.game?.id.source}
{data.game?.local && <small className="text-base-content/60 font-semibold">local</small>}</DetailElement>