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 /
|
/ "TMs only" / "HMs only" for the selected game and sort by power /
|
||||||
accuracy / recency — or, with a machine filter on, by TM/HM number
|
accuracy / recency — or, with a machine filter on, by TM/HM number
|
||||||
(numbers are baked into the snapshot). Items filter by category. Each
|
(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
|
has its own detail page; the move, ability and item pages list the
|
||||||
learn it (filterable, narrowed to species that existed by the selected
|
Pokémon connected to them (learners / users / wild holders) as a
|
||||||
game's generation). Query, scroll, tab and filters persist.
|
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"
|
- **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
|
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
|
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 { el, clear } from '../lib/dom.js';
|
||||||
import { loadSnapshot } from '../data/snapshot.js';
|
import { loadSnapshot } from '../data/snapshot.js';
|
||||||
import { settings } from '../store/settings.js';
|
import { settings } from '../store/settings.js';
|
||||||
|
import { prettify } from '../data/pokedex-resolver.js';
|
||||||
import { Sprite } from '../components/Sprite.js';
|
import { Sprite } from '../components/Sprite.js';
|
||||||
|
|
||||||
export async function AbilityDetail(id) {
|
export async function AbilityDetail(id) {
|
||||||
@ -21,9 +22,51 @@ export async function AbilityDetail(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const style = settings.get().spriteStyle;
|
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);
|
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(
|
clear(view).append(
|
||||||
el('nav', { class: 'lookup__nav' }, el('a', { class: 'link', href: '#/search' }, '‹ Lookup')),
|
el('nav', { class: 'lookup__nav' }, el('a', { class: 'link', href: '#/search' }, '‹ Lookup')),
|
||||||
el(
|
el(
|
||||||
@ -45,20 +88,21 @@ export async function AbilityDetail(id) {
|
|||||||
el(
|
el(
|
||||||
'section',
|
'section',
|
||||||
{ class: 'detail__section' },
|
{ class: 'detail__section' },
|
||||||
el('h2', {}, `Pokémon with this ability (${mons.length})`),
|
el(
|
||||||
mons.length
|
'h2',
|
||||||
|
{},
|
||||||
|
`Pokémon with this ability${vg === 'all' ? '' : ` in ${prettify(vg)}`} (${mons.length})`,
|
||||||
|
),
|
||||||
|
predatesGame
|
||||||
? el(
|
? el(
|
||||||
'div',
|
'p',
|
||||||
{ class: 'ab-mons' },
|
{ class: 'detail__muted' },
|
||||||
...mons.map((sp) =>
|
`Not in ${prettify(vg)} — this ability was introduced in Gen ${a.generation}.`,
|
||||||
el(
|
|
||||||
'a',
|
|
||||||
{ class: 'ab-mon', href: `#/pokemon/${sp.id}` },
|
|
||||||
Sprite(sp.id, { style, alt: sp.name, size: 48 }),
|
|
||||||
el('span', {}, sp.name.replace(/-/g, ' ')),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
: null,
|
||||||
|
mons.length > 24 ? filterInput : null,
|
||||||
|
mons.length
|
||||||
|
? grid
|
||||||
: el('p', { class: 'detail__muted' }, 'None on record.'),
|
: el('p', { class: 'detail__muted' }, 'None on record.'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -309,17 +309,27 @@ export async function TeamView() {
|
|||||||
'dl',
|
'dl',
|
||||||
{ class: 'pfacts' },
|
{ class: 'pfacts' },
|
||||||
fact('Average BST', String(avgBst)),
|
fact('Average BST', String(avgBst)),
|
||||||
fact('Fastest', `${prettify(fastest.name)} (${fastest.stats?.spe ?? '?'} Spe)`),
|
fact('Fastest', monLink(fastest, `${fastest.stats?.spe ?? '?'} Spe`)),
|
||||||
fact(
|
fact(
|
||||||
'Bulkiest',
|
'Bulkiest',
|
||||||
`${prettify(bulkiest.name)} (${
|
monLink(
|
||||||
(bulkiest.stats?.hp || 0) + (bulkiest.stats?.def || 0) + (bulkiest.stats?.spd || 0)
|
bulkiest,
|
||||||
} HP+Def+SpD)`,
|
`${(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) {
|
function compare(mem) {
|
||||||
const vg = snap.versionGroupByKey.get(settings.get().versionGroup);
|
const vg = snap.versionGroupByKey.get(settings.get().versionGroup);
|
||||||
const gen = vg ? vg.generation : 9;
|
const gen = vg ? vg.generation : 9;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user