Browse Source

feat(Toasts) Adding toasts

main
Jonathan McCaffrey 4 years ago
parent
commit
4322be0053
  1. 1
      Components/Components.csproj
  2. 30
      Components/Feedback/AlertComponent.razor
  3. 8
      Components/Feedback/SeverityType.cs
  4. 114
      Components/Feedback/ToastComponent.razor
  5. 28
      Components/Inputs/CodeLinkComponent.razor
  6. 8
      Components/_Imports.razor
  7. 11
      IGP/App.razor
  8. BIN
      IGP/Database.db
  9. 38
      IGP/IGP.csproj
  10. 11
      IGP/Index.razor
  11. 54
      IGP/Localizations.Designer.cs
  12. 0
      IGP/Localizations.properties
  13. 24
      IGP/Localizations.resx
  14. 1
      IGP/Pages/AboutPage.razor
  15. 12
      IGP/Pages/Agile/AgilePage.razor
  16. 2
      IGP/Pages/BuildCalculator/BuildCalculatorPage.razor
  17. 56
      IGP/Pages/HarassCalculatorPage.razor
  18. 2
      IGP/Pages/MakingOf/MakingOfPage.razor
  19. 8
      IGP/Pages/MakingOf/Parts/MakingOfFeedback.razor
  20. 42
      IGP/Portals/ToastPortal.razor
  21. 9
      IGP/Program.cs
  22. 2
      IGP/_Imports.razor
  23. 13
      IGP/wwwroot/css/app.css
  24. 2
      IGP/wwwroot/generated/AgileTaskModels.json
  25. 9
      IGP/wwwroot/index.html
  26. 9
      Model/Feedback/SeverityType.cs
  27. 8
      Model/Feedback/ToastModel.cs
  28. 12
      Services/IServices.cs
  29. 64
      Services/Website/ToastService.cs

1
Components/Components.csproj

@ -21,6 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Markdig" Version="0.28.1" /> <PackageReference Include="Markdig" Version="0.28.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-preview.2.22153.2" /> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-preview.2.22153.2" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.0-preview.2.22153.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

30
Components/Feedback/AlertComponent.razor

@ -1,4 +1,5 @@
<div class="alertContainer @Type.ToString().ToLower()"> @using Model.Feedback
<div class="alertContainer @Type.ToLower()">
@if (Title != null) { @if (Title != null) {
<div class="alertTitle"> <div class="alertTitle">
@Title @Title
@ -21,24 +22,25 @@
width: 100%; width: 100%;
} }
.alertContainer.@SeverityType.Warning.ToString().ToLower() {
border-color: #2a2000; .alertContainer.@SeverityType.Warning.ToLower() {
background-color: #ffbf0029; background-color: var(--severity-warning-color);
border-color: var(--severity-warning-border-color);
} }
.alertContainer.@SeverityType.Error.ToString().ToLower() { .alertContainer.@SeverityType.Error.ToLower() {
border-color: #290102; background-color: var(--severity-error-color);
background-color: #4C2C33; border-color: var(--severity-error-border-color);
} }
.alertContainer.@SeverityType.Information.ToString().ToLower() { .alertContainer.@SeverityType.Information.ToLower() {
border-color: #030129; background-color: var(--severity-information-color);
background-color: #2c3a4c; border-color: var(--severity-information-border-color);
} }
.alertContainer.@SeverityType.Success.ToString().ToLower() { .alertContainer.@SeverityType.Success.ToLower() {
border-color: #042901; background-color: var(--severity-success-color);
background-color: #2E4C2C; border-color: var(--severity-success-border-color);
} }
.alertTitle { .alertTitle {
@ -56,6 +58,6 @@
public RenderFragment? Message { get; set; } public RenderFragment? Message { get; set; }
[Parameter] [Parameter]
public SeverityType Type { get; set; } = SeverityType.Warning; public string Type { get; set; } = SeverityType.Warning;
} }

8
Components/Feedback/SeverityType.cs

@ -1,8 +0,0 @@
namespace Components.Feedback;
public enum SeverityType {
Warning,
Information,
Error,
Success
}

114
Components/Feedback/ToastComponent.razor

@ -0,0 +1,114 @@
@using Services
@inject IToastService toastService
@implements IDisposable
@if (Toast == null)
{
<div>Add toast object...</div>
}
else
{
<div class="toastContainer @Toast.SeverityType.ToLower() @FadeoutStyle">
<div class="toastTitle">
@Toast.Title
</div>
<div>
@Toast.Message
</div>
</div>
}
<style>
.toastContainer {
border: 4px solid;
border-radius: 4px;
padding: 16px;
display: flex;
flex-direction: column;
justify-items: stretch;
width: 100%;
opacity: 1;
}
.fadeout {
transition: opacity 3s ease-in;
opacity: 0;
}
.toastContainer.@SeverityType.Warning.ToLower() {
background-color: var(--severity-warning-color);
border-color: var(--severity-warning-border-color);
}
.toastContainer.@SeverityType.Error.ToLower() {
background-color: var(--severity-error-color);
border-color: var(--severity-error-border-color);
}
.toastContainer.@SeverityType.Information.ToLower() {
background-color: var(--severity-information-color);
border-color: var(--severity-information-border-color);
}
.toastContainer.@SeverityType.Success.ToLower() {
background-color: var(--severity-success-color);
border-color: var(--severity-success-border-color);
}
.toastTitle {
font-weight: 800;
}
</style>
@code {
[Parameter]
public ToastModel? Toast { get; set; } = default!;
private bool isFadingOut = false;
private string FadeoutStyle => isFadingOut ? "fadeout" : "";
private int removalTime = 150000;
private int fadeoutTime = 4000;
//private int fade
private Timer removalTimer = null!;
private Timer fadeoutTimer = null!;
protected override void OnInitialized()
{
#if DEBUG
removalTime = 5000;
#endif
removalTimer = new Timer(removalTime);
removalTimer.Elapsed += OnRemoval!;
removalTimer.Enabled = true;
fadeoutTimer = new Timer(removalTime - fadeoutTime);
fadeoutTimer.Elapsed += OnFadeout!;
fadeoutTimer.Enabled = true;
}
void OnFadeout(object source, ElapsedEventArgs eventArgs)
{
isFadingOut = true;
StateHasChanged();
}
void OnRemoval(object source, ElapsedEventArgs eventArgs)
{
toastService.RemoveToast(Toast!);
}
public void Dispose()
{
removalTimer.Dispose();
fadeoutTimer.Dispose();
}
}

28
Components/Inputs/CodeLinkComponent.razor

@ -0,0 +1,28 @@
<a href="@Href" class="codeLinkButton">
View on GitHub
</a>
<style>
.codeLinkButton {
color: white;
background-color: var(--info);
border: 1px solid var(--info-border);
padding: 16px;
border-radius: 3px;
display: block;
width: 180px;
text-align: center;
}
.codeLinkButton:hover {
color: white;
background-color: var(--info-hover);
border: 2px solid var(--info-border-hover);
}
</style>
@code {
[Parameter]
public string Href { get; set; } = "";
}

8
Components/_Imports.razor

@ -7,4 +7,10 @@
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using System.Text @using System.Text
@using System.Text.Json @using System.Text.Json
@using YamlDotNet.Serialization @using YamlDotNet.Serialization
@using Model.Feedback
@using System;
@using System.Threading.Tasks;
@using System.Timers;

11
IGP/App.razor

@ -14,6 +14,7 @@
</Router> </Router>
<EntityDialogPortal/> <EntityDialogPortal/>
<ToastPortal/>
<style> <style>
a { a {
@ -30,7 +31,15 @@
:root { :root {
/* Duplicate Code, to deal with cache issues. See wwwroot/css/app.css for proper :root */ --severity-warning-color: #2a2000;
--severity-warning-border-color: #755c13;
--severity-error-color: #290102;
--severity-error-border-color: #4C2C33;
--severity-information-color: #030129;
--severity-information-border-color: #2c3a4c;
--severity-success-color: #042901;
--severity-success-border-color: #2E4C2C;
--accent: #432462; --accent: #432462;
--primary: #4308a3; --primary: #4308a3;
--primary-border: #2c0b62; --primary-border: #2c0b62;

BIN
IGP/Database.db

Binary file not shown.

38
IGP/IGP.csproj

@ -15,10 +15,15 @@
<DefineConstants>TRACE;NO_SQL</DefineConstants> <DefineConstants>TRACE;NO_SQL</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Markdig" Version="0.28.1"/> <PackageReference Include="Markdig" Version="0.28.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0-preview.2.22153.2"/> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0-preview.2.22153.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0-preview.2.22153.2" PrivateAssets="all"/> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0-preview.2.22153.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.0-preview.2.22153.2" />
<!-- <!--
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.2.22153.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.2.22153.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="7.0.0-preview.2.22153.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="7.0.0-preview.2.22153.1" />
@ -27,18 +32,33 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js"/> <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Components\Components.csproj" />
<ProjectReference Include="..\Contexts\Contexts.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Services\Services.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\generated" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Components\Components.csproj"/> <EmbeddedResource Update="Localizations.resx">
<ProjectReference Include="..\Contexts\Contexts.csproj"/> <Generator>ResXFileCodeGenerator</Generator>
<ProjectReference Include="..\Model\Model.csproj"/> <LastGenOutput>Localizations.Designer.cs</LastGenOutput>
<ProjectReference Include="..\Services\Services.csproj"/> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="wwwroot\generated"/> <Compile Update="Localizations.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Example.resx</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>
</Project> </Project>

11
IGP/Index.razor

@ -1,9 +1,20 @@
@page "/" @page "/"
@using Microsoft.Extensions.Localization
@layout PageLayout @layout PageLayout
@inject IStringLocalizer<Localizations> Loc
<DevOnlyComponent> <DevOnlyComponent>
<DocumentationIndexPage></DocumentationIndexPage> <DocumentationIndexPage></DocumentationIndexPage>
@Loc["Greeting"].Value
@Loc["Greeting"]
@Loc["Greeting"].Name
@Loc["Greeting"].ResourceNotFound
</DevOnlyComponent> </DevOnlyComponent>
<HomePage></HomePage> <HomePage></HomePage>

54
IGP/Localizations.Designer.cs generated

@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IGP {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Localizations {
private static System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Localizations() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IGP.Localizations", typeof(Localizations).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
internal static string Greeting {
get {
return ResourceManager.GetString("Greeting", resourceCulture);
}
}
}
}

0
IGP/Localizations.properties

24
IGP/Localizations.resx

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>Hello</value>
</data>
</root>

1
IGP/Pages/AboutPage.razor

@ -1,6 +1,5 @@
@layout PageLayout @layout PageLayout
@page "/about" @page "/about"
<LayoutMediumContentComponent> <LayoutMediumContentComponent>

12
IGP/Pages/Agile/AgilePage.razor

@ -5,7 +5,13 @@
@page "/agile" @page "/agile"
@if (AgileService.IsLoaded()) @if (!AgileService.IsLoaded())
{
<LoadingComponent/>
}
else
{ {
<LayoutMediumContentComponent> <LayoutMediumContentComponent>
@ -69,10 +75,6 @@
</PaperComponent> </PaperComponent>
</LayoutMediumContentComponent> </LayoutMediumContentComponent>
} }
else
{
<LoadingComponent/>
}
@code { @code {

2
IGP/Pages/BuildCalculator/BuildCalculatorPage.razor

@ -13,7 +13,7 @@
<LayoutLargeContentComponent> <LayoutLargeContentComponent>
<WebsiteTitleComponent>Build Calculator</WebsiteTitleComponent> <WebsiteTitleComponent>Build Calculator</WebsiteTitleComponent>
<AlertComponent Type="SeverityType.Warning"> <AlertComponent Type="@SeverityType.Warning">
<Title>Work In Progress and Not Fully Tested</Title> <Title>Work In Progress and Not Fully Tested</Title>
<Message> <Message>
Currently not considering training queue times. Lacking error toasts for invalid actions. Performance needs to be optimized. Calculations haven't been thoroughly compared against real gameplay. Added a 2 second delay to actions to account for casual micro (will probably tweak later). Currently not considering training queue times. Lacking error toasts for invalid actions. Performance needs to be optimized. Calculations haven't been thoroughly compared against real gameplay. Added a 2 second delay to actions to account for casual micro (will probably tweak later).

56
IGP/Pages/HarassCalculatorPage.razor

@ -38,13 +38,13 @@
<FormNumberComponent Min="0" <FormNumberComponent Min="0"
Value="@((int)NumberOfTownHallsExisting)" Value="@((int)NumberOfTownHallsExisting)"
OnChange="@(e => { NumberOfTownHallsExisting = int.Parse(e.Value!.ToString()!); Calculate();})"> OnChange="@(e => { NumberOfTownHallsExisting = int.Parse(e.Value!.ToString()!); Calculate();})">
<FormLabelComponent>Number of townhalls existing</FormLabelComponent> <FormLabelComponent>Number of townhalls you have</FormLabelComponent>
</FormNumberComponent> </FormNumberComponent>
<FormNumberComponent Min="0" <FormNumberComponent Min="0"
Value="@((int)TravelTime)" Value="@((int)TravelTime)"
OnChange="@(e => { TravelTime = int.Parse(e.Value!.ToString()!); Calculate();})"> OnChange="@(e => { TravelTime = int.Parse(e.Value!.ToString()!); Calculate();})">
<FormLabelComponent>Travel time</FormLabelComponent> <FormLabelComponent>Worker travel time to alloy</FormLabelComponent>
</FormNumberComponent> </FormNumberComponent>
<FormDisplayComponent Label="Total alloy lost"> <FormDisplayComponent Label="Total alloy lost">
@ -93,9 +93,9 @@
<InfoAnswerComponent> <InfoAnswerComponent>
Well, let's assume you lost a full alloy line of workers, and have to take that 741 alloy cost (300 to rebuy the workers, and 441 in lost mining time.) Well, let's assume you lost a full alloy line of workers, and have to take that 741 alloy cost (300 to rebuy the workers, and 441 in lost mining time.)
<br/><br/> <br/><br/>
If you were to set the <b>Number of townhalls existing</b> to 2, the calculator will consider worker transfer micro. Allowing you to cut the total cost by roughly 315 alloy. However, that number isn't entirely accurate, you are also going to have to bump up the <b>Travel time</b> to account for the time it takes the transferred workers to arrive at the decimated alloy line. If you were to set the <b>Number of townhalls you have</b> to 2, the calculator will consider worker transfer micro. Allowing you to cut the total cost by roughly 315 alloy. However, that number isn't entirely accurate, you are also going to have to bump up the <b>Worker travel time to alloy</b> to account for the time it takes the transferred workers to arrive at the decimated alloy line.
<br/><br/> <br/><br/>
Let's say it takes 10 seconds for workers to transfer from your second base. We can divide that number by 2, to represent our bases, and add those 5 additional seconds to <b>Travel time</b>, for the more accurate loss of 456 alloy (saving you 285 alloy.) <i>Which is much better than not transferring workers!</i> Let's say it takes 10 seconds for workers to transfer from your second base. We can divide that number by 2, to represent our bases, and add those 5 additional seconds to <b>Worker travel time to alloy</b>, for the more accurate loss of 456 alloy (saving you 285 alloy.) <i>Which is much better than not transferring workers!</i>
</InfoAnswerComponent> </InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>
@ -146,53 +146,7 @@
Can I see the code for the calculation? Can I see the code for the calculation?
</InfoQuestionComponent> </InfoQuestionComponent>
<InfoAnswerComponent> <InfoAnswerComponent>
<CodeLinkComponent Href="https://github.com/JonathanMcCaffrey/IGP-Fan-Reference/blob/main/IGP/Pages/HarassCalculatorPage.razor#L223-L281"/>
<CodeComponent>
<div style="color: green;">//TotalAlloyHarassment is set after Calculate() function is called</div>
<div>
float TotalAlloyHarassment;
float CostOfWorker = 50;
float AlloyMinedPerSecondByWorker = 1;
float TimeToProduceWorker = 20;
float TravelTime = 1;
float NumberOfWorkersLostToHarass = 1;
float NumberOfTownHallsExisting = 1;
float SimultaneousProductionFloor() {
if (NumberOfTownHallsExisting &lt;= 0 || NumberOfWorkersLostToHarass &lt;= 0) {
return 0;
}
return (float)Math.Floor(NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass));
}
float LeftOverWorkersToProduceCount() {
return NumberOfWorkersLostToHarass % (Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass));
}
float WorkerReplacementCost() {
return CostOfWorker * NumberOfWorkersLostToHarass;
}
float DelayedMiningCost() {
return TotalAlloyHarassment - WorkerReplacementCost();
}
void Calculate() {
TotalAlloyHarassment = WorkerReplacementCost();
for (var workerProductionIndex = 0; workerProductionIndex &lt; SimultaneousProductionFloor(); workerProductionIndex++) {
TotalAlloyHarassment += AlloyMinedPerSecondByWorker * (TimeToProduceWorker + TravelTime) * (workerProductionIndex + 1);
}
TotalAlloyHarassment += LeftOverWorkersToProduceCount() * (TimeToProduceWorker + TravelTime) * AlloyMinedPerSecondByWorker;
}
</div>
</CodeComponent>
</InfoAnswerComponent> </InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>

2
IGP/Pages/MakingOf/MakingOfPage.razor

@ -5,7 +5,7 @@
<LayoutLargeContentComponent> <LayoutLargeContentComponent>
<WebsiteTitleComponent>Making Of</WebsiteTitleComponent> <WebsiteTitleComponent>Making Of</WebsiteTitleComponent>
<AlertComponent Type="SeverityType.Warning"> <AlertComponent Type="@SeverityType.Warning">
<Title>Under Construction</Title> <Title>Under Construction</Title>
<Message>This page is still being worked on. It will list the tech and design choices made for this website. It's is strictly for educational and reference purposes, and it has nothing to do with IMMORTAL: Gates of Pyre.</Message> <Message>This page is still being worked on. It will list the tech and design choices made for this website. It's is strictly for educational and reference purposes, and it has nothing to do with IMMORTAL: Gates of Pyre.</Message>
</AlertComponent> </AlertComponent>

8
IGP/Pages/MakingOf/Parts/MakingOfFeedback.razor

@ -28,19 +28,19 @@
<Title>Alert Message</Title> <Title>Alert Message</Title>
<Description>Used to convey important information to the viewer. Comes in Yellow (Warning), Blue (Information), Red (Error), and Green (Success). Mostly used to warn viewers of pre-alpha or incomplete content being viewed.</Description> <Description>Used to convey important information to the viewer. Comes in Yellow (Warning), Blue (Information), Red (Error), and Green (Success). Mostly used to warn viewers of pre-alpha or incomplete content being viewed.</Description>
<Example> <Example>
<AlertComponent Type="SeverityType.Warning"> <AlertComponent Type="@SeverityType.Warning">
<Title>Warning Alert Title</Title> <Title>Warning Alert Title</Title>
<Message>Warning Alert Message</Message> <Message>Warning Alert Message</Message>
</AlertComponent> </AlertComponent>
<AlertComponent Type="SeverityType.Information"> <AlertComponent Type="@SeverityType.Information">
<Title>Information Alert Title</Title> <Title>Information Alert Title</Title>
<Message>Information Alert Message</Message> <Message>Information Alert Message</Message>
</AlertComponent> </AlertComponent>
<AlertComponent Type="SeverityType.Error"> <AlertComponent Type="@SeverityType.Error">
<Title>Error Alert Title</Title> <Title>Error Alert Title</Title>
<Message>Error Alert Message</Message> <Message>Error Alert Message</Message>
</AlertComponent> </AlertComponent>
<AlertComponent Type="SeverityType.Success"> <AlertComponent Type="@SeverityType.Success">
<Title>Succsess Alert Title</Title> <Title>Succsess Alert Title</Title>
<Message>Succsess Alert Message</Message> <Message>Succsess Alert Message</Message>
</AlertComponent> </AlertComponent>

42
IGP/Portals/ToastPortal.razor

@ -0,0 +1,42 @@
@implements IDisposable;
@inject IToastService toastService
@if (toastService.HasToasts())
{
<div class="toastsContainer">
@foreach (var toast in toastService.GetToasts())
{
<ToastComponent Toast="toast"/>
}
</div>
}
<style>
.toastsContainer {
position: fixed;
top: 64px;
right: 64px;
}
</style>
@code {
protected override void OnInitialized()
{
toastService.Subscribe(OnUpdate);
}
public void Dispose()
{
toastService.Unsubscribe(OnUpdate);
}
void OnUpdate()
{
StateHasChanged();
}
}

9
IGP/Program.cs

@ -4,6 +4,7 @@ using Services;
using Services.Development; using Services.Development;
using Services.Immortal; using Services.Immortal;
using Services.Website; using Services.Website;
using System.Globalization;
#if NO_SQL #if NO_SQL
#else #else
@ -11,6 +12,11 @@ using Contexts;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
#endif #endif
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
var builder = WebAssemblyHostBuilder.CreateDefault(args); var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning); builder.Logging.SetMinimumLevel(LogLevel.Warning);
@ -19,6 +25,8 @@ builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddLocalization();
builder.Services.AddSingleton<INavigationService, NavigationService>(); builder.Services.AddSingleton<INavigationService, NavigationService>();
builder.Services.AddSingleton<IKeyService, KeyService>(); builder.Services.AddSingleton<IKeyService, KeyService>();
@ -40,6 +48,7 @@ builder.Services.AddSingleton(new HttpClient
builder.Services.AddSingleton<IEntityDialogService, EntityDialogService>(); builder.Services.AddSingleton<IEntityDialogService, EntityDialogService>();
builder.Services.AddSingleton<IToastService, ToastService>();
#if NO_SQL #if NO_SQL

2
IGP/_Imports.razor

@ -7,6 +7,7 @@
@using Components.Navigation @using Components.Navigation
@using Components.Shared @using Components.Shared
@using Components.Utils @using Components.Utils
@using System.Globalization
@using IGP.Dialog @using IGP.Dialog
@using IGP.Pages @using IGP.Pages
@using IGP.Pages.Agile.Parts @using IGP.Pages.Agile.Parts
@ -27,6 +28,7 @@
@using IGP.Pages.Notes.Parts @using IGP.Pages.Notes.Parts
@using IGP.Portals @using IGP.Portals
@using Markdig @using Markdig
@using Model.Feedback
@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web

13
IGP/wwwroot/css/app.css

@ -4,6 +4,15 @@
@import "components/table.css"; @import "components/table.css";
:root { :root {
--severity-warning-color: #2a2000;
--severity-warning-border-color: #755c13;
--severity-error-color: #290102;
--severity-error-border-color: #4C2C33;
--severity-information-color: #030129;
--severity-information-border-color: #2c3a4c;
--severity-success-color: #042901;
--severity-success-border-color: #2E4C2C;
--accent: #432462; --accent: #432462;
--primary: #4308a3; --primary: #4308a3;
--primary-border: #2c0b62; --primary-border: #2c0b62;
@ -22,12 +31,14 @@
--info: #451376; --info: #451376;
--info-border: #210b36; --info-border: #210b36;
--info-hover: #451376;
--info-border-hover: #210b36;
--dialog-border-color: black; --dialog-border-color: black;
--dialog-border-width: 2px; --dialog-border-width: 2px;
--dialog-radius: 6px; --dialog-radius: 6px;
} }
html { html {
box-sizing: border-box; box-sizing: border-box;
} }

2
IGP/wwwroot/generated/AgileTaskModels.json

File diff suppressed because one or more lines are too long

9
IGP/wwwroot/index.html

@ -13,11 +13,11 @@
<link href="IGP.styles.css" rel="stylesheet"/> <link href="IGP.styles.css" rel="stylesheet"/>
</head> </head>
<body style="background-color: var(--background); color: white;"> <body style="background-color: #161618; color: white;">
<div id="app"> <div id="app">
<div style="width: 100vw; height: 100vh; background-color: black;"></div> <div style="width: 100vw; height: 100vh; background-color: black;"></div>
</div> </div>
<script src="_framework/blazor.webassembly.js"></script> <script src="_framework/blazor.webassembly.js" autostart="false"></script>
<script crossorigin="anonymous" <script crossorigin="anonymous"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script> src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
@ -28,6 +28,11 @@
integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2"
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script> src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script>
<script src="javascript/download.js"></script> <script src="javascript/download.js"></script>
<script>
Blazor.start({
applicationCulture: 'en-US'
});
</script>
</body> </body>
</html> </html>

9
Model/Feedback/SeverityType.cs

@ -0,0 +1,9 @@
namespace Model.Feedback;
public class SeverityType
{
public static string Warning = "Warning";
public static string Information = "Information";
public static string Error = "Error";
public static string Success = "Success";
}

8
Model/Feedback/ToastModel.cs

@ -0,0 +1,8 @@
namespace Model.Feedback;
public class ToastModel
{
public string Title { get; set; } = "addTitle";
public string Message { get; set; } = "addMessage";
public string SeverityType { get; set; } = "addType";
}

12
Services/IServices.cs

@ -15,11 +15,23 @@ using Model.Notes;
using Model.Website; using Model.Website;
using Model.Website.Enums; using Model.Website.Enums;
using Model.Development.Git; using Model.Development.Git;
using Model.Feedback;
using Model.Work.Tasks; using Model.Work.Tasks;
using Services.Immortal; using Services.Immortal;
namespace Services; namespace Services;
public interface IToastService
{
public void Subscribe(Action action);
public void Unsubscribe(Action action);
void AddToast(ToastModel toast);
void RemoveToast(ToastModel toast);
bool HasToasts();
List<ToastModel> GetToasts();
void ClearAllToasts();
}
public interface IEntityDialogService public interface IEntityDialogService
{ {

64
Services/Website/ToastService.cs

@ -0,0 +1,64 @@
using Model.Feedback;
namespace Services.Website;
public class ToastService : IToastService
{
private readonly List<ToastModel> toasts = new();
private event Action OnChange = null!;
#if DEBUG
public ToastService()
{
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Error, Title = "Example Error"});
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Information, Title = "Example Information"});
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Success, Title = "Example Success"});
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Warning, Title = "Example Warning"});
}
#endif
private void NotifyDataChanged() {
OnChange();
}
public void Subscribe(Action action) {
OnChange += action;
}
public void Unsubscribe(Action action) {
OnChange += action;
}
public void AddToast(ToastModel toast)
{
toasts.Add(toast);
NotifyDataChanged();
}
public void RemoveToast(ToastModel toast)
{
toasts.Remove(toast);
NotifyDataChanged();
}
public bool HasToasts()
{
return toasts.Count > 0;
}
public List<ToastModel> GetToasts()
{
return toasts;
}
public void ClearAllToasts()
{
toasts.Clear();
NotifyDataChanged();
}
}
Loading…
Cancel
Save