From 3193b167ac56d4fdf5a1426e1ab0018f8efc25c2 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 8 Sep 2026 12:26:52 -0400 Subject: [PATCH] Search moves: hide "HMs only" for games without HMs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu --- src/views/SearchView.js | 93 ++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 30 deletions(-) diff --git a/src/views/SearchView.js b/src/views/SearchView.js index 962ea47..d9d86b7 100644 --- a/src/views/SearchView.js +++ b/src/views/SearchView.js @@ -111,38 +111,59 @@ export async function SearchView() { function buildFilters() { clear(filters); 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( - pill('mvType', [['', 'Any type'], ...TYPES.map((t) => [t, prettify(t)])], ui.get().mvType, (v) => { - ui.set({ mvType: v }); - run(); - }), - pill( - 'mvClass', - [['', 'Any category'], ['physical', 'Physical'], ['special', 'Special'], ['status', 'Status']], - ui.get().mvClass, - (v) => { - ui.set({ mvClass: v }); + ...[ + pill('mvType', [['', 'Any type'], ...TYPES.map((t) => [t, prettify(t)])], ui.get().mvType, (v) => { + ui.set({ mvType: v }); run(); - }, - ), - pill( - 'mvSort', - [ - ['name', 'A–Z'], - ['power', 'Power'], - ['accuracy', 'Accuracy'], - ['gen', 'Newest'], - // "By number" only makes sense with a TM/HM filter on. - ...(ui.get().mvTm || ui.get().mvHm ? [['tm', 'TM / HM number']] : []), - ], - ui.get().mvSort, - (v) => { - ui.set({ mvSort: v }); - run(); - }, - ), - machineToggle('mvTm', 'TMs only'), - machineToggle('mvHm', 'HMs only'), + }), + pill( + 'mvClass', + [['', 'Any category'], ['physical', 'Physical'], ['special', 'Special'], ['status', 'Status']], + ui.get().mvClass, + (v) => { + ui.set({ mvClass: v }); + run(); + }, + ), + pill( + 'mvSort', + [ + ['name', 'A–Z'], + ['power', 'Power'], + ['accuracy', 'Accuracy'], + ['gen', 'Newest'], + // "By number" only makes sense with a TM/HM filter on. + ...(ui.get().mvTm || ui.get().mvHm ? [['tm', 'TM / HM number']] : []), + ], + 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') { filters.append( @@ -379,7 +400,19 @@ export async function SearchView() { run(); 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, () => { + offSettings(); ui.set({ searchScroll: window.scrollY }); });