diff --git a/.github/workflows/azure-static-web-apps-lemon-ground-063b78b1e.yml b/.github/workflows/azure-static-web-apps-lemon-ground-063b78b1e.yml new file mode 100644 index 0000000..4b258fa --- /dev/null +++ b/.github/workflows/azure-static-web-apps-lemon-ground-063b78b1e.yml @@ -0,0 +1,46 @@ +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - authentication + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - authentication + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v3 + with: + submodules: true + lfs: false + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LEMON_GROUND_063B78B1E }} + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + action: "upload" + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: "Client" # App source code path + api_location: "Api" # Api source code path - optional + output_location: "wwwroot" # Built app content directory - optional + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LEMON_GROUND_063B78B1E }} + action: "close" diff --git a/App.razor b/App.razor deleted file mode 100644 index 34eb91e..0000000 --- a/App.razor +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - @if (context.User.Identity?.IsAuthenticated != true) - { - - } - else - { -

You are not authorized to access this resource.

- } -
-
- -
-
-
diff --git a/DungeonMasterDashboard.Server/Controllers/AccountController.cs b/DungeonMasterDashboard.Server/Controllers/AccountController.cs new file mode 100644 index 0000000..2b3ee0a --- /dev/null +++ b/DungeonMasterDashboard.Server/Controllers/AccountController.cs @@ -0,0 +1,52 @@ +using DungeonMasterDashboard.Server.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; + +namespace DungeonMasterDashboard.Server.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class AccountController : ControllerBase + { + private readonly UserManager userManager; + + public AccountController(UserManager userManager) + { + this.userManager = userManager; + } + + [HttpGet] + public IActionResult Welcome() + { + if (User.Identity == null || !User.Identity.IsAuthenticated) + { + return Ok("You are NOT authenticated"); + } + + return Ok("You are authenticated"); + } + + [Authorize] + [HttpGet("Profile")] + public async Task Profile() + { + var currentUser = await userManager.GetUserAsync(User); + if (currentUser == null) + { + return BadRequest(); + } + + var userProfile = new UserProfile + { + Id = currentUser.Id, + Name = currentUser.UserName ?? "", + Email = currentUser.Email ?? "", + PhoneNumber = currentUser.PhoneNumber ?? "" + }; + + return Ok(userProfile); + } + } +} diff --git a/DungeonMasterDashboard.Server/DungeonMasterDashboard.Server.csproj b/DungeonMasterDashboard.Server/DungeonMasterDashboard.Server.csproj new file mode 100644 index 0000000..1e8abfd --- /dev/null +++ b/DungeonMasterDashboard.Server/DungeonMasterDashboard.Server.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + + + diff --git a/DungeonMasterDashboard.Server/Models/UserProfile.cs b/DungeonMasterDashboard.Server/Models/UserProfile.cs new file mode 100644 index 0000000..7ed26f4 --- /dev/null +++ b/DungeonMasterDashboard.Server/Models/UserProfile.cs @@ -0,0 +1,11 @@ +namespace DungeonMasterDashboard.Server.Models +{ + public class UserProfile + { + public string Id { get; set; } = ""; + public string Name { get; set; } = ""; + public string Email { get; set; } = ""; + public string PhoneNumber { get; set; } = ""; + + } +} diff --git a/DungeonMasterDashboard.Server/Program.cs b/DungeonMasterDashboard.Server/Program.cs new file mode 100644 index 0000000..596c6bd --- /dev/null +++ b/DungeonMasterDashboard.Server/Program.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.ResponseCompression; + +var builder = WebApplication.CreateBuilder(new WebApplicationOptions +{ + Args = args, + ContentRootPath = AppContext.BaseDirectory, + WebRootPath = "wwwroot" +}); + +builder.Services.AddControllers(); + +builder.WebHost.UseUrls("http://0.0.0.0:8080"); + +var app = builder.Build(); + +app.UseHttpsRedirection(); + +app.UseBlazorFrameworkFiles(); +app.UseStaticFiles(); + +app.UseRouting(); + +app.MapControllers(); +app.MapFallbackToFile("index.html"); + +app.Run(); diff --git a/DungeonMasterDashboard.Server/Properties/launchSettings.json b/DungeonMasterDashboard.Server/Properties/launchSettings.json new file mode 100644 index 0000000..6316d96 --- /dev/null +++ b/DungeonMasterDashboard.Server/Properties/launchSettings.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5041", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7090;http://localhost:5041", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DungeonMasterDashboard.Server/appsettings.Development.json b/DungeonMasterDashboard.Server/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/DungeonMasterDashboard.Server/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DungeonMasterDashboard.Server/appsettings.json b/DungeonMasterDashboard.Server/appsettings.json new file mode 100644 index 0000000..a29e5b5 --- /dev/null +++ b/DungeonMasterDashboard.Server/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=dm_dashboard;Integrated Security=True;TrustServerCertificate=True" + } +} diff --git a/DungeonMasterDashboard.Server/dotnet-tools.json b/DungeonMasterDashboard.Server/dotnet-tools.json new file mode 100644 index 0000000..12789b3 --- /dev/null +++ b/DungeonMasterDashboard.Server/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "10.0.3", + "commands": [ + "dotnet-ef" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/DungeonMasterDashboard.csproj b/DungeonMasterDashboard.csproj deleted file mode 100644 index 9fc42bd..0000000 --- a/DungeonMasterDashboard.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - net10.0 - enable - enable - true - service-worker-assets.js - true - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - diff --git a/DungeonMasterDashboard.slnx b/DungeonMasterDashboard.slnx deleted file mode 100644 index 5f538c5..0000000 --- a/DungeonMasterDashboard.slnx +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/.github/workflows/gh-pages.yml b/DungeonMasterDashboard/.github/workflows/gh-pages.yml similarity index 100% rename from .github/workflows/gh-pages.yml rename to DungeonMasterDashboard/.github/workflows/gh-pages.yml diff --git a/DungeonMasterDashboard/App.razor b/DungeonMasterDashboard/App.razor new file mode 100644 index 0000000..8030f94 --- /dev/null +++ b/DungeonMasterDashboard/App.razor @@ -0,0 +1,17 @@ + + + + @* + @if (context.User.Identity?.IsAuthenticated != true) + { + + } + else + { +

You are not authorized to access this resource.

+ } +
*@ +
+ +
+
diff --git a/DungeonMasterDashboard/DungeonMasterDashboard.csproj b/DungeonMasterDashboard/DungeonMasterDashboard.csproj new file mode 100644 index 0000000..542be95 --- /dev/null +++ b/DungeonMasterDashboard/DungeonMasterDashboard.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + enable + enable + true + service-worker-assets.js + + + + + + + + + + + + + + + diff --git a/DungeonMasterDashboard/DungeonMasterDashboard.slnx b/DungeonMasterDashboard/DungeonMasterDashboard.slnx new file mode 100644 index 0000000..c2870be --- /dev/null +++ b/DungeonMasterDashboard/DungeonMasterDashboard.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/DungeonMasterDashboard/Layout/LoginDisplay.razor b/DungeonMasterDashboard/Layout/LoginDisplay.razor new file mode 100644 index 0000000..0d616bd --- /dev/null +++ b/DungeonMasterDashboard/Layout/LoginDisplay.razor @@ -0,0 +1,22 @@ +@inject NavigationManager Navigation +@* @inject AuthenticationStateProvider authStateProvider *@ + +@* + + Hello, @context.User.Identity?.Name! + + + + Log in + Register + + *@ + +@code{ + // public void BeginLogOut() + // { + // var custAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvider; + // custAuthStateProvider.Logout(); + // Navigation.NavigateTo("/"); + // } +} diff --git a/Layout/MainLayout.razor b/DungeonMasterDashboard/Layout/MainLayout.razor similarity index 77% rename from Layout/MainLayout.razor rename to DungeonMasterDashboard/Layout/MainLayout.razor index ca781b1..8dceaf1 100644 --- a/Layout/MainLayout.razor +++ b/DungeonMasterDashboard/Layout/MainLayout.razor @@ -7,7 +7,6 @@
- About
diff --git a/Layout/MainLayout.razor.css b/DungeonMasterDashboard/Layout/MainLayout.razor.css similarity index 94% rename from Layout/MainLayout.razor.css rename to DungeonMasterDashboard/Layout/MainLayout.razor.css index ecf25e5..baef3ee 100644 --- a/Layout/MainLayout.razor.css +++ b/DungeonMasterDashboard/Layout/MainLayout.razor.css @@ -1,77 +1,77 @@ -.page { - position: relative; - display: flex; - flex-direction: column; -} - -main { - flex: 1; -} - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - - .top-row ::deep a, .top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; - } - - .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { - text-decoration: underline; - } - - .top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } - -@media (max-width: 640.98px) { - .top-row { - justify-content: space-between; - } - - .top-row ::deep a, .top-row ::deep .btn-link { - margin-left: 0; - } -} - -@media (min-width: 641px) { - .page { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .top-row { - position: sticky; - top: 0; - z-index: 1; - } - - .top-row.auth ::deep a:first-child { - flex: 1; - text-align: right; - width: 0; - } - - .top-row, article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } -} +.page { + position: relative; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} + +.sidebar { + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); +} + +.top-row { + background-color: #f7f7f7; + border-bottom: 1px solid #d6d5d5; + justify-content: flex-end; + height: 3.5rem; + display: flex; + align-items: center; +} + + .top-row ::deep a, .top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; + } + + .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { + text-decoration: underline; + } + + .top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; + } + +@media (max-width: 640.98px) { + .top-row { + justify-content: space-between; + } + + .top-row ::deep a, .top-row ::deep .btn-link { + margin-left: 0; + } +} + +@media (min-width: 641px) { + .page { + flex-direction: row; + } + + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } + + .top-row { + position: sticky; + top: 0; + z-index: 1; + } + + .top-row.auth ::deep a:first-child { + flex: 1; + text-align: right; + width: 0; + } + + .top-row, article { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } +} diff --git a/DungeonMasterDashboard/Layout/NavMenu.razor b/DungeonMasterDashboard/Layout/NavMenu.razor new file mode 100644 index 0000000..6e14523 --- /dev/null +++ b/DungeonMasterDashboard/Layout/NavMenu.razor @@ -0,0 +1,49 @@ + + + + +@code { + private bool collapseNavMenu = true; + + private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; + + private void ToggleNavMenu() + { + collapseNavMenu = !collapseNavMenu; + } +} diff --git a/Layout/NavMenu.razor.css b/DungeonMasterDashboard/Layout/NavMenu.razor.css similarity index 96% rename from Layout/NavMenu.razor.css rename to DungeonMasterDashboard/Layout/NavMenu.razor.css index 617b89c..6724fd1 100644 --- a/Layout/NavMenu.razor.css +++ b/DungeonMasterDashboard/Layout/NavMenu.razor.css @@ -1,83 +1,83 @@ -.navbar-toggler { - background-color: rgba(255, 255, 255, 0.1); -} - -.top-row { - min-height: 3.5rem; - background-color: rgba(0,0,0,0.4); -} - -.navbar-brand { - font-size: 1.1rem; -} - -.bi { - display: inline-block; - position: relative; - width: 1.25rem; - height: 1.25rem; - margin-right: 0.75rem; - top: -1px; - background-size: cover; -} - -.bi-house-door-fill-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); -} - -.bi-plus-square-fill-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); -} - -.bi-list-nested-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); -} - -.nav-item { - font-size: 0.9rem; - padding-bottom: 0.5rem; -} - - .nav-item:first-of-type { - padding-top: 1rem; - } - - .nav-item:last-of-type { - padding-bottom: 1rem; - } - - .nav-item ::deep a { - color: #d7d7d7; - border-radius: 4px; - height: 3rem; - display: flex; - align-items: center; - line-height: 3rem; - } - -.nav-item ::deep a.active { - background-color: rgba(255,255,255,0.37); - color: white; -} - -.nav-item ::deep a:hover { - background-color: rgba(255,255,255,0.1); - color: white; -} - -@media (min-width: 641px) { - .navbar-toggler { - display: none; - } - - .collapse { - /* Never collapse the sidebar for wide screens */ - display: block; - } - - .nav-scrollable { - /* Allow sidebar to scroll for tall menus */ - height: calc(100vh - 3.5rem); - overflow-y: auto; - } -} +.navbar-toggler { + background-color: rgba(255, 255, 255, 0.1); +} + +.top-row { + min-height: 3.5rem; + background-color: rgba(0,0,0,0.4); +} + +.navbar-brand { + font-size: 1.1rem; +} + +.bi { + display: inline-block; + position: relative; + width: 1.25rem; + height: 1.25rem; + margin-right: 0.75rem; + top: -1px; + background-size: cover; +} + +.bi-house-door-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); +} + +.bi-plus-square-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); +} + +.bi-list-nested-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); +} + +.nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + + .nav-item:first-of-type { + padding-top: 1rem; + } + + .nav-item:last-of-type { + padding-bottom: 1rem; + } + + .nav-item ::deep a { + color: #d7d7d7; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + } + +.nav-item ::deep a.active { + background-color: rgba(255,255,255,0.37); + color: white; +} + +.nav-item ::deep a:hover { + background-color: rgba(255,255,255,0.1); + color: white; +} + +@media (min-width: 641px) { + .navbar-toggler { + display: none; + } + + .collapse { + /* Never collapse the sidebar for wide screens */ + display: block; + } + + .nav-scrollable { + /* Allow sidebar to scroll for tall menus */ + height: calc(100vh - 3.5rem); + overflow-y: auto; + } +} diff --git a/DungeonMasterDashboard/Layout/RedirectToLogin.razor b/DungeonMasterDashboard/Layout/RedirectToLogin.razor new file mode 100644 index 0000000..bf01957 --- /dev/null +++ b/DungeonMasterDashboard/Layout/RedirectToLogin.razor @@ -0,0 +1,8 @@ +@inject NavigationManager Navigation + +@code { + protected override void OnInitialized() + { + Navigation.NavigateTo("auth/login"); + } +} diff --git a/DungeonMasterDashboard/Models/RegisterDto.cs b/DungeonMasterDashboard/Models/RegisterDto.cs new file mode 100644 index 0000000..50ad32a --- /dev/null +++ b/DungeonMasterDashboard/Models/RegisterDto.cs @@ -0,0 +1,8 @@ +namespace DungeonMasterDashboard.Models +{ + public class RegisterDto + { + public string Email { get; set; } = ""; + public string Password { get; set; } = ""; + } +} diff --git a/DungeonMasterDashboard/Models/UserProfile.cs b/DungeonMasterDashboard/Models/UserProfile.cs new file mode 100644 index 0000000..8b4b0d2 --- /dev/null +++ b/DungeonMasterDashboard/Models/UserProfile.cs @@ -0,0 +1,11 @@ +namespace DungeonMasterDashboard.Models +{ + public class UserProfile + { + public string Id { get; set; } = ""; + public string Name { get; set; } = ""; + public string Email { get; set; } = ""; + public string PhoneNumber { get; set; } = ""; + + } +} diff --git a/DungeonMasterDashboard/Pages/Authentication.razor b/DungeonMasterDashboard/Pages/Authentication.razor new file mode 100644 index 0000000..183b5cf --- /dev/null +++ b/DungeonMasterDashboard/Pages/Authentication.razor @@ -0,0 +1,149 @@ +@page "/auth/{action}" + +DMD @Action + +@if (Action == "login") +{ +
+

Login

+
+ + @if (error.Length > 0) + { + + } + + @*Log In Form*@ + @*EMAIL*@ +
+ + +
+ + @*PASSWORD*@ +
+ + +
+ + @* LOG IN BUTTON AND CANCEL +
+
+ +
+
+ Cancel +
+
*@ +
+} else if (Action == "register") +{ +
+
+
+

Register

+
+ + @if (errors.Length > 0) + { + + } + + @*Register Form*@ + @*EMAIL*@ +
+ +
+ +
+
+ + @*PASSWORD*@ +
+ +
+ +
+
+ + @*CONFIRM PASSWORD*@ +
+ +
+ +
+
+ + @* REGISTER BUTTON & CANCEL +
+
+ +
+
+ Cancel +
+
*@ +
+
+
+} + +@* @inject AuthenticationStateProvider provider *@ +@inject NavigationManager navManager +@code{ + [Parameter] public string? Action { get; set; } + + private string email = ""; + private string password = ""; + private string error = ""; + + // Registration fields + private string[] errors = []; + private string confirmPassword = ""; + + // private async Task LoginAsync() + // { + // var authStateProvider = (CustomAuthenticationStateProvider)provider; + // var formResult = await authStateProvider.LoginAsync(email, password); + // if (formResult.Success) + // { + // navManager.NavigateTo("/"); + // } else + // { + // error = formResult.Errors[0]; + // } + // } + + // private async Task RegisterAsync() + // { + // if (password != confirmPassword) + // { + // errors = ["Password and Confirm Password do not match!"]; + // return; + // } + // var authStateProvider = (CustomAuthenticationStateProvider)provider; + // var registerDto = new RegisterDto + // { + // Email = email, + // Password = password + // }; + // var formResult = await authStateProvider.RegisterAsync(registerDto); + // if (formResult.Success) + // { + // navManager.NavigateTo("/"); + // } else + // { + // errors = formResult.Errors; + // } + // } +} diff --git a/Pages/Counter.razor b/DungeonMasterDashboard/Pages/Counter.razor similarity index 93% rename from Pages/Counter.razor rename to DungeonMasterDashboard/Pages/Counter.razor index 9340be8..625853e 100644 --- a/Pages/Counter.razor +++ b/DungeonMasterDashboard/Pages/Counter.razor @@ -1,6 +1,5 @@ @page "/counter" @using Microsoft.AspNetCore.Authorization -@attribute [Authorize] Counter diff --git a/DungeonMasterDashboard/Pages/Home.razor b/DungeonMasterDashboard/Pages/Home.razor new file mode 100644 index 0000000..9001e0b --- /dev/null +++ b/DungeonMasterDashboard/Pages/Home.razor @@ -0,0 +1,7 @@ +@page "/" + +Home + +

Hello, world!

+ +Welcome to your new app. diff --git a/Pages/NotFound.razor b/DungeonMasterDashboard/Pages/NotFound.razor similarity index 100% rename from Pages/NotFound.razor rename to DungeonMasterDashboard/Pages/NotFound.razor diff --git a/DungeonMasterDashboard/Pages/Profile.razor b/DungeonMasterDashboard/Pages/Profile.razor new file mode 100644 index 0000000..b6f6acb --- /dev/null +++ b/DungeonMasterDashboard/Pages/Profile.razor @@ -0,0 +1,53 @@ +@page "/profile" + +DMD Profile + +@if (user == null) +{ +

@message

+} +else +{ +

Profile

+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+} + +@inject HttpClient httpClient +@code { + private UserProfile? user = null; + private string message = ""; + + protected override async Task OnInitializedAsync() + { + try + { + message = "Loading. . ."; + + user = await httpClient.GetFromJsonAsync("api/Account/Profile"); + } + catch + { + message = "Cannot read user profile"; + } + } +} diff --git a/Program.cs b/DungeonMasterDashboard/Program.cs similarity index 59% rename from Program.cs rename to DungeonMasterDashboard/Program.cs index c845e22..9ea7066 100644 --- a/Program.cs +++ b/DungeonMasterDashboard/Program.cs @@ -3,14 +3,15 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); + builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); -builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); - -builder.Services.AddOidcAuthentication(options => +// If you don't have an API yet, just point to the same origin. +// This avoids requiring WebApiAddress. +builder.Services.AddScoped(_ => new HttpClient { - builder.Configuration.Bind("Auth0", options.ProviderOptions); + BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); await builder.Build().RunAsync(); diff --git a/Properties/launchSettings.json b/DungeonMasterDashboard/Properties/launchSettings.json similarity index 96% rename from Properties/launchSettings.json rename to DungeonMasterDashboard/Properties/launchSettings.json index 4b4f942..c6569c4 100644 --- a/Properties/launchSettings.json +++ b/DungeonMasterDashboard/Properties/launchSettings.json @@ -1,15 +1,15 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:7277;http://localhost:5095", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7277;http://localhost:5095", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DungeonMasterDashboard/Services/CustomAuthenticationStateProvider.cs b/DungeonMasterDashboard/Services/CustomAuthenticationStateProvider.cs new file mode 100644 index 0000000..241a989 --- /dev/null +++ b/DungeonMasterDashboard/Services/CustomAuthenticationStateProvider.cs @@ -0,0 +1,150 @@ +using Microsoft.AspNetCore.Components.Authorization; +using System.Net.Http.Json; +using System.Security.Claims; +using System.Text.Json.Nodes; +using System.Net.Http.Headers; +using Blazored.LocalStorage; +using DungeonMasterDashboard.Models; + +namespace DungeonMasterDashboard.Services +{ + public class CustomAuthenticationStateProvider : AuthenticationStateProvider + { + private readonly HttpClient httpClient; + private readonly ISyncLocalStorageService localStorage; + + public CustomAuthenticationStateProvider(HttpClient httpClient, ISyncLocalStorageService localStorage) + { + this.httpClient = httpClient; + this.localStorage = localStorage; + + var accessToken = localStorage.GetItem("accessToken"); + if (accessToken != null) + { + this.httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + } + } + + public override async Task GetAuthenticationStateAsync() + { + /* + //var user = new ClaimsPrincipal(new ClaimsIdentity()); // non-authenticated user + var claims = new List { new Claim(ClaimTypes.Name, "John") }; + var identity = new ClaimsIdentity(claims, "ANY"); + var user = new ClaimsPrincipal(identity); + + return Task.FromResult(new AuthenticationState(user)); + */ + + var user = new ClaimsPrincipal(new ClaimsIdentity()); // non-authenticated user + + try + { + var response = await httpClient.GetAsync("manage/info"); + if (response.IsSuccessStatusCode) + { + var strResponse = await response.Content.ReadAsStringAsync(); + var jsonResponse = JsonNode.Parse(strResponse); + var email = jsonResponse!["email"]!.ToString(); + + var claims = new List + { + new(ClaimTypes.Name, email), + new(ClaimTypes.Email, email) + }; + + // Set the principal + var identity = new ClaimsIdentity(claims, "Token"); + user = new ClaimsPrincipal(identity); + return new AuthenticationState(user); + } + } + catch + { + + } + + return new AuthenticationState(user); + } + + public async Task LoginAsync(string email, string password) + { + try + { + var response = await httpClient.PostAsJsonAsync("/login", new { email, password }); + if (response.IsSuccessStatusCode) + { + var strResponse = await response.Content.ReadAsStringAsync(); + var jsonResponse = JsonNode.Parse(strResponse); + var accessToken = jsonResponse?["accessToken"]?.ToString(); + var refreshToken = jsonResponse?["refreshToken"]?.ToString(); + + localStorage.SetItem("accessToken", accessToken); + localStorage.SetItem("refreshToken", refreshToken); + + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + + // Refresh auth state + NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); + + // Success! + return new FormResult { Success = true }; + } + else + { + return new FormResult { Success = false, Errors = ["Bad Email or Password"] }; + } + } catch { } + + return new FormResult { Success = false, Errors = [ "Connection Error" ] }; + } + + public void Logout() + { + // delete tokens from local storage + localStorage.RemoveItem("accessToken"); + localStorage.RemoveItem("refreshToken"); + httpClient.DefaultRequestHeaders.Authorization = null; + NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); + } + + public async Task RegisterAsync(RegisterDto registerDto) + { + try + { + var response = await httpClient.PostAsJsonAsync("/register", registerDto); + if (response.IsSuccessStatusCode) + { + var loginResponse = await LoginAsync(registerDto.Email, registerDto.Password); + return loginResponse; + } + + // Registration Errors + var strResponse = await response.Content.ReadAsStringAsync(); + Console.WriteLine(strResponse); + var jsonResponse = JsonNode.Parse(strResponse); + var errorsObject = jsonResponse!["errors"]!.AsObject(); + var errorsList = new List(); + foreach (var error in errorsObject) + { + errorsList.Add(error.Value![0]!.ToString()); + } + + var formResult = new FormResult + { + Success = false, + Errors = errorsList.ToArray() + }; + + return formResult; + } catch { } + return new FormResult { Success = false, Errors = ["Connection Error"] }; + } + } + + public class FormResult + { + public bool Success { get; set; } + public string[] Errors { get; set; } = []; + } +} diff --git a/_Imports.razor b/DungeonMasterDashboard/_Imports.razor similarity index 83% rename from _Imports.razor rename to DungeonMasterDashboard/_Imports.razor index cc17512..393c71a 100644 --- a/_Imports.razor +++ b/DungeonMasterDashboard/_Imports.razor @@ -1,6 +1,5 @@ @using System.Net.Http @using System.Net.Http.Json -@using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @@ -9,3 +8,6 @@ @using Microsoft.JSInterop @using DungeonMasterDashboard @using DungeonMasterDashboard.Layout + +@using DungeonMasterDashboard.Services +@using DungeonMasterDashboard.Models diff --git a/wwwroot/appsettings.Development.json b/DungeonMasterDashboard/wwwroot/appsettings.Development.json similarity index 95% rename from wwwroot/appsettings.Development.json rename to DungeonMasterDashboard/wwwroot/appsettings.Development.json index fdae94a..5b0f66f 100644 --- a/wwwroot/appsettings.Development.json +++ b/DungeonMasterDashboard/wwwroot/appsettings.Development.json @@ -1,6 +1,6 @@ -{ - "Local": { - "Authority": "https://login.microsoftonline.com/", - "ClientId": "33333333-3333-3333-33333333333333333" - } -} +{ + "Local": { + "Authority": "https://login.microsoftonline.com/", + "ClientId": "33333333-3333-3333-33333333333333333" + } +} diff --git a/DungeonMasterDashboard/wwwroot/appsettings.json b/DungeonMasterDashboard/wwwroot/appsettings.json new file mode 100644 index 0000000..3872340 --- /dev/null +++ b/DungeonMasterDashboard/wwwroot/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Application": "Warning" + } + }, + "AllowedHosts": "*", + "WebApiAddress": "https://localhost:7090" +} diff --git a/wwwroot/css/app.css b/DungeonMasterDashboard/wwwroot/css/app.css similarity index 97% rename from wwwroot/css/app.css rename to DungeonMasterDashboard/wwwroot/css/app.css index fe44b1d..08b5997 100644 --- a/wwwroot/css/app.css +++ b/DungeonMasterDashboard/wwwroot/css/app.css @@ -1,115 +1,115 @@ -html, body { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -h1:focus { - outline: none; -} - -a, .btn-link { - color: #0071c1; -} - -.btn-primary { - color: #fff; - background-color: #1b6ec2; - border-color: #1861ac; -} - -.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; -} - -.content { - padding-top: 1.1rem; -} - -.valid.modified:not([type=checkbox]) { - outline: 1px solid #26b050; -} - -.invalid { - outline: 1px solid red; -} - -.validation-message { - color: red; -} - -#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; - position: fixed; - width: 100%; - z-index: 1000; -} - - #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; - padding: 1rem 1rem 1rem 3.7rem; - color: white; -} - - .blazor-error-boundary::after { - content: "An error has occurred." - } - -.loading-progress { - position: absolute; - display: block; - width: 8rem; - height: 8rem; - inset: 20vh 0 auto 0; - margin: 0 auto 0 auto; -} - - .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-text { - position: absolute; - text-align: center; - font-weight: bold; - inset: calc(20vh + 3.25rem) 0 auto 0.2rem; -} - - .loading-progress-text:after { - content: var(--blazor-load-percentage-text, "Loading"); - } - -code { - color: #c02d76; -} - -.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder { - color: var(--bs-secondary-color); - text-align: end; -} - -.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder { - text-align: start; +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +h1:focus { + outline: none; +} + +a, .btn-link { + color: #0071c1; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.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; +} + +.content { + padding-top: 1.1rem; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + +#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; + position: fixed; + width: 100%; + z-index: 1000; +} + + #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; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + + .blazor-error-boundary::after { + content: "An error has occurred." + } + +.loading-progress { + position: absolute; + display: block; + width: 8rem; + height: 8rem; + inset: 20vh 0 auto 0; + margin: 0 auto 0 auto; +} + + .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-text { + position: absolute; + text-align: center; + font-weight: bold; + inset: calc(20vh + 3.25rem) 0 auto 0.2rem; +} + + .loading-progress-text:after { + content: var(--blazor-load-percentage-text, "Loading"); + } + +code { + color: #c02d76; +} + +.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder { + color: var(--bs-secondary-color); + text-align: end; +} + +.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder { + text-align: start; } \ No newline at end of file diff --git a/wwwroot/favicon.png b/DungeonMasterDashboard/wwwroot/favicon.png similarity index 100% rename from wwwroot/favicon.png rename to DungeonMasterDashboard/wwwroot/favicon.png diff --git a/wwwroot/icon-192.png b/DungeonMasterDashboard/wwwroot/icon-192.png similarity index 100% rename from wwwroot/icon-192.png rename to DungeonMasterDashboard/wwwroot/icon-192.png diff --git a/wwwroot/icon-512.png b/DungeonMasterDashboard/wwwroot/icon-512.png similarity index 100% rename from wwwroot/icon-512.png rename to DungeonMasterDashboard/wwwroot/icon-512.png diff --git a/wwwroot/index.html b/DungeonMasterDashboard/wwwroot/index.html similarity index 84% rename from wwwroot/index.html rename to DungeonMasterDashboard/wwwroot/index.html index 2a99601..2a22fdd 100644 --- a/wwwroot/index.html +++ b/DungeonMasterDashboard/wwwroot/index.html @@ -31,8 +31,7 @@ Reload 🗙 - - + diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css diff --git a/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.js b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.js similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.js rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.js diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.js.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.min.js rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js diff --git a/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map b/DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map similarity index 100% rename from wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map rename to DungeonMasterDashboard/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map diff --git a/wwwroot/manifest.webmanifest b/DungeonMasterDashboard/wwwroot/manifest.webmanifest similarity index 100% rename from wwwroot/manifest.webmanifest rename to DungeonMasterDashboard/wwwroot/manifest.webmanifest diff --git a/wwwroot/sample-data/weather.json b/DungeonMasterDashboard/wwwroot/sample-data/weather.json similarity index 94% rename from wwwroot/sample-data/weather.json rename to DungeonMasterDashboard/wwwroot/sample-data/weather.json index b745973..f0648e7 100644 --- a/wwwroot/sample-data/weather.json +++ b/DungeonMasterDashboard/wwwroot/sample-data/weather.json @@ -1,27 +1,27 @@ -[ - { - "date": "2022-01-06", - "temperatureC": 1, - "summary": "Freezing" - }, - { - "date": "2022-01-07", - "temperatureC": 14, - "summary": "Bracing" - }, - { - "date": "2022-01-08", - "temperatureC": -13, - "summary": "Freezing" - }, - { - "date": "2022-01-09", - "temperatureC": -16, - "summary": "Balmy" - }, - { - "date": "2022-01-10", - "temperatureC": -2, - "summary": "Chilly" - } -] +[ + { + "date": "2022-01-06", + "temperatureC": 1, + "summary": "Freezing" + }, + { + "date": "2022-01-07", + "temperatureC": 14, + "summary": "Bracing" + }, + { + "date": "2022-01-08", + "temperatureC": -13, + "summary": "Freezing" + }, + { + "date": "2022-01-09", + "temperatureC": -16, + "summary": "Balmy" + }, + { + "date": "2022-01-10", + "temperatureC": -2, + "summary": "Chilly" + } +] diff --git a/wwwroot/service-worker.js b/DungeonMasterDashboard/wwwroot/service-worker.js similarity index 98% rename from wwwroot/service-worker.js rename to DungeonMasterDashboard/wwwroot/service-worker.js index fe614da..c6d0085 100644 --- a/wwwroot/service-worker.js +++ b/DungeonMasterDashboard/wwwroot/service-worker.js @@ -1,4 +1,4 @@ -// In development, always fetch from the network and do not enable offline support. -// This is because caching would make development more difficult (changes would not -// be reflected on the first load after each change). -self.addEventListener('fetch', () => { }); +// In development, always fetch from the network and do not enable offline support. +// This is because caching would make development more difficult (changes would not +// be reflected on the first load after each change). +self.addEventListener('fetch', () => { }); diff --git a/wwwroot/service-worker.published.js b/DungeonMasterDashboard/wwwroot/service-worker.published.js similarity index 97% rename from wwwroot/service-worker.published.js rename to DungeonMasterDashboard/wwwroot/service-worker.published.js index 51a0e5c..1899cb5 100644 --- a/wwwroot/service-worker.published.js +++ b/DungeonMasterDashboard/wwwroot/service-worker.published.js @@ -1,55 +1,55 @@ -// Caution! Be sure you understand the caveats before publishing an application with -// offline support. See https://aka.ms/blazor-offline-considerations - -self.importScripts('./service-worker-assets.js'); -self.addEventListener('install', event => event.waitUntil(onInstall(event))); -self.addEventListener('activate', event => event.waitUntil(onActivate(event))); -self.addEventListener('fetch', event => event.respondWith(onFetch(event))); - -const cacheNamePrefix = 'offline-cache-'; -const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; -const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/, /\.webmanifest$/ ]; -const offlineAssetsExclude = [ /^service-worker\.js$/ ]; - -// Replace with your base path if you are hosting on a subfolder. Ensure there is a trailing '/'. -const base = "/"; -const baseUrl = new URL(base, self.origin); -const manifestUrlList = self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href); - -async function onInstall(event) { - console.info('Service worker: Install'); - - // Fetch and cache all matching items from the assets manifest - const assetsRequests = self.assetsManifest.assets - .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) - .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) - .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); - await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); -} - -async function onActivate(event) { - console.info('Service worker: Activate'); - - // Delete unused caches - const cacheKeys = await caches.keys(); - await Promise.all(cacheKeys - .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName) - .map(key => caches.delete(key))); -} - -async function onFetch(event) { - let cachedResponse = null; - if (event.request.method === 'GET') { - // For all navigation requests, try to serve index.html from cache, - // unless that request is for an offline resource. - // If you need some URLs to be server-rendered, edit the following check to exclude those URLs - const shouldServeIndexHtml = event.request.mode === 'navigate' - && !manifestUrlList.some(url => url === event.request.url); - - const request = shouldServeIndexHtml ? 'index.html' : event.request; - const cache = await caches.open(cacheName); - cachedResponse = await cache.match(request); - } - - return cachedResponse || fetch(event.request); -} +// Caution! Be sure you understand the caveats before publishing an application with +// offline support. See https://aka.ms/blazor-offline-considerations + +self.importScripts('./service-worker-assets.js'); +self.addEventListener('install', event => event.waitUntil(onInstall(event))); +self.addEventListener('activate', event => event.waitUntil(onActivate(event))); +self.addEventListener('fetch', event => event.respondWith(onFetch(event))); + +const cacheNamePrefix = 'offline-cache-'; +const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; +const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/, /\.webmanifest$/ ]; +const offlineAssetsExclude = [ /^service-worker\.js$/ ]; + +// Replace with your base path if you are hosting on a subfolder. Ensure there is a trailing '/'. +const base = "/"; +const baseUrl = new URL(base, self.origin); +const manifestUrlList = self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href); + +async function onInstall(event) { + console.info('Service worker: Install'); + + // Fetch and cache all matching items from the assets manifest + const assetsRequests = self.assetsManifest.assets + .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) + .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) + .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); + await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); +} + +async function onActivate(event) { + console.info('Service worker: Activate'); + + // Delete unused caches + const cacheKeys = await caches.keys(); + await Promise.all(cacheKeys + .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName) + .map(key => caches.delete(key))); +} + +async function onFetch(event) { + let cachedResponse = null; + if (event.request.method === 'GET') { + // For all navigation requests, try to serve index.html from cache, + // unless that request is for an offline resource. + // If you need some URLs to be server-rendered, edit the following check to exclude those URLs + const shouldServeIndexHtml = event.request.mode === 'navigate' + && !manifestUrlList.some(url => url === event.request.url); + + const request = shouldServeIndexHtml ? 'index.html' : event.request; + const cache = await caches.open(cacheName); + cachedResponse = await cache.match(request); + } + + return cachedResponse || fetch(event.request); +} diff --git a/Layout/LoginDisplay.razor b/Layout/LoginDisplay.razor deleted file mode 100644 index 7775a52..0000000 --- a/Layout/LoginDisplay.razor +++ /dev/null @@ -1,19 +0,0 @@ -@using Microsoft.AspNetCore.Components.WebAssembly.Authentication -@inject NavigationManager Navigation - - - - Hello, @context.User.Identity?.Name! - - - - Log in - - - -@code{ - public void BeginLogOut() - { - Navigation.NavigateToLogout("authentication/logout"); - } -} diff --git a/Layout/NavMenu.razor b/Layout/NavMenu.razor deleted file mode 100644 index 0c48203..0000000 --- a/Layout/NavMenu.razor +++ /dev/null @@ -1,39 +0,0 @@ - - - - -@code { - private bool collapseNavMenu = true; - - private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; - - private void ToggleNavMenu() - { - collapseNavMenu = !collapseNavMenu; - } -} diff --git a/Layout/RedirectToLogin.razor b/Layout/RedirectToLogin.razor deleted file mode 100644 index a1cf400..0000000 --- a/Layout/RedirectToLogin.razor +++ /dev/null @@ -1,9 +0,0 @@ -@using Microsoft.AspNetCore.Components.WebAssembly.Authentication -@inject NavigationManager Navigation - -@code { - protected override void OnInitialized() - { - Navigation.NavigateToLogin("authentication/login"); - } -} diff --git a/Pages/Authentication.razor b/Pages/Authentication.razor deleted file mode 100644 index a773ba0..0000000 --- a/Pages/Authentication.razor +++ /dev/null @@ -1,15 +0,0 @@ -@page "/authentication/{action}" -@using Microsoft.AspNetCore.Components.WebAssembly.Authentication - - -@if (Action == "login") -{ -

Log In Page

-} else -{ -

Not Log In Page

-} - -@code{ - [Parameter] public string? Action { get; set; } -} diff --git a/Pages/Home.razor b/Pages/Home.razor deleted file mode 100644 index 798591d..0000000 --- a/Pages/Home.razor +++ /dev/null @@ -1,11 +0,0 @@ -@page "/" - -Home - -

Hello, world!

- - - -Welcome to your new app. diff --git a/Pages/Weather.razor b/Pages/Weather.razor deleted file mode 100644 index 3ea2b1c..0000000 --- a/Pages/Weather.razor +++ /dev/null @@ -1,57 +0,0 @@ -@page "/weather" -@inject HttpClient Http - -Weather - -

Weather

- -

This component demonstrates fetching data from the server.

- -@if (forecasts == null) -{ -

Loading...

-} -else -{ - - - - - - - - - - - @foreach (var forecast in forecasts) - { - - - - - - - } - -
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
-} - -@code { - private WeatherForecast[]? forecasts; - - protected override async Task OnInitializedAsync() - { - forecasts = await Http.GetFromJsonAsync("sample-data/weather.json"); - } - - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public string? Summary { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - } -} diff --git a/README.md b/README.md index 8c695a2..46a774e 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# DungeonMasterDashboard \ No newline at end of file +# DungeonMasterDashboard + +This has saved me https://youtu.be/uYkfk-rMmlM?si=nmG6-jGQuyA-nf9D \ No newline at end of file diff --git a/wwwroot/appsettings.json b/wwwroot/appsettings.json deleted file mode 100644 index 6dcdbbe..0000000 --- a/wwwroot/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "Data Source=(local);Initial Catalog=NewDatabase;Integrated Security=True;Connect Timeout=30;Encrypt=True;Trust Server Certificate=True;Application Intent=ReadWrite;Multi Subnet Failover=False;Command Timeout=30" - }, - - "Local": { - "Authority": "https://login.microsoftonline.com/", - "ClientId": "33333333-3333-3333-33333333333333333" - } -}