- AbilityDetail: "Pokémon with this ability" grid now gets a filter box and the same game/generation narrowing as the move and item pages, plus a note when the ability postdates the selected game (Libero in Ruby/Sapphire -> "introduced in Gen 8"). - TeamView "At a glance": Fastest / Bulkiest names now link to their Pokémon pages. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
111 lines
3.3 KiB
JavaScript
111 lines
3.3 KiB
JavaScript
import { el, clear } from '../lib/dom.js';
|
||
import { loadSnapshot } from '../data/snapshot.js';
|
||
import { settings } from '../store/settings.js';
|
||
import { prettify } from '../data/pokedex-resolver.js';
|
||
import { Sprite } from '../components/Sprite.js';
|
||
|
||
export async function AbilityDetail(id) {
|
||
const view = el('section', { class: 'view lookup' });
|
||
const snap = await loadSnapshot();
|
||
const a = snap.abilityById.get(id);
|
||
|
||
if (!a) {
|
||
view.append(
|
||
el(
|
||
'div',
|
||
{ class: 'view--error' },
|
||
el('h1', {}, 'Unknown ability'),
|
||
el('a', { class: 'button', href: '#/search' }, 'Back to lookup'),
|
||
),
|
||
);
|
||
return view;
|
||
}
|
||
|
||
const style = settings.get().spriteStyle;
|
||
const vg = settings.get().versionGroup;
|
||
const gen = snap.versionGroupByKey.get(vg)?.generation ?? 9;
|
||
|
||
// All-games: every species with the ability. A specific game: only those
|
||
// that existed by its generation.
|
||
let mons = a.pokemon.map((pid) => snap.speciesById.get(pid)).filter(Boolean);
|
||
if (vg !== 'all') mons = mons.filter((sp) => sp.generation <= gen);
|
||
mons.sort((x, y) => x.id - y.id);
|
||
|
||
const CAP = 400;
|
||
const grid = el('div', { class: 'ab-mons' });
|
||
function paint(q) {
|
||
const qq = (q || '').trim().toLowerCase().replace(/\s+/g, '-');
|
||
const shown = qq ? mons.filter((sp) => sp.name.includes(qq)) : mons;
|
||
clear(grid);
|
||
if (!shown.length) {
|
||
grid.append(el('p', { class: 'detail__muted' }, 'No matches.'));
|
||
return;
|
||
}
|
||
for (const sp of shown.slice(0, CAP)) {
|
||
grid.append(
|
||
el(
|
||
'a',
|
||
{ class: 'ab-mon', href: `#/pokemon/${sp.id}` },
|
||
Sprite(sp.id, { style, alt: sp.name, size: 48 }),
|
||
el('span', {}, sp.name.replace(/-/g, ' ')),
|
||
),
|
||
);
|
||
}
|
||
if (shown.length > CAP) {
|
||
grid.append(
|
||
el('p', { class: 'detail__muted' }, `+${shown.length - CAP} more — filter to narrow.`),
|
||
);
|
||
}
|
||
}
|
||
paint('');
|
||
const filterInput = el('input', {
|
||
type: 'search',
|
||
class: 'search__input learners__filter',
|
||
placeholder: 'Filter Pokémon…',
|
||
oninput: (e) => paint(e.target.value),
|
||
});
|
||
|
||
const predatesGame = vg !== 'all' && a.generation > gen;
|
||
|
||
clear(view).append(
|
||
el('nav', { class: 'lookup__nav' }, el('a', { class: 'link', href: '#/search' }, '‹ Lookup')),
|
||
el(
|
||
'header',
|
||
{ class: 'lookup__head lookup__head--item' },
|
||
el(
|
||
'div',
|
||
{},
|
||
el('h1', {}, a.name.replace(/-/g, ' ')),
|
||
el('span', { class: 'lookup__class' }, `Introduced Gen ${a.generation}`),
|
||
),
|
||
),
|
||
el(
|
||
'section',
|
||
{ class: 'detail__section' },
|
||
el('h2', {}, 'Effect'),
|
||
el('p', {}, a.effect || 'No description available.'),
|
||
),
|
||
el(
|
||
'section',
|
||
{ class: 'detail__section' },
|
||
el(
|
||
'h2',
|
||
{},
|
||
`Pokémon with this ability${vg === 'all' ? '' : ` in ${prettify(vg)}`} (${mons.length})`,
|
||
),
|
||
predatesGame
|
||
? el(
|
||
'p',
|
||
{ class: 'detail__muted' },
|
||
`Not in ${prettify(vg)} — this ability was introduced in Gen ${a.generation}.`,
|
||
)
|
||
: null,
|
||
mons.length > 24 ? filterInput : null,
|
||
mons.length
|
||
? grid
|
||
: el('p', { class: 'detail__muted' }, 'None on record.'),
|
||
),
|
||
);
|
||
return view;
|
||
}
|