From e61bf7ac6cc56588f15ae039fc3b128b6ed61dd9 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 27 Aug 2026 13:40:18 -0400 Subject: [PATCH] Stylised game-cover tiles in the game picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Each game renders as a two-tone tile split in its version colours (Scarlet/Violet, Sword/Shield, Ruby/Sapphire…), keyed by version group with a per-generation fallback (src/data/game-colors.js) - Clean flat split with a bottom scrim for legibility — no gloss/bubble Co-Authored-By: Claude Sonnet 5 --- src/components/GameSheet.js | 13 ++++++--- src/data/game-colors.js | 51 +++++++++++++++++++++++++++++++++++ src/styles/layout.css | 53 +++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 src/data/game-colors.js diff --git a/src/components/GameSheet.js b/src/components/GameSheet.js index 902cc12..56e49f7 100644 --- a/src/components/GameSheet.js +++ b/src/components/GameSheet.js @@ -6,6 +6,7 @@ import { prettify, } from '../data/pokedex-resolver.js'; import { settings } from '../store/settings.js'; +import { gameColors } from '../data/game-colors.js'; let openInstance = null; @@ -101,12 +102,14 @@ export async function openGameSheet() { for (const vg of versionGroups) { const active = vg.key === st.versionGroup; const dexCount = dexesForVersionGroup(snap, vg.key).length; + const [c1, c2] = gameColors(vg.key, generation.id); grid.append( el( 'button', { - class: `gamecard${active ? ' is-active' : ''}`, + class: `gamecard gamecard--cover${active ? ' is-active' : ''}`, type: 'button', + style: `--g1:${c1};--g2:${c2}`, onclick: () => { settings.set({ versionGroup: vg.key, pokedex: null }); if (dexesForVersionGroup(snap, vg.key).length <= 1) { @@ -118,8 +121,12 @@ export async function openGameSheet() { }, }, el('span', { class: 'gamecard__name' }, prettify(vg.name || vg.key)), - el('span', { class: 'gamecard__meta' }, vg.versions.map(prettify).join(' / ')), - el('span', { class: 'gamecard__meta' }, `${dexCount} ${dexCount === 1 ? 'dex' : 'dexes'}`), + el( + 'span', + { class: 'gamecard__foot' }, + el('span', { class: 'gamecard__meta' }, vg.versions.map(prettify).join(' / ')), + el('span', { class: 'gamecard__dex' }, `${dexCount} ${dexCount === 1 ? 'dex' : 'dexes'}`), + ), ), ); } diff --git a/src/data/game-colors.js b/src/data/game-colors.js new file mode 100644 index 0000000..a7cecbf --- /dev/null +++ b/src/data/game-colors.js @@ -0,0 +1,51 @@ +/** + * Signature colours for each game, used to render a stylised "cover" tile in + * the game picker (real box art is Nintendo's and not in the API). Two + * colours = the paired versions; games without a listed entry fall back to + * a per-generation hue. + */ +const GAME = { + 'red-blue': ['#e0362f', '#2f6cd8'], + 'red-green-japan': ['#e0362f', '#39ab57'], + 'blue-japan': ['#2f6cd8', '#3f8ad0'], + yellow: ['#f4c21a', '#f0a81f'], + 'gold-silver': ['#d7a521', '#b9bcc6'], + crystal: ['#41a3c4', '#6fd0d8'], + 'ruby-sapphire': ['#b4302e', '#2e5cb4'], + emerald: ['#12904a', '#26b56b'], + 'firered-leafgreen': ['#e4552b', '#57b04b'], + 'diamond-pearl': ['#7fb0e2', '#e0a3c8'], + platinum: ['#9aa0ab', '#c9ccd4'], + 'heartgold-soulsilver': ['#d7a521', '#b9bcc6'], + 'black-white': ['#26262b', '#b9b9c2'], + 'black-2-white-2': ['#2b2b31', '#aeaeb8'], + 'x-y': ['#4c7bc4', '#c43b3b'], + 'omega-ruby-alpha-sapphire': ['#b4302e', '#2e5cb4'], + 'sun-moon': ['#f0952b', '#4062b4'], + 'ultra-sun-ultra-moon': ['#e3781e', '#34489e'], + 'lets-go-pikachu-lets-go-eevee': ['#f4c21a', '#c08a52'], + 'sword-shield': ['#00a0c6', '#c33b84'], + 'brilliant-diamond-and-shining-pearl': ['#6f5ac4', '#d06fa6'], + 'legends-arceus': ['#3e7c6a', '#b08d4a'], + 'scarlet-violet': ['#c9352e', '#7c4da0'], + 'the-teal-mask': ['#2e8b7a', '#39a892'], + 'the-indigo-disk': ['#3b3ba0', '#5a5ac4'], + colosseum: ['#3a3a44', '#6e5aa0'], + xd: ['#4a2e6e', '#6a45a0'], +}; + +const GEN = { + 1: ['#e0362f', '#e8564f'], + 2: ['#d7a521', '#e0b94a'], + 3: ['#12904a', '#2eb56b'], + 4: ['#6e86c4', '#9ab0dc'], + 5: ['#44444c', '#666670'], + 6: ['#5b7bc4', '#7c9adc'], + 7: ['#f0952b', '#f5b45a'], + 8: ['#3aa6c6', '#5ec6dc'], + 9: ['#c9352e', '#e0564f'], +}; + +export function gameColors(versionGroupKey, generation = 9) { + return GAME[versionGroupKey] || GEN[generation] || GEN[9]; +} diff --git a/src/styles/layout.css b/src/styles/layout.css index b764a98..f336815 100644 --- a/src/styles/layout.css +++ b/src/styles/layout.css @@ -621,6 +621,59 @@ text-transform: capitalize; } +/* Cover tiles: a clean split of the two version colours, no gloss. */ +.gamecard--cover { + position: relative; + overflow: hidden; + min-height: 88px; + justify-content: flex-end; + gap: 6px; + padding: 14px; + border: none; + color: #fff; + background: linear-gradient(105deg, var(--g1) 0%, var(--g1) 42%, var(--g2) 58%, var(--g2) 100%); + box-shadow: var(--shadow); +} +.gamecard--cover::after { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(to top, rgba(0, 0, 0, 0.28), transparent 55%); +} +.gamecard--cover > * { + position: relative; +} +.gamecard--cover:hover { + border: none; + transform: translateY(-3px); +} +.gamecard--cover.is-active { + background: linear-gradient(105deg, var(--g1) 0%, var(--g1) 42%, var(--g2) 58%, var(--g2) 100%); + box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); +} +.gamecard--cover .gamecard__name { + font-size: 1rem; + line-height: 1.15; +} +.gamecard__foot { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} +.gamecard--cover .gamecard__meta { + color: rgba(255, 255, 255, 0.9); +} +.gamecard__dex { + font-size: 0.68rem; + font-weight: 700; + padding: 2px 8px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.2); + color: #fff; + white-space: nowrap; +} + /* ================= Detail: type-themed hero + tabbed sheet ========= */ .pdetail { --ink: #fff;