feat(#22): Add sprites
@@ -37,4 +37,4 @@ User authentication is handled by [Supabase Auth](https://supabase.com/auth).
|
||||
|
||||
## Dependencies
|
||||
|
||||
The living dex tracker's sprite collection is taken from [pokesprite](https://github.com/msikma/pokesprite), which is licensed under [the MIT license](https://github.com/msikma/pokesprite/blob/master/LICENSE).
|
||||
The living dex tracker's sprite collection is taken from [PokéAPI Sprites](https://github.com/PokeAPI/sprites), which is licensed under [the Creative Commons CC0 1.0 Universal license](https://github.com/PokeAPI/sprites/blob/master/LICENCE.txt).
|
||||
|
||||
@@ -1,35 +1,97 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import pokeApiPokemon from '$lib/helpers/pokeapi-pokemon.json';
|
||||
|
||||
export let pokemonName: string;
|
||||
export let pokedexNumber: string | number;
|
||||
export let form: string | undefined;
|
||||
export let shiny: boolean | undefined = false;
|
||||
|
||||
let imagePath = null as string | null;
|
||||
let blah = '';
|
||||
|
||||
async function fetchImagePath() {
|
||||
try {
|
||||
let url = `/api/sprite?pokedexNumber=${pokedexNumber}`;
|
||||
if (form) {
|
||||
url += `&form=${form}`;
|
||||
}
|
||||
function setImagePath() {
|
||||
let rootFolder =
|
||||
'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/home';
|
||||
// let rootFolder = 'sprites/home';
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch image path');
|
||||
}
|
||||
const data = await response.json();
|
||||
|
||||
imagePath = `./sprites/regular/${data.spriteFileName}`;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
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, '');
|
||||
|
||||
// Get the PokeApi id for the pokemon
|
||||
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('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;
|
||||
}
|
||||
|
||||
if (strippedPokedexNumber == '869') {
|
||||
console.log(sanitisedPokemonName, sanitisedForm);
|
||||
}
|
||||
|
||||
// If the form is contained in the identifier, use that
|
||||
if (
|
||||
pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.identifier === sanitisedPokemonName + '-' + sanitisedForm
|
||||
)
|
||||
) {
|
||||
pokeApiId = pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.identifier === sanitisedPokemonName + '-' + sanitisedForm
|
||||
)?.id;
|
||||
} else {
|
||||
// If the form is not contained in the identifier, use the species_id
|
||||
pokeApiId = pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.species_id.toString() === strippedPokedexNumber
|
||||
)?.id;
|
||||
}
|
||||
} else {
|
||||
pokeApiId = pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.species_id.toString() === strippedPokedexNumber
|
||||
)?.id;
|
||||
}
|
||||
|
||||
imagePath = `${rootFolder}/${pokeApiId}.png`;
|
||||
blah = `${pokeApiId}.png`;
|
||||
// blah = `${strippedPokedexNumber}${form?.length && form !== 'Female' ? '-' + form : ''}.png`;
|
||||
}
|
||||
|
||||
onMount(fetchImagePath);
|
||||
onMount(setImagePath);
|
||||
</script>
|
||||
|
||||
{#if imagePath}
|
||||
<!-- {blah} -->
|
||||
<img src={imagePath} alt="sprite" />
|
||||
{:else}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import sprites from '$lib/helpers/sprites.json';
|
||||
|
||||
interface PokemonSpritesData {
|
||||
[key: string]: {
|
||||
forms: {
|
||||
[key: string]: {
|
||||
is_prev_gen_icon?: boolean;
|
||||
is_alias_of?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export async function GET({ url }) {
|
||||
const pokedexNumber = url.searchParams.get('pokedexNumber');
|
||||
const form = url.searchParams.get('form') ?? undefined;
|
||||
|
||||
if (!pokedexNumber) {
|
||||
return json({
|
||||
status: 400,
|
||||
error: 'Pokédex number is required'
|
||||
});
|
||||
}
|
||||
|
||||
const spriteFileName = getPokemonSpriteFileName(pokedexNumber, form);
|
||||
|
||||
if (spriteFileName) {
|
||||
// If spriteUrl is found, return it with status 200
|
||||
return json({
|
||||
status: 200,
|
||||
spriteFileName: spriteFileName
|
||||
});
|
||||
} else {
|
||||
// If spriteUrl is not found, return 404
|
||||
return json({
|
||||
status: 404,
|
||||
error: `Sprite URL not found for the specified Pokémon with Pokédex number ${pokedexNumber} and form ${form}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getPokemonSpriteFileName(number: string, form?: string): string | undefined {
|
||||
const spritesData: PokemonSpritesData = sprites;
|
||||
|
||||
// Check if the Pokémon number exists in the sprites JSON
|
||||
if (spritesData[number] && spritesData[number]['gen-8']) {
|
||||
const forms = spritesData[number]['gen-8'].forms;
|
||||
let formName = '$';
|
||||
|
||||
// If a form is provided and it exists for the Pokémon, set the form name
|
||||
if (form && forms[form]) {
|
||||
formName = form;
|
||||
}
|
||||
|
||||
// Check if the form has an alias
|
||||
if (forms[formName].is_alias_of) {
|
||||
formName = forms[formName].is_alias_of;
|
||||
}
|
||||
|
||||
const fileName = `${spritesData[number].slug.eng.toLowerCase()}${formName !== '$' ? '-' + formName : ''}.png`;
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// If the Pokémon number doesn't exist or doesn't have gen-8 sprites, return undefined
|
||||
return undefined;
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
import Pagination from '$lib/components/Pagination.svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import type { PokedexEntry } from '$lib/models/PokedexEntry';
|
||||
import PokemonSprite from '$lib/components/PokemonSprite.svelte';
|
||||
|
||||
let combinedData = null as CombinedData[] | null;
|
||||
let failedToLoad = false;
|
||||
@@ -55,6 +56,8 @@
|
||||
<title>Living Dex Tracker - My Boxes</title>
|
||||
</svelte:head>
|
||||
|
||||
<!-- <PokemonSprite pokemonName={'Raichu'} pokedexNumber={26} form={'Alolan'} /> -->
|
||||
|
||||
<div class="container mx-auto">
|
||||
{#if !localUser}
|
||||
<p>Please <a href="/signin" class="underline text-primary hover:text-secondary">sign in</a></p>
|
||||
@@ -65,7 +68,7 @@
|
||||
|
||||
<div class="flex flex-wrap -mx-2">
|
||||
{#each boxNumbers as boxNumber}
|
||||
<div class="mb-8 w-1/2 px-2">
|
||||
<div class="mb-8 md:w-1/2 px-2">
|
||||
<h2 class="text-xl font-bold mb-4">Box {boxNumber}</h2>
|
||||
<div class="grid grid-cols-6">
|
||||
{#each combinedData as { pokedexEntry, catchRecord }}
|
||||
@@ -75,11 +78,17 @@
|
||||
style="grid-column-start: {pokedexEntry[currentPlacement]
|
||||
.column}; grid-row-start: {pokedexEntry[currentPlacement].row}"
|
||||
>
|
||||
<PokemonSprite
|
||||
pokemonName={pokedexEntry.pokemon}
|
||||
pokedexNumber={pokedexEntry.pokedexNumber}
|
||||
form={pokedexEntry.form}
|
||||
/>
|
||||
<!-- {pokedexEntry.form ? `(${pokedexEntry.form})` : ''} -->
|
||||
<!-- <div class="font-bold">
|
||||
{pokedexEntry.pokemon}
|
||||
{pokedexEntry.form ? `(${pokedexEntry.form})` : ''}
|
||||
</div> -->
|
||||
<div>{pokedexEntry.pokedexNumber.toString().padStart(3, '0')}</div>
|
||||
<!-- <div>{pokedexEntry.pokedexNumber.toString().padStart(3, '0')}</div> -->
|
||||
<!-- <div>
|
||||
Caught: {catchRecord.caught ? 'Yes' : 'No'} <br />
|
||||
Needs to Evolve: {catchRecord.haveToEvolve ? 'Yes' : 'No'} <br />
|
||||
|
||||
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 176 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 89 KiB |