Add a National reset; replace native confirm()/alert() with the app dialog
- selection: clearAllGames() wipes seen/caught for every game but keeps the global favorites/notes record. - Progress view: a "Reset caught / seen…" action (custom dialog) that calls clearAllGames — the soft, favorites-preserving reset. Settings → "Clear tracking data" stays as the full wipe (now spells out that it also drops favorites and notes, and points here for the softer one). - Swept the remaining window.confirm / window.alert calls (Settings clear-tracking, clear-cache, backup import result; ShinyView delete-hunt) onto chooseDialog for a consistent look. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
This commit is contained in:
parent
edef6bf879
commit
3f887b2f8a
@ -126,7 +126,9 @@ Every game's seen/caught tally against its own dex, from its own per-game
|
||||
bucket. Leads with the games you've played (selected at least once, or
|
||||
imported a save for); the rest sit behind a toggle. The National Dex row is
|
||||
the union across all games. **Edit** the "Your games" list to reset a
|
||||
game's caught/seen or drop it from the list.
|
||||
game's caught/seen or drop it from the list; **Reset caught / seen…** wipes
|
||||
every game at once (favorites and notes are kept — only Settings →
|
||||
_Clear tracking data_ removes those).
|
||||
|
||||
### Shiny hunt tracker (`#/shiny`)
|
||||
|
||||
|
||||
@ -149,6 +149,15 @@ export function clearGame(vgKey) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipe seen/caught for every game (a "National Dex reset"). Favorites and
|
||||
* notes — the global `pokemon` record — are kept. Use `selection.replace`
|
||||
* for the full wipe that also drops those.
|
||||
*/
|
||||
export function clearAllGames() {
|
||||
selection.set((s) => ({ ...s, games: {} }));
|
||||
}
|
||||
|
||||
/** Aggregate seen/caught over a species list for one game (union when 'all'). */
|
||||
export function stats(speciesIds, vgKey = curGame()) {
|
||||
const get = vgKey === 'all' ? unionEntry : (id) => selection.get().games[vgKey]?.[id] || GBLANK;
|
||||
|
||||
@ -3382,6 +3382,13 @@
|
||||
color: var(--text-dim);
|
||||
text-align: right;
|
||||
}
|
||||
.prog__bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.prog__legend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -3389,6 +3396,19 @@
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.prog__resetall {
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--danger);
|
||||
cursor: pointer;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.prog__resetall:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.prog__key {
|
||||
display: inline-block;
|
||||
width: 1.1rem;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { el, clear, onTeardown } from '../lib/dom.js';
|
||||
import { loadSnapshot } from '../data/snapshot.js';
|
||||
import { settings } from '../store/settings.js';
|
||||
import { selection, stats, statsNational, clearGame } from '../store/selection.js';
|
||||
import { selection, stats, statsNational, clearGame, clearAllGames } from '../store/selection.js';
|
||||
import { ui } from '../store/ui.js';
|
||||
import { playedGames, isPlayed, unmarkPlayed } from '../store/playedGames.js';
|
||||
import { dexesForVersionGroup, versionGroupsByGeneration } from '../data/pokedex-resolver.js';
|
||||
@ -172,6 +172,23 @@ export async function ProgressView() {
|
||||
}
|
||||
render();
|
||||
|
||||
async function resetEverything() {
|
||||
const nat = statsNational(snap.species.map((s) => s.id));
|
||||
if (!nat.seen && !nat.caught) return;
|
||||
const pick = await chooseDialog({
|
||||
title: 'Reset caught / seen',
|
||||
body: `Clear all ${nat.caught} caught and ${nat.seen} seen, across every game? Favorites and notes are kept.`,
|
||||
choices: [
|
||||
{ key: 'reset', label: 'Reset everything', class: 'button--danger' },
|
||||
{ key: null, label: 'Cancel', class: 'button--ghost' },
|
||||
],
|
||||
});
|
||||
if (pick === 'reset') {
|
||||
clearAllGames();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
clear(view).append(
|
||||
el(
|
||||
'nav',
|
||||
@ -185,12 +202,21 @@ export async function ProgressView() {
|
||||
el('p', {}, 'What you’ve caught in each game. Tap one to switch to it.'),
|
||||
),
|
||||
el(
|
||||
'p',
|
||||
{ class: 'prog__legend' },
|
||||
el('span', { class: 'prog__key prog__key--caught' }),
|
||||
' caught ',
|
||||
el('span', { class: 'prog__key prog__key--seen' }),
|
||||
' seen',
|
||||
'div',
|
||||
{ class: 'prog__bar' },
|
||||
el(
|
||||
'p',
|
||||
{ class: 'prog__legend' },
|
||||
el('span', { class: 'prog__key prog__key--caught' }),
|
||||
' caught ',
|
||||
el('span', { class: 'prog__key prog__key--seen' }),
|
||||
' seen',
|
||||
),
|
||||
el(
|
||||
'button',
|
||||
{ type: 'button', class: 'prog__resetall', onclick: resetEverything },
|
||||
'Reset caught / seen…',
|
||||
),
|
||||
),
|
||||
list,
|
||||
);
|
||||
|
||||
@ -223,9 +223,17 @@ export async function SettingsView() {
|
||||
if (data.formTracking) formTracking.replace(data.formTracking);
|
||||
if (data.shinyHunts) shinyHunts.replace(data.shinyHunts);
|
||||
if (data.playedGames) playedGames.replace(data.playedGames);
|
||||
alert('Import complete.');
|
||||
await chooseDialog({
|
||||
title: 'Import complete',
|
||||
body: 'Your backup was restored.',
|
||||
choices: [{ key: null, label: 'OK' }],
|
||||
});
|
||||
} catch {
|
||||
alert('That file could not be read as a Pokédex backup.');
|
||||
await chooseDialog({
|
||||
title: 'Couldn’t read that file',
|
||||
body: 'It doesn’t look like a Pocketdex backup.',
|
||||
choices: [{ key: null, label: 'OK' }],
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -322,10 +330,16 @@ export async function SettingsView() {
|
||||
{
|
||||
class: 'button button--danger',
|
||||
type: 'button',
|
||||
onclick: () => {
|
||||
if (confirm('Clear all seen/caught/favorite tracking? This cannot be undone.')) {
|
||||
selection.replace({ version: 3, pokemon: {}, games: {} });
|
||||
}
|
||||
onclick: async () => {
|
||||
const pick = await chooseDialog({
|
||||
title: 'Clear all tracking data',
|
||||
body: 'Removes seen/caught for every game plus all favorites and notes, and can’t be undone. To keep favorites and notes, use “Reset caught / seen” on the Progress screen instead.',
|
||||
choices: [
|
||||
{ key: 'clear', label: 'Clear everything', class: 'button--danger' },
|
||||
{ key: null, label: 'Cancel', class: 'button--ghost' },
|
||||
],
|
||||
});
|
||||
if (pick === 'clear') selection.replace({ version: 3, pokemon: {}, games: {} });
|
||||
},
|
||||
},
|
||||
'Clear tracking data',
|
||||
@ -337,12 +351,21 @@ export async function SettingsView() {
|
||||
type: 'button',
|
||||
onclick: async () => {
|
||||
if (!('caches' in window)) return;
|
||||
if (
|
||||
confirm('Clear cached PokéAPI data and sprites? They will re-download when online.')
|
||||
) {
|
||||
for (const key of await caches.keys()) await caches.delete(key);
|
||||
alert('Caches cleared.');
|
||||
}
|
||||
const pick = await chooseDialog({
|
||||
title: 'Clear cached data',
|
||||
body: 'Drops cached PokéAPI responses and sprites. They re-download next time you’re online.',
|
||||
choices: [
|
||||
{ key: 'clear', label: 'Clear cache', class: 'button--danger' },
|
||||
{ key: null, label: 'Cancel', class: 'button--ghost' },
|
||||
],
|
||||
});
|
||||
if (pick !== 'clear') return;
|
||||
for (const key of await caches.keys()) await caches.delete(key);
|
||||
await chooseDialog({
|
||||
title: 'Cache cleared',
|
||||
body: '',
|
||||
choices: [{ key: null, label: 'OK' }],
|
||||
});
|
||||
},
|
||||
},
|
||||
'Clear cached API data',
|
||||
|
||||
@ -6,6 +6,7 @@ import { toggle, entry } from '../store/selection.js';
|
||||
import { buzz } from '../lib/haptics.js';
|
||||
import { Sprite } from '../components/Sprite.js';
|
||||
import { openPokemonPicker } from '../components/PokemonPicker.js';
|
||||
import { chooseDialog } from '../lib/dialog.js';
|
||||
|
||||
// Representative full-game odds (as 1/N), with a shiny-charm variant.
|
||||
export const METHODS = [
|
||||
@ -131,8 +132,16 @@ export async function ShinyView() {
|
||||
{
|
||||
type: 'button',
|
||||
class: 'button button--danger',
|
||||
onclick: () => {
|
||||
if (confirm('Delete this hunt?')) {
|
||||
onclick: async () => {
|
||||
const pick = await chooseDialog({
|
||||
title: 'Delete this hunt?',
|
||||
body: `${(sp?.name || 'This hunt').replace(/-/g, ' ')} — ${h.count} checks logged.`,
|
||||
choices: [
|
||||
{ key: 'del', label: 'Delete', class: 'button--danger' },
|
||||
{ key: null, label: 'Cancel', class: 'button--ghost' },
|
||||
],
|
||||
});
|
||||
if (pick === 'del') {
|
||||
removeHunt(h.id);
|
||||
render();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user