diff --git a/src/bun/api/drives.ts b/src/bun/api/drives.ts index a5f2969..e714038 100644 --- a/src/bun/api/drives.ts +++ b/src/bun/api/drives.ts @@ -32,7 +32,7 @@ export async function getDevices (): Promise { const blockDevicesRaw = await si.blockDevices(); const layout = await si.diskLayout(); - const blockDevices = blockDevicesRaw.filter(l => l.device && l.type === 'part' && l.mount); + const blockDevices = blockDevicesRaw.filter(l => l.device && (l.type === 'part' || l.type === 'disk') && l.mount); const fsSizes = await si.fsSize(); const sizes = new Map(fsSizes.map(s => [s.mount, s])); const layoutMap = new Map(layout.map(l => [l.device, l])); @@ -65,26 +65,29 @@ export async function getDevicesCurated (): Promise const devices = await getDevices(); drives.push(...devices.filter(d => d.hasWriteAccess)); - const homeDir = os.homedir(); - const homeDirDevice = devices.filter(d => d.mountPoint).reverse() - .find(d => homeDir.startsWith(d.mountPoint!)); - if (homeDirDevice) + if (process.platform !== 'win32') { - const [hasReadAccess, hasWriteAccess] = await getAccess(homeDir); + const homeDir = os.homedir(); + const homeDirDevice = devices.filter(d => d.mountPoint).reverse() + .find(d => homeDir.startsWith(d.mountPoint!)); + if (homeDirDevice) + { + const [hasReadAccess, hasWriteAccess] = await getAccess(homeDir); - drives.push({ - parent: homeDirDevice.parent, - device: homeDirDevice.device, - size: homeDirDevice.size, - used: homeDirDevice.used, - isRemovable: homeDirDevice.isRemovable, - mountPoint: homeDir, - type: homeDirDevice.type, - label: 'Home', - interfaceType: homeDirDevice.interfaceType, - hasReadAccess, - hasWriteAccess - }); + drives.push({ + parent: homeDirDevice.parent, + device: homeDirDevice.device, + size: homeDirDevice.size, + used: homeDirDevice.used, + isRemovable: homeDirDevice.isRemovable, + mountPoint: homeDir, + type: homeDirDevice.type, + label: 'Home', + interfaceType: homeDirDevice.interfaceType, + hasReadAccess, + hasWriteAccess + }); + } } return drives; diff --git a/src/bun/api/system.ts b/src/bun/api/system.ts index b50554a..8a98360 100644 --- a/src/bun/api/system.ts +++ b/src/bun/api/system.ts @@ -12,7 +12,6 @@ import { getDevices, getDevicesCurated } from "./drives"; import getFolderSize from "get-folder-size"; import si from 'systeminformation'; -// steam://open/keyboard?XPosition=%i&YPosition=%i&Width=%i&Height=%i&Mode=%d export const system = new Elysia({ prefix: '/api/system' }) .post('/show_keyboard', async ({ body: { XPosition, YPosition, Width, Height } }) => { @@ -67,12 +66,23 @@ export const system = new Elysia({ prefix: '/api/system' }) .get('/drives', async () => { const drives = await getDevices(); + if (process.platform === 'win32') + return drives.map(d => + { + d.mountPoint += '/'; + return d; + }); return drives; }) + // Drives that are vaiable for downloads .get('/drives/download', async () => { const drives = await getDevicesCurated(); - const downloadsPath = config.get('downloadPath'); + let downloadsPath = config.get('downloadPath'); + if (!path.isAbsolute(downloadsPath)) + { + downloadsPath = path.resolve(process.cwd(), downloadsPath); + } const currentDownloadsSize = await getFolderSize(downloadsPath); let used = false; const drivesDownload: DownloadsDrive[] = drives @@ -115,6 +125,7 @@ export const system = new Elysia({ prefix: '/api/system' }) drives: drivesDownload, }; }) + // Create Folder .put('/dirs', async ({ body: { dirname, name } }) => { await fs.mkdir(path.join(dirname, name)); @@ -123,7 +134,11 @@ export const system = new Elysia({ prefix: '/api/system' }) }) .get('/dirs', async ({ query: { path: startingPath } }) => { - const currentPath = startingPath ?? dirname(Bun.main); + let currentPath = startingPath ?? dirname(process.cwd()); + if (!path.isAbsolute(currentPath)) + { + currentPath = path.resolve(process.cwd(), currentPath); + } const paths = await fs.readdir(currentPath, { withFileTypes: true }); return { name: path.basename(currentPath), diff --git a/src/mainview/components/AnimatedBackground.tsx b/src/mainview/components/AnimatedBackground.tsx index ee254d3..e1bbe9b 100644 --- a/src/mainview/components/AnimatedBackground.tsx +++ b/src/mainview/components/AnimatedBackground.tsx @@ -48,7 +48,7 @@ export function AnimatedBackground (data: { let backgroundElements: JSX.Element | undefined = undefined; if (true) { - backgroundElements =
+ backgroundElements =
@@ -66,7 +66,7 @@ export function AnimatedBackground (data: { > {!!lastBackgroundUrl &&
} {!!backgroundUrl &&
} - {blurBackground &&
} + {blurBackground &&
} {data.animated && animateBackground &&
{backgroundElements}
} diff --git a/src/mainview/components/CardList.tsx b/src/mainview/components/CardList.tsx index 03232b0..69beb6a 100644 --- a/src/mainview/components/CardList.tsx +++ b/src/mainview/components/CardList.tsx @@ -1,10 +1,11 @@ import { FocusContext, + FocusDetails, useFocusable, } from "@noriginmedia/norigin-spatial-navigation"; import { GameMeta } from "../../shared/constants"; -import GameCard, { GameCardParams } from "./GameCard"; +import GameCard, { GameCardFocusHandler, GameCardParams } from "./GameCard"; import { JSX } from "react"; import { twMerge } from "tailwind-merge"; import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts"; @@ -22,7 +23,7 @@ export function CardList (data: { games: GameMetaExtra[]; grid?: boolean; onSelectGame?: (id: string) => void; - onGameFocus?: (id: string, node: HTMLElement) => void; + onGameFocus?: GameCardFocusHandler; className?: string; }) { @@ -54,10 +55,10 @@ export function CardList (data: { data-index={i} title={g.title} subtitle={g.subtitle ?? ""} - onFocus={(id, node) => + onFocus={(id, node, details) => { - g.onFocus?.(); - data.onGameFocus?.(id, node); + g.onFocus?.(details); + data.onGameFocus?.(id, node, details); }} onAction={handleAction} preview={preview} @@ -74,7 +75,7 @@ export function CardList (data: { ref={ref} save-child-focus="session" className={twMerge("my-6 items-center justify-center-safe h-(--game-card-height) ", - data.grid ? "card-grid h-fit gap-5" : 'card-list gap-6', + data.grid ? "card-grid h-fit gap-5" : 'card-list md:gap-6 sm:gap-2', data.className )} onKeyDown={(e) => diff --git a/src/mainview/components/CollectionList.tsx b/src/mainview/components/CollectionList.tsx index 47edc0a..5c0c88f 100644 --- a/src/mainview/components/CollectionList.tsx +++ b/src/mainview/components/CollectionList.tsx @@ -4,12 +4,13 @@ import { useSuspenseQuery } from "@tanstack/react-query"; import { useNavigate } from "@tanstack/react-router"; import { CardList, GameMetaExtra } from "./CardList"; import { SaveSource } from "../scripts/spatialNavigation"; +import { GameCardFocusHandler } from "./GameCard"; export default function CollectionList (data: { id: string, setBackground: (url: string) => void; className?: string; - onFocus?: (node: HTMLElement) => void; + onFocus?: GameCardFocusHandler; }) { const navigate = useNavigate(); @@ -42,12 +43,12 @@ export default function CollectionList (data: { SaveSource('game-list'); navigate({ to: `/collection/${id}`, viewTransition: { types: ['zoom-in'] } }); }} - onGameFocus={(id, node) => + onGameFocus={(id, node, details) => { data.setBackground( `https://picsum.photos/id/${10 + (id ?? 0)}/1920/1080.webp`, ); - data.onFocus?.(node); + data.onFocus?.(id, node, details); }} /> ); diff --git a/src/mainview/components/CollectionsDetail.tsx b/src/mainview/components/CollectionsDetail.tsx index 1066557..5d76df8 100644 --- a/src/mainview/components/CollectionsDetail.tsx +++ b/src/mainview/components/CollectionsDetail.tsx @@ -10,6 +10,7 @@ import { GamePadButtonCode, useShortcutContext, useShortcuts } from '../scripts/ import { Router } from '..'; import { PopSource } from '../scripts/spatialNavigation'; import { GameListFilterType } from '@/shared/constants'; +import { GameCardFocusHandler } from './GameCard'; export interface CollectionsDetailParams { @@ -42,6 +43,14 @@ export function CollectionsDetail (data: CollectionsDetailParams) useShortcuts(focusKey, () => [{ label: "Back", button: GamePadButtonCode.B, action: HandleGoBack }]); const { shortcuts } = useShortcutContext(); + const handleScroll: GameCardFocusHandler = (id, node, details) => + { + if (!(details.nativeEvent instanceof MouseEvent)) + { + node.scrollIntoView({ block: 'center', behavior: 'smooth' }); + } + }; + return ( @@ -56,7 +65,7 @@ export function CollectionsDetail (data: CollectionsDetailParams) grid setBackground={data.setBackground} filters={data.filters} - onFocus={(node) => node.scrollIntoView({ block: 'center', behavior: 'smooth' })} + onFocus={handleScroll} id={`${focusKey}-list`}> diff --git a/src/mainview/components/ContextDialog.tsx b/src/mainview/components/ContextDialog.tsx index f22ce26..d4a8db9 100644 --- a/src/mainview/components/ContextDialog.tsx +++ b/src/mainview/components/ContextDialog.tsx @@ -30,7 +30,7 @@ export function OptionElement (data: DialogEntry & { onFocus?: () => void; class const handleAction = data.action ? () => data.action?.({ close: context.close, focus: focusSelf }) : undefined; const { ref, focused, focusSelf, focusKey, hasFocusedChild } = useFocusable({ focusKey: `${context.id}-list-option-${data.id}`, - onEnterPress: handleAction, + onEnterPress: data.shortcuts ? handleAction : undefined, onFocus: handleFocus, trackChildren: typeof data.content !== 'string' }); diff --git a/src/mainview/components/FilePicker.tsx b/src/mainview/components/FilePicker.tsx index 97d1154..c7aac7d 100644 --- a/src/mainview/components/FilePicker.tsx +++ b/src/mainview/components/FilePicker.tsx @@ -36,7 +36,7 @@ function List (data: { const { setCurrentPath, startingPath, allowNewFolderCreation, currentPath, isDirectoryPicker } = useContext(FilePickerContext); const { ref, focusKey } = useFocusable({ focusKey: data.id, preferredChildFocusKey: `${data.id}...` }); const handleReturn = () => setCurrentPath(data.parentPath); - useShortcuts(focusKey, () => [{ label: "Directoy Up", button: GamePadButtonCode.L1, action: handleReturn }], [handleReturn]); + useShortcuts(focusKey, () => [{ label: "Directory Up", button: GamePadButtonCode.L1, action: handleReturn }], [handleReturn]); return
; } const shortcuts: Shortcut[] = []; + let action: () => void; if (f.isDirectory) { shortcuts.push({ label: "Enter", button: GamePadButtonCode.A, action: () => setCurrentPath(fullPath) }); + action = () => setCurrentPath(fullPath); if (isDirectoryPicker) shortcuts.push({ label: "Select", button: GamePadButtonCode.X, action: () => data.select(fullPath) }); } else { shortcuts.push({ label: "Select", button: GamePadButtonCode.A, action: () => data.select(fullPath) }); + action = () => data.select(fullPath); } const entry: DialogEntry = { content: f.name, id: `${data.id}-${f.name}`, type: 'primary', icon, - shortcuts + shortcuts, + action }; return entry; }), ...(allowNewFolderCreation && currentPath ? [{ @@ -157,7 +161,7 @@ function DriveElement (data: { id: string, isActive: boolean, label: string; onS { const { ref, focused } = useFocusable({ focusKey: data.id, onEnterPress: data.onSelect }); return
  • (data.startingPath); - const { data: files, refetch: refetchFiles } = useQuery(filesQuery(currentPath, data.id)); - const { data: drives } = useQuery(drivesQuery); + const { data: files, refetch: refetchFiles, isLoading: filesLoading } = useQuery(filesQuery(currentPath, data.id)); + const { data: drives, isLoading: drivesLoading } = useQuery(drivesQuery); const fullPath = files ? path.join(files.parentPath, files.name) : ''; const activeDrive = drives?.filter(d => !!d.mountPoint).sort((a, b) => b.mountPoint!.length - a.mountPoint!.length).filter(d => fullPath.startsWith(d.mountPoint!))[0]; @@ -268,6 +272,7 @@ export default function FilePicker (data: { }>{p}
  • )} + {(filesLoading || drivesLoading) && }
    } -
      -
    • - +
        +
      • +
      • {Object.entries(data.options)?.map(([id, option]) => ( ))} -
      • - +
      • +
      diff --git a/src/mainview/components/GameCard.tsx b/src/mainview/components/GameCard.tsx index 5b14777..14f2751 100644 --- a/src/mainview/components/GameCard.tsx +++ b/src/mainview/components/GameCard.tsx @@ -1,7 +1,8 @@ -import { useFocusable } from "@noriginmedia/norigin-spatial-navigation"; +import { FocusDetails, useFocusable } from "@noriginmedia/norigin-spatial-navigation"; import classNames from "classnames"; -import { JSX, useEffect } from "react"; +import { JSX } from "react"; import { twMerge } from "tailwind-merge"; +import useActiveControl from "../scripts/gamepads"; export function GameCardSkeleton () { @@ -16,6 +17,8 @@ export function GameCardSkeleton () ); } +export type GameCardFocusHandler = (id: string, node: HTMLElement, details: FocusDetails) => void; + export interface GameCardParams { title: string; @@ -27,7 +30,7 @@ export interface GameCardParams id: string; badges?: JSX.Element[]; className?: string; - onFocus?: (id: string, node: HTMLElement) => void; + onFocus?: GameCardFocusHandler; onBlur?: (id: string) => void; onAction?: () => void; clickFocuses?: boolean; @@ -37,10 +40,11 @@ export default function GameCard (data: GameCardParams) { const { ref, focused, focusSelf } = useFocusable({ focusKey: data.focusKey, - onFocus: () => data.onFocus?.(data.id, ref.current as any), + onFocus: (l, p, detals) => data.onFocus?.(data.id, ref.current as any, detals), onEnterPress: () => data.onAction?.(), onBlur: () => data.onBlur?.(data.id) }); + const { isPointer } = useActiveControl(); return (
    • -
      +
      {typeof data.preview === "string" ? ( - + ) : ( typeof data.preview === 'function' ? data.preview({ focused }) : data.preview )}
      @@ -83,18 +90,21 @@ export default function GameCard (data: GameCardParams) {data.badges?.map((b, i) =>
      {b}
      ) }
      -
      -
      +
      +
      {data.title}
      -
      {data.subtitle}
      +
      {data.subtitle}
    • ); diff --git a/src/mainview/components/GameList.tsx b/src/mainview/components/GameList.tsx index 5f342f9..14e16a3 100644 --- a/src/mainview/components/GameList.tsx +++ b/src/mainview/components/GameList.tsx @@ -6,6 +6,7 @@ import { SaveSource } from "../scripts/spatialNavigation"; import { rommApi } from "../scripts/clientApi"; import { HardDrive } from "lucide-react"; import { JSX } from "react"; +import { GameCardFocusHandler } from "./GameCard"; export interface GameListParams { @@ -14,7 +15,7 @@ export interface GameListParams grid?: boolean, setBackground?: (url: string) => void; onGameSelect?: (id: FrontEndId) => void; - onFocus?: (node: HTMLElement) => void; + onFocus?: GameCardFocusHandler; className?: string; } @@ -52,7 +53,7 @@ export function GameList (data: GameListParams) type="game" grid={data.grid} className={data.className} - onGameFocus={(id, node) => data.onFocus?.(node)} + onGameFocus={data.onFocus} games={games.data?.games .map( (g) => @@ -69,7 +70,7 @@ export function GameList (data: GameListParams) title: g.name ?? "", subtitle: (
      - {!!g.path_platform_cover && } + {!!g.path_platform_cover && }

      {g.platform_display_name}

      ), diff --git a/src/mainview/components/Header.tsx b/src/mainview/components/Header.tsx index 8ba0201..e021551 100644 --- a/src/mainview/components/Header.tsx +++ b/src/mainview/components/Header.tsx @@ -14,10 +14,6 @@ import Bell, Bluetooth, Clock, - Lock, - Power, - ShieldAlert, - Sun, User, Wifi, WifiHigh, @@ -29,9 +25,10 @@ import { useQuery } from "@tanstack/react-query"; import { getCurrentUserApiUsersMeGetOptions, statsApiStatsGetOptions } from "../../clients/romm/@tanstack/react-query.gen"; import { RPC_URL } from "../../shared/constants"; import { JSX, useEffect, useRef } from "react"; -import { useLocation, useNavigate } from "@tanstack/react-router"; +import { useNavigate } from "@tanstack/react-router"; import { SaveSource } from "../scripts/spatialNavigation"; import { systemApi } from "../scripts/clientApi"; +import { twMerge } from "tailwind-merge"; function HeaderAvatar (data: { id: string; @@ -116,7 +113,7 @@ function NotificationStatus () { const hasUnread = false; return
      - +
      ; } @@ -170,13 +167,13 @@ function BluetoothStatus () function WiFiStatus () { - const { data: wifi } = useQuery({ + const { data: wifi, isLoading } = useQuery({ queryKey: ['wifi'], queryFn: () => systemApi.api.system.info.wifi.get().then(d => d.data), refetchInterval: 3000 }); - return
      + return (!!wifi && wifi.length > 0) || isLoading ?
      {wifi?.map(w => { const className = "w-6 h-6"; @@ -195,7 +192,7 @@ function WiFiStatus ()
      ; })} -
      ; +
    : undefined; } function BatteryStatus () @@ -224,7 +221,7 @@ function BatteryStatus () batteryIcon = ; } } - return
    + return !!battery && battery.hasBattery &&
    {batteryIcon} {battery?.percent} %
    ; @@ -271,7 +268,9 @@ export function HeaderUI (data: { buttons?: HeaderButton[]; accounts?: HeaderAcc
    {accounts?.map(a => )} {data.title}
    -
    -
    +
    +
    @@ -297,7 +296,7 @@ export function HeaderUI (data: { buttons?: HeaderButton[]; accounts?: HeaderAcc
    {data.buttonElements ?? data.buttons?.map(b => void; className?: string; onFocus?: (node: HTMLElement) => void; }) +export function PlatformsList (data: { id: string, setBackground: (url: string) => void; className?: string; onFocus?: GameCardFocusHandler; }) { const navigate = useNavigate(); const { data: platforms } = useSuspenseQuery( @@ -29,7 +30,7 @@ export function PlatformsList (data: { id: string, setBackground: (url: string) type="platform" id={data.id} className={data.className} - onGameFocus={(id, node) => data.onFocus?.(node)} + onGameFocus={data.onFocus} games={platforms.sort((a, b) => a.updated_at.getTime() - b.updated_at.getTime()) .map((g) => { diff --git a/src/mainview/components/ShortcutPrompt.tsx b/src/mainview/components/ShortcutPrompt.tsx index 6ce7eb9..35889d8 100644 --- a/src/mainview/components/ShortcutPrompt.tsx +++ b/src/mainview/components/ShortcutPrompt.tsx @@ -1,11 +1,11 @@ -import React, { MouseEventHandler } from "react"; +import { MouseEventHandler } from "react"; import SvgIcon, { IconType } from "./SvgIcon"; import classNames from "classnames"; import { twMerge } from "tailwind-merge"; export default function ShortcutPrompt (data: { id: string; - icon: IconType; + icon?: IconType; label?: string; className?: string; onClick?: MouseEventHandler; @@ -17,14 +17,15 @@ export default function ShortcutPrompt (data: { style={{ viewTransitionName: data.id }} className={twMerge( "flex md:gap-2 bg-base-100 text-base-content neutral-content md:pl-2 md:pr-3 md:py-1.5 rounded-full items-center md:text-lg drop-shadow-sm ring-[1px] ring-base-content/10 drop-shadow-black/30", - "sm:text-sm", + "sm:text-sm sm:p-1", + "xs:text-xs sm:p-1", data.className, classNames({ "hover:bg-base-300 cursor-pointer": !!data.onClick, }) )} > - + {data.icon && } {data.label}
    ); diff --git a/src/mainview/components/Shortcuts.tsx b/src/mainview/components/Shortcuts.tsx index 31de171..8e15f77 100644 --- a/src/mainview/components/Shortcuts.tsx +++ b/src/mainview/components/Shortcuts.tsx @@ -1,4 +1,4 @@ -import { GamepadButtonEvent } from '../scripts/gamepads'; +import useActiveControl, { GamepadButtonEvent } from '../scripts/gamepads'; import { GamePadButtonCode, Shortcut } from '../scripts/shortcuts'; import ShortcutPrompt from './ShortcutPrompt'; import { IconType } from './SvgIcon'; @@ -23,16 +23,38 @@ const iconMap: Record = { [GamePadButtonCode.Steam]: 'steamdeck_button_quickaccess' }; +const keyboardMap: Record = { + [GamePadButtonCode.A]: 'ENTER', + [GamePadButtonCode.B]: 'ESC', + [GamePadButtonCode.X]: 'BACKSPACE', + [GamePadButtonCode.Y]: 'SPACE', + [GamePadButtonCode.L1]: 'Q', + [GamePadButtonCode.R1]: 'E', + [GamePadButtonCode.L2]: '', + [GamePadButtonCode.R2]: '', + [GamePadButtonCode.Select]: '', + [GamePadButtonCode.Start]: '', + [GamePadButtonCode.LJoy]: '', + [GamePadButtonCode.RJoy]: '', + [GamePadButtonCode.Up]: '', + [GamePadButtonCode.Down]: '', + [GamePadButtonCode.Left]: '', + [GamePadButtonCode.Right]: '', + [GamePadButtonCode.Steam]: '' +}; + export default function Shortcuts (data: { shortcuts?: Shortcut[]; }) { + const { control } = useActiveControl(); + const showKeyboard = control === 'keyboard' || control === 'mouse'; return (
    {data.shortcuts?.filter(s => !!s.label).map((s, i) => s.action?.(new GamepadButtonEvent('gamepadbuttondown', { button: s.button, isClick: true }))} - icon={iconMap[s.button]} - label={s.label} /> + icon={showKeyboard ? undefined : iconMap[s.button]} + label={showKeyboard ? `${keyboardMap[s.button]} | ${s.label}` : s.label} /> )}
    ); diff --git a/src/mainview/components/options/Button.tsx b/src/mainview/components/options/Button.tsx index 894a493..ca13f94 100644 --- a/src/mainview/components/options/Button.tsx +++ b/src/mainview/components/options/Button.tsx @@ -12,7 +12,7 @@ export function Button (data: { children?: any, className?: string, disabled?: boolean, - type: "reset" | "button" | "submit" | undefined; + type?: "reset" | "button" | "submit"; shortcutLabel?: string; focusClassName?: string; } & InteractParams & FocusParams) diff --git a/src/mainview/components/options/DownloadDirectoryOption.tsx b/src/mainview/components/options/DownloadDirectoryOption.tsx index d327556..760ddd0 100644 --- a/src/mainview/components/options/DownloadDirectoryOption.tsx +++ b/src/mainview/components/options/DownloadDirectoryOption.tsx @@ -22,6 +22,7 @@ export default function DownloadDirectoryOption (data: PathSettingsOptionParams) type={data.type} save={setSettingMutation.mutate} allowNewFolderCreation={data.allowNewFolderCreation} + requireConfirmation={data.requireConfirmation} isDirectoryPicker={true} localValue={localValue} setLocalValue={(v) => diff --git a/src/mainview/index.css b/src/mainview/index.css index 179cfed..f30ada9 100644 --- a/src/mainview/index.css +++ b/src/mainview/index.css @@ -3,8 +3,7 @@ @plugin "daisyui"; @theme { - --game-card-height: calc(var(--spacing) * 100); - --game-card-width: calc(var(--spacing) * 64); + --breakpoint-xs: 20rem; --animate-wiggle: wiggle 0.3s ease-in-out 1; --animate-rotate: rotate 0.3s ease-in-out 1 0.2s; @@ -107,6 +106,24 @@ } } +@layer base { + @variant sm { + :root { + --game-card-height: calc(var(--spacing) * 55); + --game-card-width: calc(var(--spacing) * 35.2); + } + } +} + +@layer base { + @variant md { + :root { + --game-card-height: calc(var(--spacing) * 100); + --game-card-width: calc(var(--spacing) * 64); + } + } +} + symbol path { fill: var(--color-base-content) !important; } @@ -135,7 +152,7 @@ html { } .menu-icon svg { - @apply sm:size-7 md:size-9 transition-all; + @apply sm:size-6 md:size-9 transition-all; } .menu-icon.focus svg { @@ -143,7 +160,8 @@ html { } .header-icon svg { - @apply w-8 h-8 min-w-8 min-h-8; + @apply md:w-8 md:h-8 md:min-w-8 md:min-h-8; + @apply sm:w-5 sm:h-5 sm:min-w-5 sm:min-h-5; } .header-icon-small svg { diff --git a/src/mainview/routes/index.tsx b/src/mainview/routes/index.tsx index 1734902..c1216ec 100644 --- a/src/mainview/routes/index.tsx +++ b/src/mainview/routes/index.tsx @@ -9,6 +9,7 @@ import Search, Power, OctagonAlert, + Maximize, } from "lucide-react"; import { @@ -19,6 +20,7 @@ import { useMutation } from "@tanstack/react-query"; import { FocusContext, + FocusDetails, useFocusable, } from "@noriginmedia/norigin-spatial-navigation"; import classNames from "classnames"; @@ -79,9 +81,14 @@ function HomeList (data: { preferredChildFocusKey: `${data.selectedFilter}-list` }); - const handleNodeFocus = (node: HTMLElement) => + const handleNodeFocus = (id: string, node: HTMLElement, details: FocusDetails) => { - node.scrollIntoView({ inline: 'center', behavior: initFocus ? 'smooth' : 'instant' }); + const isMounseEvent = details.nativeEvent instanceof MouseEvent; + if (!isMounseEvent) + { + node?.scrollIntoView({ inline: 'center', behavior: initFocus ? 'smooth' : 'instant' }); + } + setInitFocus(true); }; @@ -101,7 +108,7 @@ function HomeList (data: { (ref.current as HTMLElement)?.scrollBy({ top: 0, left: deltaY, - behavior: 'auto' + behavior: 'instant' }); } else @@ -109,7 +116,7 @@ function HomeList (data: { (ref.current as HTMLElement)?.scrollBy({ top: 0, left: deltaY, - behavior: 'auto' + behavior: 'instant' }); } }); @@ -145,7 +152,9 @@ function MainMenu (data: {})
      , action: () => document.documentElement.requestFullscreen() }, { id: "search", icon: }, { id: "power-button", icon: , external: true, action: () => closeMutation.mutate() } ]} />
      -
      +
      -
      +
      @@ -283,7 +293,9 @@ export default function ConsoleHomeUI ()
      -