From 876e6676089df1b97a25dc0d31dceeff9235c4c6 Mon Sep 17 00:00:00 2001 From: Julien Loir <6706489+Namaneo@users.noreply.github.com> Date: Sat, 26 Aug 2023 22:25:47 +0200 Subject: [PATCH] UI rework --- cores/cores.json | 61 ++--------- cores/lib2048.a | Bin 157940 -> 0 bytes ui/sources/entities/game.js | 9 +- ui/sources/entities/save.js | 6 +- ui/sources/entities/system.js | 6 -- ui/sources/index.jsx | 8 +- ui/sources/modals/games-modal.jsx | 161 +++++++++++++++++++++++------- ui/sources/pages/cheats-page.jsx | 3 +- ui/sources/pages/home-page.jsx | 96 ++++++------------ ui/sources/pages/install-page.jsx | 72 ------------- ui/sources/pages/saves-page.jsx | 3 +- ui/sources/services/files.js | 31 ++---- ui/sources/services/path.js | 16 +++ ui/sources/services/requests.js | 15 +-- ui/sources/services/wasi.js | 4 +- ui/sources/styles/index.css | 73 +++++++------- 16 files changed, 238 insertions(+), 326 deletions(-) delete mode 100644 cores/lib2048.a delete mode 100644 ui/sources/pages/install-page.jsx diff --git a/cores/cores.json b/cores/cores.json index 32273d2..bad393b 100644 --- a/cores/cores.json +++ b/cores/cores.json @@ -1,83 +1,34 @@ { - "2048": { - "name": "2048", - "repository": "libretro-2048", - "makefile": "Makefile.libretro", - "systems": [ - { - "name": "Get to the 2048 tile!", - "standalone": true - } - ] - }, "gambatte": { "name": "Gambatte", "repository": "gambatte-libretro", - "systems": [ - { - "name": "Game Boy", - "extension": "gb" - }, - { - "name": "Game Boy Color", - "extension": "gbc" - } - ] + "systems": ["Game Boy", "Game Boy Color"] }, "vbam": { "name": "VBA-M", "repository": "vbam-libretro", "directory": "src/libretro", - "systems": [ - { - "name": "Game Boy Advance", - "extension": "gba" - } - ] + "systems": ["Game Boy Advance"] }, "desmume": { "name": "DeSmuME", "directory": "desmume/src/frontend/libretro", - "systems": [ - { - "name": "Nintendo DS", - "extension": "nds" - } - ] + "systems": ["Nintendo DS"] }, "nestopia": { "name": "Nestopia", "directory": "libretro", - "systems": [ - { - "name": "NES", - "extension": "nes" - } - ] + "systems": ["NES"] }, "snes9x": { "name": "Snes9x", "directory": "libretro", - "systems": [ - { - "name": "SNES", - "extension": "smc" - } - ] + "systems": ["SNES"] }, "genesis": { "name": "Genesis Plus GX", "repository": "Genesis-Plus-GX", "makefile": "Makefile.libretro", - "systems": [ - { - "name": "Master System", - "extension": "sms" - }, - { - "name": "Mega Drive", - "extension": "bin" - } - ] + "systems": ["Master System", "Mega Drive"] } } diff --git a/cores/lib2048.a b/cores/lib2048.a deleted file mode 100644 index c718b815b4914f67bf932d2fb42133d24ec21f91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157940 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

EaB}HOzxt|Ov-9VdN`BIm_M_Cl+Z@lT zce+0-Y0W-9?H|S$U&H!;1^SuSAWT>C`tGy((imzEEM}VnEjhemeWRkLeVzIvq7}E8 z($zT$UH*9311vR!31qG~*lvP-C)j!DZEUHvD;|dZ!#ua$uGnCw>l<+n7~31ExzMUP zYtU91v>yz@=7T1k?T&vBHpdd|hP&V0 z&iJD?`JY>HOGMll$vzawf=w;lzYW|8nO<#z75%KvfclMcw|#}%VRymicB2*d$!opt z*thQ0ehypB7R@=>H;{Hb(z)dLGk)9@J(;LK<4ia+09)?ypHc~>x}~r)fcpTwmZV@o zV5_!K(b&E;|6;2aHIT4I*xOHxf6pKP7=@ejy@~OIHu>^RuB_g`tWMls&c50;`3cVCw|W5{}rkW#R9M?xNF_NZgS9cg*ocxTJDZ6|WQY;y7J)U=!@ zTN7XCG0dTkCN90_K+Nl{6M()!d?yfotzKSMUX{Q6o_SUH8qmG=it<{B-3RaD6ji`$ zmR#@+W-c{znqiuuy0WU=UJY;Q)pE$-Ui=ldgfri1o-&17o?|lEs@8LMctZrpad|{#NV= zjm8~v>iVcLJ$crqw8ElS*VdFjJpLC&Q)*I+M$CFHuEaZe%E-*j-)H_L5+9%ph>;C#GT#J<#B%L_ zC@np*0gO7iMW-99Y@$|c9jrQzo$Zv

|_+_8+Wlj?|mlqCUq?vjfp0uQrJC@4dr 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

-fEm_nHea0FtlbLe{vA%*u%%_bDln)uUX8P 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 game.rom == `${this.game}.${system.extension}`); - if (!game) - return system.standalone; - - return true; + return system.games.find(game => game.name == this.game) != null; } } diff --git a/ui/sources/entities/system.js b/ui/sources/entities/system.js index 85c063f..5267c39 100644 --- a/ui/sources/entities/system.js +++ b/ui/sources/entities/system.js @@ -10,12 +10,6 @@ export class System { /** @type {string} */ core_name; - /** @type {string} */ - extension; - - /** @type {boolean} */ - standalone; - /** @type {Game[]} */ games; } diff --git a/ui/sources/index.jsx b/ui/sources/index.jsx index 6e714f3..f5ee6cb 100644 --- a/ui/sources/index.jsx +++ b/ui/sources/index.jsx @@ -4,9 +4,8 @@ import { createRoot } from 'react-dom/client'; import { Redirect, Route } from 'react-router'; import { IonReactMemoryRouter } from '@ionic/react-router'; import { IonApp, IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs, setupIonicReact, useIonLoading } from '@ionic/react'; -import { cloudDownload, gameController, keyOutline, save } from 'ionicons/icons'; +import { gameController, keyOutline, save } from 'ionicons/icons'; import { HomePage } from './pages/home-page'; -import { InstallPage } from './pages/install-page'; import { SavesPage } from './pages/saves-page'; import { CheatsPage } from './pages/cheats-page'; import Database from './services/database'; @@ -67,7 +66,6 @@ function Junie() { - } /> @@ -78,10 +76,6 @@ function Junie() { Games - - - Install - Saves diff --git a/ui/sources/modals/games-modal.jsx b/ui/sources/modals/games-modal.jsx index 6a37b7f..0b7627d 100644 --- a/ui/sources/modals/games-modal.jsx +++ b/ui/sources/modals/games-modal.jsx @@ -1,31 +1,86 @@ -import { IonButton, IonButtons, IonCard, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonPage, IonProgressBar, IonTitle, IonToolbar, useIonAlert } from '@ionic/react'; -import { cloudDownloadOutline, trashOutline } from 'ionicons/icons'; -import { useState } from 'react'; +import { IonButton, IonButtons, IonCard, IonContent, IonHeader, IonIcon, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonPage, IonProgressBar, IonTitle, IonToolbar, useIonAlert, useIonModal } from '@ionic/react'; +import { add, closeOutline, cloudDownloadOutline, playOutline } from 'ionicons/icons'; +import { useRef, useState } from 'react'; import { useToast } from '../hooks/toast'; +import { CoreModal } from './core-modal'; +import { System } from '../entities/system'; import { Game } from '../entities/game'; import Requests from '../services/requests'; import Files from '../services/files'; +import Path from '../services/path'; + +const GameCard = ({ game, status, download, play }) => { + return ( + + +

{Path.clean(game.name)}

+

{game.system}

+ + {status.game == game.name && + + } + {status.game != game.name && !game.installed && + download(game)} disabled={!!status.game} fill="clear"> + + + } + {status.game != game.name && game.installed && + play(game)} disabled={!!status.game} fill="clear"> + + + } + + ); +} /** * @param {Object} parameters - * @param {string} parameters.system + * @param {System} parameters.system * @param {() => void} parameters.close * @returns {JSX.Element} */ export const GamesModal = ({ system, close }) => { - const [download, setDownload] = useState({ game: null, progress: 0 }); + const list = useRef(/** @type {HTMLIonListElement} */ (null)); + const input = useRef(/** @type {HTMLInputElement} */ (null)); + + const sort = () => [...system.games.sort((g1, g2) => g1.rom < g2.rom ? -1 : 1)]; + + const [game, setGame] = useState(null); + const [games, setGames] = useState(sort(system.games)); + const [status, setStatus] = useState({ game: null, progress: 0 }); + + const [start, stop] = useIonModal(CoreModal, { system, game, close: () => stop() }); const [present, dismiss] = useToast('Game successfully installed!'); const [alert] = useIonAlert(); + /** + * @param {FileList} input + * @returns {Promise} + */ + const install = async (input) => { + if (!input?.length) + return; + + const file = input[0]; + + const buffer = new Uint8Array(await file.arrayBuffer()) + await Files.Games.add(system.name, file.name, buffer); + + const games = await Files.Games.get(); + system.games.push(games.find(game => game.rom == file.name)); + + setGames(sort(system.games)); + } + /** * @param {Game} game * @returns {Promise} */ - const install = async (game) => { - setDownload({ game: game.name, progress: 0 }); + const download = async (game) => { + setStatus({ game: game.name, progress: 0 }); const data = await Requests.fetchGame(system, game, progress => { - setDownload({ game: game.name, progress }); + setStatus({ game: game.name, progress }); }); if (!data) { @@ -34,7 +89,7 @@ export const GamesModal = ({ system, close }) => { message: `${game.name} (${system.name})`, buttons: [ 'OK' ], }); - setDownload({ game: null, progress: 0 }); + setStatus({ game: null, progress: 0 }); return; } @@ -44,7 +99,8 @@ export const GamesModal = ({ system, close }) => { dismiss(); present(`${game.name} (${system.name})`); - setDownload({ game: null, progress: 0 }); + setStatus({ game: null, progress: 0 }); + setGames(sort(system.games)); } /** @@ -55,7 +111,17 @@ export const GamesModal = ({ system, close }) => { await Files.Games.remove(game.system, game.rom); game.installed = false; - setDownload({ game: null, progress: 0 }); + await list.current.closeSlidingItems(); + setGames(sort(system.games)); + } + + /** + * @param {Game} game + * @returns {void} + */ + const play = (game) => { + setGame(game); + start({ cssClass: 'fullscreen' }); } return ( @@ -65,35 +131,62 @@ export const GamesModal = ({ system, close }) => { Games - Close + input.current.click()}> + install(e.target.files)} hidden /> + + + + + - {system.games.map(game => - - - -

{game.name}

-

{game.system}

+ + + + Installed + + + {games.filter(game => game.installed).map(game => ( + + + + + remove(game)}>Delete + + + + ))} + + {!games.filter(game => game.installed).length && + + You haven't installed any game yet. - {download.game == game.name && - - } - {download.game != game.name && !game.installed && - install(game)} disabled={!!download.game} fill="clear"> - - - } - {download.game != game.name && game.installed && - remove(game)} disabled={!!download.game} fill="clear"> - - - } -
-
- )} + } + + + + + Available + + + {games.filter(game => !game.installed).map(game => ( + + + + ))} + + {!games.filter(game => !game.installed).length && + + No game is available to download.
+ Try refreshing the library from the home page. +
+ } + +
+
diff --git a/ui/sources/pages/cheats-page.jsx b/ui/sources/pages/cheats-page.jsx index 93ac514..2a9e761 100644 --- a/ui/sources/pages/cheats-page.jsx +++ b/ui/sources/pages/cheats-page.jsx @@ -7,6 +7,7 @@ import { System } from '../entities/system'; import { Game } from '../entities/game'; import Files from '../services/files'; import Requests from '../services/requests'; +import Path from '../services/path'; /** * @returns {JSX.Element} @@ -105,7 +106,7 @@ export const CheatsPage = () => { }

{cheat.name}

-

{list.game}

+

{Path.clean(list.game)}

{list.system}

showModal(list, cheat)} fill="clear"> diff --git a/ui/sources/pages/home-page.jsx b/ui/sources/pages/home-page.jsx index 70a0483..e36c053 100644 --- a/ui/sources/pages/home-page.jsx +++ b/ui/sources/pages/home-page.jsx @@ -1,24 +1,18 @@ -import { IonButton, IonButtons, IonCard, IonContent, IonHeader, IonIcon, IonItem, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonPage, IonTitle, IonToolbar, useIonModal, useIonViewWillEnter } from '@ionic/react'; -import { add, playOutline, informationCircleOutline } from 'ionicons/icons'; -import { useRef, useState } from 'react'; +import { IonButton, IonButtons, IonCard, IonCardHeader, IonCardSubtitle, IonCardTitle, IonContent, IonHeader, IonIcon, IonLoading, IonPage, IonTitle, IonToolbar, useIonModal, useIonViewWillEnter } from '@ionic/react'; +import { useState } from 'react'; +import { informationCircleOutline, refreshOutline } from 'ionicons/icons'; import { useToast } from '../hooks/toast'; -import { CoreModal } from '../modals/core-modal'; +import { GamesModal } from '../modals/games-modal'; import { System } from '../entities/system'; -import { Game } from '../entities/game'; -import Audio from '../services/audio'; import Requests from '../services/requests'; -import Files from '../services/files'; /** * @returns {JSX.Element} */ export const HomePage = () => { - const fileInput = useRef(/** @type {HTMLInputElement} */ (null)); - - const [systems, setSystems] = useState(/** @type {System[]} */ ([])); - const [system, setSystem] = useState(/** @type {System} */ (null)); - const [games, setGames] = useState(/** @type {Game[]} */ ([])); - const [game, setGame] = useState(/** @type {Game} */ (null)); + const [systems, setSystems] = useState(/** @type {System[]} */ ([]) ); + const [system, setSystem] = useState(/** @type {System} */ (null) ); + const [loading, setLoading] = useState(/** @type {boolean} */ (false)); const version = window.junie_build.split('-')[0]; const build = window.junie_build.split('-')[1]; @@ -26,53 +20,31 @@ export const HomePage = () => { const [present] = useToast(`Junie - ${version} (${build})`); /** - * @param {FileList} input * @returns {Promise} */ - const addGame = async (input) => { - if (!input?.length) - return; - - const file = input[0]; - - const system = systems.find(x => x.extension == file.name.split('.').pop()); - if (!system) - return; + const refreshLibrary = async () => { + setLoading(true); - const buffer = new Uint8Array(await file.arrayBuffer()) - Files.Games.add(system.name, file.name, buffer); - - setGames(await Files.Games.get()); - } + await Requests.refreshLibrary() + setSystems(await Requests.getSystems()); - /** - * @param {Game} game - * @returns {Promise} - */ - const deleteGame = async (game) => { - await Files.Games.remove(game.system, game.rom); - setGames(await Files.Games.get()); + setLoading(false); } /** - * @param {Game} system + * @param {System} system * @returns {void} */ - const showModal = (game) => { - const system = systems.find(system => system.name == game.system); - + const showModal = (system) => { setSystem(system); - setGame(game); open({ cssClass: 'fullscreen' }); } - const [open, close] = useIonModal(CoreModal, { system, game, close: () => close() }); + const [open, close] = useIonModal(GamesModal, { system, close: () => close() }); useIonViewWillEnter(async () => { - Audio.unlock(); setSystems(await Requests.getSystems()); - setGames(await Files.Games.get()); }); return ( @@ -80,42 +52,30 @@ export const HomePage = () => { + Junie present(date)}> - Junie - fileInput.current.click()}> - addGame(e.target.files)} hidden /> - + + - - - {games.map(game => - - - - -

{game.name}

-

{game.system}

-
- showModal(game)} fill="clear"> - - -
- - deleteGame(game)}>Delete - -
-
- )} -
+ + + {systems.map(system => + showModal(system)}> + + {system.name} + {system.core_name} - {system.games.length} games + + + )} diff --git a/ui/sources/pages/install-page.jsx b/ui/sources/pages/install-page.jsx deleted file mode 100644 index 6e5684c..0000000 --- a/ui/sources/pages/install-page.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import { IonButton, IonButtons, IonCard, IonCardHeader, IonCardSubtitle, IonCardTitle, IonContent, IonHeader, IonIcon, IonLoading, IonPage, IonTitle, IonToolbar, useIonModal, useIonViewWillEnter } from '@ionic/react'; -import { useState } from 'react'; -import { refreshOutline } from 'ionicons/icons'; -import { GamesModal } from '../modals/games-modal'; -import { System } from '../entities/system'; -import Requests from '../services/requests'; - -/** - * @returns {JSX.Element} - */ -export const InstallPage = () => { - const [systems, setSystems] = useState(/** @type {System[]} */ ([]) ); - const [system, setSystem] = useState(/** @type {System} */ (null) ); - const [loading, setLoading] = useState(/** @type {boolean} */ (false)); - - /** - * @returns {Promise} - */ - const refreshLibrary = async () => { - setLoading(true); - - await Requests.refreshLibrary() - setSystems(await Requests.getSystems()); - - setLoading(false); - } - - /** - * @param {System} system - * @returns {void} - */ - const showModal = (system) => { - setSystem(system); - - open({ cssClass: 'fullscreen' }); - } - - const [open, close] = useIonModal(GamesModal, { system, close: () => close() }); - - useIonViewWillEnter(async () => { - setSystems(await Requests.getSystems()); - }); - - return ( - - - - - Systems - - - - - - - - - - - {systems.filter(system => !system.standalone).map(system => - showModal(system)}> - - {system.name} - {system.core_name} - {system.games.length} games - - - )} - - - - ); -}; diff --git a/ui/sources/pages/saves-page.jsx b/ui/sources/pages/saves-page.jsx index 1af8706..0fd57e1 100644 --- a/ui/sources/pages/saves-page.jsx +++ b/ui/sources/pages/saves-page.jsx @@ -8,6 +8,7 @@ import { Save } from '../entities/save'; import Requests from '../services/requests'; import Files from '../services/files'; import Zip from '../services/zip'; +import Path from '../services/path'; /** * @returns {JSX.Element} @@ -135,7 +136,7 @@ export const SavesPage = () => { } -

{save.game?.replaceAll(/ \(.*\)/g, '')}

+

{Path.clean(save.game)}

{save.system}

showModal(save)} fill="clear"> diff --git a/ui/sources/services/files.js b/ui/sources/services/files.js index a99f9ba..e4800e7 100644 --- a/ui/sources/services/files.js +++ b/ui/sources/services/files.js @@ -39,17 +39,11 @@ export default class Files { } /** - * @param {string[]} suffixes * @returns {Promise} */ - static async list(...suffixes) { + static async list() { const fs = await this.#fs(); - - const paths = await fs.list(); - - return suffixes - ? paths.filter(p => suffixes.some(s => p.endsWith(s))) - : paths; + return await fs.list(); } /** @@ -136,10 +130,10 @@ export default class Files { for (const core of Object.keys(Files.#cores)) { for (const system of Files.#cores[core].systems) { systems.push({ - ...system, + name: system, lib_name: core, core_name: Files.#cores[core].name, - games: stored.find(x => x.name == system.name)?.games, + games: stored.find(x => x.name == system)?.games, }); } } @@ -178,7 +172,7 @@ export default class Files { * @returns {Promise} */ static async get() { - const paths = await Files.list('.sav', '.dsv', '.srm', '.rtc', '.state', '.cht'); + const paths = (await Files.list()).filter(path => path.split('/').length == 4); return paths.map(path => new Save(path)).reduce((saves, save) => { const found = saves.find(x => x.system == save.system && x.game == save.game); @@ -196,8 +190,7 @@ export default class Files { */ static async fix(save, system, game) { for (const path of save.paths) { - const filename = game.rom.replace(`.${system.extension}`, ''); - const new_path = path.replace(save.system, system.name).replaceAll(save.game, filename); + const new_path = path.replace(save.system, system.name).replaceAll(save.game, game.name); const data = await Files.read(path); await Files.remove(path); @@ -220,7 +213,7 @@ export default class Files { * @returns {Promise} */ static async get() { - const paths = await Files.list('.cht'); + const paths = (await Files.list()).filter(path => path.endsWith('.cht')); const files = []; for (const path of paths) { @@ -254,20 +247,16 @@ export default class Files { */ static async get() { const systems = await Files.Library.get(); - const extensions = systems.map(x => x.extension); - const paths = await Files.list(...extensions); + const paths = (await Files.list()).filter(path => path.split('/').length == 3); const files = []; - for (const system of systems) - if (system.standalone) - files.push(new Game(system, system.core_name)); - for (const path of paths) { const [system_name, rom_name] = Path.parse(path); const system = systems.find(x => x.name == system_name); - files.push(new Game(system, rom_name)); + if (system) + files.push(new Game(system, rom_name, true)); } return files; diff --git a/ui/sources/services/path.js b/ui/sources/services/path.js index bb35348..5a7e4ce 100644 --- a/ui/sources/services/path.js +++ b/ui/sources/services/path.js @@ -39,4 +39,20 @@ export default class Path { const matches = path.match(/\/([^\/]*)\/([^\/]*)/); return [ matches[1], matches[2] ]; } + + /** + * @param {string} name + * @returns {string} + */ + static name(name) { + return name.substring(0, name.lastIndexOf('.')) || name; + } + + /** + * @param {string} name + * @returns {string} + */ + static clean(name) { + return name.replaceAll(/ \(.*\)/g, ''); + } } diff --git a/ui/sources/services/requests.js b/ui/sources/services/requests.js index f02367c..82735b8 100644 --- a/ui/sources/services/requests.js +++ b/ui/sources/services/requests.js @@ -1,6 +1,7 @@ import { Game } from '../entities/game'; import { System } from '../entities/system'; import Files from './files'; +import Path from './path'; export default class Requests { /** @@ -15,14 +16,11 @@ export default class Requests { html.innerHTML = await folder.text(); const elements = Array.from(html.querySelectorAll('a')); - const games = elements.map(a => { - const name = a.innerText.substring(0, a.innerText.lastIndexOf('.')); - return { name: name, rom: a.innerText }; - }); - - system.games = games.filter(game => game.rom.endsWith(`.${system.extension}`)); + system.games = elements.map(a => new Object({ name: Path.name(a.innerText), rom: a.innerText })) + .filter(game => game.rom != '.' && !game.rom.endsWith('/') && !game.rom.endsWith('.png')); } catch (e) { + console.error(e); system.games = []; } } @@ -51,11 +49,8 @@ export default class Requests { system.games = [ ...games.filter(x => !system.games.find(y => x.rom == y.rom)), - ...system.games.map(x => new Game(system, x.rom)), + ...system.games.map(x => new Game(system, x.rom, false)), ]; - - for (const game of system.games) - game.installed = !!games.find(x => x.rom == game.rom); } return systems; diff --git a/ui/sources/services/wasi.js b/ui/sources/services/wasi.js index e594882..c7d96b4 100644 --- a/ui/sources/services/wasi.js +++ b/ui/sources/services/wasi.js @@ -23,10 +23,8 @@ class FS { * @returns {Promise} */ async load(system, rom) { - const game = rom.substring(0, rom.lastIndexOf('.')) || rom; - for (const path of this.#filesystem.list()) { - if (!path.startsWith(`/${system}/${game}`)) + if (!path.startsWith(`/${system}/${Path.name(rom)}`)) continue; this.#filesystem.close(path); diff --git a/ui/sources/styles/index.css b/ui/sources/styles/index.css index 389d119..aa8f6b4 100644 --- a/ui/sources/styles/index.css +++ b/ui/sources/styles/index.css @@ -26,21 +26,51 @@ /* - * Home + * Systems + */ + #root .home ion-card { + text-align: center; + cursor: pointer; +} + + +/* + * Games */ -#root .home ion-list { +#root .games { + --background: var(--ion-background-color); +} + +#root .games .empty { + text-align: center; + font-style: italic; + padding: 18px; + color: var(--ion-color-step-400); +} + +#root .games ion-list { padding: 0; background: transparent; } -#root .home ion-item { +#root .games ion-card { + display: flex; + cursor: pointer; +} + +#root .games ion-item { + width: 100%; --padding-start: 0; } -#root .home ion-label { +#root .games ion-label { margin-left: 16px; } +#root .games ion-progress-bar { + max-width: 50px; +} + /* * Core @@ -92,41 +122,6 @@ } -/* - * Systems - */ -#root .systems ion-card { - text-align: center; - cursor: pointer; -} - - -/* - * Games - */ -#root .games { - --background: var(--ion-background-color); -} - -#root .games ion-card { - display: flex; - cursor: pointer; -} - -#root .games ion-item { - width: 100%; - --padding-start: 0; -} - -#root .games ion-label { - margin-left: 16px; -} - -#root .games ion-progress-bar { - max-width: 50px; -} - - /* * Saves */