Compare commits
34 Commits
update/com
...
master
Author | SHA1 | Date |
---|---|---|
|
0b316a3b4b | |
|
da30a2b0d5 | |
|
b1a9567d31 | |
|
7b3761d6a5 | |
|
89f60d8c29 | |
|
87be31f2f5 | |
|
ef3e432347 | |
|
5b2aafc4e5 | |
|
04320dc9e1 | |
|
1955a210aa | |
|
17607b663b | |
|
9e765c776d | |
|
9b9a313411 | |
|
6c879038f6 | |
|
764c094a64 | |
|
bdd0f2e8bb | |
|
b881c06b83 | |
|
79bda1d0fc | |
|
aea7c06819 | |
|
d04f9b260b | |
|
779ca3620c | |
|
17334250f9 | |
|
5dd07c7c3f | |
|
8953387f66 | |
|
9c87f3e4cf | |
|
8f1dbebb30 | |
|
f12217839b | |
|
b8f3b45d1c | |
|
99ac4581ae | |
|
42d3a864e4 | |
|
dd9b0006d3 | |
|
0f235895f4 | |
|
a8f2bfd2b8 | |
|
6c8119d83c |
|
@ -1,5 +1,6 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Portfolio.Application.Services.Articles;
|
||||
using Portfolio.Application.Services.NWSWeatherService;
|
||||
using Portfolio.Application.Services.PokemonNatureService;
|
||||
using Portfolio.Application.Services.PokemonService;
|
||||
using Portfolio.Application.Services.PokemonSubskillService;
|
||||
|
@ -19,6 +20,7 @@ namespace Portfolio.Application
|
|||
services.AddScoped<IPokemonService, PokemonService>();
|
||||
services.AddScoped<IPokemonSubskillService, PokemonSubskillService>();
|
||||
services.AddScoped<IPokemonNatureService, PokemonNatureService>();
|
||||
//services.AddScoped<INWSWeatherService, NWSWeatherService>();
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
using Portfolio.Domain.Features.TemperatureDay;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Portfolio.Application.Services.NWSWeatherService
|
||||
{
|
||||
public interface INWSWeatherService
|
||||
{
|
||||
Task<string> GetNearestStationAsync(double latitude, double longitude);
|
||||
Task<double?> GetDailyAverageTempAsync(string stationId, DateTime date);
|
||||
Task<List<TemperatureDay>> GetTemperatureDataAsync(double latitude, double longitude, int year);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
using Portfolio.Domain.Features.TemperatureDay;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Portfolio.Application.Services.NWSWeatherService
|
||||
{
|
||||
public class NWSWeatherService : INWSWeatherService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public NWSWeatherService(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_httpClient.DefaultRequestHeaders.Add("User-Agent", "kira.jiroux@gmail.com"); // Replace with your email ideally
|
||||
}
|
||||
|
||||
public async Task<string> GetNearestStationAsync(double latitude, double longitude)
|
||||
{
|
||||
var url = $"https://api.weather.gov/points/{latitude},{longitude}";
|
||||
var response = await _httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using var stream = await response.Content.ReadAsStreamAsync();
|
||||
var json = await JsonDocument.ParseAsync(stream);
|
||||
|
||||
var stationUrl = json.RootElement
|
||||
.GetProperty("properties")
|
||||
.GetProperty("observationStations")
|
||||
.GetString();
|
||||
|
||||
if (string.IsNullOrEmpty(stationUrl))
|
||||
throw new Exception("Could not find station info.");
|
||||
|
||||
var stationListResponse = await _httpClient.GetAsync(stationUrl);
|
||||
stationListResponse.EnsureSuccessStatusCode();
|
||||
|
||||
using var stationStream = await stationListResponse.Content.ReadAsStreamAsync();
|
||||
var stationJson = await JsonDocument.ParseAsync(stationStream);
|
||||
|
||||
var firstStation = stationJson.RootElement
|
||||
.GetProperty("features")[0]
|
||||
.GetProperty("properties")
|
||||
.GetProperty("stationIdentifier")
|
||||
.GetString();
|
||||
|
||||
return firstStation;
|
||||
}
|
||||
|
||||
public async Task<double?> GetDailyAverageTempAsync(string stationId, DateTime date)
|
||||
{
|
||||
var start = date.ToString("yyyy-MM-dd") + "T00:00:00Z";
|
||||
var end = date.ToString("yyyy-MM-dd") + "T23:59:59Z";
|
||||
|
||||
var url = $"https://api.weather.gov/stations/{stationId}/observations?start={start}&end={end}";
|
||||
var response = await _httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using var stream = await response.Content.ReadAsStreamAsync();
|
||||
var json = await JsonDocument.ParseAsync(stream);
|
||||
|
||||
var temps = new List<double>();
|
||||
|
||||
foreach (var feature in json.RootElement.GetProperty("features").EnumerateArray())
|
||||
{
|
||||
if (feature.TryGetProperty("properties", out var props) &&
|
||||
props.TryGetProperty("temperature", out var tempObj) &&
|
||||
tempObj.TryGetProperty("value", out var valueProp) &&
|
||||
valueProp.ValueKind == JsonValueKind.Number)
|
||||
{
|
||||
var celsius = valueProp.GetDouble();
|
||||
if (!double.IsNaN(celsius))
|
||||
{
|
||||
var fahrenheit = (celsius * 9.0 / 5.0) + 32.0;
|
||||
temps.Add(fahrenheit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (temps.Count == 0)
|
||||
return null;
|
||||
|
||||
return temps.Average();
|
||||
}
|
||||
|
||||
public async Task<List<TemperatureDay>> GetTemperatureDataAsync(double latitude, double longitude, int year)
|
||||
{
|
||||
var stationId = await GetNearestStationAsync(latitude, longitude);
|
||||
|
||||
var result = new List<TemperatureDay>();
|
||||
|
||||
var startDate = new DateTime(year, 1, 1);
|
||||
var endDate = new DateTime(year, 12, 31);
|
||||
|
||||
for (var date = startDate; date <= endDate; date = date.AddDays(1))
|
||||
{
|
||||
Console.WriteLine($"Fetching {date:yyyy-MM-dd}...");
|
||||
var avgTemp = await GetDailyAverageTempAsync(stationId, date);
|
||||
|
||||
if (avgTemp.HasValue)
|
||||
{
|
||||
result.Add(new TemperatureDay
|
||||
{
|
||||
Date = date,
|
||||
AvgTemp = Math.Round(avgTemp.Value, 1)
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"No data for {date:yyyy-MM-dd}");
|
||||
}
|
||||
|
||||
await Task.Delay(600); // small delay to be nice to NWS
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,12 @@ namespace Portfolio.Application.Services.PokemonService
|
|||
public interface IPokemonService
|
||||
{
|
||||
Task<List<Pokemon>> GetAllPokemonAsync();
|
||||
Task<Pokemon> GetPokemonByPokemonIdAsync(int id);
|
||||
Task<Pokemon> GetPokemonByIdAsync(int id);
|
||||
Task<List<int>> GetAllPokemonIdsAsync();
|
||||
Task<int?> GetPreviousPokemonIdAsync(int id);
|
||||
Task<int?> GetNextPokemonIdAsync(int id);
|
||||
Task<int?> GetVariationPokemonIdAsync(int id);
|
||||
Task AddPokemonAsync(Pokemon pokemon);
|
||||
Task DeletePokemonAsync(int pokemonId);
|
||||
Task UpdatePokemonAsync(Pokemon pokemon);
|
||||
|
|
|
@ -33,14 +33,40 @@ namespace Portfolio.Application.Services.PokemonService
|
|||
|
||||
}
|
||||
|
||||
public async Task<List<int>> GetAllPokemonIdsAsync()
|
||||
{
|
||||
return await _pokemonRepository.GetAllPokemonIdsAsync();
|
||||
}
|
||||
|
||||
public async Task<int?> GetNextPokemonIdAsync(int id)
|
||||
{
|
||||
return await _pokemonRepository.GetNextPokemonIdAsync(id);
|
||||
}
|
||||
|
||||
public async Task<Pokemon> GetPokemonByPokemonIdAsync(int id)
|
||||
{
|
||||
return await _pokemonRepository.GetPokemonByPokemonIdAsync(id);
|
||||
}
|
||||
|
||||
public async Task<Pokemon> GetPokemonByIdAsync(int id)
|
||||
{
|
||||
return await _pokemonRepository.GetPokemonByIdAsync(id);
|
||||
}
|
||||
|
||||
public async Task<int?> GetPreviousPokemonIdAsync(int id)
|
||||
{
|
||||
return await _pokemonRepository.GetPreviousPokemonIdAsync(id);
|
||||
|
||||
}
|
||||
|
||||
public async Task UpdatePokemonAsync(Pokemon pokemon)
|
||||
{
|
||||
await _pokemonRepository.UpdatePokemonAsync(pokemon);
|
||||
}
|
||||
|
||||
public async Task<int?> GetVariationPokemonIdAsync(int id)
|
||||
{
|
||||
return await _pokemonRepository.GetVariationPokemonIdAsync(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Portfolio.Application.Services.PokemonSubskillService
|
|||
}
|
||||
public async Task<List<PokemonSubskill>> GetAllPokemonSubskillsAsync()
|
||||
{
|
||||
Console.WriteLine("Does this fire every time");
|
||||
return await _pokemonSubskillRepository.GetAllPokemonSubskillsAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,11 @@ namespace Portfolio.Domain.Features.Pokemon
|
|||
{
|
||||
Task<List<Pokemon>> GetAllPokemonsAsync();
|
||||
Task<Pokemon> GetPokemonByIdAsync(int id);
|
||||
Task<Pokemon> GetPokemonByPokemonIdAsync(int id);
|
||||
Task<List<int>> GetAllPokemonIdsAsync();
|
||||
Task<int?> GetPreviousPokemonIdAsync(int currentPokemonId);
|
||||
Task<int?> GetNextPokemonIdAsync(int currentPokemonId);
|
||||
Task<int?> GetVariationPokemonIdAsync(int pokemonId);
|
||||
Task AddPokemonAsync(Pokemon pokemon);
|
||||
Task DeletePokemonAsync(int pokemonId);
|
||||
Task UpdatePokemonAsync(Pokemon pokemon);
|
||||
|
|
|
@ -13,10 +13,12 @@ namespace Portfolio.Domain.Features.Pokemon
|
|||
public required string PokemonName { get; set; }
|
||||
public bool IsVariation { get; set; } = false;
|
||||
public string? VariationName { get; set; }
|
||||
public string? PokemonType { get; set; }
|
||||
public required string SleepType { get; set; }
|
||||
public required string Speciality { get; set; }
|
||||
public string? PokemonImageUrl { get; set; }
|
||||
public string? PokemonShinyImageUrl { get; set; }
|
||||
public string? FlavorText { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Portfolio.Domain.Features.TemperatureDay
|
||||
{
|
||||
public class TemperatureDay
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public double AvgTemp { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Portfolio.Domain.Features.TemperatureRange
|
||||
{
|
||||
public class TemperatureRange
|
||||
{
|
||||
public double Min { get; set; }
|
||||
public double Max { get; set; }
|
||||
public string Color { get; set; } = "#ffffff";
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Portfolio.Application.Services.Articles;
|
||||
using Portfolio.Application.Services.NWSWeatherService;
|
||||
using Portfolio.Application.Services.PokemonService;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
using Portfolio.Domain.Features.Pokemon_Natures;
|
||||
|
@ -25,6 +26,7 @@ namespace Portfolio.Infrastructure
|
|||
services.AddScoped<IPokemonRepository, PokemonRepository>();
|
||||
services.AddScoped<IPokemonNatureRepository, PokemonNatureRepository>();
|
||||
services.AddScoped<IPokemonSubskillRepository, PokemonSubskillRepository>();
|
||||
//services.AddScoped<INWSWeatherService, NWSWeatherService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
124
Portfolio.Infrastructure/Migrations/20250404172651_include_pokemon_type.Designer.cs
generated
Normal file
124
Portfolio.Infrastructure/Migrations/20250404172651_include_pokemon_type.Designer.cs
generated
Normal file
|
@ -0,0 +1,124 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Portfolio.Infrastructure;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Portfolio.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20250404172651_include_pokemon_type")]
|
||||
partial class include_pokemon_type
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Portfolio.Domain.Features.Pokemon.Pokemon", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsVariation")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("PokemonId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PokemonImageUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonName")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonShinyImageUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SleepType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Speciality")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("VariationName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Pokemons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Portfolio.Domain.Features.Pokemon_Natures.PokemonNature", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BerryRating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("IngredientRating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Nature")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("SkillRating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PokemonNatures");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Portfolio.Domain.Features.Pokemon_Subskills.PokemonSubskill", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BerryRank")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("IngredientRank")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SkillRank")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("SubSkill")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PokemonSubskills");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Portfolio.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class include_pokemon_type : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "PokemonType",
|
||||
table: "Pokemons",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PokemonType",
|
||||
table: "Pokemons");
|
||||
}
|
||||
}
|
||||
}
|
127
Portfolio.Infrastructure/Migrations/20250404173359_include_flavortext.Designer.cs
generated
Normal file
127
Portfolio.Infrastructure/Migrations/20250404173359_include_flavortext.Designer.cs
generated
Normal file
|
@ -0,0 +1,127 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Portfolio.Infrastructure;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Portfolio.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20250404173359_include_flavortext")]
|
||||
partial class include_flavortext
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Portfolio.Domain.Features.Pokemon.Pokemon", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("FlavorText")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("IsVariation")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("PokemonId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PokemonImageUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonName")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonShinyImageUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SleepType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Speciality")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("VariationName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Pokemons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Portfolio.Domain.Features.Pokemon_Natures.PokemonNature", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BerryRating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("IngredientRating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Nature")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("SkillRating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PokemonNatures");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Portfolio.Domain.Features.Pokemon_Subskills.PokemonSubskill", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BerryRank")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("IngredientRank")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SkillRank")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("SubSkill")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PokemonSubskills");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Portfolio.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class include_flavortext : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "FlavorText",
|
||||
table: "Pokemons",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FlavorText",
|
||||
table: "Pokemons");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,9 @@ namespace Portfolio.Infrastructure.Migrations
|
|||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("FlavorText")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("IsVariation")
|
||||
.HasColumnType("bit");
|
||||
|
||||
|
@ -45,6 +48,9 @@ namespace Portfolio.Infrastructure.Migrations
|
|||
b.Property<string>("PokemonShinyImageUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PokemonType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SleepType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
|
|
@ -21,11 +21,14 @@ namespace Portfolio.Infrastructure.Repositories
|
|||
{
|
||||
return await _context.Pokemons.ToListAsync();
|
||||
}
|
||||
public async Task<Pokemon> GetPokemonByPokemonIdAsync(int id)
|
||||
{
|
||||
return await _context.Pokemons.FirstOrDefaultAsync(p => p.PokemonId == id);
|
||||
}
|
||||
public async Task<Pokemon> GetPokemonByIdAsync(int id)
|
||||
{
|
||||
return await _context.Pokemons.FirstOrDefaultAsync(p => p.Id == id);
|
||||
}
|
||||
|
||||
public async Task AddPokemonAsync(Pokemon pokemon)
|
||||
{
|
||||
_context.Pokemons.Add(pokemon);
|
||||
|
@ -46,5 +49,68 @@ namespace Portfolio.Infrastructure.Repositories
|
|||
_context.Pokemons.Update(pokemon);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<int?> GetPreviousPokemonIdAsync(int currentPokemonId)
|
||||
{
|
||||
// Get the previous Pokémon's PokemonId
|
||||
var prevPokemonId = await _context.Pokemons
|
||||
.Where(p => p.PokemonId < currentPokemonId)
|
||||
.OrderByDescending(p => p.PokemonId)
|
||||
.Select(p => (int?)p.PokemonId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
// If no previous PokemonId is found, wrap around to the last one
|
||||
if (prevPokemonId == null)
|
||||
{
|
||||
prevPokemonId = await _context.Pokemons
|
||||
.OrderByDescending(p => p.PokemonId) // Get the last PokemonId
|
||||
.Select(p => (int?)p.PokemonId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
return prevPokemonId;
|
||||
}
|
||||
|
||||
public async Task<int?> GetNextPokemonIdAsync(int currentPokemonId)
|
||||
{
|
||||
// Get the next Pokémon's PokemonId
|
||||
var nextPokemonId = await _context.Pokemons
|
||||
.Where(p => p.PokemonId > currentPokemonId)
|
||||
.OrderBy(p => p.PokemonId)
|
||||
.Select(p => (int?)p.PokemonId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
// If no next PokemonId is found, wrap around to the first one
|
||||
if (nextPokemonId == null)
|
||||
{
|
||||
nextPokemonId = await _context.Pokemons
|
||||
.OrderBy(p => p.PokemonId) // Get the first PokemonId
|
||||
.Select(p => (int?)p.PokemonId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
return nextPokemonId;
|
||||
}
|
||||
|
||||
public async Task<List<int>> GetAllPokemonIdsAsync()
|
||||
{
|
||||
return await _context.Pokemons
|
||||
.OrderBy(p => p.PokemonId) // Ensure it's ordered by PokemonId
|
||||
.Select(p => p.PokemonId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int?> GetVariationPokemonIdAsync(int pokemonId)
|
||||
{
|
||||
// Find a variation for the given PokemonId (where IsVariation is true)
|
||||
var variation = await _context.Pokemons
|
||||
.Where(p => p.PokemonId == pokemonId && p.IsVariation)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
// Return the Id of the variation, or null if no variation is found
|
||||
return variation?.Id;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,17 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-lumen.css" /> <!-- app.css -->
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-brite.css" /> <!-- app.css -->
|
||||
<link rel="stylesheet" href="Portfolio.WebUI.Server.styles.css" />
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body class="bg-primary-subtle">
|
||||
<Routes />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src="js/site.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div>
|
||||
@if (TemperatureDays is null || TemperatureRanges is null)
|
||||
{
|
||||
<Loading />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
<h3 class="text-xl font-bold mb-4">Temperature Blanket Visualizer</h3>
|
||||
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
<div class="d-flex">
|
||||
<div class="temperature-blanket">
|
||||
@foreach (var day in TemperatureDays)
|
||||
{
|
||||
var color = GetColorForTemp(day.AvgTemp);
|
||||
<div style="width: 6px; height: 600px; background-color:@color; margin-right: 1px;"
|
||||
title="@day.Date.ToString("MMM dd") - @day.AvgTemp°F (@color)">
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<TemperatureRangeEditor TempRanges="@TemperatureRanges" OnRangesChanged="HandleRangesChanged" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.TemperatureDay;
|
||||
using Portfolio.Domain.Features.TemperatureRange;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Crochet_Components
|
||||
{
|
||||
public partial class TemperatureBlanketVisualizer : ComponentBase
|
||||
{
|
||||
[Parameter] public List<TemperatureDay> TemperatureDays { get; set; }
|
||||
|
||||
public List<TemperatureRange> TemperatureRanges { get; set; } = new();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
TemperatureRanges = new()
|
||||
{
|
||||
new() { Min = 0, Max = 21, Color = "#ffffff" },
|
||||
new() { Min = 21, Max = 28, Color = "#ffc0cb" },
|
||||
new() { Min = 28, Max = 35, Color = "#dda0dd" },
|
||||
new() { Min = 35, Max = 42, Color = "#add8e6" },
|
||||
new() { Min = 42, Max = 49, Color = "#00008b" },
|
||||
new() { Min = 49, Max = 56, Color = "#006400" },
|
||||
new() { Min = 56, Max = 63, Color = "#07ed07" },
|
||||
new() { Min = 63, Max = 70, Color = "#ffff00" },
|
||||
new() { Min = 70, Max = 77, Color = "#ffa500" },
|
||||
new() { Min = 77, Max = 84, Color = "#ff0000" },
|
||||
new() { Min = 84, Max = 100, Color = "#000000" }
|
||||
};
|
||||
}
|
||||
|
||||
private string GetColorForTemp(double temp)
|
||||
{
|
||||
var range = TemperatureRanges.FirstOrDefault(r => temp >= r.Min && temp < r.Max);
|
||||
return range?.Color ?? "#888888";
|
||||
}
|
||||
|
||||
private void HandleRangesChanged(List<TemperatureRange> updatedRanges)
|
||||
{
|
||||
TemperatureRanges = updatedRanges;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
body {
|
||||
}
|
||||
|
||||
.temperature-blanket {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
background-color: black;
|
||||
padding: 10px;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
@using Microsoft.AspNetCore.Components.Web
|
||||
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div class="container" > @* @onmouseup="OnMouseUp" @onmousemove="OnMouseMove" *@
|
||||
<!-- Base number line -->
|
||||
@* <div class="absolute top-1/2 left-0 right-0 h-1 bg-gray-300 transform -translate-y-1/2"></div> *@
|
||||
|
||||
@* <!-- Draggable nodes for adjusting range breakpoints -->
|
||||
@for (int i = 0; i < TempRanges.Count; i++)
|
||||
{
|
||||
var left = i == 0 ? 0 : TempRanges[i - 1].Max;
|
||||
var leftPercent = (left / 100.0) * 100;
|
||||
|
||||
<div class="absolute top-1/2 transform -translate-y-1/2 -translate-x-1/2 w-4 h-4 rounded-full bg-blue-600 cursor-pointer"
|
||||
style="left: @leftPercent%"
|
||||
@onmousedown="(e) => OnMouseDown(i, e)"
|
||||
title="@left°F">
|
||||
</div>
|
||||
} *@
|
||||
|
||||
<!-- Color pickers for each range -->
|
||||
<div class="card rounded-3">
|
||||
<div class="card-header mb-3 text-center fw-bold">
|
||||
Temperature Blanket Colors
|
||||
</div>
|
||||
|
||||
@for (int i = 0; i < TempRanges.Count; i++)
|
||||
{
|
||||
var localIndex = i;
|
||||
@* if (i == 0)
|
||||
{
|
||||
<div class="row align-items-center mb-2">
|
||||
<div class="col-6 text-end pe-2">
|
||||
<label class="form-label mb-0">
|
||||
@TempRanges[i].Max°
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 ps-2">
|
||||
<input type="color"
|
||||
value="@TempRanges[i].Color"
|
||||
@onchange="e => HandleColorChange(e, localIndex)" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (i == 10)
|
||||
{
|
||||
<div class="row align-items-center mb-2">
|
||||
<div class="col-6 text-end pe-2">
|
||||
<label class="form-label mb-0">
|
||||
@TempRanges[i].Min° +
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 ps-2">
|
||||
<input type="color"
|
||||
value="@TempRanges[i].Color"
|
||||
@onchange="e => HandleColorChange(e, localIndex)" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row align-items-center mb-2">
|
||||
<div class="col-6 text-end pe-2">
|
||||
<label class="form-label mb-0">
|
||||
@TempRanges[i].Min° – @TempRanges[i].Max°
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 ps-2">
|
||||
<input type="color"
|
||||
value="@TempRanges[i].Color"
|
||||
@onchange="e => HandleColorChange(e, localIndex)" />
|
||||
</div>
|
||||
</div>
|
||||
} *@
|
||||
|
||||
<div class="row align-items-center mb-2 ms-1">
|
||||
<div class="col-6 text-end pe-2">
|
||||
<label class="form-label mb-0">
|
||||
@TempRanges[i].Min° – @TempRanges[i].Max°
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 ps-2">
|
||||
<input type="color"
|
||||
value="@TempRanges[i].Color"
|
||||
@onchange="e => HandleColorChange(e, localIndex)" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,88 @@
|
|||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Portfolio.Domain.Features.TemperatureRange;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Crochet_Components
|
||||
{
|
||||
public partial class TemperatureRangeEditor : ComponentBase
|
||||
{
|
||||
[Parameter] public List<TemperatureRange> TempRanges { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<List<TemperatureRange>> OnRangesChanged { get; set; }
|
||||
|
||||
[Inject] private IJSRuntime JS { get; set; }
|
||||
|
||||
private double windowWidth = 1000;
|
||||
private int? draggingIndex = null;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
windowWidth = await JS.InvokeAsync<double>("eval", "window.innerWidth");
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseDown(int index, MouseEventArgs e)
|
||||
{
|
||||
draggingIndex = index;
|
||||
}
|
||||
|
||||
private async void OnMouseUp()
|
||||
{
|
||||
if (draggingIndex != null)
|
||||
{
|
||||
draggingIndex = null;
|
||||
await OnRangesChanged.InvokeAsync(TempRanges);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
if (draggingIndex is not int index || index <= 0 || index >= TempRanges.Count)
|
||||
return;
|
||||
|
||||
var percent = (e.ClientX / windowWidth) * 100;
|
||||
percent = Math.Clamp(percent, 0, 100);
|
||||
|
||||
var min = TempRanges[index - 1].Min;
|
||||
var max = TempRanges[index].Max;
|
||||
|
||||
if (percent <= min + 1 || percent >= max - 1)
|
||||
return;
|
||||
|
||||
TempRanges[index - 1].Max = percent;
|
||||
TempRanges[index].Min = percent;
|
||||
}
|
||||
|
||||
private void HandleColorChange(ChangeEventArgs e, int index)
|
||||
{
|
||||
if (index < 0 || index >= TempRanges.Count)
|
||||
{
|
||||
Console.WriteLine($"Color change requested for out-of-bounds index: {index}");
|
||||
return;
|
||||
}
|
||||
|
||||
var color = e?.Value?.ToString() ?? "#000000";
|
||||
OnColorChanged(index, color);
|
||||
}
|
||||
|
||||
private async void OnColorChanged(int index, string newColor)
|
||||
{
|
||||
//Console.WriteLine($"Color change at index {index} to {newColor}");
|
||||
|
||||
if (index >= 0 && index < TempRanges.Count)
|
||||
{
|
||||
TempRanges[index].Color = newColor;
|
||||
Console.WriteLine($"Updated color: {TempRanges[index].Color}");
|
||||
await OnRangesChanged.InvokeAsync(TempRanges);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Invalid index: {index} (Count: {TempRanges.Count})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
input[type="color"] {
|
||||
width: 2.5rem;
|
||||
height: 2rem;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<!--
|
||||
https://codepen.io/dissimulate/pen/nmJyyg
|
||||
-->
|
||||
<div id="load">
|
||||
<div>G</div>
|
||||
<div>N</div>
|
||||
<div>I</div>
|
||||
<div>D</div>
|
||||
<div>A</div>
|
||||
<div>O</div>
|
||||
<div>L</div>
|
||||
</div>
|
|
@ -0,0 +1,195 @@
|
|||
body {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
#load {
|
||||
position: absolute;
|
||||
width: 600px;
|
||||
height: 36px;
|
||||
left: 50%;
|
||||
top: 40%;
|
||||
margin-left: -300px;
|
||||
overflow: visible;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#load div {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 36px;
|
||||
opacity: 0;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
animation: move 3s linear infinite;
|
||||
-o-animation: move 3s linear infinite;
|
||||
-moz-animation: move 3s linear infinite;
|
||||
-webkit-animation: move 3s linear infinite;
|
||||
transform: rotate(180deg);
|
||||
-o-transform: rotate(180deg);
|
||||
-moz-transform: rotate(180deg);
|
||||
-webkit-transform: rotate(180deg);
|
||||
color: #35C4F0;
|
||||
}
|
||||
|
||||
#load div:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
-o-animation-delay: 0.2s;
|
||||
-moz-animation-delay: 0.2s;
|
||||
-webkit-animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
#load div:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
-o-animation-delay: 0.4s;
|
||||
-webkit-animation-delay: 0.4s;
|
||||
-webkit-animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
#load div:nth-child(4) {
|
||||
animation-delay: 0.6s;
|
||||
-o-animation-delay: 0.6s;
|
||||
-moz-animation-delay: 0.6s;
|
||||
-webkit-animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
#load div:nth-child(5) {
|
||||
animation-delay: 0.8s;
|
||||
-o-animation-delay: 0.8s;
|
||||
-moz-animation-delay: 0.8s;
|
||||
-webkit-animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
#load div:nth-child(6) {
|
||||
animation-delay: 1s;
|
||||
-o-animation-delay: 1s;
|
||||
-moz-animation-delay: 1s;
|
||||
-webkit-animation-delay: 1s;
|
||||
}
|
||||
|
||||
#load div:nth-child(7) {
|
||||
animation-delay: 1.2s;
|
||||
-o-animation-delay: 1.2s;
|
||||
-moz-animation-delay: 1.2s;
|
||||
-webkit-animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
0% {
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
35% {
|
||||
left: 41%;
|
||||
-moz-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
65% {
|
||||
left: 59%;
|
||||
-moz-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
left: 100%;
|
||||
-moz-transform: rotate(-180deg);
|
||||
-webkit-transform: rotate(-180deg);
|
||||
-o-transform: rotate(-180deg);
|
||||
transform: rotate(-180deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes move {
|
||||
0% {
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
35% {
|
||||
left: 41%;
|
||||
-moz-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
65% {
|
||||
left: 59%;
|
||||
-moz-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
left: 100%;
|
||||
-moz-transform: rotate(-180deg);
|
||||
transform: rotate(-180deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes move {
|
||||
0% {
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
35% {
|
||||
left: 41%;
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
65% {
|
||||
left: 59%;
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
left: 100%;
|
||||
-webkit-transform: rotate(-180deg);
|
||||
transform: rotate(-180deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes move {
|
||||
0% {
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
35% {
|
||||
left: 41%;
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
65% {
|
||||
left: 59%;
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
left: 100%;
|
||||
-o-transform: rotate(-180deg);
|
||||
transform: rotate(-180deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
public partial class PokemonBackground
|
||||
{
|
||||
|
||||
private class PokemonImage
|
||||
{
|
||||
public string Url { get; set; } = "";
|
||||
public int Left { get; set; }
|
||||
public int Top { get; set; }
|
||||
public int Size { get; set; }
|
||||
public int Rotation { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[Parameter]
|
||||
public List<string> PokemonImages { get; set; }
|
||||
[Parameter]
|
||||
public List<string> ShinyPokemonImages { get; set; }
|
||||
|
||||
private List<PokemonImage> _pokemonImages = new List<PokemonImage>();
|
||||
private List<PokemonImage> _shinyPokemonImages = new List<PokemonImage>();
|
||||
private Random random = new Random();
|
||||
|
||||
//protected override async Task OnInitializedAsync()
|
||||
//{
|
||||
// await LoadPokemonBackgrounds();
|
||||
//}
|
||||
|
||||
//private async Task LoadPokemonBackgrounds()
|
||||
//{
|
||||
|
||||
// foreach (var pokemonimgurl in PokemonImages)
|
||||
// {
|
||||
// Console.WriteLine(pokemonimgurl);
|
||||
// _pokemonImages.Add(new PokemonImage
|
||||
// {
|
||||
// Url = pokemonimgurl, // URL retrieved from the database
|
||||
// Left = random.Next(0, 100),
|
||||
// Top = random.Next(0, 100),
|
||||
// Size = random.Next(50, 130),
|
||||
// Rotation = random.Next(0, 360)
|
||||
// });
|
||||
// }
|
||||
// foreach (var pokemonimgurl in ShinyPokemonImages)
|
||||
// {
|
||||
// _shinyPokemonImages.Add(new PokemonImage
|
||||
// {
|
||||
// Url = pokemonimgurl, // URL retrieved from the database
|
||||
// Left = random.Next(0, 100),
|
||||
// Top = random.Next(0, 100),
|
||||
// Size = random.Next(50, 130),
|
||||
// Rotation = random.Next(0, 360)
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<div class="m-1 badge @_badgeitem.ToLower() border-0"><p class="statText">@_badgeitem</p></div>
|
|
@ -0,0 +1,22 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
public partial class PokemonBadge
|
||||
{
|
||||
[Parameter]
|
||||
public string BadgeItem { get; set; }
|
||||
|
||||
private string _badgeitem { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (BadgeItem != null)
|
||||
{
|
||||
_badgeitem = BadgeItem;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
.badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 90px;
|
||||
height: 30px;
|
||||
padding: 0.25rem;
|
||||
border-radius: 30px;
|
||||
color: white;
|
||||
font-size: clamp(0.7rem, 1vw, 0.9rem);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.statText {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Sleep Type Badge Styling */
|
||||
.dozing {
|
||||
background-color: #fcdc5e;
|
||||
}
|
||||
|
||||
.snoozing {
|
||||
background-color: #4ce8ed;
|
||||
}
|
||||
|
||||
.slumbering {
|
||||
background-color: #4588fb;
|
||||
}
|
||||
|
||||
/* Speciality Badge Styling */
|
||||
.berries {
|
||||
background-color: #24d86b;
|
||||
}
|
||||
|
||||
.ingredients {
|
||||
background-color: #fdbe4d;
|
||||
}
|
||||
|
||||
.skills {
|
||||
background-color: #47a0fc;
|
||||
}
|
||||
|
||||
.all {
|
||||
background-color: #fc7992;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div class="card-wrapper d-flex flex-column align-items-center">
|
||||
<div class="pokemon-card card-holo animated @GetTypeCssClass(_pokemon.PokemonType)">
|
||||
<!-- Pokemon Name, Number, and Type -->
|
||||
<div class="z-3">
|
||||
@if (_pokemon.IsVariation)
|
||||
{
|
||||
<div class="pokemon-name"><p class="fw-bold card-title">@_pokemon.VariationName @_pokemon.PokemonName</p></div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="pokemon-name"><p class="fw-bold card-title">@_pokemon.PokemonName</p></div>
|
||||
}
|
||||
<div class="pokemon-number">
|
||||
<p class="fw-light card-text">Pokédex #<strong>@_pokemon.PokemonId</strong></p>
|
||||
</div>
|
||||
<div >
|
||||
<img class="pokemon-type" src="@GetTypeImageUrl(_pokemon.PokemonType)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pokemon Image -->
|
||||
<div class="flip-container z-1" @onclick="() => ToggleImage()">
|
||||
<div class="flipper @(isShiny ? "flipped" : "")">
|
||||
<img class="pokemon-image front" src="@_pokemon.PokemonImageUrl" />
|
||||
<img class="pokemon-image back" src="@_pokemon.PokemonShinyImageUrl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pokemon Flavortext -->
|
||||
<div class="z-3 pokemon-flavor-text @(GetTypeCssClass(_pokemon.PokemonType))">
|
||||
@if (string.IsNullOrEmpty(_pokemon.FlavorText))
|
||||
{
|
||||
<p class="fw-light">[ Pokemon Flavor Text Placeholder ]</p>
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="fw-light">@_pokemon.FlavorText</p>
|
||||
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Pokemon Sleep Type and Specialty Badges -->
|
||||
<div class="position-absolute bottom-0 end-0 z-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<PokemonBadge BadgeItem="@_pokemon.SleepType" />
|
||||
<PokemonBadge BadgeItem="@_pokemon.Speciality" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<PokemonEditButton PokemonId="@_pokemon.Id" />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,47 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
public partial class PokemonCard
|
||||
{
|
||||
[Parameter]
|
||||
public Pokemon Pokemon { get; set; }
|
||||
|
||||
private Pokemon _pokemon { get; set; }
|
||||
|
||||
private bool isShiny = false;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (Pokemon != null)
|
||||
{
|
||||
_pokemon = Pokemon;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleImage()
|
||||
{
|
||||
isShiny = !isShiny;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private string GetTypeImageUrl(string pokemonType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pokemonType))
|
||||
{
|
||||
return "https://www.serebii.net/pokemonsleep/pokemon/type/normal.png"; // Fallback image
|
||||
}
|
||||
|
||||
return $"https://www.serebii.net/pokemonsleep/pokemon/type/{pokemonType.ToLower()}.png";
|
||||
}
|
||||
|
||||
private string GetTypeCssClass(string type)
|
||||
{
|
||||
return "pokemon-type-" + type.ToLower();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
.pokemon-card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 350px; /* Prevent it from getting too huge */
|
||||
aspect-ratio: 3 / 4; /* Maintains card shape dynamically */
|
||||
overflow: hidden;
|
||||
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);
|
||||
}
|
||||
|
||||
.card-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.pokemon-name {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
left: 3%;
|
||||
transform: translateY(-50%) !important;
|
||||
font-size: clamp(1.2rem, 2vw, 2rem);
|
||||
}
|
||||
|
||||
.pokemon-number {
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: 6%;
|
||||
|
||||
transform: translateY(-50%) !important;
|
||||
font-size: clamp(0.7rem, 1.2vw, 0.75rem);
|
||||
}
|
||||
|
||||
.pokemon-type {
|
||||
position: absolute;
|
||||
top: 2%;
|
||||
right: 2%;
|
||||
width: clamp(1.5rem, 2.5vw, 2.5rem);
|
||||
height: clamp(1.5rem, 2.5vw, 2.5rem);
|
||||
}
|
||||
|
||||
.pokemon-image {
|
||||
width: 100%; /* Look to flip-container for the width/height of image */
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.pokemon-flavor-text {
|
||||
position: absolute;
|
||||
top: 60% !important;
|
||||
left: 50% !important;
|
||||
width: 90%;
|
||||
height: 20%;
|
||||
padding: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
margin-top: 3rem !important;
|
||||
transform: translateX(-50%) !important;
|
||||
display: flex; /* Centers text inside */
|
||||
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(12.5px, 1.5vw); /* Scales font but won't exceed 12.5px */
|
||||
line-height: 1.2; /* Adjust spacing for readability */
|
||||
white-space: normal; /* Ensures wrapping */
|
||||
word-wrap: break-word;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
.flip-container {
|
||||
position: absolute !important;
|
||||
top: 40% !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
perspective: 1000px;
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
aspect-ratio: 1 / 1;
|
||||
max-width: 280px;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.flipper {
|
||||
transition: transform 0.6s;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flipped {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
|
||||
.front, .back {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.back {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
|
||||
/* Type Card Styling */
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
@inject NavigationManager Navigation
|
||||
<button class="btn btn-warning rounded rounded-5 text-white " @onclick="() => EditPokemon(PokemonId)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.5.5 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11z" />
|
||||
</svg>
|
||||
</button>
|
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
public partial class PokemonEditButton
|
||||
{
|
||||
[Parameter] public int PokemonId { get; set; }
|
||||
|
||||
private void EditPokemon(int PokemonId)
|
||||
{
|
||||
Navigation.NavigateTo($"/pokemonsleep/edit/{PokemonId}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
<!-- Heading + Buttons -->
|
||||
<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>
|
||||
|
||||
<div class="col-4 text-center">
|
||||
<h1 class="text-primary">Pokémon Sleep</h1>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<div class="btn-group d-flex justify-content-end my-1">
|
||||
<!-- Home -->
|
||||
<button class="btn btn-primary mx-1 align-content-center" style="border-radius: 50px 15px; max-width: 60px;">
|
||||
<NavLink href="/pokemonsleep">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#FFF" class="bi bi-house-fill mb-1" viewBox="0 0 16 16">
|
||||
<path d="M8.707 1.5a1 1 0 0 0-1.414 0L.646 8.146a.5.5 0 0 0 .708.708L8 2.207l6.646 6.647a.5.5 0 0 0 .708-.708L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293z" />
|
||||
<path d="m8 3.293 6 6V13.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5V9.293z" />
|
||||
</svg>
|
||||
</NavLink>
|
||||
</button>
|
||||
|
||||
<!-- Pokemon Table-->
|
||||
<button class="btn btn-info mx-1" style="border-radius: 50px 15px; max-width: 60px;">
|
||||
<NavLink href="/pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#FFF" class="bi bi-table mb-1" 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>
|
||||
</NavLink>
|
||||
</button>
|
||||
|
||||
<!-- Rate Pokemon -->
|
||||
<button class="btn btn-success mx-1" style="border-radius: 50px 15px; max-width: 60px;">
|
||||
<NavLink href="/rate-pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#FFF" class="bi bi-award-fill mb-1" 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>
|
||||
</NavLink>
|
||||
</button>
|
||||
|
||||
<!-- Add Pokemon (Wrap in Auth) -->
|
||||
<button class="btn btn-warning mx-1" style="border-radius: 50px 15px; max-width: 60px;">
|
||||
<NavLink href="/pokemonsleep/add-new-pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#FFF" class="bi bi-plus-circle-fill mb-1" 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>
|
||||
</NavLink>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,135 @@
|
|||
<div class="pokemon-rating-panel">
|
||||
|
||||
<!-- Dropdown Selects -->
|
||||
<div class="ratings bg-light-subtle col">
|
||||
<h3 class="mb-3 row">Select Nature & Subskills</h3>
|
||||
|
||||
<!-- Nature -->
|
||||
<div class="d-flex justify-content-between align-items-center row">
|
||||
<div class="col">
|
||||
<label>Select Nature</label>
|
||||
<select class="form-control" @bind="SelectedNatureId">
|
||||
<option value="" disabled selected >Choose Nature...</option>
|
||||
@foreach (var nature in NatureList)
|
||||
{
|
||||
<option value="@nature.Id">@nature.Nature</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center col">
|
||||
<h4 class="mt-4">
|
||||
<span class="text-muted">@lastnaturescore</span>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subskill 1 -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 row">
|
||||
<div class="col">
|
||||
<label for="subskillSelect1">Select Level 10 Subskill</label>
|
||||
<select id="subskillSelect1" class="form-control" @bind="Subskill1">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center col">
|
||||
<h4 class="mt-4">
|
||||
<span class="text-muted">@lastS1score</span>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subskill 2 -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 row">
|
||||
<div class="col">
|
||||
<label for="subskillSelect2">Select Level 25 Subskill</label>
|
||||
<select id="subskillSelect2" class="form-control" @bind="Subskill2">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center col">
|
||||
<h4 class="mt-4">
|
||||
<span class="text-muted">@lastS2score</span>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subskill 3 -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 row">
|
||||
<div class="col">
|
||||
<label for="subskillSelect3">Select Level 50 Subskill</label>
|
||||
<select id="subskillSelect3" class="form-control" @bind="Subskill3">
|
||||
<option value="" selected disabled>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center col">
|
||||
<h4 class="mt-4">
|
||||
<span class="text-muted">@lastS3score</span>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subskill 4 Disabled -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 row">
|
||||
<div class="col">
|
||||
<label for="subskillSelect4">Select Level 75 Subskill</label>
|
||||
<select id="subskillSelect4" disabled class="form-control" @bind="Subskill4">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center col">
|
||||
<h4 class="mt-4">
|
||||
<span class="text-muted">0</span>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subskill 5 Disabled -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 row">
|
||||
<div class="col">
|
||||
<label for="subskillSelect5">Select Level 100 Subskill</label>
|
||||
<select id="subskillSelect5" disabled class="form-control mb-2" @bind="Subskill5">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center col">
|
||||
<h4 class="mt-4">
|
||||
<span class="text-muted">0</span>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<!-- Score Output -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 row">
|
||||
<h3 class="col">Final Score:</h3>
|
||||
<div class="p-2 rounded text-center col"
|
||||
style="background-color:@ScoreBackgroundColor; color:@ScoreColor; ">
|
||||
<h3>@FinalScore</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,156 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
using Portfolio.Domain.Features.Pokemon_Natures;
|
||||
using Portfolio.Domain.Features.Pokemon_Subskills;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
partial class PokemonRatingPanel
|
||||
{
|
||||
[Parameter] public Pokemon PokemonToRate { get; set; }
|
||||
[Parameter] public List<PokemonNature> NatureList { get; set; } = new();
|
||||
[Parameter] public List<PokemonSubskill> SubskillList { get; set; } = new();
|
||||
|
||||
private int SelectedNatureId;
|
||||
private int Subskill1;
|
||||
private int Subskill2;
|
||||
private int Subskill3;
|
||||
private int Subskill4;
|
||||
private int Subskill5;
|
||||
|
||||
private int FinalScore;
|
||||
private string ScoreBackgroundColor = "#FFFFFF";
|
||||
private string ScoreColor = "#000000";
|
||||
|
||||
|
||||
private int lastNatureId;
|
||||
private int lastS1, lastS2, lastS3;
|
||||
private int lastnaturescore, lastS1score, lastS2score, lastS3score;
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
// If last Nature or Subskill is different than previous
|
||||
if (PokemonToRate != null) {
|
||||
if (SelectedNatureId != lastNatureId)
|
||||
{
|
||||
lastNatureId = SelectedNatureId;
|
||||
var nature = NatureList.FirstOrDefault(n => n.Id == lastNatureId);
|
||||
lastnaturescore = PokemonToRate.Speciality switch
|
||||
{
|
||||
"Berries" => nature.BerryRating,
|
||||
"Ingredients" => nature.IngredientRating,
|
||||
"Skills" => nature.SkillRating,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
}
|
||||
if (Subskill1 != lastS1)
|
||||
{
|
||||
|
||||
lastS1 = Subskill1;
|
||||
var s1 = SubskillList.FirstOrDefault(s => s.Id == Subskill1);
|
||||
lastS1score = PokemonToRate.Speciality switch
|
||||
{
|
||||
"Berries" => s1.BerryRank,
|
||||
"Ingredients" => s1.IngredientRank,
|
||||
"Skills" => s1.SkillRank,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
}
|
||||
if (Subskill2 != lastS2)
|
||||
{
|
||||
|
||||
lastS2 = Subskill2;
|
||||
var s2 = SubskillList.FirstOrDefault(s => s.Id == Subskill2);
|
||||
lastS2score = PokemonToRate.Speciality switch
|
||||
{
|
||||
"Berries" => s2.BerryRank,
|
||||
"Ingredients" => s2.IngredientRank,
|
||||
"Skills" => s2.SkillRank,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (Subskill3 != lastS3)
|
||||
{
|
||||
lastS3 = Subskill3;
|
||||
var s3 = SubskillList.FirstOrDefault(s => s.Id == Subskill3);
|
||||
lastS3score = PokemonToRate.Speciality switch
|
||||
{
|
||||
"Berries" => s3.BerryRank,
|
||||
"Ingredients" => s3.IngredientRank,
|
||||
"Skills" => s3.SkillRank,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CalculateScore();
|
||||
StateHasChanged();
|
||||
|
||||
}
|
||||
|
||||
private void CalculateScore()
|
||||
{
|
||||
if (PokemonToRate == null || SelectedNatureId == 0 || lastS1 == 0 || lastS2 == 0 || lastS3 == 0)
|
||||
{
|
||||
|
||||
FinalScore = 0;
|
||||
ScoreBackgroundColor = "#FFFFFF";
|
||||
ScoreColor = "#000000";
|
||||
return;
|
||||
}
|
||||
|
||||
var nature = NatureList.FirstOrDefault(n => n.Id == SelectedNatureId);
|
||||
var s1 = SubskillList.FirstOrDefault(s => s.Id == Subskill1);
|
||||
var s2 = SubskillList.FirstOrDefault(s => s.Id == Subskill2);
|
||||
var s3 = SubskillList.FirstOrDefault(s => s.Id == Subskill3);
|
||||
|
||||
if (nature == null || s1 == null || s2 == null || s3 == null)
|
||||
{
|
||||
FinalScore = 0;
|
||||
ScoreBackgroundColor = "#FFFFFF";
|
||||
ScoreColor = "#000000";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FinalScore = PokemonToRate.Speciality switch
|
||||
{
|
||||
"Berries" => nature.BerryRating + s1.BerryRank + s2.BerryRank + s3.BerryRank,
|
||||
"Ingredients" => nature.IngredientRating + s1.IngredientRank + s2.IngredientRank + s3.IngredientRank,
|
||||
"Skills" => nature.SkillRating + s1.SkillRank + s2.SkillRank + s3.SkillRank,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
|
||||
// Set score background based on value
|
||||
ScoreBackgroundColor = FinalScore switch
|
||||
{
|
||||
8 => "#16C47F",
|
||||
7 => "#33CB8F",
|
||||
6 => "#50D39F",
|
||||
5 => "#6DDAAF",
|
||||
4 => "#8BE2BF",
|
||||
3 => "#A8E9CF",
|
||||
2 => "#C5F0DF",
|
||||
1 => "#E2F8EF",
|
||||
0 => "#FFFFFF",
|
||||
-1 => "#FFE7E7",
|
||||
-2 => "#FED0D0",
|
||||
-3 => "#FEB8B8",
|
||||
-4 => "#FDA0A0",
|
||||
-5 => "#FD8888",
|
||||
-6 => "#FC7171",
|
||||
-7 => "#FC5959",
|
||||
-8 => "#FB4141",
|
||||
_ => "#FFFFFF"
|
||||
};
|
||||
|
||||
ScoreColor = FinalScore == 0 ? "#000000" : "#FFFFFF";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
.pokemon-rating-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
|
||||
.ratings {
|
||||
flex: 2;
|
||||
padding: 1.5rem;
|
||||
border-radius: 5% / 3.5%;
|
||||
}
|
||||
|
||||
.select-width {
|
||||
width: 16rem;
|
||||
}
|
||||
|
||||
.score-width {
|
||||
width: 6rem;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.pokemon-rating-panel {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.ratings {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.d-flex.justify-content-between.align-items-center {
|
||||
flex-direction: column;
|
||||
align-items: stretch !important;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.select-width
|
||||
{
|
||||
width: 4rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.score-width h4 {
|
||||
margin-top: 0.5rem !important;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
<!-- Search Input -->
|
||||
<div class="pokemon-selector p-3 bg-light">
|
||||
<input class="form-control mb-3" placeholder="Search Pokémon..." @bind="SearchTerm" @oninput="HandleSearch" />
|
||||
|
||||
<!-- Scrollable Pokémon Grid -->
|
||||
<div class="row pokemon-grid">
|
||||
@foreach (var pokemon in FilteredPokemon)
|
||||
{
|
||||
bool isSelected = SelectedPokemon?.Id == pokemon.Id;
|
||||
|
||||
<div class="col-6 col-md-3 mb-3">
|
||||
<div class="card pokemon-card small-card @(isSelected ? "border-primary border-2 shadow" : "border-2 border-white")"
|
||||
@onclick="() => SelectPokemon(pokemon)">
|
||||
<img src="@pokemon.PokemonImageUrl" class="card-img-top" style="height: 50px; object-fit: contain;" />
|
||||
<div class="card-body p-2 text-center">
|
||||
<small>@pokemon.PokemonId</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,37 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
partial class PokemonSelector
|
||||
{
|
||||
|
||||
[Parameter]
|
||||
public List<Pokemon> PokemonList { get; set; } = new();
|
||||
|
||||
[Parameter]
|
||||
public Pokemon? SelectedPokemon { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<Pokemon> OnPokemonSelected { get; set; }
|
||||
|
||||
private string SearchTerm { get; set; } = string.Empty;
|
||||
|
||||
private List<Pokemon> FilteredPokemon =>
|
||||
string.IsNullOrWhiteSpace(SearchTerm)
|
||||
? PokemonList
|
||||
: PokemonList.Where(p =>
|
||||
p.PokemonName.Contains(SearchTerm, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
private async Task HandleSearch(ChangeEventArgs e)
|
||||
{
|
||||
SearchTerm = e?.Value?.ToString() ?? "";
|
||||
}
|
||||
|
||||
private async Task SelectPokemon(Pokemon pokemon)
|
||||
{
|
||||
await OnPokemonSelected.InvokeAsync(pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
.pokemon-selector {
|
||||
height: 70vh;
|
||||
width: 20vw;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5% / 3.5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.pokemon-grid {
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
.pokemon-card {
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.pokemon-card:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.small-card {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
@inject IPokemonService PokemonService
|
||||
@inject IJSRuntime JS
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<!-- Table A: Desktop View-->
|
||||
<div class="container d-none d-md-block " style="height: 70vh;">
|
||||
<!-- Main UI -->
|
||||
<div class="card shadow-sm border-0 mt-4 mx-auto col-12 col-md-10 col-lg-8 pokemontable">
|
||||
<!-- Table Header -->
|
||||
<div class="row card-header bg-secondary bg-gradient py-3 border-0">
|
||||
<div class="flex-row justify-content-between">
|
||||
<div class="text-center position-relative">
|
||||
<input class="form-control position-absolute top-0 start-0 border-0 w-25" placeholder="Search Pokémon..." @bind="SearchTerm" @oninput="HandleSearch" />
|
||||
|
||||
<h2 class="text-info text-decoration-underline">Available Pokémon</h2>
|
||||
<div class="m-1 badge bg-info position-absolute top-0 end-0 border-0"><p class="statText">@(pokemons.Count()) Pokémon</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="tableFixHead d-flex flex-column justify-content-start bg-secondary table-responsive row">
|
||||
<table class="table col table-borderless border-0 table-secondary table-striped align-middle">
|
||||
<!-- Table Head -->
|
||||
<thead class="">
|
||||
<tr class="">
|
||||
<th class="text-white text-bg-info col-2 d-none d-md-table-cell" scope="col"></th>
|
||||
<th class="text-white text-bg-info col-1" scope="col">#</th>
|
||||
<th class="text-white text-bg-info col-2" scope="col">Pokémon</th>
|
||||
<th class="text-white text-bg-info col-1 text-center" scope="col">Type</th>
|
||||
<th class="text-white text-bg-info col-2 text-center" scope="col">Sleep Type</th>
|
||||
<th class="text-white text-bg-info col-2 text-center" scope="col">Speciality</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- If/Else Pokemon Loaded-->
|
||||
@if(pokemons == null)
|
||||
{
|
||||
<tbody>
|
||||
<Loading />
|
||||
</tbody>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Table Body -->
|
||||
<tbody class="">
|
||||
<tr></tr>
|
||||
@if (FilteredPokemon != null && FilteredPokemon.Any())
|
||||
{
|
||||
|
||||
@foreach (var pokemon in FilteredPokemon)
|
||||
{
|
||||
<tr class="flex-row">
|
||||
<!-- Section: Pokemon Image -->
|
||||
@{
|
||||
string baseUrl = pokemon.PokemonImageUrl;
|
||||
string shinyUrl = pokemon.PokemonShinyImageUrl;
|
||||
}
|
||||
<td class="text-center d-none d-md-table-cell">
|
||||
@if (shinyUrl == null)
|
||||
{
|
||||
<div class="flip-container">
|
||||
<div class="flipper">
|
||||
<img class="front img-fluid" style="max-width: 100px;" src="@baseUrl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="flip-container" @onclick="() => ToggleImage(pokemon.Id)">
|
||||
<div class="flipper @(isShiny[pokemon.Id] ? "flipped" : "")">
|
||||
<img class="front img-fluid" style="max-width: 100px;" src="@baseUrl" />
|
||||
<img class="back img-fluid" style="max-width: 100px;" src="@shinyUrl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</td>
|
||||
|
||||
<!-- Section 2: Pokemon # -->
|
||||
<th class="" scope="row" style="cursor: default;">@pokemon.PokemonId</th>
|
||||
|
||||
|
||||
<!-- Section 3: Pokemon Name -->
|
||||
|
||||
<td @onclick="() => ViewPokemon(pokemon.PokemonId)" class="pokemon-name-style fw-light col-2">@(pokemon.IsVariation && ToggleVariationName(pokemon.Id, pokemon.PokemonId) ? $"{pokemon.VariationName} {pokemon.PokemonName}" : pokemon.PokemonName)</td>
|
||||
|
||||
|
||||
|
||||
<!-- Section 4: Pokemon Type -->
|
||||
<td class="">
|
||||
<div class="d-flex justify-content-center">
|
||||
<img src="@GetTypeImageUrl(pokemon.PokemonType)" style="width:36px; height:36px;" />
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Section 5: Sleep Type -->
|
||||
<td class="" style="">
|
||||
<div class="d-flex justify-content-center ">
|
||||
<PokemonBadge BadgeItem="@pokemon.SleepType" />
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Section 6: Speciality -->
|
||||
<td class="" style="">
|
||||
<div class="d-flex justify-content-center">
|
||||
<PokemonBadge BadgeItem="@pokemon.Speciality" />
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr>
|
||||
<td colspan="100%">
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 200px;">
|
||||
<p class="text-muted">Pokémon could not be found.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
}
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Desktop B: Mobile View -->
|
||||
<div class="container card border-0 d-block d-md-none mx-auto mt-4 shadow-sm">
|
||||
<!-- Table Header -->
|
||||
<div class="row card-header bg-secondary bg-gradient ml-0 py-3 border-0 bg-info">
|
||||
<div class="flex-row justify-content-between">
|
||||
<div class="text-center position-relative">
|
||||
<h2 class="text-white text-decoration-underline">Pokémon</h2>
|
||||
<div class="m-1 badge bg-white text-info position-absolute top-0 end-0 border-0 w-auto"><p class="statText">@(pokemons.Count()) Pokémon</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Table Body -->
|
||||
<div class="tableFixHead row">
|
||||
<table class="table table-striped border-0">
|
||||
|
||||
|
||||
<tbody>
|
||||
@if (pokemons == null)
|
||||
{
|
||||
<Loading />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@foreach (var pokemon in pokemons)
|
||||
{
|
||||
<tr class="border-0">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<!-- Pokemon Image -->
|
||||
<div class="me-3">
|
||||
<div class="flip-container-sm" @onclick="() => ToggleImage(pokemon.Id)">
|
||||
<div class="flipper-sm @(isShiny[pokemon.Id] ? "flipped" : "")">
|
||||
<img class="front img-fluid" src="@pokemon.PokemonImageUrl" />
|
||||
@if (pokemon.PokemonShinyImageUrl != null)
|
||||
{
|
||||
<img class="back img-fluid" src="@pokemon.PokemonShinyImageUrl" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<!-- Number and Name -->
|
||||
<h5>
|
||||
@pokemon.PokemonId -
|
||||
<span class="pokemon-name-style fw-light" @onclick="() => ViewPokemon(pokemon.PokemonId)">
|
||||
@(pokemon.IsVariation && ToggleVariationName(pokemon.Id, pokemon.PokemonId) ? $"{pokemon.VariationName} {pokemon.PokemonName}" : pokemon.PokemonName)
|
||||
</span>
|
||||
</h5>
|
||||
<!-- Stats -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2">
|
||||
<img src="@GetTypeImageUrl(pokemon.PokemonType)" style="width:28px;" />
|
||||
<PokemonBadge BadgeItem="@pokemon.SleepType" />
|
||||
<PokemonBadge BadgeItem="@pokemon.Speciality" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
|
@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
|||
using Microsoft.JSInterop;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component
|
||||
namespace Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
{
|
||||
public partial class PokemonTable
|
||||
{
|
||||
|
@ -25,7 +25,18 @@ namespace Portfolio.WebUI.Server.Components.Component
|
|||
}
|
||||
}
|
||||
}
|
||||
private string SearchTerm { get; set; } = string.Empty;
|
||||
|
||||
private List<Pokemon> FilteredPokemon =>
|
||||
string.IsNullOrWhiteSpace(SearchTerm)
|
||||
? AllPokemon
|
||||
: AllPokemon.Where(p =>
|
||||
p.PokemonName.Contains(SearchTerm, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
private async Task HandleSearch(ChangeEventArgs e)
|
||||
{
|
||||
SearchTerm = e?.Value?.ToString() ?? "";
|
||||
}
|
||||
private void ToggleImage(int Id)
|
||||
{
|
||||
if (isShiny.ContainsKey(Id))
|
||||
|
@ -34,6 +45,18 @@ namespace Portfolio.WebUI.Server.Components.Component
|
|||
}
|
||||
}
|
||||
|
||||
private bool ToggleVariationName(int Id, int PokemonId)
|
||||
{
|
||||
foreach (var pokemon in pokemons)
|
||||
{
|
||||
if (pokemon.PokemonId == PokemonId && pokemon.Id != Id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task ConfirmDelete(int Id)
|
||||
{
|
||||
bool confirm = await JS.InvokeAsync<bool>("confirm", "Are you sure you want to delete this Pokémon?");
|
||||
|
@ -54,5 +77,21 @@ namespace Portfolio.WebUI.Server.Components.Component
|
|||
{
|
||||
Navigation.NavigateTo($"/pokemonsleep/edit/{id}");
|
||||
}
|
||||
|
||||
private void ViewPokemon(int id)
|
||||
{
|
||||
Navigation.NavigateTo($"/pokemon/{id}");
|
||||
}
|
||||
|
||||
private string GetTypeImageUrl(string pokemonType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pokemonType))
|
||||
{
|
||||
return "https://www.serebii.net/pokemonsleep/pokemon/type/normal.png"; // Fallback image
|
||||
}
|
||||
|
||||
return $"https://www.serebii.net/pokemonsleep/pokemon/type/{pokemonType.ToLower()}.png";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,14 @@
|
|||
|
||||
.five-percent {
|
||||
width: 5%;
|
||||
}
|
||||
.ten-percent {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.pokemontable {
|
||||
height: 69vh;
|
||||
}
|
||||
|
||||
.tableFixHead {
|
||||
overflow: auto;
|
||||
height: 600px;
|
||||
|
@ -10,6 +20,16 @@
|
|||
z-index: 10;
|
||||
}
|
||||
|
||||
.align-top-tbody {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.pokemon-name-style {
|
||||
cursor:pointer;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
|
||||
.flip-container {
|
||||
perspective: 1000px;
|
||||
display: inline-block;
|
||||
|
@ -30,6 +50,43 @@
|
|||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
|
||||
.flip-container-sm {
|
||||
perspective: 1000px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.flipper-sm {
|
||||
transition: 0.6s;
|
||||
transform-style: preserve-3d;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flipper-sm img {
|
||||
backface-visibility: hidden;
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.flipper-sm .front {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.flipper-sm .back {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.flipper-sm.flipped {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.fixed-row-height {
|
||||
height: 90px; /* or any height that suits your card style */
|
||||
}
|
||||
|
||||
|
||||
.pokeimage {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -51,6 +108,8 @@
|
|||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.badge {
|
||||
width: 100px;
|
||||
height: 30px;
|
||||
|
@ -67,30 +126,8 @@
|
|||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.dozing {
|
||||
background-color: #fcdc5e;
|
||||
}
|
||||
|
||||
.snoozing {
|
||||
background-color: #4ce8ed;
|
||||
}
|
||||
|
||||
.slumbering {
|
||||
background-color: #4588fb;
|
||||
}
|
||||
|
||||
.berries {
|
||||
background-color: #24d86b;
|
||||
}
|
||||
|
||||
.ingredients {
|
||||
background-color: #fdbe4d;
|
||||
}
|
||||
|
||||
.skills {
|
||||
background-color: #47a0fc;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Component
|
||||
{
|
||||
public partial class PokemonBackground
|
||||
{
|
||||
|
||||
private class PokemonImage
|
||||
{
|
||||
public string Url { get; set; } = "";
|
||||
public int Left { get; set; }
|
||||
public int Top { get; set; }
|
||||
public int Size { get; set; }
|
||||
public int Rotation { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[Parameter]
|
||||
public List<string> PokemonImages { get; set; }
|
||||
[Parameter]
|
||||
public List<string> ShinyPokemonImages { get; set; }
|
||||
|
||||
private List<PokemonImage> _pokemonImages = new List<PokemonImage>();
|
||||
private List<PokemonImage> _shinyPokemonImages = new List<PokemonImage>();
|
||||
private Random random = new Random();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadPokemonBackgrounds();
|
||||
}
|
||||
|
||||
private async Task LoadPokemonBackgrounds()
|
||||
{
|
||||
|
||||
foreach (var pokemonimgurl in PokemonImages)
|
||||
{
|
||||
Console.WriteLine(pokemonimgurl);
|
||||
_pokemonImages.Add(new PokemonImage
|
||||
{
|
||||
Url = pokemonimgurl, // URL retrieved from the database
|
||||
Left = random.Next(0, 100),
|
||||
Top = random.Next(0, 100),
|
||||
Size = random.Next(50, 130),
|
||||
Rotation = random.Next(0, 360)
|
||||
});
|
||||
}
|
||||
foreach (var pokemonimgurl in ShinyPokemonImages)
|
||||
{
|
||||
_shinyPokemonImages.Add(new PokemonImage
|
||||
{
|
||||
Url = pokemonimgurl, // URL retrieved from the database
|
||||
Left = random.Next(0, 100),
|
||||
Top = random.Next(0, 100),
|
||||
Size = random.Next(50, 130),
|
||||
Rotation = random.Next(0, 360)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
<!-- Heading + Buttons -->
|
||||
<div class="top-row row w-100 mx-0 bg-secondary py-3">
|
||||
|
||||
<div class="col-4"></div>
|
||||
|
||||
<div class="col-4 text-center">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<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>
|
||||
</NavLink>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -1,131 +0,0 @@
|
|||
@inject IPokemonService PokemonService
|
||||
@inject IJSRuntime JS
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<!-- Main Body -->
|
||||
@if (pokemons == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Main UI -->
|
||||
<div class="card shadow border-0 mt-4 m-auto w-50">
|
||||
|
||||
<!-- Table Header -->
|
||||
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center position-relative">
|
||||
<h2 class="text-info">Available Pokémon</h2>
|
||||
<div class="m-1 col-1 badge bg-info position-absolute top-0 end-0"><p class="statText">@(pokemons.Count()) Pokemon</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="tableFixHead">
|
||||
<table class="table table-striped">
|
||||
|
||||
<!-- Table Head -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-bg-info" scope="col"></th>
|
||||
<th class="text-bg-info" scope="col">#</th>
|
||||
<th class="text-bg-info" scope="col">Pokemon</th>
|
||||
<th class="text-bg-info" scope="col">Sleep Type</th>
|
||||
<th class="text-bg-info" scope="col">Speciality</th>
|
||||
<th class="text-bg-info" scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<!-- Table Body -->
|
||||
<tbody>
|
||||
@foreach (var pokemon in pokemons)
|
||||
{
|
||||
<tr>
|
||||
|
||||
<!-- Section: Pokemon Image -->
|
||||
@{
|
||||
string baseUrl = pokemon.PokemonImageUrl;
|
||||
string shinyUrl = pokemon.PokemonShinyImageUrl;
|
||||
}
|
||||
<td style="text-align: center;">
|
||||
@if(shinyUrl == null){
|
||||
<div class="flip-container">
|
||||
<div class="flipper">
|
||||
<img class="front" src="@baseUrl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="flip-container" @onclick="() => ToggleImage(pokemon.Id)">
|
||||
<div class="flipper @(isShiny[pokemon.Id] ? "flipped" : "")">
|
||||
<img class="front" src="@baseUrl" />
|
||||
<img class="back" src="@shinyUrl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</td>
|
||||
|
||||
<!-- Section 2: Pokemon # -->
|
||||
<th scope="row">@pokemon.PokemonId</th>
|
||||
|
||||
<!-- Section 3: Pokemon Name -->
|
||||
@if (pokemon.IsVariation) // If a Variant
|
||||
{
|
||||
@if (pokemon.VariationName == "Alolan")
|
||||
{
|
||||
<td style="vertical-align: auto;"> Alolan @pokemon.PokemonName</td>
|
||||
}
|
||||
@if (pokemon.VariationName == "Paldean")
|
||||
{
|
||||
<td style="vertical-align: auto;"> Paldean @pokemon.PokemonName</td>
|
||||
}
|
||||
}
|
||||
else // Otherwise, Base Case
|
||||
{
|
||||
<td style="vertical-align: auto;"> @pokemon.PokemonName</td>
|
||||
}
|
||||
|
||||
<!-- Section 4: Sleep Type -->
|
||||
<td style="vertical-align: auto;">
|
||||
<div class="m-1 col-1 badge @pokemon.SleepType.ToLower()"><p class="statText">@pokemon.SleepType</p></div>
|
||||
</td>
|
||||
|
||||
<!-- Section 5: Speciality -->
|
||||
<td style="padding-right: 30px; vertical-align: auto;">
|
||||
<div class="m-1 col-1 badge @pokemon.Speciality.ToLower()"><p class="statText">@pokemon.Speciality</p></div>
|
||||
</td>
|
||||
|
||||
<!-- Section 6: Functional Buttons -->
|
||||
<td>
|
||||
<button class="btn btn-warning" @onclick="() => EditPokemon(pokemon.Id)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.5.5 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="btn btn-danger" @onclick="() => ConfirmDelete(pokemon.Id)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-trash" viewBox="0 0 16 16">
|
||||
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z" />
|
||||
<path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<div class="position-absolute bottom-0 vw-100">
|
||||
<footer class="d-flex flex-column align-content-center">
|
||||
<hr class="border-bottom border-primary border-1 mx-5">
|
||||
<p class="text-center text-primary">
|
||||
Made with Love
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-through-heart" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M2.854 15.854A.5.5 0 0 1 2 15.5V14H.5a.5.5 0 0 1-.354-.854l1.5-1.5A.5.5 0 0 1 2 11.5h1.793l.53-.53c-.771-.802-1.328-1.58-1.704-2.32-.798-1.575-.775-2.996-.213-4.092C3.426 2.565 6.18 1.809 8 3.233c1.25-.98 2.944-.928 4.212-.152L13.292 2 12.147.854A.5.5 0 0 1 12.5 0h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-.854.354L14 2.707l-1.006 1.006c.236.248.44.531.6.845.562 1.096.585 2.517-.213 4.092-.793 1.563-2.395 3.288-5.105 5.08L8 13.912l-.276-.182a22 22 0 0 1-2.685-2.062l-.539.54V14a.5.5 0 0 1-.146.354zm2.893-4.894A20.4 20.4 0 0 0 8 12.71c2.456-1.666 3.827-3.207 4.489-4.512.679-1.34.607-2.42.215-3.185-.817-1.595-3.087-2.054-4.346-.761L8 4.62l-.358-.368c-1.259-1.293-3.53-.834-4.346.761-.392.766-.464 1.845.215 3.185.323.636.815 1.33 1.519 2.065l1.866-1.867a.5.5 0 1 1 .708.708z" />
|
||||
</svg>
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
|
@ -1,12 +1,13 @@
|
|||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="page" >
|
||||
|
||||
<Sidebar/>
|
||||
|
||||
<main class="bg-primary-subtle">
|
||||
<article class="content px-4">
|
||||
<div class="page bg-primary-subtle h-100">
|
||||
<main class="h-100 w-100">
|
||||
<NavMenu3 />
|
||||
<article class="container m-auto">
|
||||
<div class="">
|
||||
@Body
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
@* <MadeWithLoveFooter/> *@
|
||||
</div>
|
||||
|
|
|
@ -1,45 +1,35 @@
|
|||
<div class="navbar navbar-expand-lg navbar-light bg-info justify-content-md-center" id="navbarsExample08">
|
||||
<div class="navbar navbar-expand bg-primary border-0">
|
||||
<div class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-light text-decoration-none px-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#FFFFFF" class="bi bi-arrow-through-heart" viewBox="0 0 16 16" style="cursor: pointer;">
|
||||
<path fill-rule="evenodd" d="M2.854 15.854A.5.5 0 0 1 2 15.5V14H.5a.5.5 0 0 1-.354-.854l1.5-1.5A.5.5 0 0 1 2 11.5h1.793l.53-.53c-.771-.802-1.328-1.58-1.704-2.32-.798-1.575-.775-2.996-.213-4.092C3.426 2.565 6.18 1.809 8 3.233c1.25-.98 2.944-.928 4.212-.152L13.292 2 12.147.854A.5.5 0 0 1 12.5 0h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-.854.354L14 2.707l-1.006 1.006c.236.248.44.531.6.845.562 1.096.585 2.517-.213 4.092-.793 1.563-2.395 3.288-5.105 5.08L8 13.912l-.276-.182a22 22 0 0 1-2.685-2.062l-.539.54V14a.5.5 0 0 1-.146.354zm2.893-4.894A20.4 20.4 0 0 0 8 12.71c2.456-1.666 3.827-3.207 4.489-4.512.679-1.34.607-2.42.215-3.185-.817-1.595-3.087-2.054-4.346-.761L8 4.62l-.358-.368c-1.259-1.293-3.53-.834-4.346.761-.392.766-.464 1.845.215 3.185.323.636.815 1.33 1.519 2.065l1.866-1.867a.5.5 0 1 1 .708.708z" />
|
||||
</svg>
|
||||
<span class="fs-4 mx-1 text-white">Kira Jiroux</span>
|
||||
</div>
|
||||
<ul class="navbar-nav">
|
||||
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Kira Jiroux
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-house-heart-fill mb-1" viewBox="0 0 16 16">
|
||||
<path d="M7.293 1.5a1 1 0 0 1 1.414 0L11 3.793V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v3.293l2.354 2.353a.5.5 0 0 1-.708.707L8 2.207 1.354 8.853a.5.5 0 1 1-.708-.707z" />
|
||||
<path d="m14 9.293-6-6-6 6V13.5A1.5 1.5 0 0 0 3.5 15h9a1.5 1.5 0 0 0 1.5-1.5zm-6-.811c1.664-1.673 5.825 1.254 0 5.018-5.825-3.764-1.664-6.691 0-5.018" />
|
||||
</svg> <span class="mx-2 mt-0">Home</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="articles">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-richtext" viewBox="0 0 16 16">
|
||||
<path d="M7.5 3.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m-.861 1.542 1.33.886 1.854-1.855a.25.25 0 0 1 .289-.047L11 4.75V7a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 7v-.5s1.54-1.274 1.639-1.208M5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5" />
|
||||
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2" />
|
||||
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z" />
|
||||
</svg> Articles
|
||||
<li>
|
||||
<NavLink class="nav-link" href="temperature-blanket">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-border-outer" viewBox="0 0 16 16">
|
||||
<path d="M7.5 1.906v.938h1v-.938zm0 1.875v.938h1V3.78h-1zm0 1.875v.938h1v-.938zM1.906 8.5h.938v-1h-.938zm1.875 0h.938v-1H3.78v1zm1.875 0h.938v-1h-.938zm2.813 0v-.031H8.5V7.53h-.031V7.5H7.53v.031H7.5v.938h.031V8.5zm.937 0h.938v-1h-.938zm1.875 0h.938v-1h-.938zm1.875 0h.938v-1h-.938zM7.5 9.406v.938h1v-.938zm0 1.875v.938h1v-.938zm0 1.875v.938h1v-.938z" />
|
||||
<path d="M0 0v16h16V0zm1 1h14v14H1z" />
|
||||
</svg><span class="mx-2 mt-0">Crochet</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<li>
|
||||
<NavLink class="nav-link" href="pokemonsleep">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-p-circle-fill" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.5 4.002V12h1.283V9.164h1.668C10.033 9.164 11 8.08 11 6.586c0-1.482-.955-2.584-2.538-2.584zm2.77 4.072c.893 0 1.419-.545 1.419-1.488s-.526-1.482-1.42-1.482H6.778v2.97z" />
|
||||
</svg> Pokemon Sleep
|
||||
</svg> <span class="mx-2 mt-0">Pokémon Sleep</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown08" data-bs-toggle="dropdown" aria-expanded="false">Pokemon Sleep</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdown08">
|
||||
<li>
|
||||
<NavLink class="nav-link" href="pokemonsleep/add-new-pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-p-circle-fill" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.5 4.002V12h1.283V9.164h1.668C10.033 9.164 11 8.08 11 6.586c0-1.482-.955-2.584-2.538-2.584zm2.77 4.072c.893 0 1.419-.545 1.419-1.488s-.526-1.482-1.42-1.482H6.778v2.97z" />
|
||||
</svg> Pokemon Sleep
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink class="nav-link" href="pokemonsleep/rate-pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-p-circle-fill" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.5 4.002V12h1.283V9.164h1.668C10.033 9.164 11 8.08 11 6.586c0-1.482-.955-2.584-2.538-2.584zm2.77 4.072c.893 0 1.419-.545 1.419-1.488s-.526-1.482-1.42-1.482H6.778v2.97z" />
|
||||
</svg> Pokemon Sleep
|
||||
</NavLink>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="#">Something else here</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
|
@ -1,10 +1,12 @@
|
|||
<div class="d-flex flex-column flex-shrink-0 p-3 bg-info vh-100" style="width: 280px; ">
|
||||
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-primary text-decoration-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-arrow-through-heart" viewBox="0 0 16 16">
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<div class="d-flex flex-column flex-shrink-0 p-3 bg-info vh-100 sidebar @(isSidebarOpen ? "open" : "closed") " style="transition: width 0.3s;">
|
||||
<div class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-primary text-decoration-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-arrow-through-heart" viewBox="0 0 16 16" @onclick="ToggleSidebar" style="cursor: pointer;">
|
||||
<path fill-rule="evenodd" d="M2.854 15.854A.5.5 0 0 1 2 15.5V14H.5a.5.5 0 0 1-.354-.854l1.5-1.5A.5.5 0 0 1 2 11.5h1.793l.53-.53c-.771-.802-1.328-1.58-1.704-2.32-.798-1.575-.775-2.996-.213-4.092C3.426 2.565 6.18 1.809 8 3.233c1.25-.98 2.944-.928 4.212-.152L13.292 2 12.147.854A.5.5 0 0 1 12.5 0h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-.854.354L14 2.707l-1.006 1.006c.236.248.44.531.6.845.562 1.096.585 2.517-.213 4.092-.793 1.563-2.395 3.288-5.105 5.08L8 13.912l-.276-.182a22 22 0 0 1-2.685-2.062l-.539.54V14a.5.5 0 0 1-.146.354zm2.893-4.894A20.4 20.4 0 0 0 8 12.71c2.456-1.666 3.827-3.207 4.489-4.512.679-1.34.607-2.42.215-3.185-.817-1.595-3.087-2.054-4.346-.761L8 4.62l-.358-.368c-1.259-1.293-3.53-.834-4.346.761-.392.766-.464 1.845.215 3.185.323.636.815 1.33 1.519 2.065l1.866-1.867a.5.5 0 1 1 .708.708z" />
|
||||
</svg>
|
||||
<span class="fs-4 mx-2">Kira Jiroux</span>
|
||||
</a>
|
||||
</div>
|
||||
<hr>
|
||||
<ul class="nav nav-pills flex-column mb-auto">
|
||||
<li class="nav-item">
|
||||
|
@ -24,6 +26,14 @@
|
|||
</svg> <span class="mx-2 mt-0">Articles</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink class="nav-link" href="temperature-blanket">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-border-outer" viewBox="0 0 16 16">
|
||||
<path d="M7.5 1.906v.938h1v-.938zm0 1.875v.938h1V3.78h-1zm0 1.875v.938h1v-.938zM1.906 8.5h.938v-1h-.938zm1.875 0h.938v-1H3.78v1zm1.875 0h.938v-1h-.938zm2.813 0v-.031H8.5V7.53h-.031V7.5H7.53v.031H7.5v.938h.031V8.5zm.937 0h.938v-1h-.938zm1.875 0h.938v-1h-.938zm1.875 0h.938v-1h-.938zM7.5 9.406v.938h1v-.938zm0 1.875v.938h1v-.938zm0 1.875v.938h1v-.938z" />
|
||||
<path d="M0 0v16h16V0zm1 1h14v14H1z" />
|
||||
</svg><span class="mx-2 mt-0">Crochet</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink class="nav-link" href="pokemonsleep">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-p-circle-fill" viewBox="0 0 16 16">
|
||||
|
@ -44,3 +54,15 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@code {
|
||||
private bool isSidebarOpen = true;
|
||||
|
||||
private async void ToggleSidebar()
|
||||
{
|
||||
isSidebarOpen = !isSidebarOpen;
|
||||
await JS.InvokeVoidAsync("console.log", $"Sidebar toggled: {isSidebarOpen}");
|
||||
StateHasChanged(); // Force the UI to update
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
.sidebar.closed {
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar.open {
|
||||
width: 256px;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
@page "/temperature-blanket"
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Crochet Tools</PageTitle>
|
||||
<head>
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-cosmo.css" /> <!-- app.css -->
|
||||
</head>
|
||||
|
||||
<h3 class="text-xl font-bold mb-4">Crochet</h3>
|
||||
<div class="">
|
||||
<TemperatureBlanketVisualizer TemperatureDays="temperatureDays" />
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.TemperatureDay;
|
||||
using Portfolio.Domain.Features.TemperatureRange;
|
||||
using Portfolio.WebUI.Server.Components.Component.Crochet_Components;
|
||||
using static Portfolio.WebUI.Server.Components.Component.Crochet_Components.TemperatureRangeEditor;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Crochet_Pages
|
||||
{
|
||||
public partial class CrochetHome
|
||||
{
|
||||
public List<TemperatureDay> temperatureDays { get; set; }
|
||||
public int YEAR = 2025;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Placeholder for loading temperature data
|
||||
// Replace with actual API call
|
||||
//temperatureDays = Enumerable.Range(0, 365).Select(i => new TemperatureDay
|
||||
//{
|
||||
// Date = new DateTime(DateTime.Now.Year - 1, 1, 1).AddDays(i),
|
||||
// AvgTemp = Random.Shared.Next(10, 95)
|
||||
//}).ToList();
|
||||
|
||||
temperatureDays = GenerateRealisticTemperatureDays(YEAR);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static List<TemperatureDay> GenerateRealisticTemperatureDays(int year)
|
||||
{
|
||||
var temperatureDays = new List<TemperatureDay>();
|
||||
var startDate = new DateTime(year, 1, 1);
|
||||
int daysInYear = DateTime.IsLeapYear(year) ? 366 : 365;
|
||||
|
||||
// Adjusted parameters for desired range
|
||||
double minAvgTemp = 20.0;
|
||||
double maxAvgTemp = 84.0;
|
||||
double amplitude = (maxAvgTemp - minAvgTemp) / 2.0; // 32.5
|
||||
double avgAnnualTemp = (maxAvgTemp + minAvgTemp) / 2.0; // 52.5
|
||||
double noiseMax = 3.0; // Small daily variation
|
||||
|
||||
for (int i = 0; i < daysInYear; i++)
|
||||
{
|
||||
var date = startDate.AddDays(i);
|
||||
double dayOfYearRatio = (2 * Math.PI * i) / daysInYear;
|
||||
|
||||
// Peak is mid-summer, trough is mid-winter
|
||||
double seasonalTemp = avgAnnualTemp + amplitude * Math.Sin(dayOfYearRatio - Math.PI / 2);
|
||||
|
||||
// Add gentle noise
|
||||
double dailyNoise = Random.Shared.NextDouble() * noiseMax * 2 - noiseMax;
|
||||
|
||||
// Final temperature, clamped to min/max
|
||||
double finalTemp = Math.Round(seasonalTemp + dailyNoise, 1);
|
||||
finalTemp = Math.Clamp(finalTemp, minAvgTemp, maxAvgTemp);
|
||||
|
||||
temperatureDays.Add(new TemperatureDay
|
||||
{
|
||||
Date = date,
|
||||
AvgTemp = finalTemp
|
||||
});
|
||||
}
|
||||
|
||||
return temperatureDays;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
@* @page "/import-temperature-data"
|
||||
|
||||
@inject NWSWeatherService WeatherService
|
||||
@inject IWebHostEnvironment Env
|
||||
|
||||
<h3>Import Temperature Data</h3>
|
||||
|
||||
@if (IsImporting)
|
||||
{
|
||||
<p>Importing temperatures... Please wait...</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-primary" @onclick="ImportAndSaveYearAsync">Import 2024 Data</button>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(Message))
|
||||
{
|
||||
<p>@Message</p>
|
||||
}
|
||||
|
||||
|
||||
|
||||
*@
|
|
@ -0,0 +1,69 @@
|
|||
using Portfolio.Application.Services.NWSWeatherService;
|
||||
using Portfolio.Domain.Features.TemperatureDay;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Crochet_Pages
|
||||
{
|
||||
public partial class TemperatureDataImporter
|
||||
{
|
||||
private readonly NWSWeatherService _weatherService;
|
||||
private readonly string _storagePath = "Data/temperature_data_2024.json"; // changeable if needed
|
||||
|
||||
public bool IsImporting = true;
|
||||
|
||||
public TemperatureDataImporter(NWSWeatherService weatherService)
|
||||
{
|
||||
_weatherService = weatherService;
|
||||
}
|
||||
|
||||
public async Task<List<TemperatureDay>> ImportAndSaveYearAsync(int year, double latitude, double longitude)
|
||||
{
|
||||
var days = new List<TemperatureDay>();
|
||||
|
||||
var stationId = await _weatherService.GetNearestStationAsync(latitude, longitude);
|
||||
if (stationId == null)
|
||||
{
|
||||
throw new Exception("Failed to find nearest station.");
|
||||
}
|
||||
|
||||
var startDate = new DateTime(year, 1, 1);
|
||||
var endDate = new DateTime(year, 12, 31);
|
||||
|
||||
for (var date = startDate; date <= endDate; date = date.AddDays(1))
|
||||
{
|
||||
var avgTemp = await _weatherService.GetDailyAverageTempAsync(stationId, date);
|
||||
if (avgTemp.HasValue)
|
||||
{
|
||||
days.Add(new TemperatureDay { Date = date, AvgTemp = avgTemp.Value });
|
||||
}
|
||||
|
||||
await Task.Delay(600); // Respectful API use
|
||||
}
|
||||
|
||||
await SaveToFileAsync(days);
|
||||
|
||||
return days;
|
||||
}
|
||||
|
||||
private async Task SaveToFileAsync(List<TemperatureDay> days)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_storagePath)!);
|
||||
|
||||
var json = JsonSerializer.Serialize(days, new JsonSerializerOptions { WriteIndented = true });
|
||||
await File.WriteAllTextAsync(_storagePath, json);
|
||||
|
||||
Console.WriteLine($"✅ Saved {days.Count} days to {_storagePath}");
|
||||
}
|
||||
|
||||
public async Task<List<TemperatureDay>> LoadSavedDataAsync()
|
||||
{
|
||||
if (!File.Exists(_storagePath))
|
||||
throw new FileNotFoundException($"No saved temperature data found at {_storagePath}");
|
||||
|
||||
var json = await File.ReadAllTextAsync(_storagePath);
|
||||
var days = JsonSerializer.Deserialize<List<TemperatureDay>>(json);
|
||||
|
||||
return days ?? new List<TemperatureDay>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,3 +7,8 @@
|
|||
<p>Ensuring that git is connected properly.</p>
|
||||
|
||||
Welcome to your new app.
|
||||
|
||||
|
||||
<div class="w-75 h-100 bg-white">
|
||||
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
@page "/pokemonsleep/add-new-pokemon"
|
||||
|
||||
@inject IPokemonService PokemonService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<PageTitle>Add New Pokémon</PageTitle>
|
||||
<PokemonHeader />
|
||||
|
||||
|
||||
@if (isSubmitting)
|
||||
{
|
||||
<p><em>Submitting...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="w-50 mt-5 m-auto create-container bg-info">
|
||||
|
||||
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<h2 class="text-info">Add New Pokémon</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container m-lg-1" >
|
||||
<EditForm class=" col mb-3" Model="NewPokemon" OnValidSubmit="HandleSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<!-- Section 1 -->
|
||||
<div class="row mt-3">
|
||||
<div class="col-sm-3 input-group mb-3 ">
|
||||
<!-- Pokemon #-->
|
||||
<span for="PokemonId" class="input-group-text">#</span>
|
||||
<InputNumber min="0" placeholder="Pokedex #" id="PokemonId" @bind-Value="NewPokemon.PokemonId" class="form-control " required />
|
||||
<!-- Pokemon Name-->
|
||||
<InputText placeholder="Pokemon Name" id="PokemonName" @bind-Value="NewPokemon.PokemonName" class="form-control w-75" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pokemon Type, Sleep Type, and Speciality -->
|
||||
<div class="row">
|
||||
<!-- Pokemon Type -->
|
||||
<div class="col mb-3 m-auto">
|
||||
<label for="PokemonType" class="form-label">Pokemon Type</label>
|
||||
<InputSelect id="PokemonType" @bind-Value="NewPokemon.PokemonType" class="form-select">
|
||||
<option dsabled value="">Select Type</option>
|
||||
<option value="Grass">Grass</option>
|
||||
<option value="Fire">Fire</option>
|
||||
<option value="Water">Water</option>
|
||||
<option value="Normal">Normal</option>
|
||||
<option value="Flying">Flying</option>
|
||||
<option value="Bug">Bug</option>
|
||||
<option value="Poison">Poison</option>
|
||||
<option value="Electric">Electric</option>
|
||||
<option value="Ground">Ground</option>
|
||||
<option value="Rock">Rock</option>
|
||||
<option value="Ice">Ice</option>
|
||||
<option value="Steel">Steel</option>
|
||||
<option value="Fighting">Fighting</option>
|
||||
<option value="Psychic">Psychic</option>
|
||||
<option value="Dark">Dark</option>
|
||||
<option value="Fairy">Fairy</option>
|
||||
<option value="Ghost">Ghost</option>
|
||||
<option value="Dragon">Dragon</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<!-- Sleep Type -->
|
||||
<div class="col mb-3 m-auto">
|
||||
<label for="SleepType" class="form-label">Sleep Type</label>
|
||||
<InputSelect id="SleepType" @bind-Value="NewPokemon.SleepType" class="form-select">
|
||||
<option value="Dozing">Dozing</option>
|
||||
<option value="Snoozing">Snoozing</option>
|
||||
<option value="Slumbering">Slumbering</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<!-- Speciality-->
|
||||
<div class="col mb-3 m-auto">
|
||||
<label for="Speciality" class="form-label">Specialty</label>
|
||||
<InputSelect id="Speciality" @bind-Value="NewPokemon.Speciality" class="form-select">
|
||||
<option value="Berries">Berries</option>
|
||||
<option value="Ingredients">Ingredients</option>
|
||||
<option value="Skills">Skills</option>
|
||||
<option value="All">All</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section 2 -->
|
||||
<div class="row">
|
||||
<div class="input-group mb-3">
|
||||
<!-- Variation Check -->
|
||||
<div class=" d-inline-flex">
|
||||
<InputCheckbox id="IsVariation" @bind-Value="NewPokemon.IsVariation" @onclick="@Toggle" class="form-check-input checkbox-styling p-3 mt-1" />
|
||||
<span for="IsVariation" class="input-group-text m-1">Variation?</span>
|
||||
</div>
|
||||
|
||||
<!-- Variation Region Input -->
|
||||
<div class="w-75 mx-2 mt-1">
|
||||
|
||||
<InputText placeholder="What Variant? (Alolan, Paldean)" hidden="@HideLabel" id="VariationName" @bind-Value="NewPokemon.VariationName" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- New Image URL Field -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Base Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="NewPokemon.PokemonImageUrl" class="form-control" />
|
||||
</div>
|
||||
<!-- Shiny Image URL Input -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Shiny Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="NewPokemon.PokemonShinyImageUrl" class="form-control" />
|
||||
</div>
|
||||
|
||||
<!-- Flavor Text Input -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="FlavorText" class="form-label">Flavor Text</label>
|
||||
<InputText id="FlavorText" @bind-Value="NewPokemon.FlavorText" class="form-control" />
|
||||
</div>
|
||||
|
||||
<!-- Form Buttons -->
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary mb-3" @onclick="Cancel">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary mb-3">Add Pokemon</button>
|
||||
</div>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Pokemon_Pages
|
||||
{
|
||||
public partial class PokemonCreate
|
||||
{
|
||||
|
@ -32,13 +32,13 @@ namespace Portfolio.WebUI.Server.Components.Pages
|
|||
isSubmitting = true;
|
||||
await PokemonService.AddPokemonAsync(NewPokemon);
|
||||
isSubmitting = false;
|
||||
Navigation.NavigateTo("/pokemonsleep");
|
||||
Navigation.NavigateTo("/pokemon");
|
||||
}
|
||||
|
||||
protected void Cancel(MouseEventArgs e)
|
||||
{
|
||||
Console.WriteLine("Testing in Cancel");
|
||||
Navigation.NavigateTo("/pokemonsleep");
|
||||
Navigation.NavigateTo("/pokemon");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
@page "/pokemonsleep/edit/{id:int}"
|
||||
@inject IPokemonService PokemonService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Edit Pokémon</PageTitle>
|
||||
<PokemonHeader />
|
||||
<head>
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-lumen.css" /> <!-- app.css -->
|
||||
</head>
|
||||
|
||||
@if (pokemon == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Total Componenet-->
|
||||
<div class="w-50 mt-3 m-auto bg-info edit-container">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="card-header bg-secondary ml-0 py-3 w-100 ">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<h2 class="text-info">Edit Pokémon</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="p-3 w-100 flex-column ">
|
||||
<EditForm class="col mb-3" Model="pokemon" OnValidSubmit="HandleSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<!-- Dex Number and Name -->
|
||||
<div class="row ">
|
||||
<div class="col-sm-3 input-group mb-3">
|
||||
<span for="PokemonId" class="input-group-text">#</span>
|
||||
<InputNumber min="0" id="PokemonId" @bind-Value="pokemon.PokemonId" class="form-control" required disabled />
|
||||
<InputText id="PokemonName" @bind-Value="pokemon.PokemonName" class="form-control w-75" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pokemon Type, Sleep Type, and Speciality -->
|
||||
<div class="row">
|
||||
<!-- Pokemon Type -->
|
||||
<div class="col mb-3 m-auto">
|
||||
<label for="PokemonType" class="form-label">Pokemon Type</label>
|
||||
<InputSelect id="PokemonType" @bind-Value="pokemon.PokemonType" class="form-select">
|
||||
<option dsabled value="">Select Type</option>
|
||||
<option value="Grass">Grass</option>
|
||||
<option value="Fire">Fire</option>
|
||||
<option value="Water">Water</option>
|
||||
<option value="Normal">Normal</option>
|
||||
<option value="Flying">Flying</option>
|
||||
<option value="Bug">Bug</option>
|
||||
<option value="Poison">Poison</option>
|
||||
<option value="Electric">Electric</option>
|
||||
<option value="Ground">Ground</option>
|
||||
<option value="Rock">Rock</option>
|
||||
<option value="Ice">Ice</option>
|
||||
<option value="Steel">Steel</option>
|
||||
<option value="Fighting">Fighting</option>
|
||||
<option value="Psychic">Psychic</option>
|
||||
<option value="Dark">Dark</option>
|
||||
<option value="Fairy">Fairy</option>
|
||||
<option value="Ghost">Ghost</option>
|
||||
<option value="Dragon">Dragon</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<!-- Sleep Type -->
|
||||
<div class="col mb-3 m-auto">
|
||||
<label for="SleepType" class="form-label">Sleep Type</label>
|
||||
<InputSelect id="SleepType" @bind-Value="pokemon.SleepType" class="form-select">
|
||||
<option value="Dozing">Dozing</option>
|
||||
<option value="Snoozing">Snoozing</option>
|
||||
<option value="Slumbering">Slumbering</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<!-- Speciality-->
|
||||
<div class="col mb-3 m-auto">
|
||||
<label for="Speciality" class="form-label">Specialty</label>
|
||||
<InputSelect id="Speciality" @bind-Value="pokemon.Speciality" class="form-select">
|
||||
<option value="Berries">Berries</option>
|
||||
<option value="Ingredients">Ingredients</option>
|
||||
<option value="Skills">Skills</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Variation Check -->
|
||||
<div class="row">
|
||||
<div class="input-group mb-3">
|
||||
<!-- Variation Check -->
|
||||
<div class=" d-inline-flex">
|
||||
<InputCheckbox id="IsVariation" @bind-Value="pokemon.IsVariation" @onclick="@Toggle" class="form-check-input checkbox-styling p-3 mt-1" />
|
||||
<span for="IsVariation" class="input-group-text m-1">Variation?</span>
|
||||
</div>
|
||||
|
||||
<!-- Variation Region Input -->
|
||||
<div class="w-75 mx-2 mt-1">
|
||||
|
||||
<InputText placeholder="What Variant? (Alolan, Paldean)" hidden="@HideLabel" id="VariationName" @bind-Value="pokemon.VariationName" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Image URL Input -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Base Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="pokemon.PokemonImageUrl" class="form-control" />
|
||||
</div>
|
||||
<!-- Shiny Image URL Input -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Shiny Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="pokemon.PokemonShinyImageUrl" class="form-control" />
|
||||
</div>
|
||||
<!-- 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" />
|
||||
</div>
|
||||
|
||||
<!-- Form Buttons -->
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary mb-3" @onclick="Cancel">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary mb-3">Save Changes</button>
|
||||
</div>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Pokemon_Pages
|
||||
{
|
||||
public partial class PokemonEdit
|
||||
{
|
||||
[Parameter] public int Id { get; set; }
|
||||
private Pokemon? pokemon;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
pokemon = await PokemonService.GetPokemonByIdAsync(Id);
|
||||
}
|
||||
|
||||
private async Task HandleSubmit()
|
||||
{
|
||||
await PokemonService.UpdatePokemonAsync(pokemon);
|
||||
//Navigation.NavigateTo("/pokemonsleep");
|
||||
await JSRuntime.InvokeVoidAsync("history.back");
|
||||
}
|
||||
|
||||
private async void Cancel()
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("history.back");
|
||||
|
||||
}
|
||||
|
||||
private bool HideLabel { get; set; } = true;
|
||||
private void Toggle()
|
||||
{
|
||||
HideLabel = !HideLabel;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
body {
|
||||
}
|
||||
|
||||
.edit-container {
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(255,255, 255, 0.19);
|
||||
border-radius: 15px;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
@page "/rate-pokemon"
|
||||
|
||||
@inject IPokemonService PokemonService
|
||||
@inject IPokemonNatureService PokemonNatureService
|
||||
@inject IPokemonSubskillService PokemonSubskillService
|
||||
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-lumen.css" /> <!-- app.css -->
|
||||
</head>
|
||||
|
||||
<PageTitle>Rate Pokémon</PageTitle>
|
||||
|
||||
<PokemonHeader />
|
||||
|
||||
<div class="mt-4">
|
||||
<div class="row">
|
||||
@if (PokemonList == null || NatureList == null || SubskillList == null)
|
||||
{
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 60vh;">
|
||||
<Loading />
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Left Panel: Selector -->
|
||||
<div class="col-4">
|
||||
<PokemonSelector
|
||||
PokemonList="PokemonList"
|
||||
SelectedPokemon="SelectedPokemon"
|
||||
OnPokemonSelected="SelectPokemon" />
|
||||
</div>
|
||||
|
||||
<!-- Center Panel: Pokemon View -->
|
||||
<div class="col-4">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
|
||||
|
||||
@if (SelectedPokemon != null)
|
||||
{
|
||||
<PokemonCard Pokemon="SelectedPokemon" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="text-muted">Please select a Pokémon to rate.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Right Panel: Rating View -->
|
||||
<div class="col-4">
|
||||
<PokemonRatingPanel
|
||||
PokemonToRate="SelectedPokemon"
|
||||
NatureList="NatureList"
|
||||
SubskillList="SubskillList"
|
||||
/>
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>
|
||||
<hr class="mt-5"/>
|
||||
</div>
|
|
@ -3,7 +3,7 @@ using Portfolio.Domain.Features.Pokemon;
|
|||
using Portfolio.Domain.Features.Pokemon_Natures;
|
||||
using Portfolio.Domain.Features.Pokemon_Subskills;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Pokemon_Pages
|
||||
{
|
||||
public partial class PokemonRate
|
||||
{
|
||||
|
@ -39,9 +39,6 @@ namespace Portfolio.WebUI.Server.Components.Pages
|
|||
private string ScoreBackgroundColor;
|
||||
private string ScoreColor;
|
||||
|
||||
private string PokemonImageUrl => SelectedPokemon != null
|
||||
? $"https://www.serebii.net/pokemonsleep/pokemon/{SelectedPokemon.Id}.png"
|
||||
: string.Empty;
|
||||
|
||||
private string PokemonSearchTerm = string.Empty;
|
||||
|
||||
|
@ -54,13 +51,15 @@ namespace Portfolio.WebUI.Server.Components.Pages
|
|||
{
|
||||
// Trigger filtering as the user types
|
||||
PokemonSearchTerm = e.Value.ToString();
|
||||
|
||||
}
|
||||
|
||||
private async Task SelectPokemon(Pokemon pokemon)
|
||||
{
|
||||
SelectedPokemon = pokemon;
|
||||
PokemonSearchTerm = string.Empty; // Reset search term
|
||||
FilteredPokemonList.Clear(); // Clear the filtered list to hide dropdown
|
||||
StateHasChanged();
|
||||
//FilteredPokemonList.Clear(); // Clear the filtered list to hide dropdown
|
||||
}
|
||||
|
||||
private async void OnPokemonSelected()
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
@page "/pokemon"
|
||||
|
||||
|
||||
@inject IPokemonService PokemonService
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<PageTitle>Pokémon Sleep</PageTitle>
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-lumen.css" /> <!-- app.css -->
|
||||
</head>
|
||||
|
||||
<div class="w-100">
|
||||
<!-- <PokemonBackground PokemonImages="pokemonImageUrls" ShinyPokemonImages="pokemonShinyImageUrls" /> -->
|
||||
|
||||
<PokemonHeader />
|
||||
|
||||
<PokemonTable AllPokemon="pokemons"/>
|
||||
|
||||
<hr class="mt-5" />
|
||||
|
||||
|
||||
</div>
|
|
@ -1,7 +1,7 @@
|
|||
using Portfolio.Application.Services.PokemonService;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Pokemon_Pages
|
||||
{
|
||||
public partial class PokemonSleep
|
||||
{
|
|
@ -0,0 +1,76 @@
|
|||
@page "/pokemonsleep"
|
||||
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<PageTitle>Pokémon Sleep</PageTitle>
|
||||
<head>
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-lumen.css" /> <!-- app.css -->
|
||||
</head>
|
||||
|
||||
<div class="">
|
||||
<div class="row w-100">
|
||||
<!-- <PokemonBackground PokemonImages="pokemonImageUrls" ShinyPokemonImages="pokemonShinyImageUrls" /> -->
|
||||
<div class="row"><PokemonHeader /></div>
|
||||
|
||||
<!-- Card -->
|
||||
<div class="row card shadow-sm border-0 p-3 pb-4 mt-4 m-auto w-75 mb-5 bg-white">
|
||||
<!-- Top Row-->
|
||||
<div class="row d-flex flex-row">
|
||||
<!-- Image side -->
|
||||
<div class="col w-50 border-0 ">
|
||||
<div>
|
||||
|
||||
</div>
|
||||
<img class="shadow-sm w-100 m-auto img-fluid" src="images/Pokemon_Sleep_ID.jpg" />
|
||||
</div>
|
||||
<!-- Text side -->
|
||||
<div class="col w-50 p-3">
|
||||
<p class="fw-bold fst-italic fs-3">Pokémon Sleep? Really?</p>
|
||||
<p class="fw-normal fs-6 text-start">
|
||||
Yes, really! Pokémon Sleep has become a fun addition to my day since it's release.
|
||||
</p>
|
||||
<p class="fw-bold fst-italic fs-3">But what do you even do?</p>
|
||||
<p class="fw-normal fs-6 text-start">
|
||||
That's harder to explain. See, it isn't as much a game, as it is a gamified sleep tracker. But it's fun to collect the Pokémon and gather their berries and ingredients and create silly little Pokémon-themed foods. Plus, it encourages me to try to get to bed in a timely manner; though, if I'm honest, I definitely put my Pokémon to bed ahead of when I do.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Second Row -->
|
||||
<div class="row mt-3">
|
||||
<p class="fw-bold fst-italic fs-3">Okay, but why a whole section dedicated to Pokémon Sleep?</p>
|
||||
<p class="fw-normal fs-6 text-start">
|
||||
Well, as it is in any Pokémon game, Natures (and in this case Subskills) matter, amongst other things. This was designed as a helpful tool in assessing new Pokémon acquired from Sleep Research.
|
||||
</p>
|
||||
</div>
|
||||
<!-- Button Row-->
|
||||
<div class="row btn-group d-flex flex-row justify-content-around mt-4">
|
||||
<div class="w-auto">
|
||||
<button class="btn btn-info">
|
||||
<NavLink href="/pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-table mb-1" 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="ps-1">Available Pokémon</span>
|
||||
</NavLink>
|
||||
</button>
|
||||
</div>
|
||||
<div class="w-auto">
|
||||
<button class="btn btn-success link">
|
||||
<NavLink href="/rate-pokemon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-award-fill mb-1" 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="ps-1">Rate Pokémon</span>
|
||||
</NavLink>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,95 @@
|
|||
@page "/pokemon/{id:int}"
|
||||
@inject IPokemonService PokemonService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<PokemonHeader />
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap-lumen.css" /> <!-- app.css -->
|
||||
</head>
|
||||
|
||||
@if (_pokemon == null)
|
||||
{
|
||||
<Loading />
|
||||
}
|
||||
else
|
||||
{
|
||||
<PageTitle>@_pokemon.PokemonName</PageTitle>
|
||||
<!-- Total Componenet-->
|
||||
|
||||
<div class="container">
|
||||
<div class="w-75 row mt-4 m-auto">
|
||||
|
||||
<!-- Previous Pokemon Button -->
|
||||
<div class="col-auto">
|
||||
<button class="mt-1 p-2 btn btn-danger rounded-5 align-self-start text-white" disabled="@(!_previousPokemonId.HasValue)" @onclick="NavigateToPrevious">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-arrow-left-circle-fill" viewBox="0 0 16 16">
|
||||
<path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0m3.5 7.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Pokemon Presentation -->
|
||||
<div class="mt-5 mx-5 col justify-content-center">
|
||||
@if (_variationPokemonId != null)
|
||||
{
|
||||
@if (_variationPokemonId != null && _pokemonVariant == null){
|
||||
<Loading />
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- If Variation Pokemon have same PokemonId -->
|
||||
@if(_pokemon.Id != _pokemonVariant.Id)
|
||||
{
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="pokemoncard m-1">
|
||||
<PokemonCard Pokemon="_pokemon" />
|
||||
</div>
|
||||
|
||||
<div class="pokemoncard m-1">
|
||||
<PokemonCard Pokemon="_pokemonVariant" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
<!-- If Variation Pokemon has diff PokemonId -->
|
||||
else
|
||||
{
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<div class="pokemoncard">
|
||||
<PokemonCard Pokemon="_pokemonVariant" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
<!-- Standard Pokemon Display -->
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<div class="pokemoncard m-1">
|
||||
<PokemonCard Pokemon="_pokemon" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Next Pokemon Button -->
|
||||
<div class="col-auto">
|
||||
<button class="mt-1 p-2 btn btn-danger rounded rounded-5 align-self-start text-white" disabled="@(!_nextPokemonId.HasValue)" @onclick="NavigateToNext">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-arrow-right-circle-fill" viewBox="0 0 16 16">
|
||||
<path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0M4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Portfolio.Domain.Features.Pokemon;
|
||||
|
||||
namespace Portfolio.WebUI.Server.Components.Pages.Pokemon_Pages
|
||||
{
|
||||
public partial class PokemonView
|
||||
{
|
||||
[Parameter] public int Id { get; set; }
|
||||
private Pokemon? _pokemon;
|
||||
private Pokemon? _pokemonVariant;
|
||||
private List<int> _pokemonIds;
|
||||
private int? _nextPokemonId;
|
||||
private int? _previousPokemonId;
|
||||
private int? _variationPokemonId;
|
||||
private int _currentIndex;
|
||||
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_pokemon = await PokemonService.GetPokemonByPokemonIdAsync(Id);
|
||||
|
||||
// These can be smart queries if your data is sorted by ID or by another property
|
||||
_pokemonIds = await PokemonService.GetAllPokemonIdsAsync();
|
||||
_currentIndex = _pokemonIds.IndexOf(_pokemon.PokemonId);
|
||||
//Console.WriteLine(_currentIndex);
|
||||
|
||||
_nextPokemonId = await PokemonService.GetNextPokemonIdAsync(Id);
|
||||
_previousPokemonId = await PokemonService.GetPreviousPokemonIdAsync(Id);
|
||||
|
||||
_variationPokemonId = await PokemonService.GetVariationPokemonIdAsync(Id);
|
||||
if (_variationPokemonId != null)
|
||||
{
|
||||
Console.WriteLine(_variationPokemonId);
|
||||
_pokemonVariant = await PokemonService.GetPokemonByIdAsync((int)_variationPokemonId);
|
||||
Console.WriteLine(_pokemonVariant.VariationName);
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigateToNext()
|
||||
{
|
||||
if (_nextPokemonId.HasValue)
|
||||
Navigation.NavigateTo($"/pokemon/{_nextPokemonId.Value}");
|
||||
}
|
||||
|
||||
private void NavigateToPrevious()
|
||||
{
|
||||
if (_previousPokemonId.HasValue)
|
||||
Navigation.NavigateTo($"/pokemon/{_previousPokemonId.Value}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
.pokemoncard {
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
flex: 0 0 auto; /* prevent flex shrink/grow */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.5rem;
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
@page "/pokemonsleep/add-new-pokemon"
|
||||
|
||||
@inject IPokemonService PokemonService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<PageTitle>Add New Pokémon</PageTitle>
|
||||
<PokemonHeader />
|
||||
|
||||
|
||||
@if (isSubmitting)
|
||||
{
|
||||
<p><em>Submitting...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="w-50 mt-5 m-auto create-container">
|
||||
|
||||
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<h2 class="text-info">Add New Pokémon</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container m-lg-1" >
|
||||
<EditForm class=" col mb-3" Model="NewPokemon" OnValidSubmit="HandleSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<!-- Section 1 -->
|
||||
<div class="row ">
|
||||
<div class="col-sm-3 input-group mb-3 ">
|
||||
<!-- Pokemon #-->
|
||||
<span for="PokemonId" class="input-group-text">#</span>
|
||||
<InputNumber min="0" placeholder="Pokedex #" id="PokemonId" @bind-Value="NewPokemon.PokemonId" class="form-control " required />
|
||||
<!-- Pokemon Name-->
|
||||
<InputText placeholder="Pokemon Name" id="PokemonName" @bind-Value="NewPokemon.PokemonName" class="form-control w-75" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section 2 -->
|
||||
<div class="row">
|
||||
<div class="input-group mb-3">
|
||||
<!-- Variation Check -->
|
||||
<div class=" d-inline-flex">
|
||||
<InputCheckbox id="IsVariation" @bind-Value="NewPokemon.IsVariation" @onclick="@Toggle" class="form-check-input checkbox-styling p-3 mt-1" />
|
||||
<span for="IsVariation" class="input-group-text m-1">Variation?</span>
|
||||
</div>
|
||||
|
||||
<!-- Variation Region Input -->
|
||||
<div class="w-75 mx-2 mt-1">
|
||||
|
||||
<InputText placeholder="What Variant? (Alolan, Paldean)" hidden="@HideLabel" id="VariationName" @bind-Value="NewPokemon.VariationName" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Section 3 -->
|
||||
<div class="row mb-3 m-auto" >
|
||||
<label for="SleepType" class="form-label">Sleep Type</label>
|
||||
<InputSelect id="SleepType" @bind-Value="NewPokemon.SleepType" class="form-select">
|
||||
<option hidden value="">Dozing / Snoozing / Slumbering</option>
|
||||
<option value="Dozing">Dozing</option>
|
||||
<option value="Snoozing">Snoozing</option>
|
||||
<option value="Slumbering">Slumbering</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
|
||||
<!-- Section 4 -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="Speciality" class="form-label">Specialty</label>
|
||||
<InputSelect id="SleepType" @bind-Value="NewPokemon.Speciality" class="form-select">
|
||||
<option hidden value="">Berries / Ingredients / Skills</option>
|
||||
<option value="Berries">Berries</option>
|
||||
<option value="Ingredients">Ingredients</option>
|
||||
<option value="Skills">Skills</option>
|
||||
<option value="Other">Other</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
|
||||
<!-- New Image URL Field -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Base Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="NewPokemon.PokemonImageUrl" class="form-control" />
|
||||
</div>
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Shiny Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="NewPokemon.PokemonShinyImageUrl" class="form-control" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mb-3">Add Pokémon</button>
|
||||
<button type="button" class="btn btn-secondary mb-3" @onclick="@Cancel">Cancel</button>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
@page "/pokemonsleep/edit/{id:int}"
|
||||
@inject IPokemonService PokemonService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Edit Pokémon</PageTitle>
|
||||
<PokemonHeader />
|
||||
|
||||
@if (pokemon == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="w-50 mt-5 m-auto create-container">
|
||||
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<h2 class="text-info">Edit Pokémon</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container m-lg-1">
|
||||
<EditForm class="col mb-3" Model="pokemon" OnValidSubmit="HandleSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3 input-group mb-3">
|
||||
<span for="PokemonId" class="input-group-text">#</span>
|
||||
<InputNumber min="0" id="PokemonId" @bind-Value="pokemon.PokemonId" class="form-control" required disabled />
|
||||
<InputText id="PokemonName" @bind-Value="pokemon.PokemonName" class="form-control w-75" required disabled />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="SleepType" class="form-label">Sleep Type</label>
|
||||
<InputSelect id="SleepType" @bind-Value="pokemon.SleepType" class="form-select">
|
||||
<option value="Dozing">Dozing</option>
|
||||
<option value="Snoozing">Snoozing</option>
|
||||
<option value="Slumbering">Slumbering</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="Speciality" class="form-label">Specialty</label>
|
||||
<InputSelect id="Speciality" @bind-Value="pokemon.Speciality" class="form-select">
|
||||
<option value="Berries">Berries</option>
|
||||
<option value="Ingredients">Ingredients</option>
|
||||
<option value="Skills">Skills</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
|
||||
<!-- New Image URL Field -->
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Base Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="pokemon.PokemonImageUrl" class="form-control" />
|
||||
</div>
|
||||
<div class="row mb-3 m-auto">
|
||||
<label for="ImageUrl" class="form-label">Shiny Image URL</label>
|
||||
<InputText id="ImageUrl" @bind-Value="pokemon.PokemonShinyImageUrl" class="form-control" />
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary mb-3">Save Changes</button>
|
||||
<button type="button" class="btn btn-secondary mb-3" @onclick="Cancel">Cancel</button>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public int Id { get; set; }
|
||||
private Pokemon? pokemon;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
pokemon = await PokemonService.GetPokemonByIdAsync(Id);
|
||||
}
|
||||
|
||||
private async Task HandleSubmit()
|
||||
{
|
||||
await PokemonService.UpdatePokemonAsync(pokemon);
|
||||
Navigation.NavigateTo("/pokemonsleep");
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
Navigation.NavigateTo("/pokemonsleep");
|
||||
}
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
@page "/pokemonsleep/rate-pokemon"
|
||||
|
||||
@inject IPokemonService PokemonService
|
||||
@inject IPokemonNatureService PokemonNatureService
|
||||
@inject IPokemonSubskillService PokemonSubskillService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Rate Pokémon</PageTitle>
|
||||
|
||||
<PokemonHeader />
|
||||
|
||||
@if (PokemonList == null || NatureList == null || SubskillList == null)
|
||||
{
|
||||
<p>Loading...</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="w-75 mt-3 m-auto rate-container">
|
||||
|
||||
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<h2 class="text-info">Pokémon Rater</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-4 col-12">
|
||||
<!-- Section 1: Pokemon Selection -->
|
||||
<div class="row pb-3">
|
||||
<div class="col-3">
|
||||
<div class="position-relative">
|
||||
<input type="text"
|
||||
class="form-control form-control-lg"
|
||||
@bind="PokemonSearchTerm"
|
||||
placeholder="Search Pokémon..."
|
||||
@oninput="OnSearchTextChanged" />
|
||||
|
||||
@if (FilteredPokemonList.Any() && !string.IsNullOrWhiteSpace(PokemonSearchTerm))
|
||||
{
|
||||
<ul class="list-group position-absolute w-100" style="z-index: 1000; max-height: 200px; overflow-y: auto;">
|
||||
@foreach (var pokemon in FilteredPokemonList)
|
||||
{
|
||||
<li class="list-group-item list-group-item-action" @onclick="() => SelectPokemon(pokemon)">
|
||||
@if (pokemon.IsVariation)
|
||||
{
|
||||
@($"{pokemon.PokemonId} {pokemon.VariationName} {pokemon.PokemonName}")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($"{pokemon.PokemonId} {pokemon.PokemonName}")
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section 2: Pokemon Rating -->
|
||||
@if (SelectedPokemon != null)
|
||||
{
|
||||
<div class="border rounded p-3 row">
|
||||
<div class="d-flex align-top col">
|
||||
|
||||
<!-- Pokemon Interface -->
|
||||
<div class="m-3 p-1 col-5">
|
||||
<!-- Image and other Pokemon info -->
|
||||
<div class="flip-container" @onclick="() => ToggleImage(SelectedPokemon.Id)">
|
||||
<div class="flipper @(isShiny[SelectedPokemon.Id] ? "flipped" : "")">
|
||||
<img class="front" src="@SelectedPokemon.PokemonImageUrl" />
|
||||
<img class="back" src="@SelectedPokemon.PokemonShinyImageUrl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-7">
|
||||
<div class="row mb-0">
|
||||
@if (SelectedPokemon.IsVariation)
|
||||
{
|
||||
<h2>@SelectedPokemon.VariationName @SelectedPokemon.PokemonName</h2>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h3>@SelectedPokemon.PokemonName</h3>
|
||||
}
|
||||
</div>
|
||||
<div class="mt-0">
|
||||
<p class="col-4">Pokédex #<strong>@SelectedPokemon.PokemonId</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-5 p-1">
|
||||
<div class="row d-flex justify-content-between">
|
||||
<div class="m-1 col badge @SelectedPokemon.SleepType.ToLower()"><p class="statText">@SelectedPokemon.SleepType</p></div>
|
||||
<div class="m-1 col badge @SelectedPokemon.Speciality.ToLower()"><p class="statText">@SelectedPokemon.Speciality</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Nature / Subskill Selection Dropdowns-->
|
||||
<div class="m-3 p-1 col">
|
||||
<h4 class="mb-3">Select Nature & Subskills</h4>
|
||||
|
||||
<!-- Nature -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label>Select Nature</label>
|
||||
<select class="form-control form-control-lg mb-2" @bind="SelectedNatureId">
|
||||
<option value="" disabled>Choose Nature...</option>
|
||||
@foreach (var nature in NatureList)
|
||||
{
|
||||
<option value="@nature.Id">@nature.Nature</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subskills -->
|
||||
<div class="row">
|
||||
<!-- Subskill 1 -->
|
||||
<div class="col-4">
|
||||
<label for="subskillSelect1">Select Level 10 Subskill</label>
|
||||
<select id="subskillSelect1" class="form-control form-control mb-2" @bind="subskillSelect1">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Subskill 2 -->
|
||||
<div class="col-4">
|
||||
<label for="subskillSelect2">Select Level 25 Subskill</label>
|
||||
<select id="subskillSelect2" class="form-control form-control mb-2" @bind="subskillSelect2">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Subskill 3 -->
|
||||
<div class="col-4">
|
||||
<label for="subskillSelect3">Select Level 50 Subskill</label>
|
||||
<select id="subskillSelect3" class="form-control form-control mb-2" @bind="subskillSelect3">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- Subskill 4 -->
|
||||
<div class="col-4">
|
||||
<label for="subskillSelect4">Select Level 75 Subskill</label>
|
||||
<select id="subskillSelect4" disabled class="form-control form-control mb-2" @bind="subskillSelect4">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Subskill 5 -->
|
||||
<div class="col-4">
|
||||
<label for="subskillSelect5">Select Level 100 Subskill</label>
|
||||
<select id="subskillSelect5" disabled class="form-control form-control mb-2" @bind="subskillSelect5">
|
||||
<option value="" disabled selected>Choose Subskill...</option>
|
||||
@foreach (var subskill in SubskillList)
|
||||
{
|
||||
<option value="@subskill.Id">@subskill.SubSkill</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Calculate -->
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 ">
|
||||
<button class="btn btn-primary mx-2" @onclick="CalculateScore">Calculate Final Score</button>
|
||||
<h4>Final Score: <span class="finalScore" style="background-color: @ScoreBackgroundColor">@FinalScore</span></h4>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
|
||||
.rate-container {
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2),
|
||||
0 6px 20px 0 rgba(255,255, 255, 0.19);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.flip-container {
|
||||
perspective: 1000px;
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.flipper {
|
||||
transition: transform 0.6s;
|
||||
transform-style: preserve-3d;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flipped {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.front, .back {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.back {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.badge {
|
||||
width: 90px;
|
||||
height: 30px;
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.statText {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.dozing {
|
||||
background-color: #fcdc5e;
|
||||
}
|
||||
|
||||
.snoozing {
|
||||
background-color: #4ce8ed;
|
||||
}
|
||||
|
||||
.slumbering {
|
||||
background-color: #4588fb;
|
||||
}
|
||||
|
||||
.berries {
|
||||
background-color: #24d86b;
|
||||
}
|
||||
|
||||
.ingredients {
|
||||
background-color: #fdbe4d;
|
||||
}
|
||||
|
||||
.skills {
|
||||
background-color: #47a0fc;
|
||||
}
|
||||
|
||||
.finalScore {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
@page "/pokemonsleep"
|
||||
|
||||
@inject IPokemonService PokemonService
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
|
||||
<PageTitle>Pokémon Sleep</PageTitle>
|
||||
|
||||
<div class="w-100">
|
||||
<PokemonBackground PokemonImages="pokemonImageUrls" ShinyPokemonImages="pokemonShinyImageUrls" />
|
||||
|
||||
<PokemonHeader />
|
||||
|
||||
<PokemonTable AllPokemon="pokemons"/>
|
||||
|
||||
</div>
|
|
@ -9,11 +9,15 @@
|
|||
@using Portfolio.WebUI.Server
|
||||
@using Portfolio.WebUI.Server.Components
|
||||
@using Portfolio.WebUI.Server.Components.Component
|
||||
@using Portfolio.WebUI.Server.Components.Component.Pokemon_Components
|
||||
@using Portfolio.WebUI.Server.Components.Component.Crochet_Components
|
||||
@using Portfolio.Domain.Features.Articles
|
||||
@using Portfolio.Domain.Features.Pokemon
|
||||
@using Portfolio.Domain.Features.Pokemon_Natures
|
||||
@using Portfolio.Domain.Features.Pokemon_Subskills
|
||||
@using Portfolio.Domain.Features.TemperatureDay
|
||||
@using Portfolio.Application.Services.Articles
|
||||
@using Portfolio.Application.Services.PokemonService
|
||||
@using Portfolio.Application.Services.PokemonNatureService
|
||||
@using Portfolio.Application.Services.PokemonSubskillService
|
||||
@using Portfolio.Application.Services.NWSWeatherService
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
|
@ -0,0 +1,9 @@
|
|||
window.getScreenWidth = () => {
|
||||
return window.innerWidth;
|
||||
};
|
||||
|
||||
window.registerResizeCallback = (dotNetHelper) => {
|
||||
window.onresize = () => {
|
||||
dotNetHelper.invokeMethodAsync('UpdateScreenWidth', window.innerWidth);
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue