Compare commits
27 commits
main
...
CornHusker
Author | SHA1 | Date | |
---|---|---|---|
db7ff97a20 | |||
50122f8447 | |||
24a4aa7a20 | |||
21ad7f208a | |||
075261de59 | |||
eb8c304020 | |||
4a6bca20bc | |||
4973464c88 | |||
e0d744ca5a | |||
6ef661f2d4 | |||
a5c5973414 | |||
158aec5dba | |||
749f827264 | |||
132fb649cb | |||
405032a6e3 | |||
759e49a64f | |||
2c3bb51f6b | |||
0e58107bdd | |||
a126d6415b | |||
158451d91f | |||
16e354aa12 | |||
645a2d4d5d | |||
e66cbcf262 | |||
35508c8264 | |||
56dda7b976 | |||
dd614b62b1 | |||
a97a181faa |
42 changed files with 1541 additions and 1 deletions
|
@ -3,7 +3,7 @@
|
|||
"isRoot": true,
|
||||
"tools": {
|
||||
"csharpier": {
|
||||
"version": "0.30.6",
|
||||
"version": "0.30.4",
|
||||
"commands": [
|
||||
"dotnet-csharpier"
|
||||
]
|
||||
|
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"ms-dotnettools.csharp",
|
||||
"ms-dotnettools.vscodeintellicode-csharp",
|
||||
"csharpier.csharpier-vscode",
|
||||
"patcx.vscode-nuget-gallery",
|
||||
"vasubasraj.flashpost"
|
||||
]
|
||||
}
|
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"dotnet.defaultSolution": "ZenithInfo.sln",
|
||||
"[csharp]": {
|
||||
"editor.defaultFormatter": "csharpier.csharpier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSaveMode": "file"
|
||||
},
|
||||
"files.associations": {
|
||||
"*.json": "jsonc"
|
||||
}
|
||||
}
|
|
@ -29,3 +29,4 @@ Please do not use issue identifiers as scopes.
|
|||
- `tooling`: changes to development tooling like dotnet tools
|
||||
- `deps`: changes to dependencies, such as updating dependencies or removing unused dependencies
|
||||
- `renovate`: changes to the Renovate configuration
|
||||
- `docker`: changes to the Dockerfile or docker-compose files
|
||||
|
|
20
Components/App.razor
Normal file
20
Components/App.razor
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="ZenithInfo.styles.css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Routes />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
23
Components/Layout/MainLayout.razor
Normal file
23
Components/Layout/MainLayout.razor
Normal file
|
@ -0,0 +1,23 @@
|
|||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<NavMenu />
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<div class="top-row px-4">
|
||||
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
|
||||
</div>
|
||||
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
96
Components/Layout/MainLayout.razor.css
Normal file
96
Components/Layout/MainLayout.razor.css
Normal file
|
@ -0,0 +1,96 @@
|
|||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
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;
|
||||
}
|
30
Components/Layout/NavMenu.razor
Normal file
30
Components/Layout/NavMenu.razor
Normal file
|
@ -0,0 +1,30 @@
|
|||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">ZenithInfo</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||
|
||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||
<nav class="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>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="counter">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="weather">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
105
Components/Layout/NavMenu.razor.css
Normal file
105
Components/Layout/NavMenu.razor.css
Normal file
|
@ -0,0 +1,105 @@
|
|||
.navbar-toggler {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggler:checked {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
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 .nav-link {
|
||||
color: #d7d7d7;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.37);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-toggler:checked ~ .nav-scrollable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
22
Components/Pages/Counter.razor
Normal file
22
Components/Pages/Counter.razor
Normal file
|
@ -0,0 +1,22 @@
|
|||
@page "/counter"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<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;
|
||||
|
||||
[Parameter]
|
||||
public int IncrementAmount { get; set; } = 1;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount += IncrementAmount;
|
||||
}
|
||||
}
|
36
Components/Pages/Error.razor
Normal file
36
Components/Pages/Error.razor
Normal file
|
@ -0,0 +1,36 @@
|
|||
@page "/Error"
|
||||
@using System.Diagnostics
|
||||
|
||||
<PageTitle>Error</PageTitle>
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
|
||||
@code{
|
||||
[CascadingParameter]
|
||||
private HttpContext? HttpContext { get; set; }
|
||||
|
||||
private string? RequestId { get; set; }
|
||||
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
protected override void OnInitialized() =>
|
||||
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||
}
|
9
Components/Pages/Home.razor
Normal file
9
Components/Pages/Home.razor
Normal file
|
@ -0,0 +1,9 @@
|
|||
@page "/"
|
||||
|
||||
<PageTitle>Home</PageTitle>
|
||||
|
||||
<h1>Hello, world!</h1>
|
||||
|
||||
Welcome to your new app.
|
||||
|
||||
<Counter IncrementAmount="10" />
|
104
Components/Pages/TurretsPages/Create.razor
Normal file
104
Components/Pages/TurretsPages/Create.razor
Normal file
|
@ -0,0 +1,104 @@
|
|||
@page "/turrets/create"
|
||||
@using System.Runtime.InteropServices.JavaScript
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZenithInfo.Models
|
||||
@inject IDbContextFactory<ZenithInfo.Data.ZenithInfoContext> DbFactory
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Create</PageTitle>
|
||||
|
||||
<h1>Create</h1>
|
||||
|
||||
<h2>Turret</h2>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<EditForm method="post" Model="Turret" OnValidSubmit="AddTurret" FormName="create" Enhance>
|
||||
<DataAnnotationsValidator />
|
||||
<ValidationSummary class="text-danger" role="alert"/>
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name:</label>
|
||||
<InputText id="name" @bind-Value="Turret.Name" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Name" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Description:</label>
|
||||
<InputText id="description" @bind-Value="Turret.Description" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Description" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="damage" class="form-label">Damage:</label>
|
||||
<InputNumber id="damage" @bind-Value="Turret.Damage" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Damage" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="reload" class="form-label">Reload:</label>
|
||||
<InputNumber id="reload" @bind-Value="Turret.Reload" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Reload" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="range" class="form-label">Range:</label>
|
||||
<InputNumber id="range" @bind-Value="Turret.Range" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Range" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="optimal range" class="form-label">Optimal Range:</label>
|
||||
<InputNumber id="optimal range" @bind-Value="Turret.OptimalRange" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.OptimalRange" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="accuracy falloff range" class="form-label">Accuracy Falloff Range:</label>
|
||||
<InputNumber id="accuracy falloff range" @bind-Value="Turret.AccuracyFalloffRange" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.AccuracyFalloffRange" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="size" class="form-label">Size:</label>
|
||||
<InputSelect id="size" @bind-Value="Turret.Size" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Size" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="rating" class="form-label">Type:</label>
|
||||
<InputSelect id="rating" @bind-Value="Turret.Type" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Type" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="icon" class="form-label">Icon:</label>
|
||||
<InputNumber id="icon" @bind-Value="Turret.Icon" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Icon" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="beam size" class="form-label">Beam Size:</label>
|
||||
<InputNumber id="beam size" @bind-Value="Turret.BeamSize" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.BeamSize" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="base cost" class="form-label">Base Cost:</label>
|
||||
<InputNumber id="base cost" @bind-Value="Turret.BaseCost" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.BaseCost" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="rarity" class="form-label">Rarity:</label>
|
||||
<InputSelect id="rarity" @bind-Value="Turret.Rarity" class="form-control" />
|
||||
<ValidationMessage For="() => Turret.Rarity" class="text-danger" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Create</button>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="/turrets">Back to List</a>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromForm]
|
||||
private Turret Turret { get; set; } = new();
|
||||
|
||||
private async Task AddTurret()
|
||||
{
|
||||
using var context = DbFactory.CreateDbContext();
|
||||
context.Turret.Add(Turret);
|
||||
await context.SaveChangesAsync();
|
||||
NavigationManager.NavigateTo("/turrets");
|
||||
}
|
||||
}
|
64
Components/Pages/TurretsPages/Index.razor
Normal file
64
Components/Pages/TurretsPages/Index.razor
Normal file
|
@ -0,0 +1,64 @@
|
|||
@page "/turrets"
|
||||
@rendermode InteractiveServer
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Microsoft.AspNetCore.Components.QuickGrid
|
||||
@using Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter
|
||||
@using ZenithInfo.Models
|
||||
@using ZenithInfo.Data
|
||||
@implements IAsyncDisposable
|
||||
@inject IDbContextFactory<ZenithInfoContext> DbFactory
|
||||
|
||||
<PageTitle>Index</PageTitle>
|
||||
|
||||
<h1>Index</h1>
|
||||
|
||||
<div>
|
||||
<input type="search" @bind="nameFilter" @bind:event="oninput" />
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<a href="turrets/create">Create New</a>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<QuickGrid Class="table" Items="FilteredTurrets" Pagination="pagination">
|
||||
<PropertyColumn Property="turret => turret.Name" Sortable="true" />
|
||||
<PropertyColumn Property="turret => turret.Description" />
|
||||
<PropertyColumn Property="turret => turret.Damage" />
|
||||
<PropertyColumn Property="turret => turret.Reload" />
|
||||
<PropertyColumn Property="turret => turret.Range" />
|
||||
<PropertyColumn Property="turret => turret.OptimalRange" Title="Optimal Range" />
|
||||
<PropertyColumn Property="turret => turret.AccuracyFalloffRange" Title="Accuracy Falloff Range" />
|
||||
<PropertyColumn Property="turret => turret.Accuracy" />
|
||||
<PropertyColumn Property="turret => turret.Size" />
|
||||
<PropertyColumn Property="turret => turret.Type" />
|
||||
<PropertyColumn Property="turret => turret.Icon" />
|
||||
<PropertyColumn Property="turret => turret.BeamSize" />
|
||||
<PropertyColumn Property="turret => turret.BaseCost" />
|
||||
<PropertyColumn Property="turret => turret.Rarity" />
|
||||
|
||||
<TemplateColumn Context="turret">
|
||||
<a href="@($"turrets/edit?id={turret.Id}")">Edit</a> |
|
||||
<a href="@($"turrets/details?id={turret.Id}")">Details</a> |
|
||||
<a href="@($"turrets/delete?id={turret.Id}")">Delete</a>
|
||||
</TemplateColumn>
|
||||
</QuickGrid>
|
||||
</div>
|
||||
|
||||
<Paginator State="pagination" />
|
||||
|
||||
@code {
|
||||
private ZenithInfoContext context = default!;
|
||||
private PaginationState pagination = new PaginationState { ItemsPerPage = 5 };
|
||||
private string nameFilter = string.Empty;
|
||||
|
||||
private IQueryable<Turret> FilteredTurrets =>
|
||||
context.Turret.Where(m => m.Name!.Contains(nameFilter));
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
context = DbFactory.CreateDbContext();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync() => await context.DisposeAsync();
|
||||
}
|
7
Components/Pages/TurretsPages/Index.razor.css
Normal file
7
Components/Pages/TurretsPages/Index.razor.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
::deep tr {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
::deep tr > td {
|
||||
vertical-align: middle;
|
||||
}
|
64
Components/Pages/Weather.razor
Normal file
64
Components/Pages/Weather.razor
Normal file
|
@ -0,0 +1,64 @@
|
|||
@page "/weather"
|
||||
@attribute [StreamRendering]
|
||||
|
||||
<PageTitle>Weather</PageTitle>
|
||||
|
||||
<h1>Weather</h1>
|
||||
|
||||
<p>This component demonstrates showing data.</p>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||
await Task.Delay(500);
|
||||
|
||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = startDate.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
}
|
6
Components/Routes.razor
Normal file
6
Components/Routes.razor
Normal file
|
@ -0,0 +1,6 @@
|
|||
<Router AppAssembly="typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
|
||||
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
||||
</Found>
|
||||
</Router>
|
10
Components/_Imports.razor
Normal file
10
Components/_Imports.razor
Normal file
|
@ -0,0 +1,10 @@
|
|||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using ZenithInfo
|
||||
@using ZenithInfo.Components
|
19
Data/ZenithInfoContext.cs
Normal file
19
Data/ZenithInfoContext.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ZenithInfo.Models;
|
||||
|
||||
namespace ZenithInfo.Data
|
||||
{
|
||||
public class ZenithInfoContext : DbContext
|
||||
{
|
||||
public ZenithInfoContext (DbContextOptions<ZenithInfoContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public DbSet<ZenithInfo.Models.Turret> Turret { get; set; } = default!;
|
||||
}
|
||||
}
|
23
Dockerfile
Normal file
23
Dockerfile
Normal file
|
@ -0,0 +1,23 @@
|
|||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["ZenithInfo.csproj", "./"]
|
||||
RUN dotnet restore "ZenithInfo.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/"
|
||||
RUN dotnet build "ZenithInfo.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "ZenithInfo.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "ZenithInfo.dll"]
|
19
Models/DamageStats.cs
Normal file
19
Models/DamageStats.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
namespace ZenithInfo.Models
|
||||
{
|
||||
public class DamageStats(
|
||||
double averageDps,
|
||||
double shieldDps,
|
||||
double hullDps,
|
||||
double averageAlpha,
|
||||
double shieldAlpha,
|
||||
double hullAlpha
|
||||
)
|
||||
{
|
||||
public double AverageDps { get; set; } = averageDps;
|
||||
public double ShieldDps { get; set; } = shieldDps;
|
||||
public double HullDps { get; set; } = hullDps;
|
||||
public double AverageAlpha { get; set; } = averageAlpha;
|
||||
public double ShieldAlpha { get; set; } = shieldAlpha;
|
||||
public double HullAlpha { get; set; } = hullAlpha;
|
||||
}
|
||||
}
|
41
Models/Effect.cs
Normal file
41
Models/Effect.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace ZenithInfo.Models
|
||||
{
|
||||
public class Effect
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public Enums.ModuleEffectTypes Type { get; set; }
|
||||
public double Duration { get; set; }
|
||||
public double ApplyDelta { get; set; }
|
||||
public Enums.IsBuffed IsBuff { get; set; }
|
||||
public bool ClearApplyOnDispel { get; set; }
|
||||
|
||||
public required ApplyEffect Apply { get; set; }
|
||||
public required TickEffect Tick { get; set; }
|
||||
public required DispelEffect Dispel { get; set; }
|
||||
public required List<string> DisplayEffect { get; set; }
|
||||
|
||||
public class ApplyEffect
|
||||
{
|
||||
public required Dictionary<string, double> Stats { get; set; }
|
||||
private object? Other { get; set; }
|
||||
public required List<string> Flags { get; set; }
|
||||
|
||||
public bool HasOther()
|
||||
{
|
||||
return Other != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class TickEffect
|
||||
{
|
||||
public required Dictionary<string, double> Stats { get; set; }
|
||||
}
|
||||
|
||||
public class DispelEffect
|
||||
{
|
||||
public required Dictionary<string, double> Stats { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
85
Models/Enums.cs
Normal file
85
Models/Enums.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace ZenithInfo.Models
|
||||
{
|
||||
public static class Enums
|
||||
{
|
||||
public enum ModuleSizes
|
||||
{
|
||||
All,
|
||||
Small,
|
||||
Medium,
|
||||
Large,
|
||||
Capital,
|
||||
MiningSmall,
|
||||
MiningMedium,
|
||||
MiningCapital,
|
||||
SmallBase,
|
||||
MediumBase,
|
||||
LargeBase,
|
||||
}
|
||||
|
||||
public enum ModuleTypes
|
||||
{
|
||||
Passive,
|
||||
Toggle,
|
||||
Active,
|
||||
AoE,
|
||||
}
|
||||
|
||||
public enum Rarities
|
||||
{
|
||||
Common,
|
||||
Rare,
|
||||
Scare,
|
||||
Unique,
|
||||
}
|
||||
|
||||
public enum DamageTypes
|
||||
{
|
||||
Shield,
|
||||
Hull,
|
||||
}
|
||||
|
||||
public enum SpinalTypes
|
||||
{
|
||||
Hitscan,
|
||||
Multishot,
|
||||
}
|
||||
|
||||
public enum TurretTypes
|
||||
{
|
||||
Artillery,
|
||||
Autocannon,
|
||||
BeamLaser,
|
||||
Blaster,
|
||||
Railgun,
|
||||
PulseLaser,
|
||||
}
|
||||
|
||||
public static Dictionary<TurretTypes, DamageTypes> TurretDamageTypes { get; } =
|
||||
new Dictionary<TurretTypes, DamageTypes>
|
||||
{
|
||||
{ TurretTypes.Artillery, DamageTypes.Hull },
|
||||
{ TurretTypes.Autocannon, DamageTypes.Hull },
|
||||
{ TurretTypes.BeamLaser, DamageTypes.Shield },
|
||||
{ TurretTypes.Blaster, DamageTypes.Shield },
|
||||
{ TurretTypes.Railgun, DamageTypes.Hull },
|
||||
{ TurretTypes.PulseLaser, DamageTypes.Shield },
|
||||
};
|
||||
|
||||
public enum ModuleEffectTypes
|
||||
{
|
||||
Duration,
|
||||
Persistent,
|
||||
AoE,
|
||||
}
|
||||
|
||||
public enum IsBuffed
|
||||
{
|
||||
True,
|
||||
False,
|
||||
Self,
|
||||
}
|
||||
}
|
||||
}
|
20
Models/Module.cs
Normal file
20
Models/Module.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
namespace ZenithInfo.Models
|
||||
{
|
||||
public class Module
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public required string Description { get; set; }
|
||||
public Enums.ModuleTypes Type { get; set; }
|
||||
public bool IsTargeted { get; set; }
|
||||
public required List<string> Effects { get; set; }
|
||||
public double Cooldown { get; set; }
|
||||
public double Duration { get; set; }
|
||||
public Enums.ModuleSizes Size { get; set; }
|
||||
public double Range { get; set; }
|
||||
public int MaxTargets { get; set; }
|
||||
public double EnergyUsage { get; set; }
|
||||
public int Icon { get; set; }
|
||||
public required Dictionary<string, object> Stats { get; set; }
|
||||
public double BaseCost { get; set; }
|
||||
}
|
||||
}
|
64
Models/Spinal.cs
Normal file
64
Models/Spinal.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
namespace ZenithInfo.Models
|
||||
{
|
||||
public class Spinal
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public required string Description { get; set; }
|
||||
public double Damage { get; set; }
|
||||
public double Reload { get; set; }
|
||||
public double Range { get; set; }
|
||||
public Enums.SpinalTypes Type { get; set; }
|
||||
public Enums.DamageTypes DamageType { get; set; }
|
||||
public Enums.ModuleSizes Size { get; set; }
|
||||
public double Velocity { get; set; }
|
||||
public double Interval { get; set; }
|
||||
public int Icon { get; set; }
|
||||
public double ParticleSize { get; set; }
|
||||
public double BaseCost { get; set; }
|
||||
public Enums.Rarities Rarity { get; set; }
|
||||
|
||||
public DamageStats Dps(int range = 0, int barrelCount = 1)
|
||||
{
|
||||
if (range > Range)
|
||||
{
|
||||
return new DamageStats(0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
double baseAlpha = Damage * barrelCount;
|
||||
double shieldAlpha = 0;
|
||||
double hullAlpha = 0;
|
||||
|
||||
double intervalTime = Interval * (barrelCount - 1);
|
||||
double totalDelay = Reload + intervalTime;
|
||||
double baseDps = baseAlpha / (totalDelay != 0 ? totalDelay : 1); // prevent divide by zero
|
||||
double shieldDps = 0;
|
||||
double hullDps = 0;
|
||||
|
||||
if (DamageType == Enums.DamageTypes.Shield)
|
||||
{
|
||||
shieldAlpha = baseAlpha;
|
||||
hullAlpha = baseAlpha * 0.5;
|
||||
shieldDps = baseDps;
|
||||
hullDps = baseDps * 0.5;
|
||||
}
|
||||
else if (DamageType == Enums.DamageTypes.Hull)
|
||||
{
|
||||
shieldAlpha = baseAlpha * 0.5;
|
||||
hullAlpha = baseAlpha;
|
||||
shieldDps = baseDps * 0.5;
|
||||
hullDps = baseDps;
|
||||
}
|
||||
|
||||
double averageDps = (shieldDps + hullDps) / 2;
|
||||
double averageAlpha = (shieldAlpha + hullAlpha) / 2;
|
||||
return new DamageStats(
|
||||
averageDps,
|
||||
shieldDps,
|
||||
hullDps,
|
||||
averageAlpha,
|
||||
shieldAlpha,
|
||||
hullAlpha
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
72
Models/Turret.cs
Normal file
72
Models/Turret.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace ZenithInfo.Models
|
||||
{
|
||||
public class Turret
|
||||
{
|
||||
// required by EF Core. see https://learn.microsoft.com/en-us/aspnet/core/blazor/tutorials/movie-database-app/part-2?view=aspnetcore-9.0&pivots=vs#add-a-data-model
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public double Damage { get; set; }
|
||||
public double Reload { get; set; }
|
||||
public double Range { get; set; }
|
||||
public double OptimalRange { get; set; }
|
||||
public double AccuracyFalloffRange { get; set; }
|
||||
public double Accuracy { get; set; }
|
||||
public Enums.ModuleSizes Size { get; set; }
|
||||
public Enums.TurretTypes Type { get; set; }
|
||||
public int Icon { get; set; }
|
||||
public double BeamSize { get; set; }
|
||||
public double BaseCost { get; set; }
|
||||
public Enums.Rarities Rarity { get; set; }
|
||||
|
||||
public Enums.DamageTypes DamageType()
|
||||
{
|
||||
return Enums.TurretDamageTypes[Type];
|
||||
}
|
||||
|
||||
public DamageStats Dps(int range = 0)
|
||||
{
|
||||
if (range > Range)
|
||||
{
|
||||
return new DamageStats(0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
double baseAlpha = Damage;
|
||||
double shieldAlpha = 0;
|
||||
double hullAlpha = 0;
|
||||
|
||||
double baseDps = baseAlpha / (Reload != 0 ? Reload : 1); // prevent divide by zero
|
||||
double shieldDps = 0;
|
||||
double hullDps = 0;
|
||||
|
||||
if (DamageType() == Enums.DamageTypes.Shield)
|
||||
{
|
||||
shieldAlpha = baseAlpha;
|
||||
hullAlpha = baseAlpha * 0.5;
|
||||
shieldDps = baseDps;
|
||||
hullDps = baseDps * 0.5;
|
||||
}
|
||||
else if (DamageType() == Enums.DamageTypes.Hull)
|
||||
{
|
||||
shieldAlpha = baseAlpha * 0.5;
|
||||
hullAlpha = baseAlpha;
|
||||
shieldDps = baseDps * 0.5;
|
||||
hullDps = baseDps;
|
||||
}
|
||||
|
||||
double averageDps = (shieldDps + hullDps) / 2;
|
||||
double averageAlpha = (shieldAlpha + hullAlpha) / 2;
|
||||
return new DamageStats(
|
||||
averageDps,
|
||||
shieldDps,
|
||||
hullDps,
|
||||
averageAlpha,
|
||||
shieldAlpha,
|
||||
hullAlpha
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
18
Models/ZIConfiguration.cs
Normal file
18
Models/ZIConfiguration.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
namespace ZenithInfo.Models
|
||||
{
|
||||
public class ZIConfiguration
|
||||
{
|
||||
public required string GlobalToken { get; init; }
|
||||
public string? DatabaseConnectionString { get; init; } = null;
|
||||
public DatabaseTypes DatabaseType { get; init; } = DatabaseTypes.Memory;
|
||||
public bool UseSentry { get; init; } = true;
|
||||
public bool UseSwagger { get; init; } = true;
|
||||
public bool LogRequests { get; init; } = true;
|
||||
}
|
||||
|
||||
public enum DatabaseTypes
|
||||
{
|
||||
Memory,
|
||||
PostgresSQL,
|
||||
}
|
||||
}
|
135
Program.cs
Normal file
135
Program.cs
Normal file
|
@ -0,0 +1,135 @@
|
|||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using ZenithInfo.Components;
|
||||
using ZenithInfo.Data;
|
||||
using ZenithInfo.Models;
|
||||
using ZenithInfo.Util.SwaggerTheme;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Configuration
|
||||
var config = builder.Configuration.GetSection("Configuration").Get<ZIConfiguration>();
|
||||
builder.Services.Configure<ZIConfiguration>(builder.Configuration.GetSection("Configuration"));
|
||||
|
||||
if (config?.GlobalToken == "CHANGE-ME")
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Global token is not a valid value, please set the `CONFIGURATION__GLOBALTOKEN` environment variable to a random value. `openssl rand -hex 64` is a good way to generate a random value."
|
||||
);
|
||||
}
|
||||
|
||||
// Initialize Database
|
||||
builder.Services.AddQuickGridEntityFrameworkAdapter();
|
||||
builder.Services.AddDbContextFactory<ZenithInfoContext>(options =>
|
||||
options.UseNpgsql(builder.Configuration.GetConnectionString("ZenithInfoContext"))
|
||||
);
|
||||
|
||||
// Sentry
|
||||
if (config?.UseSentry == true)
|
||||
{
|
||||
builder.WebHost.UseSentry();
|
||||
}
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
|
||||
builder.Services.AddHttpLogging(o => { });
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(opts =>
|
||||
{
|
||||
opts.SwaggerDoc(
|
||||
"v1",
|
||||
new OpenApiInfo
|
||||
{
|
||||
Title = "Zenith Info API",
|
||||
Version = "v1",
|
||||
Description = "Zenith's official information provider!",
|
||||
}
|
||||
);
|
||||
opts.AddSecurityDefinition(
|
||||
"Bearer",
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Description =
|
||||
"JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
Scheme = "Bearer",
|
||||
}
|
||||
);
|
||||
opts.AddSecurityRequirement(
|
||||
new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer",
|
||||
},
|
||||
Scheme = "oauth2",
|
||||
Name = "Bearer",
|
||||
In = ParameterLocation.Header,
|
||||
},
|
||||
new List<string>()
|
||||
},
|
||||
}
|
||||
);
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
opts.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFile));
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
foreach (var resource in assembly.GetManifestResourceNames())
|
||||
{
|
||||
app.Logger.LogDebug("Resource: {Resource}", resource);
|
||||
}
|
||||
|
||||
if (config?.UseSwagger == true)
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(CustomStyle.CustomModern);
|
||||
}
|
||||
|
||||
if (config?.LogRequests == true)
|
||||
{
|
||||
app.UseHttpLogging();
|
||||
}
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
|
||||
|
||||
if (config?.DatabaseType == DatabaseTypes.Memory)
|
||||
{
|
||||
app.Logger.LogWarning(
|
||||
"`Memory` database type is in use. Data will be lost when the application is restarted. If you are not in a development environment, you should use `PostgresSQL` instead."
|
||||
);
|
||||
}
|
||||
|
||||
// if (app.Environment.IsDevelopment())
|
||||
// {
|
||||
// app.Logger.LogInformation(
|
||||
// "Development mode detected, printing configuration: {Configuration}",
|
||||
// config?.ToJson()
|
||||
// );
|
||||
// }
|
||||
|
||||
app.Run();
|
41
Properties/launchSettings.json
Normal file
41
Properties/launchSettings.json
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:48070",
|
||||
"sslPort": 44382
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5150",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7047;http://localhost:5150",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
Util/RandomStringGenerator.cs
Normal file
26
Util/RandomStringGenerator.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace ZenithInfo.Util;
|
||||
|
||||
public class RandomStringGenerator
|
||||
{
|
||||
private static readonly char[] chars =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*+?".ToCharArray();
|
||||
|
||||
public static string GenerateRandomString(int length)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
byte[] buffer = new byte[1];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
rng.GetBytes(buffer);
|
||||
var randomIndex = buffer[0] % chars.Length;
|
||||
stringBuilder.Append(chars[randomIndex]);
|
||||
}
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
12
Util/SwaggerTheme/CustomStyle.cs
Normal file
12
Util/SwaggerTheme/CustomStyle.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using AspNetCore.Swagger.Themes;
|
||||
|
||||
namespace ZenithInfo.Util.SwaggerTheme;
|
||||
|
||||
public class CustomStyle : ModernStyle
|
||||
{
|
||||
protected CustomStyle(string fileName)
|
||||
: base(fileName) { }
|
||||
|
||||
public static CustomStyle CustomModern => new("modern.custom.css");
|
||||
}
|
117
Util/SwaggerTheme/modern.custom.css
Normal file
117
Util/SwaggerTheme/modern.custom.css
Normal file
|
@ -0,0 +1,117 @@
|
|||
:root {
|
||||
/* Light mode (Catppuccin Latte) */
|
||||
--catppuccin-pink: #ea76cb;
|
||||
--catppuccin-mauve: #8839ef;
|
||||
--catppuccin-red: #d20f39;
|
||||
--catppuccin-maroon: #e64553;
|
||||
--catppuccin-peach: #fe640b;
|
||||
--catppuccin-yellow: #df8e1d;
|
||||
--catppuccin-green: #40a02b;
|
||||
--catppuccin-teal: #179299;
|
||||
--catppuccin-sky: #04a5e5;
|
||||
--catppuccin-sapphire: #209fb5;
|
||||
--catppuccin-blue: #1e66f5;
|
||||
--catppuccin-lavender: #7287fd;
|
||||
--catppuccin-text: #4c4f69;
|
||||
--catppuccin-subtext1: #5c5f77;
|
||||
--catppuccin-subtext0: #6c6f85;
|
||||
--catppuccin-overlay2: #7c7f93;
|
||||
--catppuccin-overlay1: #8c8fa1;
|
||||
--catppuccin-overlay0: #9ca0b0;
|
||||
--catppuccin-surface2: #acb0be;
|
||||
--catppuccin-surface1: #bcc0cc;
|
||||
--catppuccin-surface0: #ccd0da;
|
||||
--catppuccin-base: #eff1f5;
|
||||
--catppuccin-mantle: #e6e9ef;
|
||||
--catppuccin-crust: #dce0e8;
|
||||
|
||||
--link: var(--catppuccin-blue);
|
||||
--link-hover: var(--catppuccin-sapphire);
|
||||
--accent: var(--catppuccin-green);
|
||||
--error: var(--catppuccin-red);
|
||||
|
||||
/* Body */
|
||||
--body-background-color: var(--catppuccin-base);
|
||||
--swagger-main-color: var(--catppuccin-text);
|
||||
--scrollbar-thumb-color: var(--catppuccin-surface1);
|
||||
--scrollbar-thumb-hover-color: var(--catppuccin-surface0);
|
||||
|
||||
/* Loading */
|
||||
--loading-container-border-color: var(--accent);
|
||||
|
||||
/* Errors Container */
|
||||
--errors-wrapper-background-color: var(--catppuccin-surface0);
|
||||
--errors-wrapper-border-color: var(--error);
|
||||
--errors-wrapper-errors-color: var(--error);
|
||||
|
||||
/* Topbar */
|
||||
--topbar-background-color: var(--catppuccin-surface0);
|
||||
--topbar-pinned-background-color: var(--catppuccin-surface0);
|
||||
--topbar-border-color: var(--accent);
|
||||
--topbar-select-label-color: var(--catppuccin-text);
|
||||
--topbar-select-border-color: var(--accent);
|
||||
|
||||
/* Infobox */
|
||||
--swagger-info-link: var(--link);
|
||||
--swagger-info-link-hover: var(--link-hover);
|
||||
--api-version-background-color: var(--catppuccin-surface2);
|
||||
--api-version-stamp-background-color: var(--accent);
|
||||
--api-version-color: var(--catppuccin-base);
|
||||
|
||||
/* Authorization */
|
||||
--btn-authorize-background-color: var(--catppuccin-surface0);
|
||||
--btn-authorize-border-color: var(--catppuccin-green);
|
||||
--btn-authorize-font-color: var(--catppuccin-green);
|
||||
--btn-authorize-svg-fill-color: var(--catppuccin-green);
|
||||
--auth-container-background-color: var(--catppuccin-surface0);
|
||||
--auth-container-errors-color: var(--catppuccin-red);
|
||||
--auth-wrapper-background-color: var(--catppuccin-mantle);
|
||||
--auth-wrapper-border-color: var(--accent);
|
||||
|
||||
/* Form Elements */
|
||||
--select-border-color: var(--accent);
|
||||
--input-background-color: var(--catppuccin-surface0);
|
||||
--input-border-color: var(--accent);
|
||||
--input-invalid-border-color: var(--error);
|
||||
--input-disabled-background-color: var(--catppuccin-crust);
|
||||
--input-disabled-border-color: var(--catppuccin-surface1);
|
||||
|
||||
/* Dialog */
|
||||
--dialog-background-color: var(--catppuccin-mantle);
|
||||
--dialog-border-color: var(--accent);
|
||||
}
|
||||
|
||||
.swagger-ui .topbar .download-url-wrapper input[type="text"], .swagger-ui .topbar .download-url-wrapper .select-label select {
|
||||
background-color: var(--catppuccin-surface0);
|
||||
color: var(--catppuccin-text);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
/* Dark mode (Catppuccin Mocha) */
|
||||
--catppuccin-pink: #f5c2e7;
|
||||
--catppuccin-mauve: #cba6f7;
|
||||
--catppuccin-red: #f38ba8;
|
||||
--catppuccin-maroon: #eba0ac;
|
||||
--catppuccin-peach: #fab387;
|
||||
--catppuccin-yellow: #f9e2af;
|
||||
--catppuccin-green: #a6e3a1;
|
||||
--catppuccin-teal: #94e2d5;
|
||||
--catppuccin-sky: #89dceb;
|
||||
--catppuccin-sapphire: #74c7ec;
|
||||
--catppuccin-blue: #89b4fa;
|
||||
--catppuccin-lavender: #b4befe;
|
||||
--catppuccin-text: #cdd6f4;
|
||||
--catppuccin-subtext1: #bac2de;
|
||||
--catppuccin-subtext0: #a6adc8;
|
||||
--catppuccin-overlay2: #9399b2;
|
||||
--catppuccin-overlay1: #7f849c;
|
||||
--catppuccin-overlay0: #6c7086;
|
||||
--catppuccin-surface2: #585b70;
|
||||
--catppuccin-surface1: #45475a;
|
||||
--catppuccin-surface0: #313244;
|
||||
--catppuccin-base: #1e1e2e;
|
||||
--catppuccin-mantle: #181825;
|
||||
--catppuccin-crust: #11111b;
|
||||
}
|
||||
}
|
41
ZenithInfo.csproj
Normal file
41
ZenithInfo.csproj
Normal file
|
@ -0,0 +1,41 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.SwaggerUI.Themes" Version="2.0.0" />
|
||||
<PackageReference Include="Sentry.AspNetCore" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\" />
|
||||
<Folder Include="Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Util\SwaggerTheme\modern.custom.css" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
22
ZenithInfo.sln
Normal file
22
ZenithInfo.sln
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZenithInfo", "ZenithInfo.csproj", "{49ED62A1-936C-41EC-949D-D490C8F45711}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{49ED62A1-936C-41EC-949D-D490C8F45711}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{49ED62A1-936C-41EC-949D-D490C8F45711}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49ED62A1-936C-41EC-949D-D490C8F45711}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{49ED62A1-936C-41EC-949D-D490C8F45711}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
12
appsettings.Development.json
Normal file
12
appsettings.Development.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Trace"
|
||||
}
|
||||
},
|
||||
"Configuration": {
|
||||
// DO NOT USE THIS AUTHTOKEN IN PRODUCTION!!!
|
||||
"AuthToken": "hi",
|
||||
"UseSentry": false
|
||||
}
|
||||
}
|
27
appsettings.json
Normal file
27
appsettings.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Configuration": {
|
||||
"AuthToken": "CHANGE-ME",
|
||||
"UseSwagger": true,
|
||||
"LogRequests": true,
|
||||
"UseSentry": true
|
||||
},
|
||||
"Sentry": {
|
||||
"Dsn": "https://92b5c863371d9362c50a39b3faccd26d@sentry.csw.im/5",
|
||||
"SendDefaultPii": true,
|
||||
"MaxRequestBodySize": "Always",
|
||||
"MinimumBreadcrumbLevel": "Debug",
|
||||
"MinimumEventLevel": "Warning",
|
||||
"AttachStackTrace": true,
|
||||
"Debug": true,
|
||||
"DiagnosticLevel": "Error",
|
||||
"TracesSampleRate": 1.0
|
||||
}
|
||||
}
|
13
docker-compose.dev.yml
Normal file
13
docker-compose.dev.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
services:
|
||||
zenithinfo-dev:
|
||||
container_name: zenithinfo
|
||||
extends:
|
||||
service: zenithinfo
|
||||
file: ./docker-compose.yml
|
||||
build:
|
||||
context: .
|
||||
environment:
|
||||
CONFIGURATION__AUTHTOKEN: 'hi'
|
||||
CONFIGURATION__DATABASETYPE: 'Memory'
|
||||
LOGGING__LOGLEVEL_DEFAULT: 'Trace'
|
||||
CONFIGURATION__USESENTRY: false
|
57
docker-compose.yml
Normal file
57
docker-compose.yml
Normal file
|
@ -0,0 +1,57 @@
|
|||
services:
|
||||
zenithinfo:
|
||||
image: www.coastalcommits.com/zenith/zenithinfo:latest
|
||||
ports:
|
||||
- 8000:8000
|
||||
environment:
|
||||
# All of the environment variables present here use double underscores (__), NOT single underscores (_).
|
||||
# The only exception is the `ASPNETCORE_URLS` environment variable, which uses single underscores.
|
||||
|
||||
# This is used to push data into Zenith Info from the game.
|
||||
# `openssl rand -hex 64` is a good way to generate a random value. DO NOT CHECK THIS INTO GIT!
|
||||
CONFIGURATION__AUTHTOKEN: 'CHANGE-ME'
|
||||
|
||||
# This is used to configure the IP address and port that the application will listen on.
|
||||
# 0.0.0.0 is used to listen on all available IP addresses.
|
||||
# Alternatively, you can specify localhost or 127.0.0.1 to listen on only the local machine.
|
||||
# Multiple IP address / port combinations can be specified, separated by semicolons.
|
||||
# Example: http://0.0.0.0:8000;http://127.0.0.1:8000 - Listen on all available IP addresses on port 8000, as well as only on the local machine on port 8000. (Redundant)
|
||||
ASPNETCORE_URLS: 'http://0.0.0.0:8000'
|
||||
|
||||
# Valid values are `Memory` or `PostgresSQL`. This is used to determine which database to use.
|
||||
# `Memory` is used for development and testing, and is not recommended for production, as data is not persistent.
|
||||
CONFIGURATION__DATABASETYPE: 'PostgresSQL'
|
||||
CONFIGURATION__DATABASECONNECTIONSTRING: 'postgres://zenithinfo:zenithinfo@postgres:5432/zenithinfo'
|
||||
|
||||
# Determines the log level for the application's default logger.
|
||||
# Valid values are `Trace`, `Debug`, `Information`, `Warning`, `Error`, and `Critical`.
|
||||
# `Trace` is the most verbose, and is recommended for development.
|
||||
# `Information` is the default, and is recommended for production.
|
||||
LOGGING__LOGLEVEL__DEFAULT: 'Information'
|
||||
|
||||
# This is used to log requests to the application.
|
||||
# If you are concerned about security or privacy, you should disable this.
|
||||
CONFIGURATION__LOGREQUESTS: true
|
||||
|
||||
# Using Sentry will send errors to my personal Sentry instance, https://sentry.csw.im/
|
||||
# This is not required for the application to run, but it is recommended for debugging purposes.
|
||||
CONFIGURATION__USESENTRY: true
|
||||
|
||||
# This is used to enable Swagger API Documentation for the application.
|
||||
# If enabled, you can access the API documentation at the /swagger/index.html endpoint.
|
||||
CONFIGURATION__USESWAGGER: true
|
||||
|
||||
database:
|
||||
image: postgres:15.4
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: zenithinfo
|
||||
POSTGRES_PASSWORD: zenithinfo
|
||||
POSTGRES_DB: zenithinfo
|
||||
ports:
|
||||
- 5433:5432
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
51
wwwroot/app.css
Normal file
51
wwwroot/app.css
Normal file
|
@ -0,0 +1,51 @@
|
|||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #006bb7;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid #e50000;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: #e50000;
|
||||
}
|
||||
|
||||
.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."
|
||||
}
|
||||
|
||||
.darker-border-checkbox.form-check-input {
|
||||
border-color: #929292;
|
||||
}
|
7
wwwroot/bootstrap/bootstrap.min.css
vendored
Normal file
7
wwwroot/bootstrap/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
wwwroot/bootstrap/bootstrap.min.css.map
Normal file
1
wwwroot/bootstrap/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
BIN
wwwroot/favicon.png
Normal file
BIN
wwwroot/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue