From 01563dc341fd42d7e751671b87c5ee5c655cf0bc Mon Sep 17 00:00:00 2001 From: William M Schmidt Date: Fri, 18 Sep 2026 23:18:09 +0200 Subject: [PATCH 1/3] Built the loading card with skeleton animation --- src/App.css | 85 ++++++++++++++++++++++++++++++++++++++++++ src/PokemonDetails.tsx | 56 +++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 1 deletion(-) diff --git a/src/App.css b/src/App.css index 168968a..7577f82 100644 --- a/src/App.css +++ b/src/App.css @@ -392,6 +392,86 @@ box-shadow: var(--shadow); } +/* + Pokemon card loading +*/ + +.pokemon-card-loading { + min-height: 386px; +} + +.skeleton { + background: linear-gradient( + 100deg, + var(--border) 25%, + var(--bg) 50%, + var(--border) 75% + ); + background-size: 200% 100%; + animation: skeleton-loading 1.5s ease-in-out infinite; +} + +.skeleton-image { + width: 100px; + height: 100px; + flex: 0 0 auto; + border-radius: 50%; +} + +.skeleton-header-text { + display: grid; + gap: 10px; + width: min(220px, 100%); +} + +.skeleton-title { + width: 75%; + height: 25px; + border-radius: 6px; +} + +.skeleton-subtitle { + width: 48%; + height: 17px; + border-radius: 5px; +} + +.skeleton-label { + width: 35%; + height: 17px; + border-radius: 5px; +} + +.skeleton-value { + width: 100%; + height: 38px; + border-radius: 10px; +} + +.skeleton-section-title { + width: 85px; + height: 18px; + border-radius: 5px; +} + +.skeleton-stat { + width: 100%; + height: 20px; + border-radius: 8px; +} + +@keyframes skeleton-loading { + to { + background-position: -200% 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .skeleton { + animation: none; + } +} + .pokemon-card-close { position: absolute; top: 10px; @@ -523,6 +603,11 @@ padding: 16px; } + .skeleton-image { + width: 80px; + height: 80px; + } + .pokemon-card-header img { width: 80px; height: 80px; diff --git a/src/PokemonDetails.tsx b/src/PokemonDetails.tsx index 43d75ec..3f49a7b 100644 --- a/src/PokemonDetails.tsx +++ b/src/PokemonDetails.tsx @@ -39,7 +39,61 @@ function PokemonDetails({ } if (isPending) { - return

Loading Pokémon details...

; + return ( +
+
+ ); } if (isError || selectedPokemon === null) { From 1f9b96e16761476aa0d6101f7a24a022f2901581 Mon Sep 17 00:00:00 2001 From: William M Schmidt Date: Fri, 18 Sep 2026 23:20:15 +0200 Subject: [PATCH 2/3] Updated with favorite, and added a card with 2 hydration states instead of 2 cards --- src/PokemonDetails.tsx | 140 ++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 72 deletions(-) diff --git a/src/PokemonDetails.tsx b/src/PokemonDetails.tsx index 3f49a7b..3142637 100644 --- a/src/PokemonDetails.tsx +++ b/src/PokemonDetails.tsx @@ -38,78 +38,22 @@ function PokemonDetails({ ); } - if (isPending) { - return ( -
-
- ); - } - - if (isError || selectedPokemon === null) { - return

Could not load Pokémon details.

; - } - - const statRows = Array.from( - { length: Math.ceil(selectedPokemon.stats.length / 3) }, - (_, rowIndex) => selectedPokemon.stats.slice(rowIndex * 3, rowIndex * 3 + 3) - ); - - const favorite = isFavorite(selectedPokemon.id); - const name = capitalize(selectedPokemon.name); + const statRows = selectedPokemon + ? Array.from( + { length: Math.ceil(selectedPokemon.stats.length / 3) }, + (_, rowIndex) => + selectedPokemon.stats.slice(rowIndex * 3, rowIndex * 3 + 3) + ) + : []; + const favorite = selectedPokemon ? isFavorite(selectedPokemon.id) : false; + const name = selectedPokemon ? capitalize(selectedPokemon.name) : ''; return ( -
+