Align ability page with move/item; link Team at-a-glance names
- 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
This commit is contained in:
parent
9810eb0996
commit
262e1a454e
@ -102,9 +102,11 @@ Working app with a type-themed UI:
|
||||
/ "TMs only" / "HMs only" for the selected game and sort by power /
|
||||
accuracy / recency — or, with a machine filter on, by TM/HM number
|
||||
(numbers are baked into the snapshot). Items filter by category. Each
|
||||
has its own detail page — the move page lists every Pokémon that can
|
||||
learn it (filterable, narrowed to species that existed by the selected
|
||||
game's generation). Query, scroll, tab and filters persist.
|
||||
has its own detail page; the move, ability and item pages list the
|
||||
Pokémon connected to them (learners / users / wild holders) as a
|
||||
filterable grid, narrowed to the selected game (by generation, or
|
||||
exactly by version for held items). Query, scroll, tab and filters
|
||||
persist.
|
||||
- **Team** — a lineup of up to 6. Coverage leads with a "weak spots"
|
||||
summary (types that hit 2+ members, or that someone's weak to and nobody
|
||||
resists), then a full matchup grid with a diverging resist◀│▶weak bar per
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
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) {
|
||||
@ -21,9 +22,51 @@ export async function AbilityDetail(id) {
|
||||
}
|
||||
|
||||
const style = settings.get().spriteStyle;
|
||||
const mons = a.pokemon.map((pid) => snap.speciesById.get(pid)).filter(Boolean);
|
||||
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(
|
||||
@ -45,20 +88,21 @@ export async function AbilityDetail(id) {
|
||||
el(
|
||||
'section',
|
||||
{ class: 'detail__section' },
|
||||
el('h2', {}, `Pokémon with this ability (${mons.length})`),
|
||||
mons.length
|
||||
el(
|
||||
'h2',
|
||||
{},
|
||||
`Pokémon with this ability${vg === 'all' ? '' : ` in ${prettify(vg)}`} (${mons.length})`,
|
||||
),
|
||||
predatesGame
|
||||
? el(
|
||||
'div',
|
||||
{ class: 'ab-mons' },
|
||||
...mons.map((sp) =>
|
||||
el(
|
||||
'a',
|
||||
{ class: 'ab-mon', href: `#/pokemon/${sp.id}` },
|
||||
Sprite(sp.id, { style, alt: sp.name, size: 48 }),
|
||||
el('span', {}, sp.name.replace(/-/g, ' ')),
|
||||
),
|
||||
),
|
||||
'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.'),
|
||||
),
|
||||
);
|
||||
|
||||
@ -309,17 +309,27 @@ export async function TeamView() {
|
||||
'dl',
|
||||
{ class: 'pfacts' },
|
||||
fact('Average BST', String(avgBst)),
|
||||
fact('Fastest', `${prettify(fastest.name)} (${fastest.stats?.spe ?? '?'} Spe)`),
|
||||
fact('Fastest', monLink(fastest, `${fastest.stats?.spe ?? '?'} Spe`)),
|
||||
fact(
|
||||
'Bulkiest',
|
||||
`${prettify(bulkiest.name)} (${
|
||||
(bulkiest.stats?.hp || 0) + (bulkiest.stats?.def || 0) + (bulkiest.stats?.spd || 0)
|
||||
} HP+Def+SpD)`,
|
||||
monLink(
|
||||
bulkiest,
|
||||
`${(bulkiest.stats?.hp || 0) + (bulkiest.stats?.def || 0) + (bulkiest.stats?.spd || 0)} HP+Def+SpD`,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function monLink(sp, tail) {
|
||||
return el(
|
||||
'span',
|
||||
{},
|
||||
el('a', { class: 'link', href: `#/pokemon/${sp.id}` }, prettify(sp.name)),
|
||||
` (${tail})`,
|
||||
);
|
||||
}
|
||||
|
||||
function compare(mem) {
|
||||
const vg = snap.versionGroupByKey.get(settings.get().versionGroup);
|
||||
const gen = vg ? vg.generation : 9;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user