Pokemon Cards are beautiful, serving different card views based on type. Also got pokemon going to their own separate extension in order for table button to appear better. Excellent!

This commit is contained in:
Kira Jiroux 2025-04-10 18:16:07 -04:00
parent 17334250f9
commit 779ca3620c
10 changed files with 262 additions and 20 deletions

View File

@ -1,7 +1,7 @@
@attribute [StreamRendering]
@rendermode InteractiveServer
<div class="position-relative bg-white pokemon-card border border-5 border-info-subtle shadow-sm ">
<div class="mx-2 pokemon-card card-holo animated @GetTypeCssClass(_pokemon.PokemonType)">
<!-- Pokemon Name, Number, and Type -->
<div class="z-3">
@if (_pokemon.IsVariation)
@ -28,7 +28,8 @@
</div>
</div>
<div class="bg-info-subtle border rounded border-2 border-info z-3 pokemon-flavor-text">
<!-- Pokemon Flavortext -->
<div class="z-3 pokemon-flavor-text @(GetTypeCssClass(_pokemon.PokemonType))">
@if (string.IsNullOrEmpty(_pokemon.FlavorText))
{
<p class="">[ Pokemon Flavor Text Placeholder ]</p>

View File

@ -36,5 +36,11 @@ namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
return $"https://www.serebii.net/pokemonsleep/pokemon/type/{pokemonType.ToLower()}.png";
}
private string GetTypeCssClass(string type)
{
return "pokemon-type-" + type.ToLower();
}
}
}

View File

@ -4,9 +4,24 @@
height: 32rem;
max-width: 24rem;
max-height: 32rem;
background-color: var(--bg-color);
border-width: .5rem;
border-style: solid;
border-radius: 5% / 3.5%;
border-color: var(--border-color);
box-shadow: 0 0 10px var(--border-color);
}
.pokemon-card:hover {
z-index: 10;
box-shadow: 0 0 10px var(--border-color), 0 0 20px var(--border-color), 0 0 30px var(--border-color);
transition: box-shadow 0.3s ease, transform 0.2s ease;
animation: glowPulse 1.5s ease-in-out infinite;
transform: translateY(-13px);
}
.pokemon-name {
position: absolute;
top: 0 !important;
@ -60,13 +75,20 @@
align-items: start;
justify-content: center; /* Horizontally centers text */
overflow: hidden; /* Ensures no scrollbar */
border-width: 2px;
border-radius: 5% / 13%;
border-style: solid;
border-color: var(--border-color);
background-color: var(--flavor-bg-color);
}
.pokemon-flavor-text p {
margin: 0;
width: 100%;
text-align: start;
font-size: min(14px, 1.5vw); /* Scales font but won't exceed 14px */
font-size: min(13px, 1.5vw); /* Scales font but won't exceed 13px */
line-height: 1.2; /* Adjust spacing for readability */
white-space: normal; /* Ensures wrapping */
word-wrap: break-word;
@ -127,6 +149,7 @@
font-size: .8rem;
}
/* Sleep Type Badge Styling */
.dozing {
background-color: #fcdc5e;
}
@ -139,6 +162,7 @@
background-color: #4588fb;
}
/* Speciality Badge Styling */
.berries {
background-color: #24d86b;
}
@ -151,3 +175,210 @@
background-color: #47a0fc;
}
/* Type Card Styling */
/* Type Themes - define vars only */
.pokemon-type-grass {
--border-color: #45ca24;
--bg-color: #e5f8dc;
--flavor-bg-color: #f2fbe9;
}
.pokemon-type-fire {
--border-color: #ff662c;
--bg-color: #ffe3d5;
--flavor-bg-color: #fff0e9;
}
.pokemon-type-water {
--border-color: #2b99fe;
--bg-color: #d6ecff;
--flavor-bg-color: #eaf5ff;
}
.pokemon-type-normal {
--border-color: #ababab;
--bg-color: #ededed;
--flavor-bg-color: #f7f7f7;
}
.pokemon-type-flying {
--border-color: #9ed3ff;
--bg-color: #e7f5ff;
--flavor-bg-color: #f3fbff;
}
.pokemon-type-bug {
--border-color: #a7b023;
--bg-color: #f2f6cd;
--flavor-bg-color: #f9fbe4;
}
.pokemon-type-poison {
--border-color: #9f4ed7;
--bg-color: #edd6f8;
--flavor-bg-color: #f7ebfc;
}
.pokemon-type-electric {
--border-color: #ffdf00;
--bg-color: #fff8c6;
--flavor-bg-color: #fffbdf;
}
.pokemon-type-ground {
--border-color: #af7d38;
--bg-color: #f0ddc2;
--flavor-bg-color: #f8eee2;
}
.pokemon-type-rock {
--border-color: #bebd8d;
--bg-color: #f4f3dc;
--flavor-bg-color: #faf9ee;
}
.pokemon-type-ice {
--border-color: #45e0ff;
--bg-color: #d1f7ff;
--flavor-bg-color: #e9fbff;
}
.pokemon-type-steel {
--border-color: #6db7de;
--bg-color: #daedf7;
--flavor-bg-color: #eef6fb;
}
.pokemon-type-fighting {
--border-color: #ffa803;
--bg-color: #ffe9c6;
--flavor-bg-color: #fff3df;
}
.pokemon-type-psychic {
--border-color: #ff6887;
--bg-color: #ffd6df;
--flavor-bg-color: #ffe8ef;
}
.pokemon-type-dark {
--border-color: #544b4c;
--bg-color: #dedcdc;
--flavor-bg-color: #f1f0f0;
}
.pokemon-type-fairy {
--border-color: #ffb5ff;
--bg-color: #ffe6ff;
--flavor-bg-color: #fff2ff;
}
.pokemon-type-ghost {
--border-color: #714775;
--bg-color: #e2d2e4;
--flavor-bg-color: #f0e8f1;
}
.pokemon-type-dragon {
--border-color: #5669e2;
--bg-color: #d6dbfa;
--flavor-bg-color: #eaedfc;
}
.card-holo {
position: relative;
background-image: url("https://assets.codepen.io/13471/sparkles.gif"), url("https://assets.codepen.io/13471/holo.png"), linear-gradient(125deg, #ff008450 15%, #fca40040 30%, #ffff0030 40%, #00ff8a20 60%, #00cfff40 70%, #cc4cfa50 85% );
background-blend-mode: screen;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
overflow: hidden;
border-radius: 1rem;
transition: transform 0.4s ease;
}
.card-holo:hover::before {
animation: holoGradient 12s ease 0s 1;
}
.card-holo:hover::after {
animation: holoSparkle 12s ease 0s 1;
}
@keyframes holoSparkle {
0%, 100% {
opacity: .75;
background-position: 50% 50%;
filter: brightness(1.2) contrast(1.25);
}
5%, 8% {
opacity: 1;
background-position: 40% 40%;
filter: brightness(.8) contrast(1.2);
}
13%, 16% {
opacity: .5;
background-position: 50% 50%;
filter: brightness(1.2) contrast(.8);
}
35%, 38% {
opacity: 1;
background-position: 60% 60%;
filter: brightness(1) contrast(1);
}
55% {
opacity: .33;
background-position: 45% 45%;
filter: brightness(1.2) contrast(1.25);
}
}
@keyframes holoGradient {
0%, 100% {
opacity: 0.5;
background-position: 50% 50%;
filter: brightness(.5) contrast(1);
}
5%, 9% {
background-position: 100% 100%;
opacity: 1;
filter: brightness(.75) contrast(1.25);
}
13%, 17% {
background-position: 0% 0%;
opacity: .88;
}
35%, 39% {
background-position: 100% 100%;
opacity: 1;
filter: brightness(.5) contrast(1);
}
55% {
background-position: 0% 0%;
opacity: 1;
filter: brightness(.75) contrast(1.25);
}
}
@keyframes glowPulse {
0% {
box-shadow: 0 0 15px var(--border-color);
}
50% {
box-shadow: 0 0 25px var(--border-color);
}
100% {
box-shadow: 0 0 15px var(--border-color);
}
}

View File

@ -1,6 +1,6 @@

<!-- Heading + Buttons -->
<div class="top-row row rounded-bottom-5 w-100 bg-secondary py-3">
<div class="top-row row rounded-bottom-5 w-100 bg-secondary border-bottom border-start border-end border-2 border-primary py-3">
<div class="col-4"></div>
@ -8,26 +8,26 @@
<h1 class="text-primary">Pokémon Sleep</h1>
</div>
<div class="col-4 text-end">
<div class="btn-group col my-1">
<NavLink class="btn btn-danger" style="border-radius: 50px 15px;" href="/pokemonsleep">
<div class="col-4">
<div class="btn-group d-flex justify-content-end my-1">
<NavLink class="btn btn-primary mx-1" style="border-radius: 50px 15px;" href="/pokemonsleep">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-table" viewBox="0 0 16 16">
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 2h-4v3h4zm0 4h-4v3h4zm0 4h-4v3h3a1 1 0 0 0 1-1zm-5 3v-3H6v3zm-5 0v-3H1v2a1 1 0 0 0 1 1zm-4-4h4V8H1zm0-4h4V4H1zm5-3v3h4V4zm4 4H6v3h4z" />
</svg>
<span class="mx-1">Pokémon</span>
</NavLink>
<NavLink class="btn btn-primary" style="border-radius: 50px 15px;" href="/pokemonsleep/rate-pokemon">
<NavLink class="btn btn-success mx-1" style="border-radius: 50px 15px;" href="/pokemonsleep/rate-pokemon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-award-fill" viewBox="0 0 16 16">
<path d="m8 0 1.669.864 1.858.282.842 1.68 1.337 1.32L13.4 6l.306 1.854-1.337 1.32-.842 1.68-1.858.282L8 12l-1.669-.864-1.858-.282-.842-1.68-1.337-1.32L2.6 6l-.306-1.854 1.337-1.32.842-1.68L6.331.864z" />
<path d="M4 11.794V16l4-1 4 1v-4.206l-2.018.306L8 13.126 6.018 12.1z" />
</svg>
<span class="mx-1">Rate Pokémon</span>
</NavLink>
<NavLink class="btn btn-info" style="border-radius: 50px 15px;" href="/pokemonsleep/add-new-pokemon">
<NavLink class="btn btn-info mx-1" style="border-radius: 50px 15px;" href="/pokemonsleep/add-new-pokemon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M8.5 4.5a.5.5 0 0 0-1 0v3h-3a.5.5 0 0 0 0 1h3v3a.5.5 0 0 0 1 0v-3h3a.5.5 0 0 0 0-1h-3z" />
</svg>
<span class="mx-1">Add New Pokémon</span>
<span class="mx-1">Add Pokémon</span>
</NavLink>

View File

@ -77,7 +77,7 @@
</td>
<!-- Section 2: Pokemon # -->
<th scope="row">@pokemon.PokemonId</th>
<th scope="row" style="cursor: default;">@pokemon.PokemonId</th>
<!-- Section 3: Pokemon Name -->
@ -85,23 +85,23 @@
{
@if (pokemon.VariationName == "Alolan")
{
<td @onclick="() => ViewPokemon(pokemon.PokemonId)"> Alolan @pokemon.PokemonName</td>
<td @onclick="() => ViewPokemon(pokemon.PokemonId)" class="pokemon-name-style"> Alolan @pokemon.PokemonName</td>
}
@if (pokemon.VariationName == "Paldean")
{
<td @onclick="() => ViewPokemon(pokemon.PokemonId)"> Paldean @pokemon.PokemonName</td>
<td @onclick="() => ViewPokemon(pokemon.PokemonId)" class="pokemon-name-style"> Paldean @pokemon.PokemonName</td>
}
}
else // Otherwise, Base Case
{
<td @onclick="() => ViewPokemon(pokemon.PokemonId)"> @pokemon.PokemonName</td>
<td @onclick="() => ViewPokemon(pokemon.PokemonId)" class="pokemon-name-style"> @pokemon.PokemonName</td>
}
<!-- Section 4: Pokemon Type -->
<td>
<div class="d-flex justify-content-center">
<img src="@GetTypeImageUrl(pokemon.PokemonType)" class="" style="width:36px; height:36px;" />
<img src="@GetTypeImageUrl(pokemon.PokemonType)" style="width:36px; height:36px;" />
</div>
</td>

View File

@ -57,7 +57,7 @@ namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
private void ViewPokemon(int id)
{
Navigation.NavigateTo($"/pokemonsleep/pokemon/{id}");
Navigation.NavigateTo($"/pokemon/{id}");
}
private string GetTypeImageUrl(string pokemonType)

View File

@ -16,6 +16,9 @@
z-index: 10;
}
.pokemon-name-style {
cursor:pointer;
}
.flip-container {
@ -77,6 +80,7 @@
left: 50%;
transform: translate(-50%, -50%);
font-size: 13px;
cursor: default;
}
.dozing {

View File

@ -118,7 +118,7 @@ else
<!-- Flavor Text Input -->
<div class="row mb-3 m-auto">
<label for="FlavorText" class="form-label">Flavor Text</label>
<InputText id="FlavorText" @bind-Value="pokemon.FlavorText" class="form-control" required />
<InputText id="FlavorText" @bind-Value="pokemon.FlavorText" class="form-control" />
</div>
<!-- Form Buttons -->

View File

@ -1,4 +1,4 @@
@page "/pokemonsleep/pokemon/{id:int}"
@page "/pokemon/{id:int}"
@inject IPokemonService PokemonService
@inject NavigationManager Navigation

View File

@ -39,13 +39,13 @@ namespace Portfolio.WebUI.Server.Components.Pages.Pokemon_Pages
private void NavigateToNext()
{
if (_nextPokemonId.HasValue)
Navigation.NavigateTo($"/pokemonsleep/pokemon/{_nextPokemonId.Value}");
Navigation.NavigateTo($"/pokemon/{_nextPokemonId.Value}");
}
private void NavigateToPrevious()
{
if (_previousPokemonId.HasValue)
Navigation.NavigateTo($"/pokemonsleep/pokemon/{_previousPokemonId.Value}");
Navigation.NavigateTo($"/pokemon/{_previousPokemonId.Value}");
}
}