diff --git a/testFrontend/SafeNSound.Frontend/Layout/NavMenu.razor b/testFrontend/SafeNSound.Frontend/Layout/NavMenu.razor
index b407901..2a0fd8a 100644
--- a/testFrontend/SafeNSound.Frontend/Layout/NavMenu.razor
+++ b/testFrontend/SafeNSound.Frontend/Layout/NavMenu.razor
@@ -10,8 +10,8 @@
<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
<nav class="nav flex-column">
<div class="nav-item px-3">
- <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
- <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
+ <NavLink class="nav-link" href="/Auth" Match="NavLinkMatch.All">
+ <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Auth
</NavLink>
</div>
<div class="nav-item px-3">
diff --git a/testFrontend/SafeNSound.Frontend/Pages/Auth.razor b/testFrontend/SafeNSound.Frontend/Pages/Auth.razor
new file mode 100644
index 0000000..533fc01
--- /dev/null
+++ b/testFrontend/SafeNSound.Frontend/Pages/Auth.razor
@@ -0,0 +1,68 @@
+@page "/Auth"
+
+
+<h1>Auth</h1>
+
+<span>Username (L?, R): </span>
+<FancyTextBox @bind-Value="@Username"/><br/>
+<span>Email (L? R): </span>
+<FancyTextBox @bind-Value="@Email"/><br/>
+<span>Password (L, R): </span>
+<FancyTextBox @bind-Value="@Password"/><br/>
+<span>Type (R): </span>
+<FancyTextBox @bind-Value="@UserType"/><span> (one of user|monitor|admin)</span><br/>
+<LinkButton OnClick="Login">Login</LinkButton>
+<LinkButton OnClick="Register">Register</LinkButton>
+<br/><br/>
+
+@if (Exception != null) {
+ <div class="alert alert-danger">
+ <strong>Error:</strong><br/>
+ <pre>
+ @Exception
+ </pre>
+ </div>
+}
+
+@if (Result != null) {
+ <div class="alert alert-success">
+ <strong>Result:</strong><br/>
+ <pre>
+ @Result.ToJson(indent: true)
+ </pre>
+ </div>
+}
+
+@code {
+ private string Username { get; set; } = "";
+ private string Email { get; set; } = "";
+ private string Password { get; set; } = "";
+ private string UserType { get; set; } = "";
+
+ private Exception? Exception { get; set; }
+ private object? Result { get; set; }
+
+ private async Task Register() {
+ Result = null;
+ Exception = null;
+ try {
+ Result = await Authentication.Register(new() {
+ Username = Username,
+ Password = Password,
+ Email = Email,
+ UserType = UserType
+ });
+ }
+ catch (Exception ex) {
+ Exception = ex;
+ }
+ finally {
+ StateHasChanged();
+ }
+ }
+
+ private Task Login() {
+ throw new NotImplementedException();
+ }
+
+}
\ No newline at end of file
diff --git a/testFrontend/SafeNSound.Frontend/Pages/Counter.razor b/testFrontend/SafeNSound.Frontend/Pages/Counter.razor
deleted file mode 100644
index 372905f..0000000
--- a/testFrontend/SafeNSound.Frontend/Pages/Counter.razor
+++ /dev/null
@@ -1,19 +0,0 @@
-@page "/counter"
-
-<PageTitle>Counter</PageTitle>
-
-<h1>Counter</h1>
-
-<p role="status">Current count: @currentCount</p>
-
-<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
-
-@code {
- private int currentCount = 0;
-
- private void IncrementCount()
- {
- currentCount++;
- }
-
-}
\ No newline at end of file
diff --git a/testFrontend/SafeNSound.Frontend/Program.cs b/testFrontend/SafeNSound.Frontend/Program.cs
index b48b6db..2642a75 100644
--- a/testFrontend/SafeNSound.Frontend/Program.cs
+++ b/testFrontend/SafeNSound.Frontend/Program.cs
@@ -1,11 +1,48 @@
+using System.Net;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using SafeNSound.Frontend;
+using SafeNSound.Sdk;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
+builder.Services.AddSingleton<SafeNSoundConfiguration>();
+builder.Services.AddSingleton<SafeNSoundAuthentication>();
+
+
+try {
+ builder.Configuration.AddJsonStream(await new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }.GetStreamAsync("/appsettings.json"));
+#if DEBUG
+ builder.Configuration.AddJsonStream(await new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }.GetStreamAsync("/appsettings.Development.json"));
+#endif
+}
+catch (HttpRequestException e) {
+ if (e.StatusCode == HttpStatusCode.NotFound)
+ Console.WriteLine("Could not load appsettings, server returned 404.");
+ else
+ Console.WriteLine("Could not load appsettings: " + e);
+}
+catch (Exception e) {
+ Console.WriteLine("Could not load appsettings: " + e);
+}
+
+builder.Logging.AddConfiguration(
+ builder.Configuration.GetSection("Logging"));
+
+builder.Services.AddBlazoredLocalStorage(config => {
+ config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
+ config.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
+ config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
+ config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
+ config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
+ config.JsonSerializerOptions.WriteIndented = false;
+});
await builder.Build().RunAsync();
\ No newline at end of file
diff --git a/testFrontend/SafeNSound.Frontend/SafeNSound.Frontend.csproj b/testFrontend/SafeNSound.Frontend/SafeNSound.Frontend.csproj
index 06f60b4..99a5265 100644
--- a/testFrontend/SafeNSound.Frontend/SafeNSound.Frontend.csproj
+++ b/testFrontend/SafeNSound.Frontend/SafeNSound.Frontend.csproj
@@ -5,11 +5,18 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
+
+ <BlazorEnableCompression>false</BlazorEnableCompression>
+ <BlazorCacheBootResources>false</BlazorCacheBootResources>
+ <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all"/>
+ <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.2" />
+ <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="9.0.1" />
+ <PackageReference Include="Blazored.LocalStorage" Version="4.5.0"/>
</ItemGroup>
<ItemGroup>
diff --git a/testFrontend/SafeNSound.Frontend/_Imports.razor b/testFrontend/SafeNSound.Frontend/_Imports.razor
index f125423..0103f88 100644
--- a/testFrontend/SafeNSound.Frontend/_Imports.razor
+++ b/testFrontend/SafeNSound.Frontend/_Imports.razor
@@ -7,4 +7,11 @@
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using SafeNSound.Frontend
-@using SafeNSound.Frontend.Layout
\ No newline at end of file
+@using SafeNSound.Frontend.Layout
+@using SafeNSound.Sdk
+
+@using ArcaneLibs.Blazor.Components
+@using ArcaneLibs.Extensions
+
+@inject SafeNSoundAuthentication Authentication
+@inject SafeNSoundConfiguration Config
\ No newline at end of file
diff --git a/testFrontend/SafeNSound.Frontend/wwwroot/appsettings.json b/testFrontend/SafeNSound.Frontend/wwwroot/appsettings.json
new file mode 100644
index 0000000..f77ef07
--- /dev/null
+++ b/testFrontend/SafeNSound.Frontend/wwwroot/appsettings.json
@@ -0,0 +1,13 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Trace",
+ "System": "Information",
+ "Microsoft": "Information",
+ "ArcaneLibs.Blazor.Components.AuthorizedImage": "Information"
+ }
+ },
+ "SafeNSound": {
+ "BaseUrl": "http://localhost:3000"
+ }
+}
diff --git a/testFrontend/SafeNSound.Frontend/wwwroot/css/app.css b/testFrontend/SafeNSound.Frontend/wwwroot/css/app.css
index 7b3eb5d..45a7488 100644
--- a/testFrontend/SafeNSound.Frontend/wwwroot/css/app.css
+++ b/testFrontend/SafeNSound.Frontend/wwwroot/css/app.css
@@ -1,5 +1,21 @@
+
+article > h3:first-child {
+ padding-top: 24px;
+}
+
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ background-color: #222;
+ color: #aaa;
+}
+
+#app > div > main > div {
+ background-color: #333;
+ border-bottom: none;
+}
+
+.table, .table-striped > tbody > tr:nth-of-type(odd), .table-hover > tbody > tr:hover {
+ color: unset;
}
h1:focus {
@@ -17,7 +33,7 @@ a, .btn-link {
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
- box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
+ box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
.content {
@@ -37,11 +53,9 @@ a, .btn-link {
}
#blazor-error-ui {
- color-scheme: light only;
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
- box-sizing: border-box;
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
@@ -50,22 +64,22 @@ a, .btn-link {
z-index: 1000;
}
- #blazor-error-ui .dismiss {
- cursor: pointer;
- position: absolute;
- right: 0.75rem;
- top: 0.5rem;
- }
+#blazor-error-ui .dismiss {
+ cursor: pointer;
+ position: absolute;
+ right: 0.75rem;
+ top: 0.5rem;
+}
.blazor-error-boundary {
- background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
+ background: url(data:image/svg+xml;base64,PHN2ZyB3aWv3aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
- .blazor-error-boundary::after {
- content: "An error has occurred."
- }
+.blazor-error-boundary::after {
+ content: "An error has occurred."
+}
.loading-progress {
position: relative;
@@ -75,19 +89,19 @@ a, .btn-link {
margin: 20vh auto 1rem auto;
}
- .loading-progress circle {
- fill: none;
- stroke: #e0e0e0;
- stroke-width: 0.6rem;
- transform-origin: 50% 50%;
- transform: rotate(-90deg);
- }
+.loading-progress circle {
+ fill: none;
+ stroke: #e0e0e0;
+ stroke-width: 0.6rem;
+ transform-origin: 50% 50%;
+ transform: rotate(-90deg);
+}
- .loading-progress circle:last-child {
- stroke: #1b6ec2;
- stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
- transition: stroke-dasharray 0.05s ease-in-out;
- }
+.loading-progress circle:last-child {
+ stroke: #1b6ec2;
+ stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
+ transition: stroke-dasharray 0.05s ease-in-out;
+}
.loading-progress-text {
position: absolute;
@@ -96,19 +110,10 @@ a, .btn-link {
inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}
- .loading-progress-text:after {
- content: var(--blazor-load-percentage-text, "Loading");
- }
-
-code {
- color: #c02d76;
+.loading-progress-text:after {
+ content: var(--blazor-load-percentage-text, "Loading");
}
-.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
- color: var(--bs-secondary-color);
- text-align: end;
+pre {
+ font-family: JetBrainsMono, var(--bs-font-monospace);
}
-
-.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
- text-align: start;
-}
\ No newline at end of file
|