diff --git a/app/components/gameCard.js b/app/components/gameCard.js index cee2736..1e0ffd6 100644 --- a/app/components/gameCard.js +++ b/app/components/gameCard.js @@ -55,7 +55,7 @@ export function createGameCard(manifest, progress) { // Show time played today if available. const today = getTodayDateString(); if (progress.dailyTime && typeof progress.dailyTime[today] === 'number' - && progress.dailyTime[today] > 0) { + && progress.dailyTime[today] > 0) { details.push(`Today: ${formatDuration(progress.dailyTime[today])}`); } if (details.length > 0) { @@ -71,17 +71,15 @@ export function createGameCard(manifest, progress) { button.textContent = `Play ${manifest.name}`; button.setAttribute('aria-label', `Play ${manifest.name}`); - /** - * Dispatches a custom event when the game card button is clicked. - * @fires CustomEvent#game:select - */ - button.addEventListener('click', () => { + + // Dispatches a game:select custom event when any part of the card is clicked. + article.addEventListener('click', () => { const event = new CustomEvent('game:select', { bubbles: true, composed: true, detail: { gameId: manifest.id }, }); - button.dispatchEvent(event); + article.dispatchEvent(event); }); article.appendChild(img); diff --git a/app/components/tests/gameCard.test.js b/app/components/tests/gameCard.test.js index 695557f..ad0d080 100644 --- a/app/components/tests/gameCard.test.js +++ b/app/components/tests/gameCard.test.js @@ -64,6 +64,22 @@ describe('createGameCard', () => { expect(firedEvent.detail.gameId).toBe(validManifest.id); }); + it('clicking the card body (outside the button) fires game:select', () => { + const card = createGameCard(validManifest); + document.body.appendChild(card); + + let firedEvent = null; + card.addEventListener('game:select', (e) => { + firedEvent = e; + }); + + // Simulate a click directly on the article element (not via the button). + card.click(); + + expect(firedEvent).not.toBeNull(); + expect(firedEvent.detail.gameId).toBe(validManifest.id); + }); + it(' has a non-empty alt attribute', () => { const card = createGameCard(validManifest); const img = card.querySelector('img'); diff --git a/app/styles/game-card.css b/app/styles/game-card.css index dbea124..23a54be 100644 --- a/app/styles/game-card.css +++ b/app/styles/game-card.css @@ -16,12 +16,19 @@ overflow: hidden; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); transition: box-shadow var(--transition-fast); + cursor: pointer; } .game-card:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); } +/* Show a card-level focus ring when the Play button inside receives keyboard focus. */ +.game-card:focus-within { + outline: 3px solid var(--focus-ring); + outline-offset: 2px; +} + .game-card img { width: 100%; aspect-ratio: 1 / 1;