data(*): Fix remaining sprites

This commit is contained in:
Josh Creek
2026-01-18 13:14:18 +00:00
parent 71df0de3df
commit eba34158fe
18 changed files with 2843 additions and 2854 deletions
+4
View File
@@ -19,6 +19,10 @@ A web app to track completion of a living Pokédex.
N.B. All local emails are captured by MailPit when running Supabase in Docker.
8. You can now use [the app](http://localhost:5173/).
## Reference Data Updates
The seed data lives in `supabase/migrations/20260118001000_seed_reference_data.sql`. Update that migration directly when new data is added.
## Building
To create a production version:
+1391 -1391
View File
File diff suppressed because it is too large Load Diff
+46 -70
View File
@@ -1,99 +1,75 @@
<script lang="ts">
import { onMount } from 'svelte';
import pokeApiPokemon from '$lib/helpers/pokeapi-pokemon.json';
import { PUBLIC_USE_LOCAL_POKEMON_SPRITE_FOLDER } from '$env/static/public';
export let pokemonName: string;
export let pokedexNumber: string | number;
export let form: string | undefined;
export let spriteKey: string | undefined;
export let shiny: boolean | undefined = false;
let imagePath = null as string | null;
let blah = '';
function setImagePath() {
function isFemaleForm(value?: string) {
return /^female\b/i.test((value ?? '').trim());
}
function buildFallbackKey() {
const strippedPokedexNumber = pokedexNumber.toString().replace(/^0+/, '') || '0';
if (!form) return strippedPokedexNumber;
let formValue = form.trim();
formValue = formValue.replace(/^female[-\s]*/i, '');
formValue = formValue.replace(/\s*\(.*?\)/g, '').replace(/\s*\[.*?\]/g, '').trim();
if (!formValue || formValue.toLowerCase() === 'male') return strippedPokedexNumber;
formValue = formValue
.toLowerCase()
.replace(/%/g, '')
.replace(/\balolan\b/g, 'alola')
.replace(/\bgalarian\b/g, 'galar')
.replace(/\bhisuian\b/g, 'hisui')
.replace(/\bpaldean\b/g, 'paldea')
.replace(/\bform(e)?$/, '')
.replace(/\bability$/, '')
.replace(/[^a-z0-9]+/g, '-')
.replace(/(^-|-$)/g, '')
.replace(/2/g, 'two')
.replace(/3/g, 'three')
.replace(/4/g, 'four');
return formValue ? `${strippedPokedexNumber}-${formValue}` : strippedPokedexNumber;
}
function computeImagePath() {
let rootFolder =
PUBLIC_USE_LOCAL_POKEMON_SPRITE_FOLDER === 'true'
? '/sprites/home'
: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/home';
if (form === 'Female') {
rootFolder += '/female';
}
if (shiny) {
rootFolder += '/shiny';
}
// Remove leading zeros
const strippedPokedexNumber = pokedexNumber.toString().replace(/^0+/, '');
// Sanitise the pokemon name by making it all lowercase and replacing any spaces with hyphens and removing other characters
let sanitisedPokemonName = pokemonName.toLowerCase().replace(/[^a-z]/g, '');
/**
* Sprite Resolution Strategy:
* 1. For forms with PokeAPI entries (regional forms): Use PokeAPI ID (e.g., 10107.png)
* 2. For forms without PokeAPI entries (Unown, Burmy, etc.): Use {pokedexNumber}-{form} (e.g., 201-a.png)
* 3. For base forms: Use PokeAPI ID matching species_id
*/
let pokeApiId;
if (form && form.length > 0 && form !== 'Female') {
// Sanitise the form by making it all lowercase and replacing spaces with hyphens
let sanitisedForm = form
.toLowerCase()
.replaceAll(' ', '-')
.replaceAll('!', 'exclamation')
.replaceAll('?', 'question')
.replaceAll('2', 'two')
.replaceAll('3', 'three')
.replaceAll('4', 'four');
switch (sanitisedForm) {
case 'alolan':
sanitisedForm = 'alola';
break;
case 'galarian':
sanitisedForm = 'galar';
break;
case 'hisuian':
sanitisedForm = 'hisui';
break;
// case 'rainbow-ribbon':
// sanitisedForm = 'rainbow-swirl-ribbon-sweet';
// break;
default:
break;
}
// Try to find by PokeAPI identifier (e.g., "meowth-alola" -> 10107)
const pokeApiEntry = pokeApiPokemon.find(
(pokemon) => pokemon.identifier === sanitisedPokemonName + '-' + sanitisedForm
);
if (pokeApiEntry) {
// Pattern 1: Use PokeAPI ID (e.g., 10107.png for Meowth-Alola)
pokeApiId = pokeApiEntry.id;
} else {
// Pattern 2: Use {pokedexNumber}-{form} (e.g., 201-a.png for Unown-A)
pokeApiId = `${strippedPokedexNumber}-${sanitisedForm}`;
}
} else {
pokeApiId = pokeApiPokemon.find(
(pokemon) => pokemon.species_id.toString() === strippedPokedexNumber
)?.id;
if (isFemaleForm(form)) {
rootFolder += '/female';
}
imagePath = `${rootFolder}/${pokeApiId}.png`;
blah = `${pokeApiId}.png`;
// blah = `${strippedPokedexNumber}${form?.length && form !== 'Female' ? '-' + form : ''}.png`;
const resolvedSpriteKey = spriteKey?.trim() || buildFallbackKey();
if (!spriteKey?.trim()) {
console.warn('Missing sprite key for pokemon entry', {
pokemonName,
pokedexNumber,
form
});
}
return `${rootFolder}/${resolvedSpriteKey}.png`;
}
onMount(setImagePath);
$: imagePath = computeImagePath();
</script>
{#if imagePath}
<!-- {blah} -->
<img src={imagePath} alt="sprite" />
{:else}
<span class="loading loading-spinner loading-xs"></span>
@@ -68,6 +68,7 @@
pokemonName={pokedexEntry.pokemon}
pokedexNumber={pokedexEntry.pokedexNumber}
form={pokedexEntry.form}
spriteKey={pokedexEntry.spriteKey}
shiny={showShiny}
/>
</div>
@@ -530,6 +530,7 @@
pokemonName={pokedexEntry.pokemon}
pokedexNumber={pokedexEntry.pokedexNumber}
form={pokedexEntry.form}
spriteKey={pokedexEntry.spriteKey}
shiny={showShiny}
/>
</div>
+2
View File
@@ -10,6 +10,7 @@ export interface PokedexEntry {
pokedexNumber: number;
pokemon: string;
form: string;
spriteKey: string;
canGigantamax: boolean;
regionToCatchIn: string;
gamesToCatchIn: string[];
@@ -25,6 +26,7 @@ export interface PokedexEntryDB {
pokedexNumber: number;
pokemon: string;
form: string | null;
spriteKey: string | null;
canGigantamax: boolean;
regionToCatchIn: string | null;
gamesToCatchIn: string[] | null;
@@ -19,6 +19,7 @@ class CombinedDataRepository {
pokedexNumber: entry.pokedexNumber,
pokemon: entry.pokemon,
form: entry.form || '',
spriteKey: entry.spriteKey || '',
canGigantamax: entry.canGigantamax,
regionToCatchIn: entry.regionToCatchIn || '',
gamesToCatchIn: entry.gamesToCatchIn || [],
@@ -47,6 +47,7 @@ class PokedexEntryRepository {
pokedexNumber: entry.pokedexNumber,
pokemon: entry.pokemon,
form: entry.form || '',
spriteKey: entry.spriteKey || '',
canGigantamax: entry.canGigantamax,
regionToCatchIn: entry.regionToCatchIn || '',
gamesToCatchIn: entry.gamesToCatchIn || [],
@@ -83,6 +84,7 @@ class PokedexEntryRepository {
if (data.pokedexNumber !== undefined) dbData.pokedexNumber = data.pokedexNumber;
if (data.pokemon !== undefined) dbData.pokemon = data.pokemon;
if (data.form !== undefined) dbData.form = data.form;
if (data.spriteKey !== undefined) dbData.spriteKey = data.spriteKey;
if (data.canGigantamax !== undefined) dbData.canGigantamax = data.canGigantamax;
if (data.regionToCatchIn !== undefined) dbData.regionToCatchIn = data.regionToCatchIn;
if (data.gamesToCatchIn !== undefined) dbData.gamesToCatchIn = data.gamesToCatchIn;
@@ -110,6 +112,7 @@ class PokedexEntryRepository {
if (data.pokedexNumber !== undefined) dbData.pokedexNumber = data.pokedexNumber;
if (data.pokemon !== undefined) dbData.pokemon = data.pokemon;
if (data.form !== undefined) dbData.form = data.form;
if (data.spriteKey !== undefined) dbData.spriteKey = data.spriteKey;
if (data.canGigantamax !== undefined) dbData.canGigantamax = data.canGigantamax;
if (data.regionToCatchIn !== undefined) dbData.regionToCatchIn = data.regionToCatchIn;
if (data.gamesToCatchIn !== undefined) dbData.gamesToCatchIn = data.gamesToCatchIn;

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

@@ -57,6 +57,7 @@ CREATE TABLE pokemon (
"pokedexNumber" INTEGER NOT NULL,
pokemon TEXT NOT NULL,
form TEXT,
"spriteKey" TEXT,
"originRegionId" BIGINT NOT NULL REFERENCES regions(id) ON DELETE RESTRICT,
"canGigantamax" BOOLEAN DEFAULT FALSE,
"regionToEvolveIn" TEXT,
@@ -334,6 +335,7 @@ SELECT
p."pokedexNumber",
p.pokemon,
p.form,
p."spriteKey",
p."canGigantamax",
r.name AS "regionToCatchIn",
r."releaseOrder" AS "regionReleaseOrder",
File diff suppressed because it is too large Load Diff