<section id="ficha" hidden data-focus-trap> from the HTML:
hidden: it starts hidden.data-focus-trap: while it is visible, focus cannot leave it (the arrows do not escape to the grid behind it).
onclick to onclick: () => abrirFicha(g.id) and add this to
main.js (also add description, playtime and year to the imports:
import { description, playtime, year } from "/_sdk/kit/format.js";):
const ficha = document.querySelector("#ficha"); next to the other constants).
ejg.library.byId(id)returns the game instantly, with no waiting.ejg.game.details(id)asks for what the library does not include: the description, screenshots (screenshots), trailers (trailers) and recent sessions (recentSessions). It is asynchronous, so we paint the page first and fill in the text afterwards.turnokeeps a game’s description from landing on another game’s page if the user opens and closes pages quickly.description(text)turns the description format (## title,- bulletand paragraphs separated by a blank line) into safe HTML elements. Do not useinnerHTMLwith text that comes from outside.playtime(seconds)→ “12 h 34 min” or “Not played”.year(date)→ “2017”.- Here we do use the large images (
cover,hero): a page has only one.
- Play, or Running if
ejg.game.isRunning(id). The example’s source strings areJugarandEn marcha. ejg.game.edit(id)opens ejGames’ game editor (name, art, executable…). When it closes,focus-returnarrives and focus returns to the button.
bindNav that Back closes the page and that the
favorite also works inside it, to change the hints depending on where you are,
and to repaint when something changes:
bindNav, the hint bar and the last two lines with this,
and add debounce to the dom.js import. It groups several notices in a row
into a single repaint. When a game closes, its new hours arrive through the same
notice, which is why repintar also updates the open page. The page CSS, in
short (the full file is in
examples/ejemplo-tema/style.css):

