feat: Implemented audio effects

This commit is contained in:
Simeon Radivoev 2026-04-01 21:20:34 +03:00
parent fe0ab3b498
commit edbc390d14
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
125 changed files with 1137 additions and 217 deletions

View file

@ -8,12 +8,12 @@ import { ChevronRight, Joystick } from "lucide-react";
import { GamePadButtonCode, useShortcuts } from "@/mainview/scripts/shortcuts";
import { scrollIntoNearestParent, useDragScroll } from "@/mainview/scripts/utils";
import FocusDots from "../FocusDots";
import { Router } from "@/mainview";
import { StoreEmulatorCard } from "./StoreEmulatorCard";
import { FOCUS_KEYS } from "@/mainview/scripts/types";
import Carousel from "../Carousel";
import { useRouter } from "@tanstack/react-router";
function SeeAllCard (data: { id: string; onAction: () => void; onFocus?: (details: { node: HTMLElement, instant: boolean; }) => void; })
function SeeAllCard (data: { id: string; onAction: () => void; onFocus?: (details: { node: HTMLElement, instant?: boolean; }) => void; })
{
const { ref, focusKey } = useFocusable({
focusKey: data.id,
@ -39,6 +39,7 @@ export function EmulatorsSection (data: {
header?: any;
} & FocusParams)
{
const router = useRouter();
const { ref, focusKey } = useFocusable({
focusKey: FOCUS_KEYS.EMULATOR_SECTION(data.id),
trackChildren: true,
@ -68,7 +69,7 @@ export function EmulatorsSection (data: {
scrollIntoNearestParent(node, { behavior: details.instant ? 'instant' : 'smooth' });
}} />
)) ?? Array.from({ length: 8 }).map((_, i) => <div key={i} className="skeleton h-38 w-full rounded-4xl" />)}
<SeeAllCard id={`${FOCUS_KEYS.EMULATOR_SECTION}-see-all`} onAction={() => Router.navigate({ to: '/store/tab/emulators', viewTransition: { types: ['zoom-in'] } })} onFocus={({ node, instant }) => scrollIntoNearestParent(node, { behavior: instant ? 'instant' : 'smooth' })} />
<SeeAllCard id={`${FOCUS_KEYS.EMULATOR_SECTION}-see-all`} onAction={() => router.navigate({ to: '/store/tab/emulators', viewTransition: { types: ['zoom-in'] } })} onFocus={({ node, instant }) => scrollIntoNearestParent(node, { behavior: instant ? 'instant' : 'smooth' })} />
</Carousel>
</section>

View file

@ -30,7 +30,7 @@ export function GamesSection (data: {
useEffect(() =>
{
if (focused)
focusSelf();
focusSelf({ instant: true });
}, [!!data.games]);
return (

View file

@ -9,6 +9,7 @@ import { ChevronRight, CircleQuestionMark, SearchAlert } from "lucide-react";
import { GamePadButtonCode, useShortcuts } from "@/mainview/scripts/shortcuts";
import { RPC_URL } from "@/shared/constants";
import { FOCUS_KEYS } from "@/mainview/scripts/types";
import { oneShot } from "@/mainview/scripts/audio/audio";
// ── Single missing-emulator card ───────────────────────────────────────────
interface MissingCardProps
@ -19,7 +20,11 @@ interface MissingCardProps
function MissingCard ({ emulator: em, onSelect }: MissingCardProps)
{
const handleSelect = () => onSelect?.(em.name, focusKey);
const handleSelect = () =>
{
onSelect?.(em.name, focusKey);
oneShot('click');
};
const { ref, focusKey } = useFocusable({
focusKey: FOCUS_KEYS.MISSING_CARD(em.name),

View file

@ -9,6 +9,7 @@ import { BadgeCheck, ChevronRight, EllipsisVertical, FileQuestion, IceCream2, Pa
import { FOCUS_KEYS } from "@/mainview/scripts/types";
import { FlatpackIcon } from "@/mainview/scripts/brandIcons";
import { JSX } from "react";
import { oneShot } from "@/mainview/scripts/audio/audio";
export const emulatorStatusIcons: Record<string, JSX.Element> = {
store: <Store />,
@ -26,7 +27,11 @@ export function StoreEmulatorCard (data: {
className?: string;
})
{
const handleSelect = () => data.onSelect?.(data.emulator.name, focusKey);
const handleSelect = () =>
{
data.onSelect?.(data.emulator.name, focusKey);
oneShot('click');
};
const { ref, focusKey } = useFocusable({
focusKey: FOCUS_KEYS.EMULATOR_CARD(data.id),
@ -45,6 +50,7 @@ export function StoreEmulatorCard (data: {
ref={ref}
role="button"
tabIndex={0}
data-sound-category="emulator"
data-installed={data.emulator.validSources.some(s => s.exists)}
onClick={isTouch ? handleSelect : undefined}
className={twMerge("relative focusable focusable-info bg-base-100 rounded-4xl transition-shadow focused:not-control-mouse:animate-scale-small shadow-lg border border-base-content/10 active:ring-4 active:ring-base-content active:transition-none", data.className)}
@ -87,7 +93,7 @@ export function StoreEmulatorCard (data: {
</div>;
})}
{isMouse && <>
<Button onAction={handleSelect} style="base" className="grow text-base-content/40" id={`${data.emulator.name}-details`} >Details<ChevronRight /></Button>
<Button onAction={e => data.onSelect?.(data.emulator.name, focusKey)} style="base" className="grow text-base-content/40" id={`${data.emulator.name}-details`} >Details<ChevronRight /></Button>
</>}
</div>