import { el, clear, onTeardown } from '../lib/dom.js'; import { loadSnapshot } from '../data/snapshot.js'; import { settings } from '../store/settings.js'; import { selection, stats, statsNational } from '../store/selection.js'; import { ui } from '../store/ui.js'; import { playedGames, isPlayed } from '../store/playedGames.js'; import { dexesForVersionGroup, versionGroupsByGeneration } from '../data/pokedex-resolver.js'; function bar(seen, caught, total) { const pc = total ? (caught / total) * 100 : 0; const ps = total ? (seen / total) * 100 : 0; const track = el('div', { class: 'prog__track' }); const seenEl = el('div', { class: 'prog__seen' }); const caughtEl = el('div', { class: 'prog__caught' }); seenEl.style.width = `${ps}%`; caughtEl.style.width = `${pc}%`; track.append(seenEl, caughtEl); return track; } export async function ProgressView() { const view = el('section', { class: 'view lookup progressview' }); const snap = await loadSnapshot(); const speciesIdsFor = (vgKey) => { const ids = new Set(); for (const dex of dexesForVersionGroup(snap, vgKey)) { for (const [sid] of dex.entries) ids.add(sid); } return [...ids]; }; function gameRow(vg, { played }) { const s = stats(speciesIdsFor(vg.key), vg.key); return el( 'button', { type: 'button', class: `prog__row${played ? ' prog__row--played' : ''}`, onclick: () => { settings.set({ versionGroup: vg.key, pokedex: null }); location.hash = '#/'; }, }, el('span', { class: 'prog__name' }, vg.name), bar(s.seen, s.caught, s.total), el('span', { class: 'prog__count' }, `${s.caught} / ${s.total}`), ); } const list = el('div', { class: 'prog' }); function render() { clear(list); const gens = versionGroupsByGeneration(snap); const anyPlayed = gens.some(({ versionGroups }) => versionGroups.some((vg) => isPlayed(vg.key))); const showAll = ui.get().progShowAll || !anyPlayed; // National total — caught in any game. const nat = statsNational(snap.species.map((s) => s.id)); list.append( el( 'div', { class: 'prog__row prog__row--nat' }, el('span', { class: 'prog__name' }, 'National Dex'), bar(nat.seen, nat.caught, nat.total), el('span', { class: 'prog__count' }, `${nat.caught} / ${nat.total}`), ), ); // Games you've played (imported a save for, or opened at least once). if (anyPlayed) { list.append(el('h3', { class: 'prog__gen' }, 'Your games')); for (const { versionGroups } of gens) { for (const vg of versionGroups) { if (isPlayed(vg.key)) list.append(gameRow(vg, { played: true })); } } } // Everything else — behind a toggle, since a single unified caught // record makes every game report a total whether or not you've touched it. const rest = []; let restCount = 0; for (const { generation, versionGroups } of gens) { const unplayed = versionGroups.filter((vg) => !isPlayed(vg.key)); if (!unplayed.length) continue; rest.push(el('h3', { class: 'prog__gen' }, `Gen ${generation.id} · ${generation.name}`)); for (const vg of unplayed) { rest.push(gameRow(vg, { played: false })); restCount++; } } if (restCount) { if (anyPlayed) { list.append( el( 'button', { type: 'button', class: 'prog__toggle', onclick: () => { ui.set({ progShowAll: !ui.get().progShowAll }); render(); }, }, showAll ? 'Hide other games' : `Show all other games (${restCount})`, ), ); } if (showAll) list.append(el('div', { class: 'prog__rest' }, ...rest)); } } render(); clear(view).append( el('nav', { class: 'lookup__nav' }, el('a', { class: 'link', href: '#/settings' }, '‹ Settings')), el( 'header', { class: 'view__header' }, el('h1', {}, 'Progress by game'), el('p', {}, 'What you’ve caught in each game. Tap one to switch to it.'), ), el( 'p', { class: 'prog__legend' }, el('span', { class: 'prog__key prog__key--caught' }), ' caught ', el('span', { class: 'prog__key prog__key--seen' }), ' seen', ), list, ); const offSel = selection.subscribe(render); const offPlayed = playedGames.subscribe(render); onTeardown(view, () => { offSel(); offPlayed(); }); return view; }