First time back after a while. Rolled back some changes that made the app inoperable (specifically NWSWeatherService). Temp Blanket visualizer works, including color editing for ranges. Need to plug in real data.
This commit is contained in:
parent
bdd0f2e8bb
commit
764c094a64
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div>
|
||||
@if (TemperatureDays is null || TemperatureRanges is null)
|
||||
{
|
||||
<Loading />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
<div>
|
||||
<h3 class="text-xl font-bold mb-4">Temperature Blanket Reviewer</h3>
|
||||
|
||||
<div style="display: flex; overflow-x: auto; background-color: black; padding: 10px;">
|
||||
@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>
|
||||
|
||||
<TemperatureRangeEditor TempRanges="@TemperatureRanges" OnRangesChanged="HandleRangesChanged" />
|
||||
</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 = "#90ee90" },
|
||||
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,34 @@
|
|||
@using Microsoft.AspNetCore.Components.Web
|
||||
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div class="relative w-full h-24 px-4" @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="flex gap-2 mt-6">
|
||||
@for (int i = 0; i < TempRanges.Count; i++)
|
||||
{
|
||||
var localIndex = i;
|
||||
<input type="color"
|
||||
value="@TempRanges[i].Color"
|
||||
@onchange="e => HandleColorChange(e, localIndex)" />
|
||||
}
|
||||
</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})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,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">
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
@page "/temperature-blanket"
|
||||
|
||||
@attribute [StreamRendering]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<h3 class="text-xl font-bold mb-4">Crochet</h3>
|
||||
|
||||
<TemperatureBlanketVisualizer TemperatureDays="temperatureDays" />
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
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; }
|
||||
|
||||
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();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,11 +10,14 @@
|
|||
@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.PokemonSubskillService
|
||||
@using Portfolio.Application.Services.NWSWeatherService
|
Loading…
Reference in New Issue