New view (linked from Settings > Your data): the unified caught record counted against every game's dex at once — National total on top, then each version group grouped by generation with a seen/caught bar and X / Y count. Tapping a game switches the active version group and jumps to the dex. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
147 lines
8.2 KiB
Markdown
147 lines
8.2 KiB
Markdown
# Pokédex PWA
|
|
|
|
A responsive, offline-capable Pokédex reference built on
|
|
[PokéAPI](https://pokeapi.co/). Vanilla JS + Vite + Workbox — no UI
|
|
framework.
|
|
|
|
## Two headline features
|
|
|
|
| Feature | How it works |
|
|
| --- | --- |
|
|
| **Game series selection** | Pick a *game* (PokéAPI version group, e.g. Scarlet & Violet). If it has more than one regional dex (Paldea / Kitakami / Blueberry) a sub-dex switcher appears. The choice drives which species show, their regional numbering, and which version's flavor text the detail page uses. Stored in `localStorage`. |
|
|
| **Unified Pokémon selection** | One tracking record per Pokémon, keyed by **National Dex id**. Mark Pikachu once and every game's view reflects it — each dex computes its own "Seen / Caught" totals by intersecting its species list with that single map. `#/progress` breaks that down for every game at once. The active Pokémon is also a single deep-linkable route (`#/pokemon/25`). |
|
|
|
|
## Data & storage split
|
|
|
|
- **Preferences + tracking state** → `localStorage` (`pdx.settings`, `pdx.selection`). Tiny, synchronous, restored on reload.
|
|
- **Build-time snapshot** (`src/data/snapshot.json`, ~150 KB) → generated by `npm run snapshot` from PokéAPI: every species (id, name, generation, types), all regional Pokédex lists, and all version groups. Precached by the service worker, so the list / search / game switching work on the first offline launch.
|
|
- **Detail data** (stats, abilities, flavor text, evolution) → fetched lazily from `pokeapi.co` per Pokémon, then cached by the service worker (stale-while-revalidate, 30-day TTL).
|
|
- **Sprites** → cache-first with a capped LRU.
|
|
|
|
Export / import of `settings` + `selection` as JSON lives in **Settings**.
|
|
|
|
## Scripts
|
|
|
|
```bash
|
|
npm install
|
|
npm run snapshot # fetch data from PokéAPI -> src/data/snapshot.json (run once; refreshes if >30 days old)
|
|
npm run dev # vite dev server
|
|
npm run build # runs snapshot (prebuild) then vite build
|
|
npm run preview # serve the production build (needed to exercise the service worker)
|
|
```
|
|
|
|
Deploying under a sub-path (e.g. GitHub Pages project site): `BASE_PATH=/repo-name/ npm run build`.
|
|
|
|
## Docker
|
|
|
|
Multi-stage build (Node → nginx) that serves the static `dist/`:
|
|
|
|
```bash
|
|
docker compose up --build # → http://localhost:8080
|
|
# or without compose:
|
|
docker build -t pokedex-pwa .
|
|
docker run --rm -p 8080:80 pokedex-pwa
|
|
```
|
|
|
|
The build stage runs `npm run build`, whose `prebuild` step fetches the
|
|
PokéAPI snapshot — so `docker build` needs network access to `pokeapi.co`
|
|
unless a fresh `src/data/snapshot.json` is already present (it gets copied in
|
|
and reused). Serving under a sub-path: `docker build --build-arg BASE_PATH=/dex/ .`.
|
|
`nginx.conf` sets the SPA fallback and long-cache headers for `/assets/*`
|
|
while keeping `index.html` / `sw.js` uncached.
|
|
|
|
## Project layout
|
|
|
|
```
|
|
scripts/build-snapshot.mjs PokéAPI -> snapshot.json
|
|
src/
|
|
main.js boot: theme, nav, router, SW registration
|
|
router.js hash router (#/, #/pokemon/:id, #/games, #/search, #/settings)
|
|
sw.js Workbox service worker (injectManifest)
|
|
store/ createStore + settings + selection (localStorage)
|
|
data/ snapshot loader, pokedex resolver, lazy API client
|
|
components/ Card, Sprite, TypeChip, StatBar, ProgressHeader, Nav
|
|
views/ DexGrid, PokemonDetail, GamePicker, SearchView, SettingsView
|
|
styles/ tokens.css (palette, type colors, light/dark), layout.css
|
|
```
|
|
|
|
## Status
|
|
|
|
Working app with a type-themed UI:
|
|
|
|
- **Dex grid** — type-tinted cards (official artwork, spotlight, ghost number),
|
|
per-dex progress, name/number filter, caught/favorite filters, plus a
|
|
filter drawer: type, generation, ability, egg group, minimum BST, and
|
|
"fully evolved only" (derived client-side from each species' evolves-from
|
|
link — no extra fetches). A "Notes" chip filters to Pokémon with a note;
|
|
cards with one get a small 📝 mark.
|
|
- **Notes** — a free-text note per Pokémon on its detail page (trade plans,
|
|
where you caught it, anything), autosaving as you type and flushing
|
|
immediately on blur or navigation so a quick tab-away never drops a
|
|
keystroke. Rides along in the existing JSON export/import.
|
|
- **Forms** — Megas, Gigantamax, regional forms and alternate formes in the
|
|
snapshot; a pill switcher on the detail page rebuilds types / stats /
|
|
matchups / abilities / learnset / artwork for the chosen form. Purely
|
|
cosmetic variants (Unown's 27 letters, Vivillon's 19 patterns, Furfrou
|
|
trims, seasonal Deerling/Sawsbuck, Flabébé line colours, Alcremie's 62
|
|
decorations, Pikachu caps — 278 across 50 species) get a separate compact
|
|
"Appearance" dropdown that only swaps the sprite. Cards show a "+N forms"
|
|
badge.
|
|
- **Detail** — type-gradient hero + tabbed sheet (About / Stats / Evolution /
|
|
Moves / Locations); coloured animated stat bars; defensive type matchups;
|
|
evolution chain re-parented to the selected game's generation; learnset with
|
|
per-move power/type/accuracy/PP/effect (era-accurate via `past_values`,
|
|
incl. pre-Gen-4 physical/special-by-type), the TM/HM group ordered by
|
|
TM number for the selected game; wild encounter locations.
|
|
- **Game-aware** — abilities gated to Gen 3+ (hidden to Gen 5+); type chart
|
|
applies Gen 1 / pre-Gen 6 rules.
|
|
- **Games** — overlay picker with stylised version-colour cover tiles,
|
|
sub-dex switch, and an "All games" (National, no gen limits) option.
|
|
- **Search** — tabbed lookup: Pokémon, Moves, Items and Abilities, all
|
|
browsable offline from the snapshot. Moves filter by type / damage class
|
|
/ "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, 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
|
|
type; plus offensive STAB gaps and at-a-glance stats. A Compare table
|
|
stacks the six side by side (the same table is also a standalone
|
|
`#/compare` view with its own picker — up to 4 Pokémon, persisted).
|
|
A third Calc mode is a damage calculator —
|
|
pick (or quick-pick from your team) an attacker + move + defender, and
|
|
get a damage range, % of HP, hits-to-KO, STAB/effectiveness badges, with
|
|
level/nature/EV controls; it's a base-stats estimate (31 IVs assumed,
|
|
no items/abilities/weather/terrain). All three follow the selected
|
|
game — its generation's type chart, era-accurate typings (pre-Gen-6
|
|
Clefairy is Normal, etc.), and era move data. Toggleable in the nav
|
|
from Settings. Links out to a Natures table and an interactive Type
|
|
chart (tap a type for its offensive + defensive breakdown; both
|
|
gen-aware).
|
|
- **Settings** — theme (System / Light / Dark / Black / Sepia) + accent
|
|
colour, text size, an in-app reduce-motion override (on top of the OS
|
|
preference, which is always respected too), sprite style, haptic
|
|
feedback on catch (Vibration API), which screen to land on at launch,
|
|
JSON export/import.
|
|
- **PWA** — Workbox SW: precache shell + snapshot, SWR for API JSON,
|
|
cache-first LRU for sprites, in-app update toast. Installable: PNG +
|
|
maskable icons, `beforeinstallprompt` captured for an in-app "Install"
|
|
offer (toast + Settings button), manifest shortcuts to Team / Search /
|
|
Type chart.
|
|
|
|
Not yet done: version-exclusive badges, an interactive region map (PokéAPI
|
|
has no map imagery or coordinates), and a formal Lighthouse pass.
|
|
|
|
## Notes
|
|
|
|
- `npm audit` reports the known esbuild dev-server advisory via Vite 5. It
|
|
affects the local dev server only, not the production build. Vite 8 (which
|
|
fixes it) requires a newer Node than this environment has.
|
|
- Data and images © Nintendo / Game Freak / The Pokémon Company, served via
|
|
PokéAPI. This project is a non-commercial reference tool.
|