Search moves: hide "HMs only" for games without HMs

Gen 8+ games (Sword/Shield, Scarlet/Violet, Legends Arceus) dropped HMs
entirely, so "HMs only" there just zeroed the list with no way to see
why. buildFilters now checks whether the selected game actually has any
TM / HM machines and only renders the checkbox that applies; a filter
left stuck on from a previous game is cleared (and the "by number" sort
reverts) when it no longer has a control. SearchView also re-runs its
filters + results when the version group changes, so switching games
from the Games sheet updates it live.

"TMs only" + "HMs only" together already show the union (verified: 58 in
FRLG = 50 TMs + 8 HMs, ordered TM01…HM08).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
This commit is contained in:
chris 2026-09-08 12:26:52 -04:00
parent fa302af7f1
commit 3193b167ac

View File

@ -111,38 +111,59 @@ export async function SearchView() {
function buildFilters() { function buildFilters() {
clear(filters); clear(filters);
if (tab === 'moves') { if (tab === 'moves') {
const vg = settings.get().versionGroup;
const gameHasKind = (kind) =>
snap.moves.some((m) =>
m.machines.some(
(x) => (vg === 'all' || x.vg === vg) && (x.tm || '').startsWith(kind),
),
);
const hasTm = gameHasKind('TM');
const hasHm = gameHasKind('HM'); // false for Gen 8+ games, which dropped HMs
// A machine filter left on for a game that has no such machines would
// silently zero the list with no visible checkbox to switch it off.
if ((!hasTm && ui.get().mvTm) || (!hasHm && ui.get().mvHm)) {
ui.set({ mvTm: hasTm && ui.get().mvTm, mvHm: hasHm && ui.get().mvHm });
if (!ui.get().mvTm && !ui.get().mvHm && ui.get().mvSort === 'tm') {
ui.set({ mvSort: 'name' });
}
}
filters.append( filters.append(
pill('mvType', [['', 'Any type'], ...TYPES.map((t) => [t, prettify(t)])], ui.get().mvType, (v) => { ...[
ui.set({ mvType: v }); pill('mvType', [['', 'Any type'], ...TYPES.map((t) => [t, prettify(t)])], ui.get().mvType, (v) => {
run(); ui.set({ mvType: v });
}),
pill(
'mvClass',
[['', 'Any category'], ['physical', 'Physical'], ['special', 'Special'], ['status', 'Status']],
ui.get().mvClass,
(v) => {
ui.set({ mvClass: v });
run(); run();
}, }),
), pill(
pill( 'mvClass',
'mvSort', [['', 'Any category'], ['physical', 'Physical'], ['special', 'Special'], ['status', 'Status']],
[ ui.get().mvClass,
['name', 'AZ'], (v) => {
['power', 'Power'], ui.set({ mvClass: v });
['accuracy', 'Accuracy'], run();
['gen', 'Newest'], },
// "By number" only makes sense with a TM/HM filter on. ),
...(ui.get().mvTm || ui.get().mvHm ? [['tm', 'TM / HM number']] : []), pill(
], 'mvSort',
ui.get().mvSort, [
(v) => { ['name', 'AZ'],
ui.set({ mvSort: v }); ['power', 'Power'],
run(); ['accuracy', 'Accuracy'],
}, ['gen', 'Newest'],
), // "By number" only makes sense with a TM/HM filter on.
machineToggle('mvTm', 'TMs only'), ...(ui.get().mvTm || ui.get().mvHm ? [['tm', 'TM / HM number']] : []),
machineToggle('mvHm', 'HMs only'), ],
ui.get().mvSort,
(v) => {
ui.set({ mvSort: v });
run();
},
),
hasTm ? machineToggle('mvTm', 'TMs only') : null,
hasHm ? machineToggle('mvHm', 'HMs only') : null,
].filter(Boolean),
); );
} else if (tab === 'items') { } else if (tab === 'items') {
filters.append( filters.append(
@ -379,7 +400,19 @@ export async function SearchView() {
run(); run();
requestAnimationFrame(() => window.scrollTo(0, ui.get().searchScroll || 0)); requestAnimationFrame(() => window.scrollTo(0, ui.get().searchScroll || 0));
// Switching games (from the Games sheet) changes which TM/HM filters
// apply and the numbers shown — refresh the filter row and results.
let lastVg = settings.get().versionGroup;
const offSettings = settings.subscribe((s) => {
if (s.versionGroup === lastVg) return;
lastVg = s.versionGroup;
syncUI();
run();
});
onTeardown(view, () => { onTeardown(view, () => {
offSettings();
ui.set({ searchScroll: window.scrollY }); ui.set({ searchScroll: window.scrollY });
}); });