commit
e43d9a90e7
267 changed files with 17049 additions and 0 deletions
@ -0,0 +1,42 @@
|
||||
name: Azure Static Web Apps CI/CD |
||||
|
||||
on: |
||||
push: |
||||
branches: |
||||
- develop |
||||
pull_request: |
||||
types: [opened, synchronize, reopened, closed] |
||||
branches: |
||||
- develop |
||||
|
||||
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@v2 |
||||
with: |
||||
submodules: true |
||||
- 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_CALM_MUD_04916B210 }} |
||||
repo_token: ${{ secrets.GITHUB_TOKEN }} |
||||
action: "upload" |
||||
app_location: "IGP" |
||||
api_location: "" |
||||
output_location: "./wwwroot" |
||||
|
||||
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_CALM_MUD_04916B210 }} |
||||
action: "close" |
||||
@ -0,0 +1,42 @@
|
||||
name: Azure Static Web Apps CI/CD |
||||
|
||||
on: |
||||
push: |
||||
branches: |
||||
- main |
||||
pull_request: |
||||
types: [opened, synchronize, reopened, closed] |
||||
branches: |
||||
- main |
||||
|
||||
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@v2 |
||||
with: |
||||
submodules: true |
||||
- 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_NICE_COAST_0F8B08010 }} |
||||
repo_token: ${{ secrets.GITHUB_TOKEN }} |
||||
action: "upload" |
||||
app_location: "IGP" |
||||
api_location: "" |
||||
output_location: "./wwwroot" |
||||
|
||||
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_NICE_COAST_0F8B08010 }} |
||||
action: "close" |
||||
@ -0,0 +1,266 @@
|
||||
## Ignore Visual Studio temporary files, build results, and |
||||
## files generated by popular Visual Studio add-ons. |
||||
|
||||
# User-specific files |
||||
*.suo |
||||
*.user |
||||
*.userosscache |
||||
*.sln.docstates |
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio) |
||||
*.userprefs |
||||
|
||||
# Build results |
||||
[Dd]ebug/ |
||||
[Dd]ebugPublic/ |
||||
[Rr]elease/ |
||||
[Rr]eleases/ |
||||
x64/ |
||||
x86/ |
||||
bld/ |
||||
[Bb]in/ |
||||
[Oo]bj/ |
||||
[Ll]og/ |
||||
|
||||
# Visual Studio 2015 cache/options directory |
||||
.vs/ |
||||
# Uncomment if you have tasks that create the project's static files in wwwroot |
||||
#wwwroot/ |
||||
|
||||
# MSTest test Results |
||||
[Tt]est[Rr]esult*/ |
||||
[Bb]uild[Ll]og.* |
||||
|
||||
# NUNIT |
||||
*.VisualState.xml |
||||
TestResult.xml |
||||
|
||||
# Build Results of an ATL Project |
||||
[Dd]ebugPS/ |
||||
[Rr]eleasePS/ |
||||
dlldata.c |
||||
|
||||
# DNX |
||||
project.lock.json |
||||
project.fragment.lock.json |
||||
artifacts/ |
||||
|
||||
*_i.c |
||||
*_p.c |
||||
*_i.h |
||||
*.ilk |
||||
*.meta |
||||
*.obj |
||||
*.pch |
||||
*.pdb |
||||
*.pgc |
||||
*.pgd |
||||
*.rsp |
||||
*.sbr |
||||
*.tlb |
||||
*.tli |
||||
*.tlh |
||||
*.tmp |
||||
*.tmp_proj |
||||
*.log |
||||
*.vspscc |
||||
*.vssscc |
||||
.builds |
||||
*.pidb |
||||
*.svclog |
||||
*.scc |
||||
|
||||
# Chutzpah Test files |
||||
_Chutzpah* |
||||
|
||||
# Visual C++ cache files |
||||
ipch/ |
||||
*.aps |
||||
*.ncb |
||||
*.opendb |
||||
*.opensdf |
||||
*.sdf |
||||
*.cachefile |
||||
*.VC.db |
||||
*.VC.VC.opendb |
||||
|
||||
# Visual Studio profiler |
||||
*.psess |
||||
*.vsp |
||||
*.vspx |
||||
*.sap |
||||
|
||||
# TFS 2012 Local Workspace |
||||
$tf/ |
||||
|
||||
# Guidance Automation Toolkit |
||||
*.gpState |
||||
|
||||
# ReSharper is a .NET coding add-in |
||||
_ReSharper*/ |
||||
*.[Rr]e[Ss]harper |
||||
*.DotSettings.user |
||||
|
||||
# JustCode is a .NET coding add-in |
||||
.JustCode |
||||
|
||||
# TeamCity is a build add-in |
||||
_TeamCity* |
||||
|
||||
# DotCover is a Code Coverage Tool |
||||
*.dotCover |
||||
|
||||
# NCrunch |
||||
_NCrunch_* |
||||
.*crunch*.local.xml |
||||
nCrunchTemp_* |
||||
|
||||
# MightyMoose |
||||
*.mm.* |
||||
AutoTest.Net/ |
||||
|
||||
# Web workbench (sass) |
||||
.sass-cache/ |
||||
|
||||
# Installshield output folder |
||||
[Ee]xpress/ |
||||
|
||||
# DocProject is a documentation generator add-in |
||||
DocProject/buildhelp/ |
||||
DocProject/Help/*.HxT |
||||
DocProject/Help/*.HxC |
||||
DocProject/Help/*.hhc |
||||
DocProject/Help/*.hhk |
||||
DocProject/Help/*.hhp |
||||
DocProject/Help/Html2 |
||||
DocProject/Help/html |
||||
|
||||
# Click-Once directory |
||||
publish/ |
||||
|
||||
# Publish Web Output |
||||
*.[Pp]ublish.xml |
||||
*.azurePubxml |
||||
# TODO: Comment the next line if you want to checkin your web deploy settings |
||||
# but database connection strings (with potential passwords) will be unencrypted |
||||
#*.pubxml |
||||
*.publishproj |
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to |
||||
# checkin your Azure Web App publish settings, but sensitive information contained |
||||
# in these scripts will be unencrypted |
||||
PublishScripts/ |
||||
|
||||
# NuGet Packages |
||||
*.nupkg |
||||
# The packages folder can be ignored because of Package Restore |
||||
**/packages/* |
||||
# except build/, which is used as an MSBuild target. |
||||
!**/packages/build/ |
||||
# Uncomment if necessary however generally it will be regenerated when needed |
||||
#!**/packages/repositories.config |
||||
# NuGet v3's project.json files produces more ignoreable files |
||||
*.nuget.props |
||||
*.nuget.targets |
||||
|
||||
# Microsoft Azure Build Output |
||||
csx/ |
||||
*.build.csdef |
||||
|
||||
# Microsoft Azure Emulator |
||||
ecf/ |
||||
rcf/ |
||||
|
||||
# Windows Store app package directories and files |
||||
AppPackages/ |
||||
BundleArtifacts/ |
||||
Package.StoreAssociation.xml |
||||
_pkginfo.txt |
||||
|
||||
# Visual Studio cache files |
||||
# files ending in .cache can be ignored |
||||
*.[Cc]ache |
||||
# but keep track of directories ending in .cache |
||||
!*.[Cc]ache/ |
||||
|
||||
# Others |
||||
ClientBin/ |
||||
~$* |
||||
*~ |
||||
*.dbmdl |
||||
*.dbproj.schemaview |
||||
*.jfm |
||||
*.pfx |
||||
*.publishsettings |
||||
node_modules/ |
||||
orleans.codegen.cs |
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components |
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) |
||||
#bower_components/ |
||||
|
||||
# RIA/Silverlight projects |
||||
Generated_Code/ |
||||
|
||||
# Backup & report files from converting an old project file |
||||
# to a newer Visual Studio version. Backup files are not needed, |
||||
# because we have git ;-) |
||||
_UpgradeReport_Files/ |
||||
Backup*/ |
||||
UpgradeLog*.XML |
||||
UpgradeLog*.htm |
||||
|
||||
# SQL Server files |
||||
*.mdf |
||||
*.ldf |
||||
|
||||
# Business Intelligence projects |
||||
*.rdl.data |
||||
*.bim.layout |
||||
*.bim_*.settings |
||||
|
||||
# Microsoft Fakes |
||||
FakesAssemblies/ |
||||
|
||||
# GhostDoc plugin setting file |
||||
*.GhostDoc.xml |
||||
|
||||
# Node.js Tools for Visual Studio |
||||
.ntvs_analysis.dat |
||||
|
||||
# Visual Studio 6 build log |
||||
*.plg |
||||
|
||||
# Visual Studio 6 workspace options file |
||||
*.opt |
||||
|
||||
# Visual Studio LightSwitch build output |
||||
**/*.HTMLClient/GeneratedArtifacts |
||||
**/*.DesktopClient/GeneratedArtifacts |
||||
**/*.DesktopClient/ModelManifest.xml |
||||
**/*.Server/GeneratedArtifacts |
||||
**/*.Server/ModelManifest.xml |
||||
_Pvt_Extensions |
||||
|
||||
# Paket dependency manager |
||||
.paket/paket.exe |
||||
paket-files/ |
||||
|
||||
# FAKE - F# Make |
||||
.fake/ |
||||
|
||||
# JetBrains Rider |
||||
.idea/ |
||||
*.sln.iml |
||||
|
||||
# CodeRush |
||||
.cr/ |
||||
|
||||
# Python Tools for Visual Studio (PTVS) |
||||
__pycache__/ |
||||
*.pyc |
||||
|
||||
**/.DS_Store |
||||
|
||||
**/.vs/ |
||||
.DS_Store |
||||
@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor"> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net7.0</TargetFramework> |
||||
<Nullable>enable</Nullable> |
||||
<ImplicitUsings>enable</ImplicitUsings> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<SupportedPlatform Include="browser" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Markdig" Version="0.28.1" /> |
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-preview.2.22153.2" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<Folder Include="Inputs\" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Model\Model.csproj" /> |
||||
<ProjectReference Include="..\Services\Services.csproj" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<None Remove="Inputs\" /> |
||||
</ItemGroup> |
||||
</Project> |
||||
@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,4 @@
|
||||
|
||||
.entityDialogBackground { |
||||
|
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
<div class="code"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.code { |
||||
font-family: monospace; |
||||
border: 2px solid white; |
||||
color: white; |
||||
padding: 8px; |
||||
background-color: black; |
||||
white-space: pre; |
||||
overflow-x: scroll; |
||||
} |
||||
|
||||
.code::-webkit-scrollbar { |
||||
height: 0; |
||||
background: transparent; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,72 @@
|
||||
@if (IsOnDev) { |
||||
<div class="devOnlyContainer"> |
||||
<div class="devOnlyTitleContainer"> |
||||
<div class="devOnlyTitle"> |
||||
DevOnly UI |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="devOnlyContentContainer"> |
||||
<div class="devOnlyContent"> |
||||
|
||||
@ChildContent |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<style> |
||||
.devOnlyContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.devOnlyTitle { |
||||
background-color: rgba(20,20,20,0.75); |
||||
padding: 10px; |
||||
color: orange; |
||||
font-weight: bolder; |
||||
font-size: 1.5rem; |
||||
} |
||||
|
||||
.devOnlyContent { |
||||
background-color: rgba(20,20,20,0.75); |
||||
width: 100%; |
||||
padding: 10px; |
||||
} |
||||
|
||||
|
||||
.devOnlyTitleContainer { |
||||
background: repeating-linear-gradient( 45deg, blue, blue 50px, orange 51px, orange 100px); |
||||
margin-right: auto; |
||||
padding: 10px; |
||||
border-left: 6px dashed orange; |
||||
border-right: 6px dashed orange; |
||||
border-top: 6px dashed orange; |
||||
text-shadow: 4px 4px 1px blue; |
||||
} |
||||
|
||||
.devOnlyContentContainer { |
||||
border: 6px dashed orange; |
||||
background: repeating-linear-gradient( 45deg, blue, blue 50px, orange 51px, orange 100px); |
||||
box-shadow: 5px 5px 5px blue; |
||||
padding: 20px; |
||||
} |
||||
</style> |
||||
} |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
NavigationManager NavigationManager { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
bool IsOnDev; |
||||
|
||||
protected override void OnInitialized() { |
||||
IsOnDev = NavigationManager.BaseUri.Contains("https://localhost"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,78 @@
|
||||
<div class="entityDisplaySection"> |
||||
<div class="entityDisplayHeader"> |
||||
<div class="entityDisplayTitle"> |
||||
@Title |
||||
</div> |
||||
<div class="entityDisplayBorder"> |
||||
</div> |
||||
</div> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.entityDisplaySection { |
||||
position: relative; |
||||
padding: 8px; |
||||
display: flex; |
||||
gap: 12px; |
||||
flex-direction: column; |
||||
margin-top: 14px; |
||||
margin-top: 20px; |
||||
padding: 12px; |
||||
background-color: var(--info); |
||||
border-top-right-radius: 12px; |
||||
border-bottom-left-radius: 2px; |
||||
border-bottom-right-radius: 2px; |
||||
} |
||||
|
||||
.entityDisplayHeader { |
||||
bottom: 100%; |
||||
position: absolute; |
||||
white-space: pre; |
||||
width: 100%; |
||||
line-height: 0px; |
||||
right: 0px; |
||||
top: -4px; |
||||
display: flex; |
||||
} |
||||
|
||||
.entityDisplayTitle { |
||||
font-weight: 800; |
||||
font-size: 1.4rem; |
||||
padding-right: 8px; |
||||
text-shadow: 3px 0 0 var(--info), -3px 0 0 var(--info), 0 3px 0 var(--info), 0 -3px 0 var(--info), 2px 2px var(--info), -2px -2px 0 var(--info), 2px -2px 0 var(--info), -2px 2px 0 var(--info); |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.entityDisplayHeader { |
||||
position: inherit; |
||||
width: 100%; |
||||
margin: 0px; |
||||
} |
||||
|
||||
.entityDisplaySection { |
||||
position: inherit; |
||||
width: 100%; |
||||
margin: 0px; |
||||
max-width: none; |
||||
border-top-right-radius: 0px; |
||||
border-bottom-left-radius: 0px; |
||||
border-bottom-right-radius: 0px; |
||||
} |
||||
|
||||
.entityDisplayTitle { |
||||
position: inherit; |
||||
margin: 0px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Parameter] |
||||
public string Title { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,66 @@
|
||||
<div class="tooltipWrapper"> |
||||
<div class="tooltipContent"> |
||||
@((MarkupString)InfoText) |
||||
</div> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.tooltipWrapper { |
||||
position: relative; |
||||
display: inline-block; |
||||
width: 100%; |
||||
|
||||
|
||||
} |
||||
|
||||
.tooltipContent { |
||||
visibility: hidden; |
||||
position: absolute; |
||||
width: 520px; |
||||
max-width: 93vw; |
||||
bottom: 100%; |
||||
|
||||
margin-top: 60px; |
||||
|
||||
margin-left: -60px; |
||||
margin-bottom: 36px; |
||||
background-color: #363636; |
||||
color: #fff; |
||||
border-radius: 6px; |
||||
|
||||
padding-left: 20px; |
||||
padding-right: 20px; |
||||
padding-bottom: 20px; |
||||
padding-top: 20px; |
||||
border: 2px solid black; |
||||
white-space: break-spaces; |
||||
z-index: 2147483647; |
||||
} |
||||
|
||||
|
||||
.tooltipWrapper:hover .tooltipContent { |
||||
visibility: visible; |
||||
|
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.tooltipContent { |
||||
margin: auto; |
||||
margin-bottom: 20px; |
||||
position: absolute; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Parameter] |
||||
public string InfoText { get; set; } |
||||
|
||||
[Parameter] |
||||
public int? Margin { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,116 @@
|
||||
<div class="makingOfContainer"> |
||||
<div class="makingInfo"> |
||||
<div class="makingTitle">@Title</div> |
||||
<div class="makingDescription">@Description</div> |
||||
</div> |
||||
|
||||
<div class="makingofGrid"> |
||||
<div class="makingofItem"> |
||||
<details open> |
||||
<summary>Example</summary> |
||||
|
||||
<div class="shownCode"> |
||||
@Example |
||||
</div> |
||||
</details> |
||||
</div> |
||||
<div class="makingofItem"> |
||||
<details open> |
||||
<summary>Usage</summary> |
||||
<div class="shownCode"> |
||||
@Usage |
||||
</div> |
||||
</details> |
||||
</div> |
||||
<div class="makingofItem"> |
||||
<details open> |
||||
<summary>Code</summary> |
||||
<div class="shownCode"> |
||||
@Code |
||||
</div> |
||||
</details> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<style> |
||||
.makingInfo { |
||||
margin-top: 6px; |
||||
margin-bottom: 12px; |
||||
} |
||||
|
||||
.makingTitle { |
||||
font-weight: bolder; |
||||
font-size: 1.4rem; |
||||
} |
||||
|
||||
.makingOfContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
} |
||||
|
||||
.makingofGrid { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
grid-template-columns: repeat(3, minmax(0, 1fr)); |
||||
gap: 12px; |
||||
|
||||
} |
||||
|
||||
.makingofItem { |
||||
width: 100%; |
||||
} |
||||
|
||||
.makingOfContainer details { |
||||
border: 2px dashed black; |
||||
border-radius: 4px; |
||||
} |
||||
|
||||
.makingOfContainer summary { |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background-color: rgba(0,0,0, 0.1); |
||||
} |
||||
|
||||
.shownCode { |
||||
visibility: hidden; |
||||
padding: 12px; |
||||
background-color: rgba(0,0,0, 0.1); |
||||
} |
||||
|
||||
.makingOfContainer details[open] .shownCode { |
||||
visibility: visible; |
||||
} |
||||
|
||||
.makingOfContainer details[open] summary { |
||||
border-bottom: 2px dashed black; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.makingofGrid { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment Title { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment Description { get; set; } |
||||
|
||||
|
||||
[Parameter] |
||||
public RenderFragment Example { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment Usage { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment Code { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,32 @@
|
||||
<details class="makingOfSection"> |
||||
<summary> |
||||
@Title |
||||
</summary> |
||||
|
||||
@ChildContent |
||||
</details> |
||||
|
||||
<style> |
||||
.makingOfSection { |
||||
width: 100%; |
||||
background-color: rgba(0,0,0, 0.1); |
||||
padding: 25px; |
||||
border-radius: 8px; |
||||
border: 2px black dashed; |
||||
} |
||||
|
||||
.makingOfSection > summary { |
||||
font-size: 3.4em; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public string Title { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,29 @@
|
||||
<div class="paper"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.paper { |
||||
padding-top: 24px; |
||||
padding-left: 24px; |
||||
padding-right: 24px; |
||||
padding-bottom: 24px; |
||||
margin: auto; |
||||
overflow-y: auto; |
||||
overflow-x: hidden; |
||||
border: 4px solid var(--paper-border); |
||||
background-color: var(--paper); |
||||
box-shadow: 0px 6px var(--paper-border); |
||||
width: 100%; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Parameter] |
||||
public string Title { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,61 @@
|
||||
<div class="alertContainer @Type.ToString().ToLower()"> |
||||
@if (Title != null) { |
||||
<div class="alertTitle"> |
||||
@Title |
||||
</div> |
||||
} |
||||
@if (Message != null) { |
||||
<div> |
||||
@Message |
||||
</div> |
||||
} |
||||
</div> |
||||
<style> |
||||
.alertContainer { |
||||
border: 4px solid; |
||||
border-radius: 4px; |
||||
padding: 16px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-items: stretch; |
||||
width: 100%; |
||||
} |
||||
|
||||
.alertContainer.@SeverityType.Warning.ToString().ToLower() { |
||||
border-color: #2a2000; |
||||
background-color: #ffbf0029; |
||||
} |
||||
|
||||
.alertContainer.@SeverityType.Error.ToString().ToLower() { |
||||
border-color: #290102; |
||||
background-color: #4C2C33; |
||||
} |
||||
|
||||
.alertContainer.@SeverityType.Information.ToString().ToLower() { |
||||
border-color: #030129; |
||||
background-color: #2c3a4c; |
||||
} |
||||
|
||||
.alertContainer.@SeverityType.Success.ToString().ToLower() { |
||||
border-color: #042901; |
||||
background-color: #2E4C2C; |
||||
} |
||||
|
||||
.alertTitle { |
||||
font-weight: 800; |
||||
} |
||||
|
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? Title { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? Message { get; set; } |
||||
|
||||
[Parameter] |
||||
public SeverityType Type { get; set; } = SeverityType.Warning; |
||||
|
||||
} |
||||
@ -0,0 +1,46 @@
|
||||
<div class="loadingContainer"> |
||||
<div style="flex-grow: 1"></div> |
||||
<div class="loadingText"> |
||||
Loading... |
||||
</div> |
||||
<div style="flex-grow: 3"></div> |
||||
</div> |
||||
|
||||
<style> |
||||
@@keyframes loadingKeyframes { |
||||
0% { |
||||
font-size: 1.0rem |
||||
} |
||||
|
||||
50% { |
||||
font-size: 1.4rem |
||||
} |
||||
|
||||
100% { |
||||
font-size: 1.0rem |
||||
} |
||||
} |
||||
|
||||
.loadingContainer { |
||||
width: 100%; |
||||
height: 100%; |
||||
display: flex; |
||||
flex-grow: 1; |
||||
justify-content: center; |
||||
background-color: black; |
||||
border-radius: 4px; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.loadingText { |
||||
margin-left: auto; |
||||
margin-right: auto; |
||||
animation-name: loadingKeyframes; |
||||
animation-duration: 6s; |
||||
animation-iteration-count: infinite; |
||||
animation-timing-function: ease-in-out; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
} |
||||
@ -0,0 +1,8 @@
|
||||
namespace Components.Feedback; |
||||
|
||||
public enum SeverityType { |
||||
Warning, |
||||
Information, |
||||
Error, |
||||
Success |
||||
} |
||||
@ -0,0 +1,73 @@
|
||||
<div class="formContainer"> |
||||
<div class="formTextContainer"> |
||||
<div class="formLabel"> |
||||
@Label: |
||||
</div> |
||||
<input readonly="@ReadOnly" |
||||
class="formCheckboxInput" |
||||
type="checkbox" |
||||
id="@labelId" |
||||
checked="@Value |
||||
"@onchange="OnChange"/> |
||||
</div> |
||||
@if (Info != "") { |
||||
<div class="formInfo"> |
||||
@Info |
||||
</div> |
||||
} |
||||
</div> |
||||
<style> |
||||
.formContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
width: 100%; |
||||
} |
||||
|
||||
.formTextContainer { |
||||
display: flex; |
||||
flex-direction: row; |
||||
gap: 8px; |
||||
align-items: center; |
||||
} |
||||
|
||||
.formLabel { |
||||
font-weight: 800; |
||||
} |
||||
|
||||
.formInfo { |
||||
font-size: 0.8rem; |
||||
font-style: italic; |
||||
} |
||||
|
||||
.formCheckboxInput { |
||||
background-color: var(--primary); |
||||
color: var(--primary); |
||||
border: 2px solid var(--primary-border); |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public string Label { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public string Info { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public EventCallback<ChangeEventArgs> OnChange { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool ReadOnly { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool Value { get; set; } |
||||
|
||||
private string labelId = ""; |
||||
|
||||
protected override void OnInitialized() { |
||||
labelId = Label.ToLower().Replace(" ", "_"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,55 @@
|
||||
<div class="displayContainer"> |
||||
@if (Label != "") { |
||||
<div class="formLabel"> |
||||
@Label |
||||
</div> |
||||
} |
||||
<div class="displayContent"> |
||||
@Display |
||||
</div> |
||||
@if (Info != "") { |
||||
<div class="formInfo"> |
||||
@Info |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
<style> |
||||
.displayContainer { |
||||
display: flex; |
||||
width: 100%; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
} |
||||
|
||||
.displayContent { |
||||
background-color: var(--accent); |
||||
width: 100%; |
||||
border: 1px solid var(--primary-border); |
||||
border-radius: 1px; |
||||
padding: 8px; |
||||
min-height: 42px; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
//TODO Clean up |
||||
[Parameter] |
||||
public string Label { get; set; } |
||||
|
||||
[Parameter] |
||||
public string Info { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? Display { get; set; } |
||||
|
||||
[Parameter] |
||||
public EventCallback<ChangeEventArgs> OnChange { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool? ReadOnly { get; set; } |
||||
|
||||
[Parameter] |
||||
public string? Value { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,29 @@
|
||||
@using System.Web |
||||
<div class="escapeCodeContainer"> |
||||
<textarea style="background-color: #2C2E33; width: 100%; border:3px solid #A8ADB9; border-radius:1px; padding: 8px;" |
||||
rows="8" |
||||
@onchange="OnChange" /> |
||||
|
||||
<textarea style="background-color: #2C2E33; width: 100%; border:3px solid #A8ADB9; border-radius:1px; padding: 8px;" |
||||
rows="8" |
||||
@bind="Output" /> |
||||
</div> |
||||
|
||||
<style> |
||||
.escapeCodeContainer { |
||||
display: grid; |
||||
grid-template-columns: 1fr 1fr; |
||||
gap: 8px; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
string Output = ""; |
||||
|
||||
public void OnChange(ChangeEventArgs changeEventArgs) { |
||||
var encoded = HttpUtility.HtmlEncode(changeEventArgs.Value.ToString()); |
||||
Output = encoded.Replace("@", "@@"); |
||||
Output = Output.Replace("\n", "<br />"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,154 @@
|
||||
@using Services |
||||
@using Services.Immortal |
||||
@using Model.Immortal.MemoryTester |
||||
@implements IDisposable |
||||
|
||||
@inject IMemoryTesterService MemoryTesterService |
||||
|
||||
<div class="formGuessContainer"> |
||||
@if (MemoryQuestion.Name != "") { |
||||
<div class="formLabel"> |
||||
@MemoryQuestion.Name |
||||
</div> |
||||
} |
||||
<div> |
||||
<input readonly="@MemoryQuestion.IsRevealed" |
||||
class="formTextInput @(MemoryQuestion.IsRevealed ? "revealed" : IsSubmitted == false ? "guess" : int.Parse(guess) == MemoryQuestion.Answer ? "correct" : "wrong")" |
||||
placeholder="guess..." |
||||
type="number" |
||||
value="@guess" |
||||
id="@labelId" |
||||
@onchange="OnGuessChanged"/> |
||||
</div> |
||||
</div> |
||||
|
||||
<style> |
||||
.formGuessContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
width: 100%; |
||||
} |
||||
|
||||
.formLabel { |
||||
font-weight: 800; |
||||
} |
||||
|
||||
.formInfo { |
||||
font-size: 0.8rem; |
||||
font-style: italic; |
||||
} |
||||
|
||||
.formTextInput { |
||||
background-color: #2C2E33; |
||||
border: 3px solid #A8ADB9; |
||||
border-radius: 1px; |
||||
padding: 8px; |
||||
display: block; |
||||
width: 100%; |
||||
} |
||||
|
||||
.guess { |
||||
background-color: var(--primary); |
||||
border: 4px solid var(--primary-border); |
||||
border-radius: 1px; |
||||
} |
||||
|
||||
::placeholder { |
||||
color: white; |
||||
opacity: 1; |
||||
} |
||||
|
||||
.formTextInput.correct { |
||||
border: 3px solid green; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.formTextInput.wrong { |
||||
border: 3px solid red; |
||||
border-radius: 2px; |
||||
font-weight: bold; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public string Label { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public string Info { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public EventCallback<AnswerEventArgs> OnChange { get; set; } |
||||
|
||||
[Parameter] |
||||
public MemoryQuestionModel MemoryQuestion { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool IsSubmitted { get; set; } |
||||
|
||||
|
||||
private string guess { get; set; } = ""; |
||||
|
||||
|
||||
private string labelId = ""; |
||||
|
||||
protected override void OnInitialized() { |
||||
labelId = Label.ToLower().Replace(" ", "_") + MemoryQuestion.Id; |
||||
|
||||
MemoryTesterService.Subscribe(OnMemoryEvent); |
||||
|
||||
if (MemoryQuestion.IsRevealed) { |
||||
guess = MemoryQuestion.Answer.ToString(); |
||||
} |
||||
|
||||
OnRefresh(); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
MemoryTesterService.Unsubscribe(OnMemoryEvent); |
||||
} |
||||
|
||||
void OnMemoryEvent(MemoryTesterEvent memoryTesterEvent) { |
||||
if (memoryTesterEvent == MemoryTesterEvent.OnVerify) { |
||||
OnVerify(); |
||||
} |
||||
|
||||
if (memoryTesterEvent == MemoryTesterEvent.OnRefresh) { |
||||
OnRefresh(); |
||||
} |
||||
} |
||||
|
||||
protected override void OnAfterRender(bool firstRender) { |
||||
if (MemoryQuestion.IsRevealed) { |
||||
guess = MemoryQuestion.Answer.ToString(); |
||||
} |
||||
} |
||||
|
||||
void OnVerify() { |
||||
IsSubmitted = true; |
||||
} |
||||
|
||||
void OnRefresh() { |
||||
guess = ""; |
||||
|
||||
if (MemoryQuestion.IsRevealed) { |
||||
guess = MemoryQuestion.Answer.ToString(); |
||||
} |
||||
|
||||
|
||||
IsSubmitted = false; |
||||
} |
||||
|
||||
void OnGuessChanged(ChangeEventArgs changeEventArgs) { |
||||
guess = changeEventArgs.Value.ToString(); |
||||
|
||||
OnChange.InvokeAsync(new AnswerEventArgs { |
||||
Name = MemoryQuestion.Name, |
||||
IsCorrect = int.Parse(guess) == MemoryQuestion.Answer, |
||||
Guess = int.Parse(guess) |
||||
}); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,12 @@
|
||||
<div style="font-size:0.8rem; font-style:italic;"> |
||||
<i> |
||||
@ChildContent |
||||
</i> |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,10 @@
|
||||
<div style="font-weight:800"> |
||||
@ChildContent: |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,10 @@
|
||||
<div style="display: flex; gap: 16px; width: 100%; flex-direction: column;"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,59 @@
|
||||
<div class="formNumberContainer"> |
||||
@if (FormLabelComponent != null) { |
||||
<FormLabelComponent>@FormLabelComponent</FormLabelComponent> |
||||
} |
||||
<div> |
||||
<input readonly="@ReadOnly" |
||||
class="numberInput" |
||||
type="number" |
||||
min="@Min" |
||||
max="@Max" |
||||
value="@Value" |
||||
@onchange="OnChange"/> |
||||
</div> |
||||
@if (FormInfoComponent != null) { |
||||
<FormInfoComponent>@FormInfoComponent</FormInfoComponent> |
||||
} |
||||
</div> |
||||
|
||||
<style> |
||||
.formNumberContainer { |
||||
display: flex; |
||||
width: 100%; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
} |
||||
|
||||
.numberInput { |
||||
width: 100%; |
||||
background-color: var(--primary); |
||||
border: 4px solid var(--primary-border); |
||||
border-radius: 1px; |
||||
padding: 8px; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? FormLabelComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? FormInfoComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public EventCallback<ChangeEventArgs> OnChange { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool? ReadOnly { get; set; } |
||||
|
||||
[Parameter] |
||||
public int? Value { get; set; } |
||||
|
||||
[Parameter] |
||||
public int? Min { get; set; } |
||||
|
||||
[Parameter] |
||||
public int? Max { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,30 @@
|
||||
<div style="display: flex; width: 100%; flex-direction: column; gap:6px;"> |
||||
@if (FormLabelComponent != null) { |
||||
<FormLabelComponent>@FormLabelComponent</FormLabelComponent> |
||||
} |
||||
<select style="background-color: #2C2E33; width: 100%; border:3px solid #A8ADB9; border-radius:1px; padding: 8px;" |
||||
@onchange="OnChange"> |
||||
@ChildContent |
||||
</select> |
||||
|
||||
@if (FormInfoComponent != null) { |
||||
<FormInfoComponent>@FormInfoComponent</FormInfoComponent> |
||||
} |
||||
</div> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? FormLabelComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? FormInfoComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
[Parameter] |
||||
public EventCallback<ChangeEventArgs> OnChange { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,90 @@
|
||||
<div class="form-text-container"> |
||||
@if (Label != "") { |
||||
<div class="form-label"> |
||||
@Label |
||||
</div> |
||||
} |
||||
<div> |
||||
<textarea readonly="@ReadOnly" |
||||
class="textAreaInput" |
||||
type="text" |
||||
rows="@Rows" |
||||
value="@Value" |
||||
@onchange="OnChange" /> |
||||
</div> |
||||
@if (Info != "") { |
||||
<div class="form-info"> |
||||
@Info |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
<style> |
||||
.form-text-container { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
width: 100%; |
||||
} |
||||
|
||||
.textAreaInput { |
||||
width: 100%; |
||||
border-radius: 1px; |
||||
padding: 8px; |
||||
background-color: var(--primary); |
||||
border: 4px solid var(--primary-border); |
||||
} |
||||
|
||||
.form-text-container .form-label { |
||||
font-weight: 800; |
||||
} |
||||
|
||||
.form-text-container .form-info { |
||||
font-size: 0.8rem; |
||||
font-style: italic; |
||||
} |
||||
|
||||
.form-text-container .form-text-input { |
||||
background-color: #2C2E33; |
||||
border: 3px solid #A8ADB9; |
||||
border-radius: 1px; |
||||
padding: 8px; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? FormLabelComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? FormInfoComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public EventCallback<ChangeEventArgs> OnChange { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool? ReadOnly { get; set; } |
||||
|
||||
[Parameter] |
||||
public string? Value { get; set; } |
||||
|
||||
[Parameter] |
||||
public int Rows { get; set; } = 4; |
||||
|
||||
[Parameter] |
||||
public string Label { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public string Info { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public string Placeholder { get; set; } = ""; |
||||
|
||||
private string labelId = ""; |
||||
|
||||
protected override void OnInitialized() { |
||||
labelId = Label.ToLower().Replace(" ", "_"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,75 @@
|
||||
<div class="formContainer"> |
||||
@if (Label != "") { |
||||
<div class="formLabel"> |
||||
@Label |
||||
</div> |
||||
} |
||||
<div> |
||||
<input readonly="@ReadOnly" |
||||
class="formTextInput" |
||||
placeholder="@Placeholder" |
||||
type="text" |
||||
value="@Value" |
||||
id="@labelId" |
||||
@onchange="OnChange"/> |
||||
</div> |
||||
@if (Info != "") { |
||||
<div class="formInfo"> |
||||
@Info |
||||
</div> |
||||
} |
||||
</div> |
||||
<style> |
||||
.formContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
width: 100%; |
||||
} |
||||
|
||||
.formLabel { |
||||
font-weight: 800; |
||||
} |
||||
|
||||
.formInfo { |
||||
font-size: 0.8rem; |
||||
font-style: italic; |
||||
} |
||||
|
||||
.formTextInput { |
||||
border-radius: 1px; |
||||
padding: 8px; |
||||
display: block; |
||||
width: 100%; |
||||
background-color: var(--primary); |
||||
border: 4px solid var(--primary-border); |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public string Label { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public string Info { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public string Placeholder { get; set; } = ""; |
||||
|
||||
[Parameter] |
||||
public EventCallback<ChangeEventArgs> OnChange { get; set; } |
||||
|
||||
[Parameter] |
||||
public bool ReadOnly { get; set; } |
||||
|
||||
[Parameter] |
||||
public string Value { get; set; } = ""; |
||||
|
||||
private string labelId = ""; |
||||
|
||||
protected override void OnInitialized() { |
||||
labelId = Label.ToLower().Replace(" ", "_"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,44 @@
|
||||
<div class="infoContainer"> |
||||
@if (InfoQuestionComponent != null) { |
||||
<div class="infoTitle">@InfoQuestionComponent</div> |
||||
} |
||||
@if (InfoAnswerComponent != null) { |
||||
<div>@InfoAnswerComponent</div> |
||||
} |
||||
</div> |
||||
|
||||
<style> |
||||
.infoContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
border-radius: 8px; |
||||
padding-top: 16px; |
||||
padding-left: 16px; |
||||
padding-right: 16px; |
||||
padding-bottom: 16px; |
||||
margin: auto; |
||||
width: 100%; |
||||
gap: 8px; |
||||
} |
||||
|
||||
.infoTitle { |
||||
font-weight: 800; |
||||
font-size: 1.3rem; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.infoContainer { |
||||
padding: 2px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? InfoQuestionComponent { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment? InfoAnswerComponent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,52 @@
|
||||
<button class="buttonContainer @ButtonType.ToString().ToLower()" @onclick="ButtonClicked">@ChildContent</button> |
||||
|
||||
<style> |
||||
.buttonContainer { |
||||
padding: 16px; |
||||
border: 1px solid; |
||||
border-radius: 8px; |
||||
font-weight: 800; |
||||
font-size: 1.2rem; |
||||
} |
||||
|
||||
.@(ButtonType.Primary.ToString().ToLower()) { |
||||
border-color: var(--primary); |
||||
background-color: var(--primary); |
||||
} |
||||
|
||||
.@ButtonType.Secondary.ToString().ToLower() { |
||||
border-color: var(--secondary); |
||||
background-color: var(--secondary); |
||||
} |
||||
|
||||
.@ButtonType.Primary.ToString().ToLower():hover { |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
color: white; |
||||
} |
||||
|
||||
.@ButtonType.Secondary.ToString().ToLower():hover { |
||||
background-color: var(--secondary-hover); |
||||
border-color: var(--secondary-border-hover); |
||||
color: white; |
||||
} |
||||
|
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Parameter] |
||||
public EventCallback<EventArgs> OnClick { get; set; } |
||||
|
||||
[Parameter] |
||||
public ButtonType ButtonType { get; set; } |
||||
|
||||
private void ButtonClicked(EventArgs eventArgs) { |
||||
OnClick.InvokeAsync(eventArgs); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,6 @@
|
||||
namespace Components.Inputs; |
||||
|
||||
public enum ButtonType { |
||||
Primary, // Positive Actions |
||||
Secondary // Destruction Action |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
<div class="divider"> |
||||
</div> |
||||
|
||||
<style> |
||||
.divider { |
||||
width: 100%; |
||||
border-bottom: 2px solid black; |
||||
margin-top: 6px; |
||||
margin-bottom: 6px; |
||||
height: 12px; |
||||
background-color: #545454; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,18 @@
|
||||
<div class="columnContainer"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.columnContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
flex: 1; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,40 @@
|
||||
<div class="lrg_container"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.lrg_container { |
||||
display: flex; |
||||
gap: 16px; |
||||
flex-direction: column; |
||||
width: 75%; |
||||
min-width: 1000px; |
||||
margin-left: auto; |
||||
margin-right: auto; |
||||
padding-top: 10px; |
||||
padding-bottom: 30px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.lrg_container { |
||||
width: 100%; |
||||
min-width: 350px; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
@@media only screen and (min-width: 1024px) { |
||||
.lrg_container { |
||||
margin-top: 50px; |
||||
} |
||||
} |
||||
|
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,39 @@
|
||||
<div class="med_container"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
|
||||
<style> |
||||
.med_container { |
||||
display: flex; |
||||
gap: 16px; |
||||
flex-direction: column; |
||||
width: 50%; |
||||
min-width: 1000px; |
||||
margin-left: auto; |
||||
margin-right: auto; |
||||
padding-top: 10px; |
||||
padding-bottom: 30px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.med_container { |
||||
width: 99%; |
||||
min-width: 350px; |
||||
} |
||||
} |
||||
|
||||
@@media only screen and (min-width: 1024px) { |
||||
.med_container { |
||||
margin-top: 50px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,35 @@
|
||||
<div class="med_container"> |
||||
|
||||
@ChildContent |
||||
</div> |
||||
|
||||
|
||||
<style> |
||||
.med_container { |
||||
display: flex; |
||||
gap: 16px; |
||||
flex-direction: column; |
||||
width: 50%; |
||||
margin-left: auto; |
||||
margin-right: auto; |
||||
padding-top: 10px; |
||||
padding-left: 20px; |
||||
padding-right: 20px; |
||||
padding-bottom: 30px; |
||||
border: 2px solid black; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.med_container { |
||||
width: 85%; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
<div class="rowContainer"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.rowContainer { |
||||
display: flex; |
||||
flex-direction: row; |
||||
gap: 30px; |
||||
width: 100%; |
||||
flex-wrap: wrap; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.rowContainer { |
||||
gap: 3px; |
||||
flex-direction: column; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,30 @@
|
||||
<div class="content"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
<style> |
||||
.content { |
||||
display: flex; |
||||
flex-direction: column; |
||||
flex-wrap: wrap; |
||||
gap: 20px; |
||||
padding: 20px; |
||||
border: 2px solid black; |
||||
min-height: 50vh; |
||||
padding-bottom: 124px |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.content { |
||||
padding: 10px; |
||||
border: 0px solid black; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
<div class="title"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
|
||||
<style> |
||||
.title { |
||||
padding-top: 35px; |
||||
padding-bottom: 5px; |
||||
font-size: 1.5rem; |
||||
font-weight: bolder; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.title { |
||||
padding: 10px; |
||||
border: 0px solid black; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment? ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,22 @@
|
||||
@if (Markdown == null) { |
||||
<div>Loading...</div> |
||||
} |
||||
else { |
||||
@((MarkupString)Markdown) |
||||
} |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
protected HttpClient Http { get; set; } |
||||
|
||||
[Parameter] |
||||
public string MarkdownFileName { get; set; } |
||||
|
||||
public string Markdown { get; set; } |
||||
|
||||
protected override async Task OnInitializedAsync() { |
||||
Markdown = Markdig.Markdown.ToHtml(await Http.GetStringAsync($"markdown/{MarkdownFileName}.md")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,120 @@
|
||||
@inherits LayoutComponentBase |
||||
@inject INavigationService NavigationService |
||||
@using Services |
||||
@using Model.Website |
||||
@using Model.Website.Enums |
||||
@using Microsoft.EntityFrameworkCore |
||||
@implements IDisposable |
||||
|
||||
<div onmouseleave="@HoverOut" class="desktopNavContainer"> |
||||
<div class="menuHeader" @onmouseover="() => NavigationService.ChangeNavigationState(NavigationStateType.Hovering_Menu)"> |
||||
<NavLink href="/" class="websiteTitle"> |
||||
IGP Fan Reference |
||||
</NavLink> |
||||
|
||||
@foreach (var webSection in WebSections) { |
||||
<div>@webSection.Name</div> |
||||
} |
||||
</div> |
||||
|
||||
@{ |
||||
var hoveredStyle = NavigationStateType.Hovering_Menu.Equals(NavigationService.GetNavigationState()) ? |
||||
"navMenuContainerShow" : ""; |
||||
} |
||||
<div class="navMenuContainer @hoveredStyle"> |
||||
@foreach (var section in WebSections) { |
||||
var pages = (from page in WebPages |
||||
where page.WebSectionModelId == section.Id |
||||
select page).ToList(); |
||||
|
||||
<NavSectionComponent Section=section Children=pages/> |
||||
} |
||||
</div> |
||||
</div> |
||||
|
||||
<style> |
||||
.desktopNavContainer { |
||||
position: fixed; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100vw; |
||||
height: 40px; |
||||
background-color: rgba(255,255,255,0.1); |
||||
z-index: 1001; |
||||
} |
||||
|
||||
.menuHeader { |
||||
border-bottom: 4px solid black; |
||||
position: fixed; |
||||
width: 100%; |
||||
padding: 12px; |
||||
display: flex; |
||||
justify-content: center; |
||||
gap: 32px; |
||||
height: 50px; |
||||
background-color: var(--accent); |
||||
} |
||||
|
||||
|
||||
.websiteTitle { |
||||
font-weight: bold; |
||||
color: white; |
||||
} |
||||
|
||||
.navMenuContainer { |
||||
display: none; |
||||
position: fixed; |
||||
top: 50px; |
||||
flex-direction: row; |
||||
gap: 20px; |
||||
width: 100%; |
||||
align-items: flex-start; |
||||
justify-content: center; |
||||
flex-wrap: wrap; |
||||
border-bottom: 4px solid black; |
||||
padding-top: 20px; |
||||
padding-bottom: 20px; |
||||
background-color: rgba(22, 22, 24, 0.95); |
||||
} |
||||
|
||||
.navMenuContainerShow { |
||||
display: flex; |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.desktopNavContainer { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
@@media only screen and (max-width: 480px) { |
||||
.desktopNavContainer { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public DbSet<WebSectionModel> WebSections { get; set; } |
||||
|
||||
[Parameter] |
||||
public DbSet<WebPageModel> WebPages { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
NavigationService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
NavigationService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
void HoverOut(MouseEventArgs mouseEventArgs) { |
||||
Console.WriteLine(NavigationStateType.Default); |
||||
NavigationService.ChangeNavigationState(NavigationStateType.Default); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,170 @@
|
||||
@using Model.Website |
||||
@using Microsoft.EntityFrameworkCore |
||||
<div class="mobileFooter"> |
||||
<div class="mobileNavSectionsContainer"> |
||||
@foreach (var _section in WebSections) { |
||||
<div class="mobileNavSectionButton" @onclick="() => OnSectionClicked(_section)" @onclick:preventDefault="true" @onclick:stopPropagation="true"> |
||||
<div class="mobileNavSectionButtonText"> |
||||
@_section.Name |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
<div class="fullPageButton @(selectedSection != null)" @onclick="OnPageClicked" @onclick:stopPropagation="false" @onclick:preventDefault="false"> |
||||
</div> |
||||
|
||||
@if (selectedSection != null) { |
||||
var pages = (from page in WebPages |
||||
where page.WebSectionModelId == selectedSection.Id |
||||
select page).ToList(); |
||||
|
||||
<div class="mobileNavPagesContainer"> |
||||
@foreach (var _page in pages) { |
||||
if (_page.IsPrivate.Equals("True")) { |
||||
continue; |
||||
} |
||||
<div class="mobileNavPageButton" @onclick="() => OnPageLinkClicked(_page)" @onclick:preventDefault="true" @onclick:stopPropagation="true"> |
||||
<div class="mobileNavPageButtonText"> |
||||
@_page.Name |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
|
||||
<style> |
||||
fullPageButton { |
||||
position: fixed; |
||||
width: 100vw; |
||||
height: 100vh; |
||||
bottom: 0; |
||||
display: none; |
||||
background-color: rgba(0,0,0,0.6); |
||||
} |
||||
|
||||
.fullPageButton.True { |
||||
display: block; |
||||
} |
||||
|
||||
|
||||
.mobileFooter { |
||||
position: fixed; |
||||
background-color: rgba(0,0,0,1); |
||||
width: 100vw; |
||||
bottom: 0; |
||||
display: none; |
||||
} |
||||
|
||||
.mobileNavPagesContainer { |
||||
position: fixed; |
||||
display: flex; |
||||
flex-direction: column; |
||||
bottom: 0; |
||||
width: 100vw; |
||||
background-color: black; |
||||
padding-bottom: 6px; |
||||
padding-top: 6px; |
||||
padding-left: 4px; |
||||
padding-right: 4px; |
||||
gap: 2px; |
||||
} |
||||
|
||||
.mobileNavSectionsContainer { |
||||
display: grid; |
||||
grid-auto-columns: 1fr; |
||||
grid-auto-flow: column; |
||||
width: 100%; |
||||
padding-bottom: 6px; |
||||
padding-top: 6px; |
||||
padding-left: 4px; |
||||
padding-right: 4px; |
||||
gap: 2px; |
||||
} |
||||
|
||||
.mobileNavSectionButton { |
||||
border: 1px solid var(--primary); |
||||
width: 100%; |
||||
height: 64px; |
||||
display: flex; |
||||
background-color: var(--primary); |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.mobileNavPageButton { |
||||
border: 1px solid var(--primary); |
||||
width: 100%; |
||||
height: 64px; |
||||
display: flex; |
||||
background-color: var(--primary); |
||||
cursor: pointer; |
||||
} |
||||
|
||||
|
||||
.mobileNavPageButton:hover { |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
} |
||||
|
||||
|
||||
.mobileNavSectionButton:hover { |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
} |
||||
|
||||
.mobileNavSectionButtonText { |
||||
font-size: 0.75rem; |
||||
text-align: center; |
||||
margin: auto; |
||||
font-weight: bolder; |
||||
} |
||||
|
||||
.mobileNavPageButtonText { |
||||
font-size: 1.1rem; |
||||
text-align: center; |
||||
margin: auto; |
||||
font-weight: bolder; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 480px) { |
||||
.mobileFooter { |
||||
display: block; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public DbSet<WebSectionModel> WebSections { get; set; } |
||||
|
||||
[Parameter] |
||||
public DbSet<WebPageModel> WebPages { get; set; } |
||||
|
||||
[Inject] |
||||
public NavigationManager NavigationManager { get; set; } |
||||
|
||||
|
||||
public WebSectionModel selectedSection; |
||||
public WebPageModel selectedPage; |
||||
|
||||
|
||||
void OnSectionClicked(WebSectionModel webSection) { |
||||
selectedSection = webSection; |
||||
} |
||||
|
||||
void OnPageLinkClicked(WebPageModel webPage) { |
||||
selectedPage = webPage; |
||||
selectedSection = null; |
||||
|
||||
NavigationManager.NavigateTo(webPage.Href); |
||||
} |
||||
|
||||
void OnPageClicked(EventArgs eventArgs) { |
||||
selectedPage = null; |
||||
selectedSection = null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,84 @@
|
||||
@using Services |
||||
@using Model.Website |
||||
@using Model.Website.Enums |
||||
@inject INavigationService NavigationService; |
||||
@inject NavigationManager NavigationManager; |
||||
|
||||
|
||||
@if (IsOnPage) { |
||||
<NavLink href="@Page.Href" class="navContainer navLink navSelected"> |
||||
<div class="navName"> |
||||
@Page.Name |
||||
</div> |
||||
</NavLink> |
||||
} |
||||
else { |
||||
<NavLink @onclick="() => NavigationService.ChangeNavigationState(NavigationStateType.Default)" href="@Page.Href" class="navContainer navLink"> |
||||
<div class="navName"> |
||||
@Page.Name |
||||
</div> |
||||
</NavLink> |
||||
} |
||||
|
||||
<style> |
||||
.navContainer { |
||||
cursor: pointer; |
||||
border: 2px solid black; |
||||
border: none; |
||||
height: 60px; |
||||
width: 100%; |
||||
display: block; |
||||
display: flex; |
||||
border: none; |
||||
} |
||||
|
||||
.navName { |
||||
margin: auto; |
||||
color: white; |
||||
font-size: 1.3rem; |
||||
font-weight: 600; |
||||
text-align: center; |
||||
} |
||||
|
||||
|
||||
.navLink { |
||||
background-color: var(--primary); |
||||
border: 1px solid var(--primary); |
||||
} |
||||
|
||||
.navLink:hover { |
||||
color: #8EC3FF; |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
} |
||||
|
||||
.navSelected { |
||||
background-color: var(--primary-hover); |
||||
} |
||||
|
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public WebPageModel Page { get; set; } |
||||
|
||||
bool IsOnPage = false; |
||||
|
||||
protected override async Task OnParametersSetAsync() { |
||||
var uri = NavigationManager.Uri.Remove(0, NavigationManager.BaseUri.Count()).ToLower(); |
||||
|
||||
IsOnPage = Page.Href.ToLower().Equals(uri); |
||||
} |
||||
|
||||
|
||||
void OnNavigationChanged() { |
||||
StateHasChanged(); |
||||
} |
||||
|
||||
void OnBack() { |
||||
NavigationService.Back(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,58 @@
|
||||
@using Model.Website |
||||
<div class="sectionContainer"> |
||||
<div class="sectionHeader"> |
||||
<div class="sectionTitle"> |
||||
@Section.Name |
||||
</div> |
||||
</div> |
||||
|
||||
@foreach (var childPage in Children) { |
||||
if (childPage.IsPrivate.Equals("True")) { |
||||
continue; |
||||
} |
||||
<NavLinkComponent Page=childPage></NavLinkComponent> |
||||
} |
||||
</div> |
||||
|
||||
<style> |
||||
.sectionContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 4px; |
||||
justify-content: flex-start; |
||||
position: relative; |
||||
margin-top: 12px; |
||||
padding: 18px; |
||||
width: 300px; |
||||
margin-left: 4px; |
||||
} |
||||
|
||||
.sectionHeader { |
||||
bottom: 100%; |
||||
position: absolute; |
||||
top: 0px; |
||||
left: -8px; |
||||
padding-right: 12px; |
||||
padding-left: 4px; |
||||
width: 100%; |
||||
display: flex; |
||||
line-height: 0px; |
||||
} |
||||
|
||||
.sectionTitle { |
||||
font-weight: bold; |
||||
padding-right: 8px; |
||||
margin-top: -2px; |
||||
white-space: pre; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public WebSectionModel? Section { get; set; } |
||||
|
||||
[Parameter] |
||||
public List<WebPageModel>? Children { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,163 @@
|
||||
@using Model.Website |
||||
@using Microsoft.EntityFrameworkCore |
||||
@inherits LayoutComponentBase |
||||
|
||||
<div class="tablet"> |
||||
<div class="tabletHeader" @onclick="OnNavClicked" @onclick:preventDefault="true" @onclick:stopPropagation="true"> |
||||
<div class="tabletTitle"> |
||||
IGP Fan Reference |
||||
</div> |
||||
|
||||
<div class="tabletButton"> |
||||
<div class="tabletMenuTitle"> |
||||
Menu |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
<div class="fullPageButton @NavOpen" @onclick="OnNavClicked" @onclick:stopPropagation="false" @onclick:preventDefault="false"> |
||||
</div> |
||||
|
||||
|
||||
<div class="tabletNav @NavOpen"> |
||||
@foreach (var _section in WebSections) { |
||||
var pages = (from page in WebPages |
||||
where page.WebSectionModelId == _section.Id |
||||
select page).ToList(); |
||||
|
||||
<div> |
||||
<div> |
||||
@_section.Name |
||||
</div> |
||||
|
||||
<div class="tabletNavItems"> |
||||
@foreach (var _page in pages) { |
||||
if (_page.IsPrivate.Equals("True")) { |
||||
continue; |
||||
} |
||||
<NavLink href="@_page.Href" class="tabletNavItem" @onclick="OnPageClicked"> |
||||
@_page.Name |
||||
</NavLink> |
||||
} |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
<style> |
||||
.fullPageButton { |
||||
position: fixed; |
||||
width: 100vw; |
||||
height: 100vh; |
||||
bottom: 0; |
||||
display: none; |
||||
background-color: rgba(0,0,0,0.6); |
||||
} |
||||
|
||||
.fullPageButton.True { |
||||
display: block; |
||||
} |
||||
|
||||
.tablet { |
||||
display: none; |
||||
} |
||||
|
||||
.tabletNav { |
||||
position: fixed; |
||||
background-color: rgba(30,30,30,0.98); |
||||
display: none; |
||||
height: 100vh; |
||||
padding: 32px; |
||||
overflow-y: auto; |
||||
overflow-x: hidden; |
||||
top: 0px; |
||||
gap: 22px; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.tabletNavItem { |
||||
padding: 8px; |
||||
} |
||||
|
||||
.tabletNavItems { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.tabletNav.True { |
||||
display: flex; |
||||
} |
||||
|
||||
.tabletHeader { |
||||
height: 60px; |
||||
width: 100vw; |
||||
position: fixed; |
||||
top: 0; |
||||
display: flex; |
||||
background-color: var(--accent); |
||||
border-bottom: 4px solid rgba(0,0,0,0.95); |
||||
justify-content: space-between; |
||||
} |
||||
|
||||
.tabletMenuTitle { |
||||
margin: auto; |
||||
font-weight: 700; |
||||
} |
||||
|
||||
.tabletTitle { |
||||
margin: auto; |
||||
font-weight: 700; |
||||
font-size: 1.4rem; |
||||
} |
||||
|
||||
.tabletButton { |
||||
border: 2px solid black; |
||||
background-color: rgba(0,0,0,0.3); |
||||
width: 80px; |
||||
height: 100%; |
||||
display: flex; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.tabletButton:hover { |
||||
background-color: rgba(0,0,0,0.7); |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.tablet { |
||||
display: block; |
||||
} |
||||
} |
||||
|
||||
@@media only screen and (max-width: 480px) { |
||||
.tablet { |
||||
display: none; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public DbSet<WebSectionModel> WebSections { get; set; } |
||||
|
||||
[Parameter] |
||||
public DbSet<WebPageModel> WebPages { get; set; } |
||||
|
||||
|
||||
bool NavOpen = true; |
||||
|
||||
void OnNavClicked(EventArgs eventArgs) { |
||||
NavOpen = !NavOpen; |
||||
} |
||||
|
||||
|
||||
void OnPageClicked(EventArgs eventArgs) { |
||||
NavOpen = false; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,24 @@
|
||||
@using Model.Website.Enums |
||||
@using Model.Website |
||||
@if (isDisplayable) { |
||||
@ChildContent |
||||
} |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Parameter] |
||||
public WebDeploymentType DeploymentType { get; set; } |
||||
|
||||
[Inject] |
||||
public NavigationManager MyNavigationManager { get; set; } |
||||
|
||||
bool isDisplayable; |
||||
|
||||
protected override void OnInitialized() { |
||||
isDisplayable = DeploymentType == WebDeploymentModel.DeploymentType; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,26 @@
|
||||
@using Model.Website |
||||
@if (isDisplayable) { |
||||
@ChildContent |
||||
} |
||||
else { |
||||
<LayoutView Layout="@typeof(MainLayout)"> |
||||
<p>Sorry, there's nothing at this address.</p> |
||||
</LayoutView> |
||||
} |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Inject] |
||||
public NavigationManager MyNavigationManager { get; set; } |
||||
|
||||
bool isDisplayable; |
||||
|
||||
protected override void OnInitialized() { |
||||
var page = MyNavigationManager.Uri.Remove(0, MyNavigationManager.BaseUri.Length); |
||||
isDisplayable = WebDeploymentModel.Get().Contains(page); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,4 @@
|
||||
@inherits LayoutComponentBase |
||||
|
||||
|
||||
@Body |
||||
@ -0,0 +1,19 @@
|
||||
<div style="display:inline; width: 12px;"> |
||||
<div style="height: 0px; display:flex; flex-direction:column; align-items:center;"> |
||||
<div style="height: 0px;"> |
||||
― |
||||
</div> |
||||
<div style="height: 0px;position: relative; top: -6px; left:0px; white-space:pre">@Dividee</div> |
||||
<div style="height: 0px; position: relative; top: 6px; left:0px; white-space:pre">@Divider</div> |
||||
</div> |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment Dividee { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment Divider { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,24 @@
|
||||
<div style="display:flex; flex-direction:column; align-items:center;padding-right: 12px;padding-left: 4px; font-family:monospace"> |
||||
<div style="height: 0px;display:flex; flex-direction:row; "> |
||||
<div style="font-size: 18px; height: 0px;"> |
||||
∑ |
||||
</div> |
||||
<div style="position:relative; left: 2px; top: 1px;">@IndexSymbol</div> |
||||
</div> |
||||
|
||||
<div style="height: 0px;position: relative; top: -18px; left:0px; font-size: 80%; display:flex;">@LoopEnd</div> |
||||
<div style="height: 0px; position: relative; top: 22px; left:0px; font-size: 80%; display:flex;">@LoopStart</div> |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment LoopEnd { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment LoopStart { get; set; } |
||||
|
||||
[Parameter] |
||||
public RenderFragment IndexSymbol { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,28 @@
|
||||
<span class="spoiler"> |
||||
<u>@ChildContent</u> |
||||
</span> |
||||
|
||||
<style> |
||||
.spoiler { |
||||
color: black; |
||||
background-color: black; |
||||
} |
||||
|
||||
u { |
||||
text-decoration-color: inherit; |
||||
text-decoration-thickness:1px; |
||||
} |
||||
|
||||
.spoiler:hover { |
||||
color: inherit; |
||||
background-color: inherit; |
||||
} |
||||
|
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,7 @@
|
||||
namespace Components.Utils; |
||||
|
||||
public static class Interval { |
||||
public static string ToTime(int interval) { |
||||
return TimeSpan.FromSeconds(interval).ToString(@"mm\:ss"); |
||||
} |
||||
} |
||||
@ -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 Microsoft.AspNetCore.Components.Web.Virtualization |
||||
@using Microsoft.JSInterop |
||||
@using System.Text |
||||
@using System.Text.Json |
||||
@using YamlDotNet.Serialization |
||||
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net7.0</TargetFramework> |
||||
<ImplicitUsings>enable</ImplicitUsings> |
||||
<Nullable>enable</Nullable> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.2.22153.1" /> |
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0-preview.2.22153.1"> |
||||
<PrivateAssets>all</PrivateAssets> |
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
</PackageReference> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Model\Model.csproj" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
||||
@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore; |
||||
using Model.Website; |
||||
using Model.Work.Git; |
||||
using Model.Work.Tasks; |
||||
|
||||
namespace Contexts; |
||||
|
||||
public class DatabaseContext : DbContext { |
||||
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { |
||||
Database.EnsureCreated(); |
||||
} |
||||
|
||||
public DbSet<SprintModel> SprintModels { get; set; } |
||||
public DbSet<TaskModel> TaskModels { get; set; } |
||||
public DbSet<ChangeModel> ChangeModels { get; set; } |
||||
public DbSet<PatchModel> PatchModels { get; set; } |
||||
public DbSet<WebPageModel> WebPageModels { get; set; } |
||||
public DbSet<WebSectionModel> WebSectionModels { get; set; } |
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) { |
||||
modelBuilder.Entity<PatchModel>(); |
||||
modelBuilder.Entity<TaskModel>(); |
||||
|
||||
base.OnModelCreating(modelBuilder); |
||||
} |
||||
} |
||||
@ -0,0 +1,30 @@
|
||||
@inject HttpClient HttpClient |
||||
@inject DatabaseContext Database |
||||
|
||||
<Router AppAssembly="@typeof(App).Assembly"> |
||||
<Found Context="routeData"> |
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/> |
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/> |
||||
</Found> |
||||
<NotFound> |
||||
<PageTitle>Not found</PageTitle> |
||||
<LayoutView Layout="@typeof(MainLayout)"> |
||||
<p role="alert">Sorry, there's nothing at this address.</p> |
||||
</LayoutView> |
||||
</NotFound> |
||||
</Router> |
||||
|
||||
|
||||
<style> |
||||
a { |
||||
color: #8fc5ff; |
||||
font-weight: 700; |
||||
} |
||||
|
||||
a:hover { |
||||
color: #d2f0ff; |
||||
text-decoration: underline; |
||||
text-decoration-color: #8fc5ff; |
||||
text-decoration-thickness: 3px; |
||||
} |
||||
</style> |
||||
Binary file not shown.
@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net7.0</TargetFramework> |
||||
<Nullable>enable</Nullable> |
||||
<ImplicitUsings>enable</ImplicitUsings> |
||||
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0-preview.2.22153.2" /> |
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0-preview.2.22153.2" PrivateAssets="all" /> |
||||
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.2.22153.1" /> |
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="7.0.0-preview.2.22153.1" /> |
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-preview.2.22153.1" /> |
||||
<NativeFileReference Include="e_sqlite3.o" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Components\Components.csproj" /> |
||||
<ProjectReference Include="..\Contexts\Contexts.csproj" /> |
||||
<ProjectReference Include="..\Model\Model.csproj" /> |
||||
<ProjectReference Include="..\Services\Services.csproj" /> |
||||
</ItemGroup> |
||||
</Project> |
||||
@ -0,0 +1,55 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
# Visual Studio Version 17 |
||||
VisualStudioVersion = 17.0.32112.339 |
||||
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IGP", "IGP.csproj", "{172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}" |
||||
EndProject |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "..\Model\Model.csproj", "{77395F7A-BE93-470C-9F10-F48FFA445B63}" |
||||
EndProject |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components", "..\Components\Components.csproj", "{0419E7CD-0971-4A56-A61F-C090DF60FAF6}" |
||||
EndProject |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contexts", "..\Contexts\Contexts.csproj", "{F7775F3A-E541-4292-B45F-A18C65637E33}" |
||||
EndProject |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Services", "..\Services\Services.csproj", "{621178C8-4E8B-478E-80E5-7478F0E7B67E}" |
||||
EndProject |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IGP_Convert", "..\IGP_Convert\IGP_Convert.csproj", "{82F1848E-4BF6-4B16-A9DD-574AF566712B}" |
||||
EndProject |
||||
Global |
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
Debug|Any CPU = Debug|Any CPU |
||||
Release|Any CPU = Release|Any CPU |
||||
EndGlobalSection |
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
{172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
{77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
{0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
{F7775F3A-E541-4292-B45F-A18C65637E33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{F7775F3A-E541-4292-B45F-A18C65637E33}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{F7775F3A-E541-4292-B45F-A18C65637E33}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{F7775F3A-E541-4292-B45F-A18C65637E33}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
{621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
{82F1848E-4BF6-4B16-A9DD-574AF566712B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{82F1848E-4BF6-4B16-A9DD-574AF566712B}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{82F1848E-4BF6-4B16-A9DD-574AF566712B}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{82F1848E-4BF6-4B16-A9DD-574AF566712B}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
EndGlobalSection |
||||
GlobalSection(SolutionProperties) = preSolution |
||||
HideSolutionNode = FALSE |
||||
EndGlobalSection |
||||
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
SolutionGuid = {19100811-B909-4D20-9AE0-2EB579A55B3A} |
||||
EndGlobalSection |
||||
EndGlobal |
||||
@ -0,0 +1,6 @@
|
||||
@page "/" |
||||
|
||||
@layout PageLayout |
||||
|
||||
|
||||
<HomePage></HomePage> |
||||
@ -0,0 +1,51 @@
|
||||
@inherits LayoutComponentBase; |
||||
|
||||
@inject IWebsiteService WebService; |
||||
@implements IDisposable; |
||||
|
||||
@inject DatabaseContext Database; |
||||
<div class="layoutContainer" @onclick="OnPageClicked"> |
||||
@if (!WebService.IsLoaded()) { |
||||
<LoadingComponent></LoadingComponent> |
||||
} |
||||
else { |
||||
<div class="content"> |
||||
@Body |
||||
</div> |
||||
<DesktopNavComponent WebSections=WebService.WebSectionModels |
||||
WebPages=WebService.WebPageModels/> |
||||
<TabletNavComponent WebSections=WebService.WebSectionModels |
||||
WebPages=WebService.WebPageModels/> |
||||
<MobileNavComponent WebSections=WebService.WebSectionModels |
||||
WebPages=WebService.WebPageModels/> |
||||
} |
||||
</div> |
||||
|
||||
@code { |
||||
bool NavOpen = true; |
||||
|
||||
void OnNavClicked(EventArgs eventArgs) { |
||||
NavOpen = !NavOpen; |
||||
} |
||||
|
||||
void OnPageClicked(EventArgs eventArgs) { |
||||
NavOpen = false; |
||||
} |
||||
|
||||
protected override void OnInitialized() { |
||||
WebService.Subscribe(HasChanged); |
||||
} |
||||
|
||||
protected override async Task OnInitializedAsync() { |
||||
await WebService.Load(Database); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
WebService.Unsubscribe(HasChanged); |
||||
} |
||||
|
||||
void HasChanged() { |
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,26 @@
|
||||
.layoutContainer { |
||||
height: 100vh; |
||||
overflow-y: scroll; |
||||
overflow-x: hidden; |
||||
} |
||||
|
||||
.content { |
||||
margin-top: 32px; |
||||
margin-bottom: 256px; |
||||
display: flex; |
||||
min-width: 100%; |
||||
min-height: 100%; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
@media only screen and (max-width: 1025px) { |
||||
.content { |
||||
margin-top: 120px; |
||||
} |
||||
} |
||||
|
||||
@media only screen and (max-width: 480px) { |
||||
.content { |
||||
margin-top: 20px; |
||||
} |
||||
} |
||||
@ -0,0 +1,43 @@
|
||||
@layout PageLayout |
||||
|
||||
|
||||
@page "/about" |
||||
|
||||
<LayoutMediumContentComponent> |
||||
<WebsiteTitleComponent>About</WebsiteTitleComponent> |
||||
|
||||
<PaperComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is this website for? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
This is just a "yet another third-party tool" website for a video game. If you played a game like Path of Exile, you are probably already used to seeing a bunch of said tools. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
So what is <i>this</i> specific tool for? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Ideally, this website will be a casual reference, for getting started with understanding the themes and game patterns of IMMORTAL: Gates of Pyre. That said, this tool is currently not near to achieving said goal. In the meantime, you can check out the simple calculator and database tools on this website. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
The game hasn't even been released. Isn't it a bit early for publishing community tools? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Maybe 🙂 |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
Any disclaimers? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
This website has no association with "SunSpear Games." Beyond that, any game data displayed on this website for "IMMORTAL: Gates of Pyre" may be inaccurate due to my own human error and time limitations. Use with caution. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
</PaperComponent> |
||||
</LayoutMediumContentComponent> |
||||
@ -0,0 +1,172 @@
|
||||
@implements IDisposable; |
||||
@inject IAgileService AgileService; |
||||
@inject DatabaseContext Database; |
||||
|
||||
@layout PageLayout |
||||
|
||||
@page "/agile" |
||||
|
||||
@if (AgileService.IsLoaded()) { |
||||
<LayoutMediumContentComponent> |
||||
|
||||
<WebsiteTitleComponent>Agile</WebsiteTitleComponent> |
||||
|
||||
<div class="agileViewContainer"> |
||||
@foreach (var sprint in AgileService.SprintModels.OrderBy(e => e.EndDate).Reverse()) { |
||||
<details class="sprintDisplayContainer @sprint.GetSprintType().ToLower()" open="@(sprint.GetSprintType() == SprintType.Current)"> |
||||
<summary class="sprintSummary"> |
||||
<div class="sprintTitle">@sprint.Name</div> |
||||
<div style="flex: 1; flex-grow: 1;"></div> |
||||
<div class="sprintDates"> |
||||
<div class="sprintStartDate"> |
||||
<b>Start: </b>@sprint.StartDate.Value.ToString("dd/MM/yyyy") |
||||
</div> |
||||
<div class="sprintEndDate"> |
||||
<b>End: </b>@sprint.EndDate.Value.ToString("dd/MM/yyyy") |
||||
</div> |
||||
</div> |
||||
</summary> |
||||
<SprintComponent Sprint=sprint Tasks=AgileService.TaskModels></SprintComponent> |
||||
</details> |
||||
} |
||||
|
||||
<details class="sprintDisplayContainer"> |
||||
<summary class="sprintSummary"> |
||||
<div class="sprintTitle">Backlog</div> |
||||
<div style="flex: 1; flex-grow: 1;"></div> |
||||
</summary> |
||||
<div> |
||||
<BacklogComponent Backlog=backlog></BacklogComponent> |
||||
</div> |
||||
</details> |
||||
</div> |
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent>What is Agile?</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Agile is a work methodology for determing task assignment and release deadlines. |
||||
<br/><br/> |
||||
My agile practice will be creating tasks in a backlog. Assigning them to weekly sprints. And completing all tasks in the allotted time frame. |
||||
<br/><br/> |
||||
Any unfinished tasks are moved into the next sprint, or the sprint will be extended by a week. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
</LayoutMediumContentComponent> |
||||
} |
||||
else { |
||||
<LoadingComponent></LoadingComponent> |
||||
} |
||||
|
||||
|
||||
<style> |
||||
.agileViewContainer { |
||||
display: flex; |
||||
gap: 12px; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.sprintDisplayContainer { |
||||
border: 4px solid var(--paper); |
||||
box-shadow: 0px 2px 12px rgba(0,0,0,0.2); |
||||
border-radius: 2px; |
||||
padding: 25px; |
||||
margin: auto; |
||||
width: 100%; |
||||
background-color:var(--paper); |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.sprintDisplayContainer { |
||||
padding: 2px; |
||||
} |
||||
} |
||||
|
||||
.sprintSummary { |
||||
display: flex; |
||||
width: 100%; |
||||
} |
||||
|
||||
.sprintDisplayContainer.@SprintType.Current.ToLower() { |
||||
border-color: #042901; |
||||
background-color:var(--paper); |
||||
} |
||||
|
||||
.sprintDisplayContainer.@SprintType.Planned.ToLower() { |
||||
border-color: #2a2000; |
||||
background-color:var(--paper); |
||||
} |
||||
|
||||
.sprintDisplayContainer.@SprintType.Completed.ToLower() { |
||||
border-color: #2a2000; |
||||
background-color:var(--paper); |
||||
} |
||||
|
||||
|
||||
details .sprintSummary::before { |
||||
content: "+"; |
||||
font-weight: bolder; |
||||
font-size: 1.5rem; |
||||
padding-right: 8px; |
||||
} |
||||
|
||||
details[open] .sprintSummary::before { |
||||
content: "-"; |
||||
} |
||||
|
||||
|
||||
.sprintTitle { |
||||
width: 400px; |
||||
font-size: 1.6rem; |
||||
font-weight: 800; |
||||
} |
||||
|
||||
.sprintDates { |
||||
width: 160px; |
||||
text-align: right; |
||||
} |
||||
|
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public DbSet<SprintModel> Sprints { get; set; } |
||||
|
||||
[Parameter] |
||||
public DbSet<TaskModel> Tasks { get; set; } |
||||
|
||||
|
||||
private readonly List<TaskModel> backlog = new(); |
||||
|
||||
|
||||
protected override void OnInitialized() { |
||||
AgileService.Subscribe(HasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
AgileService.Unsubscribe(HasChanged); |
||||
} |
||||
|
||||
void HasChanged() { |
||||
Sprints = AgileService.SprintModels; |
||||
Tasks = AgileService.TaskModels; |
||||
|
||||
backlog.Clear(); |
||||
|
||||
foreach (var task in Tasks) { |
||||
if (task.SprintModelId == null) { |
||||
backlog.Add(task); |
||||
} |
||||
} |
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
protected override async Task OnInitializedAsync() { |
||||
await AgileService.Load(Database); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,202 @@
|
||||
<div class="sprintContainer"> |
||||
<div class="tasksContainer"> |
||||
@foreach (var task in Backlog) { |
||||
<div class="taskContainer @task.Status.ToLower()"> |
||||
<div class="taskName">@task.Name</div> |
||||
<div class="taskDetails"> |
||||
<LayoutRowComponent> |
||||
<LayoutColumnComponent> |
||||
<div class="taskType"> |
||||
<b>Type: </b>@task.Task.Replace("_", " ") |
||||
</div> |
||||
<div class="taskStatus"> |
||||
<b>Status: </b>@task.Status.Replace("_", " ") |
||||
</div> |
||||
<div class="taskPriority"> |
||||
<b>Priority: </b>@task.Priority |
||||
</div> |
||||
</LayoutColumnComponent> |
||||
<LayoutColumnComponent> |
||||
@if (task.Finished != null) { |
||||
<div class="taskFinished"> |
||||
<b>Finished: </b>@task.Finished |
||||
</div> |
||||
} |
||||
<div class="taskCreated"> |
||||
<b>Created: </b>@task.Created |
||||
</div> |
||||
</LayoutColumnComponent> |
||||
</LayoutRowComponent> |
||||
</div> |
||||
<div class="taskDescription"> |
||||
<b>Description: </b>@task.Description |
||||
</div> |
||||
<div class="taskNotes"> |
||||
<b>Notes: </b>@task.Notes |
||||
</div> |
||||
</div> |
||||
} |
||||
|
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
<style> |
||||
.sprintContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 12px; |
||||
padding-top: 16px; |
||||
} |
||||
|
||||
.sprintDescription { |
||||
grid-area: description; |
||||
} |
||||
|
||||
.sprintStartDate { |
||||
} |
||||
|
||||
.sprintEndDate { |
||||
} |
||||
|
||||
.sprintNotes { |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.sprintContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
border: none; |
||||
margin-top: 12px; |
||||
box-shadow: none; |
||||
padding: 8px; |
||||
} |
||||
|
||||
.sprintStartDate { |
||||
text-align: left; |
||||
} |
||||
|
||||
.sprintEndDate { |
||||
text-align: left; |
||||
} |
||||
} |
||||
|
||||
.tasksContainer { |
||||
grid-area: tasks; |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 20px; |
||||
padding: 25px; |
||||
align-items: stretch; |
||||
justify-content: stretch; |
||||
justify-items: stretch; |
||||
} |
||||
|
||||
.taskContainer { |
||||
padding: 25px; |
||||
border: 1px dashed rgba(0,0,0,0.6); |
||||
box-shadow: 0px 2px 6px rgba(0,0,0,0.1); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() { |
||||
border-color: #030129; |
||||
background-color: #2c3a4c; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() { |
||||
border-color: #2a2000; |
||||
background-color: #ffbf0029; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.To_Test.ToLower() { |
||||
border-color: #030129; |
||||
background-color: #2c3a4c; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() { |
||||
border-color: #290102; |
||||
background-color: #4C2C33; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() { |
||||
border-color: #042901; |
||||
background-color: #2E4C2C; |
||||
} |
||||
|
||||
|
||||
.taskName { |
||||
font-weight: bold; |
||||
grid-area: name; |
||||
} |
||||
|
||||
.taskCreated { |
||||
grid-area: created; |
||||
} |
||||
|
||||
.taskFinished { |
||||
grid-area: finished; |
||||
} |
||||
|
||||
.taskStatus { |
||||
grid-area: status; |
||||
} |
||||
|
||||
.taskDescription { |
||||
margin-top: 10px; |
||||
grid-area: description; |
||||
} |
||||
|
||||
.taskNotes { |
||||
grid-area: notes; |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.tasksContainer { |
||||
padding: 0px; |
||||
margin-top: 12px; |
||||
padding-top: 12px; |
||||
border-top: 4px solid rgba(0,0,0,0.4) |
||||
} |
||||
|
||||
.taskContainer { |
||||
padding: 2px; |
||||
border: none; |
||||
box-shadow: none; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
|
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public List<TaskModel> Backlog { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,238 @@
|
||||
<div class="sprintContainer"> |
||||
<div class="sprintStatus"> |
||||
<b>Status: </b>@Sprint.GetSprintType() |
||||
</div> |
||||
<div class="sprintDescription"> |
||||
<b>Description: </b>@Sprint.Description |
||||
</div> |
||||
<div class="sprintNotes"> |
||||
<b>Notes: </b>@Sprint.Notes |
||||
</div> |
||||
<div class="tasksContainer"> |
||||
@if (selectedTasks.Count > 0) { |
||||
@foreach (var task in selectedTasks) { |
||||
<div class="taskContainer @task.Status.ToLower() @task.Task.ToLower()"> |
||||
<div class="taskName">@task.Name</div> |
||||
<div class="taskDetails"> |
||||
<LayoutRowComponent> |
||||
<LayoutColumnComponent> |
||||
<div class="taskType"> |
||||
<b>Type: </b>@task.Task.Replace("_", " ") |
||||
</div> |
||||
<div class="taskStatus"> |
||||
<b>Status: </b>@task.Status.Replace("_", " ") |
||||
</div> |
||||
<div class="taskPriority"> |
||||
<b>Priority: </b>@task.Priority |
||||
</div> |
||||
|
||||
</LayoutColumnComponent> |
||||
<LayoutColumnComponent> |
||||
@if (task.Finished != null) { |
||||
<div class="taskFinished"> |
||||
<b>Finished: </b>@task.Finished.Value.ToString("dd/MM/yyyy") |
||||
</div> |
||||
} |
||||
<div class="taskCreated"> |
||||
<b>Created: </b>@task.Created.Value.ToString("dd/MM/yyyy") |
||||
</div> |
||||
</LayoutColumnComponent> |
||||
</LayoutRowComponent> |
||||
</div> |
||||
<div class="taskDescription"> |
||||
<b>Description: </b>@task.Description |
||||
</div> |
||||
<div class="taskNotes"> |
||||
<b>Notes: </b>@task.Notes |
||||
</div> |
||||
</div> |
||||
} |
||||
} |
||||
else { |
||||
<div>Add Tasks...</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
|
||||
<style> |
||||
.sprintContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 12px; |
||||
padding-top: 16px; |
||||
} |
||||
|
||||
.sprintDescription { |
||||
grid-area: description; |
||||
} |
||||
|
||||
.sprintStartDate { |
||||
} |
||||
|
||||
.sprintEndDate { |
||||
} |
||||
|
||||
.sprintNotes { |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.sprintContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 6px; |
||||
border: none; |
||||
margin-top: 12px; |
||||
box-shadow: none; |
||||
padding: 8px; |
||||
} |
||||
|
||||
.sprintStartDate { |
||||
text-align: left; |
||||
} |
||||
|
||||
.sprintEndDate { |
||||
text-align: left; |
||||
} |
||||
} |
||||
|
||||
.tasksContainer { |
||||
grid-area: tasks; |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 20px; |
||||
padding: 25px; |
||||
align-items: stretch; |
||||
justify-content: stretch; |
||||
justify-items: stretch; |
||||
} |
||||
|
||||
.taskContainer { |
||||
padding: 25px; |
||||
border: 1px dashed rgba(0,0,0,0.6); |
||||
box-shadow: 0px 2px 6px rgba(0,0,0,0.1); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() { |
||||
border-color: #030129; |
||||
background-color: #2c3a4c; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() { |
||||
border-color: #2a2000; |
||||
background-color: #ffbf0029; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.To_Test.ToLower() { |
||||
border-color: #030129; |
||||
background-color: #2c3a4c; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() { |
||||
border-color: #290102; |
||||
background-color: #4C2C33; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() { |
||||
border-color: #042901; |
||||
background-color: #2E4C2C; |
||||
} |
||||
|
||||
|
||||
.taskContainer.@TaskType.Bug.ToLower() { |
||||
border-style: dotted; |
||||
border-width: 8px; |
||||
} |
||||
|
||||
|
||||
.taskName { |
||||
font-weight: bold; |
||||
grid-area: name; |
||||
font-size: 1.2rem; |
||||
} |
||||
|
||||
.taskDetails { |
||||
font-size: 0.8rem; |
||||
} |
||||
|
||||
.taskCreated { |
||||
grid-area: created; |
||||
} |
||||
|
||||
.taskFinished { |
||||
grid-area: finished; |
||||
} |
||||
|
||||
.taskStatus { |
||||
grid-area: status; |
||||
} |
||||
|
||||
.taskDescription { |
||||
margin-top: 10px; |
||||
grid-area: description; |
||||
} |
||||
|
||||
.taskNotes { |
||||
grid-area: notes; |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.tasksContainer { |
||||
padding: 0px; |
||||
margin-top: 12px; |
||||
padding-top: 12px; |
||||
border-top: 4px solid rgba(0,0,0,0.4) |
||||
} |
||||
|
||||
.taskContainer { |
||||
padding: 2px; |
||||
border: none; |
||||
box-shadow: none; |
||||
} |
||||
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() { |
||||
border-color: transparent; |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
|
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public SprintModel Sprint { get; set; } |
||||
|
||||
[Parameter] |
||||
public DbSet<TaskModel> Tasks { get; set; } |
||||
|
||||
private List<TaskModel> selectedTasks { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
selectedTasks = (from task in Tasks |
||||
where task.SprintModelId == Sprint.Id |
||||
select task).OrderBy(x => x.Created).OrderBy(x => x.Finished).Reverse().OrderBy(x => x.Status).ToList(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,288 @@
|
||||
@implements IDisposable |
||||
|
||||
@layout PageLayout |
||||
|
||||
@page "/build-calculator" |
||||
|
||||
<LayoutLargeContentComponent> |
||||
<WebsiteTitleComponent>Build Calculator</WebsiteTitleComponent> |
||||
|
||||
<AlertComponent Type="SeverityType.Warning"> |
||||
<Title>Work In Progress and Not Fully Tested</Title> |
||||
<Message> |
||||
Currently not considering training queue times. Lacking error toasts for invalid actions. Performance needs to be optimized. Calculations haven't been thoroughly compared against real gameplay. Added a 2 second delay to actions to account for casual micro (will probably tweak later). |
||||
</Message> |
||||
</AlertComponent> |
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
|
||||
<div class="calculatorGrid"> |
||||
|
||||
<div style="grid-area: timing;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Enter build details. |
||||
|
||||
<b>Timing Interval:</b> set the max interval length for the build. <i>Ex. 240 (seconds) is 4 minutes, a possible timing for Thrum build order.</i> |
||||
<b>Name:</b> the name of the build for saving purposes. <i>Ex. 'Safe Thrum Opener'</i> |
||||
<b>Notes:</b> additional notes of the build for saving purposes. <i>Ex. 'Thrums are for harassing and defending against a ground Q'Rath army.'</i> |
||||
<b>Color:</b> value to color charts when comparing builds. Not currently implemented."> |
||||
|
||||
<TimingComponent></TimingComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
|
||||
@if (true) { |
||||
<div style="grid-area: chart;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Shows economy at each game interval. Use to determine if spending additional resourcses on harvesters will help or hinder overall timing attack."> |
||||
<ChartComponent></ChartComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
} |
||||
|
||||
<div style="grid-area: filter;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Select build details, such as Faction and Immortal. Affects entities you can build."> |
||||
<FilterComponent></FilterComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
|
||||
<div style="grid-area: view;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Summary of the entity you just selected."> |
||||
<EntityClickViewComponent></EntityClickViewComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
|
||||
<div style="grid-area: bank;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Bank at time of last requested action. Use this section to determine if your build is floating too much alloy or ether."> |
||||
<BankComponent></BankComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
|
||||
<div style="grid-area: army;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Overview of current army, and when it will be ready to begin an attack."> |
||||
<ArmyComponent></ArmyComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
|
||||
<div class="gridItem gridKeys"> |
||||
|
||||
<InfoTooltipComponent InfoText="Click on the desired entity to build it. <i>You cannot build entities you cannot afford, construct an ether extractor before spending ether.</i> |
||||
|
||||
You can also use the default Immortal hotkeys, but the above hotkey UI must have focus for this to work. <i>I.e. click on it if hotkeys aren't working, and a white border should appear after key input to indicate focus.</i> |
||||
|
||||
Additionally, more entities will appear as you build the required technology. You can click or press ` to remove the last made entity. <i>But you cannot remove the starting entities at interval 0.</i>"> |
||||
|
||||
<HotkeyViewerComponent Size="80"></HotkeyViewerComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
|
||||
@if (false) { |
||||
<div style="grid-area: timeline;" class="gridItem"> |
||||
<TimelineComponent></TimelineComponent> |
||||
</div> |
||||
} |
||||
|
||||
<div style="grid-area: highlights;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Timeline highlights of your build order. Shows when you start a new action and when the action is done."> |
||||
<HighlightsComponent></HighlightsComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
|
||||
<div style="grid-area: buildorder;" class="gridItem"> |
||||
<InfoTooltipComponent InfoText="Some raw JSON data to represent your build order."> |
||||
<BuildOrderComponent></BuildOrderComponent> |
||||
</InfoTooltipComponent> |
||||
</div> |
||||
</div> |
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
<PaperComponent> |
||||
<FormLayoutComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is this tool? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
This is a calculator to determine build timings. Mostly so someone can quickly try out a few build orders to see if they somewhat make sense. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
How does it work? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
The tool calculates every second of game time. So if you attempt to build a <b>Legion Hall</b> as your first action, the tool will scan every second, until you get to one where the request can be made. In this case, that is interval 58. |
||||
<br/> |
||||
<br/> |
||||
If you then build 2 <b>Apostle of Bindings</b> a <b>Soul Foundry</b> and a 3 <b>Absolvers</b> you should see yourself roughly floating 500 alloy, with barely having any ether. Which means you could of gotten an <b>Acropolis</b> and a <b>Zentari</b> without hurting your build. |
||||
<br/> |
||||
<br/> |
||||
Try building <b>Apostle of Bindings</b> before the <b>Legion Hall</b> and see how that changes the timing of your 3 <b>Absolvers</b>. (Spoiler: <SpoilerTextComponent> your <b>Absolvers</b> will be built much faster, and you won't be floating so much alloy.</SpoilerTextComponent>) |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is CONTROl key for? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Economy and tech related upgrades for townhalls. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is SHIFT key for? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Misc building related upgrades. (Omnivores) |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is 2 key for? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
It will be for Pyre camps. Currently not implemented. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
</FormLayoutComponent> |
||||
</PaperComponent> |
||||
</LayoutLargeContentComponent> |
||||
|
||||
|
||||
<style> |
||||
.calculatorGrid { |
||||
display: grid; |
||||
gap: 8px; |
||||
max-width: 90vw; |
||||
grid-template-columns: 1fr 1fr 1fr 1fr; |
||||
grid-template-rows: 600px 400px 450px; |
||||
grid-template-areas: |
||||
'timing view view view' |
||||
'filter bank army army' |
||||
'keys keys highlights buildorder' |
||||
'chart chart chart chart'; |
||||
} |
||||
|
||||
.gridItem { |
||||
border: 2px solid var(--paper-border); |
||||
padding: 20px; |
||||
background-color: var(--paper); |
||||
} |
||||
|
||||
.gridKeys { |
||||
grid-area: keys; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.gridKeys { |
||||
background-color: #282A30; |
||||
} |
||||
|
||||
.calculatorGrid { |
||||
grid-template-columns: 1fr; |
||||
grid-template-rows: auto; |
||||
grid-template-areas: |
||||
'timing' |
||||
'view' |
||||
'filter' |
||||
'keys' |
||||
'bank' |
||||
'army' |
||||
'highlights' |
||||
'buildorder' |
||||
'chart'; |
||||
padding-left: 2px; |
||||
padding-right: 2px; |
||||
} |
||||
|
||||
|
||||
.gridItem { |
||||
padding: 0px; |
||||
border: 0px; |
||||
width: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IKeyService KeyService { get; set; } |
||||
|
||||
[Inject] |
||||
IImmortalSelectionService FilterService { get; set; } |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
[Inject] |
||||
IEconomyService EconomyService { get; set; } |
||||
|
||||
[Inject] |
||||
ITimingService TimingService { get; set; } |
||||
|
||||
Dictionary<int, List<EntityModel>> completedEntities = new(); |
||||
|
||||
List<EntityModel> entities = EntityModel.GetListOnlyHotkey(); |
||||
|
||||
protected override void OnInitialized() { |
||||
KeyService.Subscribe(HandleClick); |
||||
FilterService.Subscribe(StateHasChanged); |
||||
EconomyService.Subscribe(StateHasChanged); |
||||
TimingService.Subscribe(HandleTimingChanged); |
||||
EconomyService.Calculate(BuildOrderService, TimingService, 0); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
KeyService.Unsubscribe(HandleClick); |
||||
FilterService.Unsubscribe(StateHasChanged); |
||||
TimingService.Unsubscribe(StateHasChanged); |
||||
EconomyService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
|
||||
protected void HandleTimingChanged() { |
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); |
||||
} |
||||
|
||||
protected void HandleClick() { |
||||
var hotkey = KeyService.GetHotkey(); |
||||
|
||||
if (hotkey == "") { |
||||
return; |
||||
} |
||||
|
||||
if (hotkey == "`") { |
||||
BuildOrderService.RemoveLast(); |
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); |
||||
StateHasChanged(); |
||||
return; |
||||
} |
||||
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup(); |
||||
var isHoldSpace = KeyService.IsHoldingSpace(); |
||||
var faction = FilterService.GetFactionType(); |
||||
var immortal = FilterService.GetImmortalType(); |
||||
|
||||
var entity = EntityModel.GetFrom(hotkey, hotkeyGroup, isHoldSpace, faction, immortal); |
||||
|
||||
if (entity == null) { |
||||
return; |
||||
} |
||||
if (BuildOrderService.Add(entity, EconomyService)) { |
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
|
||||
@implements IDisposable |
||||
|
||||
<FormLayoutComponent> |
||||
<FormDisplayComponent Label="Army ready at"> |
||||
<Display>@LastInterval | T @Interval.ToTime(LastInterval)</Display> |
||||
</FormDisplayComponent> |
||||
<FormDisplayComponent Label="Army units built"> |
||||
<Display> |
||||
<div style="display: flex; width: 100%; gap: 12px; flex-wrap: wrap;"> |
||||
@foreach (var unit in armyCount) { |
||||
<div style="width:90px; height: 60px; border: 1px solid gray; padding: 8px;"> |
||||
<div>@unit.Value.ToString()x</div> |
||||
<div>@unit.Key</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</Display> |
||||
</FormDisplayComponent> |
||||
|
||||
</FormLayoutComponent> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
public IBuildOrderService BuildOrder { get; set; } |
||||
|
||||
int LastInterval; |
||||
|
||||
readonly Dictionary<string, int> armyCount = new(); |
||||
|
||||
List<EntityModel> army = new(); |
||||
|
||||
protected override void OnInitialized() { |
||||
BuildOrder.Subscribe(OnBuildOrderChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
BuildOrder.Unsubscribe(OnBuildOrderChanged); |
||||
} |
||||
|
||||
void OnBuildOrderChanged() { |
||||
armyCount.Clear(); |
||||
|
||||
LastInterval = 0; |
||||
|
||||
var entitiesOverTime = BuildOrder.GetOrders(); |
||||
|
||||
foreach (var entitiesAtTime in entitiesOverTime) { |
||||
foreach (var entity in entitiesAtTime.Value) { |
||||
if (entity.EntityType == EntityType.Army) { |
||||
if (!armyCount.TryAdd(entity.Info().Name, 1)) { |
||||
armyCount[entity.Info().Name]++; |
||||
} |
||||
|
||||
if (entity.Production() != null && entity.Production().BuildTime + entitiesAtTime.Key > LastInterval) { |
||||
LastInterval = entity.Production().BuildTime + entitiesAtTime.Key; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,73 @@
|
||||
@implements IDisposable |
||||
|
||||
<FormLayoutComponent> |
||||
<FormDisplayComponent Label="Time"> |
||||
<Display>@BuildOrderService.GetLastRequestInterval() | T @Interval.ToTime(BuildOrderService.GetLastRequestInterval())</Display> |
||||
</FormDisplayComponent> |
||||
<FormDisplayComponent Label="Alloy"> |
||||
<Display>@economy.Alloy</Display> |
||||
</FormDisplayComponent> |
||||
<FormDisplayComponent Label="Ether"> |
||||
<Display>@economy.Ether</Display> |
||||
</FormDisplayComponent> |
||||
<DevOnlyComponent> |
||||
<FormDisplayComponent Label="Pyre"> |
||||
<Display>@economy.Pyre</Display> |
||||
</FormDisplayComponent> |
||||
</DevOnlyComponent> |
||||
<FormDisplayComponent Label="Supply"> |
||||
<Display>@supplyTaken / @supplyGranted (@(supplyGranted / 16)@(extraBuildings > 0 ? "+" + extraBuildings : ""))</Display> |
||||
</FormDisplayComponent> |
||||
</FormLayoutComponent> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
[Inject] |
||||
IEconomyService EconomyService { get; set; } |
||||
|
||||
EconomyModel economy = new(); |
||||
int supplyGranted; |
||||
int supplyTaken; |
||||
int extraBuildings; |
||||
|
||||
protected override void OnInitialized() { |
||||
BuildOrderService.Subscribe(OnBuildOrderChanged); |
||||
EconomyService.Subscribe(OnBuildOrderChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
BuildOrderService.Unsubscribe(OnBuildOrderChanged); |
||||
EconomyService.Subscribe(OnBuildOrderChanged); |
||||
} |
||||
|
||||
void OnBuildOrderChanged() { |
||||
economy = EconomyService.GetEconomy(BuildOrderService.GetLastRequestInterval()); |
||||
|
||||
var ordersOverTime = BuildOrderService.GetOrders(); |
||||
|
||||
supplyTaken = (from ordersAtInterval in ordersOverTime |
||||
from order in ordersAtInterval.Value |
||||
where order.Supply() != null |
||||
where order.Supply().Takes > 0 |
||||
select order.Supply().Takes).Sum(); |
||||
|
||||
supplyGranted = (from ordersAtInterval in ordersOverTime |
||||
from order in ordersAtInterval.Value |
||||
where order.Supply() != null |
||||
where order.Supply().Grants > 0 |
||||
select order.Supply().Grants).Sum(); |
||||
|
||||
extraBuildings = 0; |
||||
if (supplyGranted > 160) { |
||||
extraBuildings = (supplyGranted - 160) / 16; |
||||
supplyGranted = 160; |
||||
} |
||||
|
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@
|
||||
@implements IDisposable |
||||
|
||||
<FormLayoutComponent> |
||||
<FormTextAreaComponent Label="JSON Data" |
||||
Rows="14" |
||||
Value="@BuildOrderService.AsJson()"> |
||||
</FormTextAreaComponent> |
||||
</FormLayoutComponent> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
BuildOrderService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
BuildOrderService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,243 @@
|
||||
@implements IDisposable |
||||
|
||||
<div class="chartsContainer"> |
||||
@foreach (var chart in charts) { |
||||
<div style="width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px"> |
||||
<div style="position: relative; border: 2px solid gray; border-radius:2px; width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px"> |
||||
@foreach (var point in chart.Points) { |
||||
<div style="position: absolute; |
||||
bottom:@point.GetValue(chart.HighestValuePoint, chart.ValueDisplayMax)px; |
||||
left:@point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax)px; |
||||
width: 0px; |
||||
height: 0px;"> |
||||
<div style="width:1px; height: 1px; border-top-right-radius:10px; border-top-left-radius:10px; border: 2px solid @chart.ChartColor; background-color:@chart.ChartColor"> |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
<style> |
||||
.chartsContainer { |
||||
position: relative; |
||||
display: flex; |
||||
gap: 20px; |
||||
flex-wrap: wrap; |
||||
justify-content: center; |
||||
margin-bottom: 20px; |
||||
} |
||||
</style> |
||||
|
||||
<FormLayoutComponent> |
||||
<FormDisplayComponent Label="Highest Alloy"> |
||||
<Display>@highestAlloyPoint</Display> |
||||
</FormDisplayComponent> |
||||
<FormDisplayComponent Label="Highest Ether"> |
||||
<Display>@highestEtherPoint</Display> |
||||
</FormDisplayComponent> |
||||
<DevOnlyComponent> |
||||
<FormDisplayComponent Label="Highest Pyre"> |
||||
<Display>@highestEtherPoint</Display> |
||||
</FormDisplayComponent> |
||||
</DevOnlyComponent> |
||||
<FormDisplayComponent Label="Highest Army"> |
||||
<Display>@highestArmyPoint</Display> |
||||
</FormDisplayComponent> |
||||
</FormLayoutComponent> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IEconomyService EconomyService { get; set; } |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
|
||||
int height = 100; |
||||
readonly int width = 250; |
||||
|
||||
List<int> valueList = new(); |
||||
|
||||
readonly List<ChartModel> charts = new(); |
||||
|
||||
|
||||
float highestAlloyPoint; |
||||
float highestEtherPoint; |
||||
float highestPyrePoint; |
||||
float highestArmyPoint; |
||||
|
||||
protected override void OnInitialized() { |
||||
EconomyService.Subscribe(GenerateChart); |
||||
BuildOrderService.Subscribe(GenerateChart); |
||||
|
||||
GenerateChart(); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
EconomyService.Unsubscribe(GenerateChart); |
||||
BuildOrderService.Unsubscribe(GenerateChart); |
||||
} |
||||
|
||||
void GenerateChart() { |
||||
var economyOverTime = EconomyService.GetOverTime(); |
||||
|
||||
charts.Clear(); |
||||
|
||||
var alloyChart = new ChartModel { |
||||
IntervalDisplayMax = width, |
||||
ValueDisplayMax = 100, |
||||
ChartColor = "Cyan" |
||||
}; |
||||
var etherChart = new ChartModel { |
||||
Offset = width, |
||||
IntervalDisplayMax = width, |
||||
ValueDisplayMax = 100, |
||||
ChartColor = "LightGreen" |
||||
}; |
||||
|
||||
var pyreChart = new ChartModel { |
||||
Offset = width * 2, |
||||
IntervalDisplayMax = width, |
||||
ValueDisplayMax = 100, |
||||
ChartColor = "Red" |
||||
}; |
||||
|
||||
var armyChart = new ChartModel { |
||||
Offset = width * 3, |
||||
IntervalDisplayMax = width, |
||||
ValueDisplayMax = 100, |
||||
ChartColor = "White" |
||||
}; |
||||
|
||||
highestAlloyPoint = 0; |
||||
highestEtherPoint = 0; |
||||
highestPyrePoint = 0; |
||||
highestArmyPoint = 0; |
||||
|
||||
for (var interval = 0; interval < economyOverTime.Count(); interval++) { |
||||
var army = from unit in BuildOrderService.GetCompletedBefore(interval) |
||||
where unit.EntityType == EntityType.Army |
||||
select unit; |
||||
|
||||
var armyValue = 0; |
||||
foreach (var unit in army) { |
||||
armyValue += unit.Production().Alloy + unit.Production().Ether; |
||||
} |
||||
|
||||
|
||||
highestArmyPoint = Math.Max(highestArmyPoint, armyValue); |
||||
|
||||
armyChart.Points.Add(new PointModel { Interval = interval, Value = armyValue }); |
||||
} |
||||
|
||||
|
||||
for (var interval = 0; interval < economyOverTime.Count(); interval++) { |
||||
var alloyPoint = new PointModel { Interval = interval }; |
||||
var etherPoint = new PointModel { Interval = interval }; |
||||
var pyrePoint = new PointModel { Interval = interval }; |
||||
|
||||
var economyAtSecond = economyOverTime[interval]; |
||||
|
||||
var alloyWorkerHarvesters = from harvester in economyAtSecond.Harvesters |
||||
where harvester.Harvest() != null |
||||
where harvester.Harvest().RequiresWorker |
||||
where harvester.Harvest().Resource == ResourceType.Alloy |
||||
select harvester; |
||||
|
||||
var alloyAutomaticHarvesters = from harvester in economyAtSecond.Harvesters |
||||
where harvester.Harvest() != null |
||||
where harvester.Harvest().RequiresWorker == false |
||||
where harvester.Harvest().Resource == ResourceType.Alloy |
||||
select harvester; |
||||
|
||||
var etherAutomaticHarvesters = from harvester in economyAtSecond.Harvesters |
||||
where harvester.Harvest() != null |
||||
where harvester.Harvest().RequiresWorker == false |
||||
where harvester.Harvest().Resource == ResourceType.Ether |
||||
select harvester; |
||||
|
||||
float autoAlloy = 0; |
||||
float workerSlots = 0; |
||||
float workerAlloy = 0; |
||||
float autoEther = 0; |
||||
|
||||
float economySpending = 0; |
||||
|
||||
foreach (var alloyAutoHarvester in alloyAutomaticHarvesters) { |
||||
autoAlloy += alloyAutoHarvester.Harvest().Slots * alloyAutoHarvester.Harvest().HarvestedPerInterval; |
||||
var production = alloyAutoHarvester.Production(); |
||||
if (production != null) { |
||||
economySpending += production.Alloy; |
||||
} |
||||
} |
||||
|
||||
foreach (var alloyWorkerHarvester in alloyWorkerHarvesters) { |
||||
workerSlots += alloyWorkerHarvester.Harvest().Slots; |
||||
var production = alloyWorkerHarvester.Production(); |
||||
if (production != null) { |
||||
economySpending += production.Alloy; |
||||
} |
||||
} |
||||
|
||||
foreach (var etherWorkerHarvester in etherAutomaticHarvesters) { |
||||
autoEther += etherWorkerHarvester.Harvest().Slots * etherWorkerHarvester.Harvest().HarvestedPerInterval; |
||||
var production = etherWorkerHarvester.Production(); |
||||
if (production != null) { |
||||
economySpending += production.Alloy; |
||||
} |
||||
} |
||||
|
||||
economySpending += (economyAtSecond.WorkerCount - 6) * 50; |
||||
|
||||
workerAlloy = Math.Min(economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount, workerSlots); |
||||
|
||||
|
||||
alloyPoint.TempValue = workerAlloy + autoAlloy; |
||||
etherPoint.Value = autoEther; |
||||
|
||||
|
||||
if (interval > 0) { |
||||
alloyPoint.TempValue += alloyChart.Points.Last().TempValue; |
||||
etherPoint.Value += etherChart.Points.Last().Value; |
||||
pyrePoint.Value = pyreChart.Points.Last().Value + 1; |
||||
} |
||||
|
||||
alloyPoint.Value = alloyPoint.TempValue - economySpending; |
||||
|
||||
highestAlloyPoint = Math.Max(highestAlloyPoint, alloyPoint.Value); |
||||
highestEtherPoint = Math.Max(highestEtherPoint, etherPoint.Value); |
||||
|
||||
alloyChart.Points.Add(alloyPoint); |
||||
etherChart.Points.Add(etherPoint); |
||||
pyreChart.Points.Add(pyrePoint); |
||||
} |
||||
|
||||
alloyChart.HighestValuePoint = (int)Math.Max(highestAlloyPoint, 5000.0f); |
||||
etherChart.HighestValuePoint = (int)Math.Max(highestEtherPoint, 2000.0f); |
||||
pyreChart.HighestValuePoint = (int)Math.Max(highestPyrePoint, 2000.0f); |
||||
|
||||
alloyChart.HighestIntervalPoint = economyOverTime.Count(); |
||||
etherChart.HighestIntervalPoint = economyOverTime.Count(); |
||||
pyreChart.HighestIntervalPoint = economyOverTime.Count(); |
||||
|
||||
armyChart.HighestValuePoint = (int)Math.Max(highestArmyPoint, 2000.0f); |
||||
armyChart.HighestIntervalPoint = economyOverTime.Count(); |
||||
|
||||
|
||||
charts.Add(alloyChart); |
||||
charts.Add(etherChart); |
||||
|
||||
|
||||
//TODO WIP |
||||
//charts.Add(pyreChart); |
||||
|
||||
charts.Add(armyChart); |
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,51 @@
|
||||
@implements IDisposable |
||||
|
||||
<div style="overflow-y: scroll; width: 100%; overflow-x: hidden; height: 550px;"> |
||||
@if (Entity != null) { |
||||
<EntityViewComponent Entity=Entity></EntityViewComponent> |
||||
} |
||||
</div> |
||||
|
||||
@code { |
||||
EntityModel Entity; |
||||
|
||||
[Inject] |
||||
IKeyService KeyService { get; set; } |
||||
|
||||
[Inject] |
||||
IImmortalSelectionService FilterService { get; set; } |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
KeyService.Subscribe(HandleClick); |
||||
BuildOrderService.Subscribe(OnBuildOrderChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
KeyService.Unsubscribe(HandleClick); |
||||
BuildOrderService.Unsubscribe(OnBuildOrderChanged); |
||||
} |
||||
|
||||
|
||||
protected void HandleClick() { |
||||
var hotkey = KeyService.GetHotkey(); |
||||
var hotkeyGroup = KeyService.GetHotkeyGroup(); |
||||
var isHoldSpace = KeyService.IsHoldingSpace(); |
||||
var faction = FilterService.GetFactionType(); |
||||
var immortal = FilterService.GetImmortalType(); |
||||
|
||||
var foundEntity = EntityModel.GetFrom(hotkey, hotkeyGroup, isHoldSpace, faction, immortal); |
||||
|
||||
if (foundEntity != null) { |
||||
Entity = foundEntity; |
||||
StateHasChanged(); |
||||
} |
||||
} |
||||
|
||||
void OnBuildOrderChanged() { |
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,38 @@
|
||||
<FormLayoutComponent> |
||||
<FormSelectComponent OnChange="@OnFactionChanged"> |
||||
<FormLabelComponent>Faction</FormLabelComponent> |
||||
<ChildContent> |
||||
<option value="@FactionType.Aru">Aru</option> |
||||
<option value="@FactionType.QRath" selected>Q'Rath</option> |
||||
</ChildContent> |
||||
</FormSelectComponent> |
||||
|
||||
<FormSelectComponent OnChange="@OnImmortalChanged"> |
||||
<FormLabelComponent>Immortal</FormLabelComponent> |
||||
<ChildContent> |
||||
@if (FilterService.GetFactionType() == FactionType.QRath) { |
||||
<option value="@ImmortalType.Orzum" selected>Orzum</option> |
||||
<option value="@ImmortalType.Ajari">Ajari</option> |
||||
} |
||||
@if (FilterService.GetFactionType() == FactionType.Aru) { |
||||
<option value="@ImmortalType.Mala" selected>Mala</option> |
||||
<option value="@ImmortalType.Xol">Xol</option> |
||||
} |
||||
</ChildContent> |
||||
</FormSelectComponent> |
||||
</FormLayoutComponent> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
public IImmortalSelectionService FilterService { get; set; } |
||||
|
||||
void OnFactionChanged(ChangeEventArgs e) { |
||||
FilterService.SelectFactionType(e.Value.ToString()); |
||||
} |
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e) { |
||||
FilterService.SelectImmortalType(e.Value.ToString()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,75 @@
|
||||
@implements IDisposable |
||||
|
||||
<div class="highlightsContainer"> |
||||
<div> |
||||
<div>Requested</div> |
||||
|
||||
@for (var i = TimingService.GetTiming() - 1; i >= 0; i--) { |
||||
@foreach (var order in BuildOrderService.GetOrdersAt(i)) { |
||||
if (order.EntityType == EntityType.Worker) { |
||||
continue; |
||||
} |
||||
<div> |
||||
@i | T @Interval.ToTime(i) |
||||
</div> |
||||
<div> |
||||
@order.Info().Name |
||||
</div> |
||||
<br/> |
||||
} |
||||
} |
||||
</div> |
||||
<div> |
||||
<div>Finished</div> |
||||
|
||||
@for (var i = TimingService.GetTiming() - 1; i >= 0; i--) { |
||||
@foreach (var order in BuildOrderService.GetCompletedAt(i)) { |
||||
if (order.EntityType == EntityType.Worker) { |
||||
continue; |
||||
} |
||||
<div> |
||||
@i | T @Interval.ToTime(i) |
||||
</div> |
||||
<div> |
||||
@order.Info().Name |
||||
</div> |
||||
<br/> |
||||
} |
||||
} |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<style> |
||||
.highlightsContainer { |
||||
overflow-y: scroll; |
||||
overflow-x: hidden; |
||||
height: 400px; |
||||
display: grid; |
||||
grid-template-columns: 1fr 1fr; |
||||
gap: 4px; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IEconomyService EconomyService { get; set; } |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
[Inject] |
||||
ITimingService TimingService { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
EconomyService.Subscribe(StateHasChanged); |
||||
BuildOrderService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
EconomyService.Unsubscribe(StateHasChanged); |
||||
BuildOrderService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,229 @@
|
||||
@implements IDisposable |
||||
|
||||
<InputPanelComponent> |
||||
<div class="keyContainer"> |
||||
@foreach (var hotkey in hotkeys) { |
||||
if (hotkey.IsHidden) { |
||||
continue; |
||||
} |
||||
|
||||
var color = hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace() || KeyService.GetAllPressedKeys().Contains(hotkey.KeyText) |
||||
? "#0a0f12" : hotkey.GetColor(); |
||||
|
||||
var x = hotkey.PositionX * Size; |
||||
var y = hotkey.PositionY * Size; |
||||
|
||||
var border = "1px solid black"; |
||||
if (hotkey.KeyText.Equals(_key)) { |
||||
border = "5px solid black"; |
||||
} |
||||
if (hotkey.KeyText.Equals(_controlGroup)) { |
||||
border = "5px solid green"; |
||||
} |
||||
|
||||
if (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace()) { |
||||
border = "5px solid green"; |
||||
} |
||||
|
||||
<div style="position:relative; |
||||
cursor:pointer; |
||||
top:@y.ToString()px; |
||||
left:@x.ToString()px; |
||||
width: 0px; |
||||
height: 0px;"> |
||||
|
||||
<div @onclick="x => { if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString())) { if (KeyService.IsHoldingSpace()) { KeyService.RemovePressedKey(hotkey.KeyText); } else { KeyService.AddPressedKey(hotkey.KeyText); } } else { KeyService.AddPressedKey(hotkey.KeyText); KeyService.RemovePressedKey(hotkey.KeyText); }}" style="background-color:@color; |
||||
border: @border; |
||||
width: @Size.ToString()px; |
||||
height: @Size.ToString()px; |
||||
overflow: hidden; |
||||
padding: 4px;"> |
||||
@hotkey.KeyText |
||||
@foreach (var entity in data.Values) { |
||||
if (!BuildOrderService.MeetsRequirements(entity, 9000)) { |
||||
continue; |
||||
} |
||||
|
||||
if (InvalidKey(entity, hotkey) || InvalidKeyGroup(entity, hotkey) || InvalidHoldSpace(entity)) { |
||||
continue; |
||||
} |
||||
|
||||
if (InvalidFaction(entity) || InvalidVanguard(entity) || InvalidNonVanguard(entity)) { |
||||
continue; |
||||
} |
||||
|
||||
var isVanguard = entity.Vanguard() != null; |
||||
var style = isVanguard ? "font-weight: bold;" : ""; |
||||
|
||||
<div style="@style">@entity.Info()?.Name</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</InputPanelComponent> |
||||
|
||||
<style> |
||||
.keyContainer { |
||||
width: 400px; |
||||
max-width: 95vw; |
||||
height: 400px; |
||||
outline: 3px solid black; |
||||
border-radius: 8px; |
||||
background-color: #282A30; |
||||
margin: auto; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.keyContainer { |
||||
transform: scale(0.85) translateX(-20px); |
||||
background-color: none; |
||||
outline: none; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public int Size { get; set; } = 100; |
||||
|
||||
[Inject] |
||||
public IKeyService KeyService { get; set; } |
||||
|
||||
[Inject] |
||||
public IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
[Inject] |
||||
public IImmortalSelectionService FilterService { get; set; } |
||||
|
||||
readonly Dictionary<string, EntityModel> data = EntityModel.GetDictionary(); |
||||
readonly List<HotkeyModel> hotkeys = HotkeyModel.GetAll(); |
||||
|
||||
public string _controlGroup = "C"; |
||||
public string _key = ""; |
||||
|
||||
protected override void OnInitialized() { |
||||
base.OnInitialized(); |
||||
|
||||
KeyService.Subscribe(OnKeyPressed); |
||||
FilterService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
KeyService.Unsubscribe(OnKeyPressed); |
||||
FilterService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
// Move to Filter Service |
||||
bool InvalidFaction(EntityModel entity) { |
||||
if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFactionType() && FilterService.GetFactionType() != FactionType.Any) { |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// Move to Filter Service |
||||
bool InvalidVanguard(EntityModel entity) { |
||||
if (entity.Vanguard() != null && entity.Vanguard()?.Immortal != FilterService.GetImmortalType() && FilterService.GetImmortalType() != ImmortalType.Any) { |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// Move to Filter Service |
||||
bool InvalidNonVanguard(EntityModel entity) { |
||||
if (entity.Replaceds().Count > 0) { |
||||
var isReplaced = false; |
||||
foreach (var replaced in entity.Replaceds()) { |
||||
if (FilterService.GetImmortalType() == replaced.Immortal) { |
||||
isReplaced = true; |
||||
break; |
||||
} |
||||
} |
||||
if (isReplaced) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool InvalidRequirements(EntityModel entity) { |
||||
return !BuildOrderService.MeetsRequirements(entity, 9000); |
||||
} |
||||
|
||||
bool InvalidKey(EntityModel entity, HotkeyModel key) { |
||||
if (entity.Hotkey()?.Hotkey == key.KeyText) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool InvalidKeyGroup(EntityModel entity, HotkeyModel key) { |
||||
if (entity.Hotkey()?.HotkeyGroup == _controlGroup) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool InvalidKey(EntityModel entity) { |
||||
if (entity.Hotkey()?.Hotkey == _key) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool InvalidKeyGroup(EntityModel entity) { |
||||
if (entity.Hotkey()?.HotkeyGroup == _controlGroup) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool InvalidHoldSpace(EntityModel entity) { |
||||
if (entity.Hotkey()?.HoldSpace == KeyService.IsHoldingSpace()) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
void OnKeyPressed() { |
||||
if (KeyService.GetAllPressedKeys().Contains("Z")) { |
||||
_controlGroup = "Z"; |
||||
} |
||||
if (KeyService.GetAllPressedKeys().Contains("TAB")) { |
||||
_controlGroup = "TAB"; |
||||
} |
||||
if (KeyService.GetAllPressedKeys().Contains("C")) { |
||||
_controlGroup = "C"; |
||||
} |
||||
if (KeyService.GetAllPressedKeys().Contains("D")) { |
||||
_controlGroup = "D"; |
||||
} |
||||
if (KeyService.GetAllPressedKeys().Contains("1")) { |
||||
_controlGroup = "1"; |
||||
} |
||||
//TODO This could be better. Duplicated code |
||||
if (KeyService.GetAllPressedKeys().Contains("2")) { |
||||
_controlGroup = "2"; |
||||
} |
||||
if (KeyService.GetAllPressedKeys().Contains("SHIFT")) { |
||||
_controlGroup = "SHIFT"; |
||||
} |
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("CONTROL")) { |
||||
_controlGroup = "CONTROL"; |
||||
} |
||||
|
||||
if (KeyService.GetAllPressedKeys().Count > 0) { |
||||
_key = KeyService.GetAllPressedKeys().First(); |
||||
} |
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,26 @@
|
||||
<div tabindex="0" |
||||
style="margin: auto;" |
||||
@onkeydown="HandleKeyDown" |
||||
@onkeyup="HandleKeyUp" |
||||
@onkeydown:preventDefault="true" |
||||
colorwn:stopPropagation="true"> |
||||
@ChildContent |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public RenderFragment ChildContent { get; set; } |
||||
|
||||
[Inject] |
||||
public IKeyService KeyService { get; set; } |
||||
|
||||
private void HandleKeyDown(KeyboardEventArgs e) { |
||||
KeyService.AddPressedKey(e.Key); |
||||
} |
||||
|
||||
private void HandleKeyUp(KeyboardEventArgs e) { |
||||
KeyService.RemovePressedKey(e.Key); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
|
||||
@implements IDisposable |
||||
|
||||
<Virtualize Items="@EconomyService.GetOverTime()" Context="economyAtSecond" ItemSize="400" OverscanCount="4"> |
||||
<div style="display: grid; gap: 8px; grid-template-columns: 1fr 1fr;"> |
||||
<div> |
||||
<div> |
||||
@economyAtSecond.Interval |
||||
</div> |
||||
<div> |
||||
T @Interval.ToTime(economyAtSecond.Interval) | A @economyAtSecond.Alloy | E @economyAtSecond.Ether |
||||
</div> |
||||
<div> |
||||
Worker Count: @(economyAtSecond.WorkerCount) |
||||
</div> |
||||
<div> |
||||
Free Worker Count: @(economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount) |
||||
</div> |
||||
<div> |
||||
Busy Worker Count: @economyAtSecond.BusyWorkerCount |
||||
</div> |
||||
<div> |
||||
Creating Worker Count: @economyAtSecond.CreatingWorkerCount |
||||
</div> |
||||
<br/> |
||||
</div> |
||||
<div> |
||||
@foreach (var order in BuildOrderService.GetOrdersAt(economyAtSecond.Interval)) { |
||||
<div> |
||||
Requested: @order.Info().Name |
||||
</div> |
||||
} |
||||
@foreach (var order in BuildOrderService.GetCompletedAt(economyAtSecond.Interval)) { |
||||
<div> |
||||
New: @order.Info().Name |
||||
</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
</Virtualize> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IEconomyService EconomyService { get; set; } |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
EconomyService.Subscribe(StateHasChanged); |
||||
BuildOrderService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
EconomyService.Unsubscribe(StateHasChanged); |
||||
BuildOrderService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
|
||||
<FormLayoutComponent> |
||||
<FormNumberComponent ReadOnly="true" |
||||
Max="600" |
||||
Min="0" |
||||
Value="@TimingService.GetTiming()" |
||||
OnChange="@OnTimingChanged"> |
||||
<FormLabelComponent>Timing interval</FormLabelComponent> |
||||
<FormInfoComponent>Altering the time interval is currently disabled.</FormInfoComponent> |
||||
</FormNumberComponent> |
||||
|
||||
<FormTextComponent Label="Name" Placeholder="Fast Thrones..." Value="@BuildOrderService.GetName()" OnChange="OnNameChanged"/> |
||||
|
||||
<FormTextAreaComponent Label="Notes" |
||||
Value="@BuildOrderService.GetNotes()" |
||||
OnChange="@OnNotesChanged"> |
||||
</FormTextAreaComponent> |
||||
<FormTextComponent Label="Color" Placeholder="red..." Value="@BuildOrderService.GetColor()" OnChange="OnColorChanged"/> |
||||
</FormLayoutComponent> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
public ITimingService TimingService { get; set; } |
||||
|
||||
[Inject] |
||||
public IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
|
||||
void OnTimingChanged(ChangeEventArgs changeEventArgs) { |
||||
TimingService.SetTiming(int.Parse(changeEventArgs.Value.ToString())); |
||||
} |
||||
|
||||
void OnTimingChanged(int value) { |
||||
TimingService.SetTiming(value); |
||||
} |
||||
|
||||
void OnNameChanged(ChangeEventArgs changeEventArgs) { |
||||
BuildOrderService.SetName(changeEventArgs.Value.ToString()); |
||||
} |
||||
|
||||
void OnColorChanged(ChangeEventArgs changeEventArgs) { |
||||
BuildOrderService.SetColor(changeEventArgs.Value.ToString()); |
||||
} |
||||
|
||||
|
||||
void OnNotesChanged(ChangeEventArgs changeEventArgs) { |
||||
BuildOrderService.SetNotes(changeEventArgs.Value.ToString()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,119 @@
|
||||
@page "/changelog" |
||||
@implements IDisposable; |
||||
@inject IGitService GitService; |
||||
@inject DatabaseContext Database; |
||||
|
||||
@layout PageLayout |
||||
|
||||
|
||||
@if (GitService.IsLoaded()) { |
||||
<LayoutMediumContentComponent> |
||||
<WebsiteTitleComponent>Change Log</WebsiteTitleComponent> |
||||
|
||||
<PaperComponent> |
||||
<FormLayoutComponent> |
||||
<FormCheckboxComponent Label="Show Important" |
||||
Info="Only show important patches. Like database updates to the latest game patch." |
||||
Value="@isViewImportant" |
||||
OnChange="OnChangeClicked"> |
||||
</FormCheckboxComponent> |
||||
</FormLayoutComponent> |
||||
</PaperComponent> |
||||
|
||||
<PaperComponent> |
||||
@foreach (var patch in Patches.OrderBy(x => x.Date).Reverse()) { |
||||
@if (!patch.Important.Equals("True") && isViewImportant) { |
||||
continue; |
||||
} |
||||
|
||||
var daysAgo = Math.Floor(DateTime.Now.Subtract(patch.Date).TotalDays); |
||||
|
||||
<div class="patchContainer"> |
||||
<div style="display: flex; justify-content: space-between;"> |
||||
<div style="font-size: 1.2rem; font-weight: bolder; margin-bottom:4px;"> |
||||
@patch.Name |
||||
</div> |
||||
<div> |
||||
@if (daysAgo == 0) { |
||||
<i>Today</i> |
||||
} |
||||
else if (daysAgo < 8) { |
||||
<i>@daysAgo days ago</i> |
||||
} |
||||
else { |
||||
<i>@patch.Date.ToString("dd/MM/yyyy")</i> |
||||
} |
||||
|
||||
</div> |
||||
</div> |
||||
<div> |
||||
@foreach (var change in patch.ChangeModels) { |
||||
@if (!change.Important.Equals("True") && isViewImportant) { |
||||
continue; |
||||
} |
||||
|
||||
<div style="display: flex; justify-content: space-between; "> |
||||
<div> |
||||
<div> |
||||
<b> |
||||
- @change.Name |
||||
|
||||
@if (change.Commit != CommitType.None) { |
||||
<span>(@change.Commit)</span> |
||||
} |
||||
: |
||||
</b> @((MarkupString)change.Description) |
||||
</div> |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
<br/> |
||||
} |
||||
|
||||
</PaperComponent> |
||||
</LayoutMediumContentComponent> |
||||
} |
||||
else { |
||||
<LoadingComponent></LoadingComponent> |
||||
} |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public DbSet<PatchModel> Patches { get; set; } |
||||
|
||||
[Parameter] |
||||
public DbSet<ChangeModel> Changes { get; set; } |
||||
|
||||
private bool isViewImportant = true; |
||||
|
||||
|
||||
protected override void OnInitialized() { |
||||
GitService.Subscribe(HasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
GitService.Unsubscribe(HasChanged); |
||||
} |
||||
|
||||
|
||||
void OnChangeClicked(ChangeEventArgs changeEventArgs) { |
||||
isViewImportant = (bool)changeEventArgs.Value; |
||||
} |
||||
|
||||
void HasChanged() { |
||||
Changes = GitService.ChangeModels; |
||||
Patches = GitService.PatchModels; |
||||
StateHasChanged(); |
||||
} |
||||
|
||||
protected override async Task OnInitializedAsync() { |
||||
GitService.Load(Database); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,94 @@
|
||||
@layout PageLayout |
||||
@implements IDisposable |
||||
|
||||
<div style="display:grid; gap: 8px;padding: 16px; height: 94vh; width: 90vw; margin: auto; margin-top: 32px; |
||||
grid-template-columns: 27% 25% 25% 23%; grid-template-rows: auto; |
||||
grid-template-areas: 'loader sand compare compare' ;"> |
||||
|
||||
|
||||
<div style="grid-area: loader; border: 2px solid black; padding: 20px;"> |
||||
Comparision Loader |
||||
<BuildLoaderComponent></BuildLoaderComponent> |
||||
</div> |
||||
|
||||
<div style="grid-area: sand; border: 2px solid black; padding: 20px;"> |
||||
Sand |
||||
<SandComponent></SandComponent> |
||||
</div> |
||||
|
||||
|
||||
<div style="grid-area: compare; border: 2px solid black; padding: 20px;"> |
||||
Comparision Charts |
||||
<ComparisonChartsComponent></ComparisonChartsComponent> |
||||
</div> |
||||
|
||||
|
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IKeyService KeyService { get; set; } |
||||
|
||||
[Inject] |
||||
IImmortalSelectionService FilterService { get; set; } |
||||
|
||||
[Inject] |
||||
IBuildOrderService BuildOrderService { get; set; } |
||||
|
||||
[Inject] |
||||
IEconomyService EconomyService { get; set; } |
||||
|
||||
[Inject] |
||||
ITimingService TimingService { get; set; } |
||||
|
||||
|
||||
Dictionary<int, List<EntityModel>> completedEntities = new(); |
||||
|
||||
|
||||
List<EntityModel> entities = EntityModel.GetListOnlyHotkey(); |
||||
|
||||
protected override void OnInitialized() { |
||||
KeyService.Subscribe(HandleClick); |
||||
FilterService.Subscribe(StateHasChanged); |
||||
EconomyService.Subscribe(StateHasChanged); |
||||
TimingService.Subscribe(HandleTimingChanged); |
||||
EconomyService.Calculate(BuildOrderService, TimingService, 0); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
KeyService.Unsubscribe(HandleClick); |
||||
FilterService.Unsubscribe(StateHasChanged); |
||||
TimingService.Unsubscribe(StateHasChanged); |
||||
EconomyService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
|
||||
protected void HandleTimingChanged() { |
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); |
||||
} |
||||
|
||||
protected void HandleClick() { |
||||
var hotkey = KeyService.GetHotkey(); |
||||
var hotkeyGroup = KeyService.GetHotkeyGroup(); |
||||
var isHoldSpace = KeyService.IsHoldingSpace(); |
||||
var faction = FilterService.GetFactionType(); |
||||
var immortal = FilterService.GetImmortalType(); |
||||
|
||||
if (hotkey == "`") { |
||||
BuildOrderService.RemoveLast(); |
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); |
||||
StateHasChanged(); |
||||
return; |
||||
} |
||||
|
||||
var entity = EntityModel.GetFrom(hotkey, hotkeyGroup, isHoldSpace, faction, immortal); |
||||
if (entity == null) { |
||||
return; |
||||
} |
||||
if (BuildOrderService.Add(entity, EconomyService)) { |
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
|
||||
@implements IDisposable |
||||
|
||||
|
||||
<div> |
||||
<Button Color="Color.Primary" @onclick="OnLoad">Load</Button> |
||||
<button @onclick="OnLoad">Load</button> |
||||
</div> |
||||
|
||||
<div> |
||||
<textarea @bind="buildData" @bind:event="oninput" |
||||
style="background-color: #36393F; width: 330px; height: 400px;"> |
||||
</textarea> |
||||
</div> |
||||
|
||||
@code { |
||||
string buildData = ""; |
||||
|
||||
[Inject] |
||||
IBuildComparisonService BuildComparisionService { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
BuildComparisionService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
BuildComparisionService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
void OnLoad() { |
||||
BuildComparisionService.LoadJson(buildData); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,22 @@
|
||||
@implements IDisposable |
||||
|
||||
<div> |
||||
<textarea readonly style="background-color: #36393F; width: 330px; height: 400px;"> |
||||
@BuildComparisonService.AsJson() |
||||
</textarea> |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
IBuildComparisonService BuildComparisonService { get; set; } |
||||
|
||||
protected override void OnInitialized() { |
||||
BuildComparisonService.Subscribe(StateHasChanged); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
BuildComparisonService.Unsubscribe(StateHasChanged); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,18 @@
|
||||
@layout PageLayout |
||||
|
||||
@page "/contact" |
||||
|
||||
<LayoutMediumContentComponent> |
||||
<WebsiteTitleComponent>Contact</WebsiteTitleComponent> |
||||
|
||||
<PaperComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
How do I contact you for feature requests and bug reports? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
You can direct message me at <b>Iremirror#3544</b> on the <a href="https://discord.gg/uMq8bMGeeN" target="_blank">IGP Fan Reference</a> discord. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
</PaperComponent> |
||||
</LayoutMediumContentComponent> |
||||
@ -0,0 +1,220 @@
|
||||
@layout PageLayout |
||||
|
||||
@page "/database" |
||||
|
||||
@implements IDisposable |
||||
|
||||
<LayoutLargeContentComponent> |
||||
<WebsiteTitleComponent>Database</WebsiteTitleComponent> |
||||
|
||||
<PaperComponent> |
||||
<FormDisplayComponent Label="Patch"> |
||||
<Display> |
||||
Game Patch: @EntityModel.GameVersion |
||||
</Display> |
||||
</FormDisplayComponent> |
||||
</PaperComponent> |
||||
|
||||
<PaperComponent> |
||||
<EntityFilterComponent></EntityFilterComponent> |
||||
|
||||
@if (searches != null) { |
||||
<div class="databaseItems"> |
||||
@foreach (var entity in searches) { |
||||
<EntityViewComponent Entity=entity></EntityViewComponent> |
||||
} |
||||
</div> |
||||
} |
||||
</PaperComponent> |
||||
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
<PaperComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is this tool? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
This is a reference database. Mostly so unit stats can be reviewed outside of the game, IMMORTAL: Gates of Pyre. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
Is this database complete? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
No. A lot of content is missing, that needs to be manually transfered from screenshots of IMMORTAL: Gates of Pyre. This will happen slowly over-time. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
Is this database updated to the latest version? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Maybe. Check this <b>@EntityModel.GameVersion</b> version number, and compare it to the number on discord, in the <b>#game-updates</b> channel. That should give a general sense of how out of date the data is. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
This database has some errors in it. |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Yup. The content is being transferred by hand, so some mistakes are expected. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
Can I see this data as raw JSON? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
<a href="/raw-database">raw json link</a> |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
</PaperComponent> |
||||
</LayoutLargeContentComponent> |
||||
|
||||
<style> |
||||
.databaseItems { |
||||
height: 700px; |
||||
overflow-x: hidden; |
||||
overflow-y: auto; |
||||
background-color: var(--background); |
||||
gap: 4px; |
||||
border-top: 4px solid var(--accent); |
||||
border-bottom: 4px solid var(--accent); |
||||
padding: 4px; |
||||
} |
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
public IEntityFilterService EntityFilterService { get; set; } |
||||
|
||||
readonly List<EntityModel> defaults = (from entity in EntityModel.GetList() |
||||
where entity.IsSpeculative == false |
||||
select entity).ToList(); |
||||
|
||||
List<EntityModel> factions; |
||||
List<EntityModel> immortals; |
||||
List<EntityModel> entities; |
||||
List<EntityModel> searches; |
||||
|
||||
|
||||
string selectedFactionType = FactionType.Any; |
||||
string selectedImmortalType = ImmortalType.Any; |
||||
string selectedEntityType = EntityType.Army; |
||||
string searchText = ""; |
||||
|
||||
protected override void OnInitialized() { |
||||
RefreshFactionSearch(); |
||||
|
||||
EntityFilterService.Subscribe(OnChange); |
||||
} |
||||
|
||||
void IDisposable.Dispose() { |
||||
EntityFilterService.Subscribe(OnChange); |
||||
} |
||||
|
||||
void OnChange(EntityFilterEvent filterEntityEvent) { |
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshFaction) { |
||||
RefreshFactionSearch(); |
||||
} |
||||
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshImmortal) { |
||||
RefreshImmortalSearch(); |
||||
} |
||||
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshEntity) { |
||||
RefreshEntitySearch(); |
||||
} |
||||
|
||||
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshSearch) { |
||||
RefreshTextSearch(); |
||||
} |
||||
} |
||||
|
||||
void RefreshFactionSearch() { |
||||
selectedFactionType = EntityFilterService.GetFactionType(); |
||||
|
||||
if (selectedFactionType == FactionType.Any) { |
||||
factions = defaults.ToList(); |
||||
} |
||||
else { |
||||
factions = (from entity in defaults |
||||
where entity.Faction() != null && entity.Faction().Faction == selectedFactionType |
||||
select entity).ToList(); |
||||
} |
||||
|
||||
RefreshImmortalSearch(); |
||||
} |
||||
|
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e) { |
||||
selectedImmortalType = e.Value.ToString(); |
||||
RefreshImmortalSearch(); |
||||
} |
||||
|
||||
void RefreshImmortalSearch() { |
||||
selectedImmortalType = EntityFilterService.GetImmortalType(); |
||||
|
||||
if (selectedImmortalType == ImmortalType.Any) { |
||||
immortals = factions.ToList(); |
||||
} |
||||
else { |
||||
immortals = (from entity in factions |
||||
where entity.Vanguard() == null || entity.Vanguard().Immortal == selectedImmortalType |
||||
select entity).ToList(); |
||||
} |
||||
|
||||
RefreshEntitySearch(); |
||||
} |
||||
|
||||
void OnEntityChanged(ChangeEventArgs e) { |
||||
selectedEntityType = e.Value.ToString(); |
||||
RefreshEntitySearch(); |
||||
} |
||||
|
||||
void RefreshEntitySearch() { |
||||
selectedEntityType = EntityFilterService.GetEntityType(); |
||||
|
||||
if (selectedEntityType == EntityType.Any) { |
||||
entities = immortals.ToList(); |
||||
} |
||||
else { |
||||
entities = (from entity in immortals |
||||
where entity.EntityType == selectedEntityType |
||||
select entity).ToList(); |
||||
} |
||||
|
||||
RefreshTextSearch(); |
||||
} |
||||
|
||||
void OnSearchTextChanged(ChangeEventArgs e) { |
||||
searchText = e.Value.ToString(); |
||||
RefreshTextSearch(); |
||||
} |
||||
|
||||
void RefreshTextSearch() { |
||||
searchText = EntityFilterService.GetSearchText(); |
||||
|
||||
if (searchText.Trim() == "") { |
||||
searches = entities.ToList(); |
||||
} |
||||
else { |
||||
searches = (from entity in entities |
||||
where entity.Info().Name.ToLower().Contains(searchText.ToLower()) |
||||
select entity).ToList(); |
||||
} |
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
|
||||
@if (Entity != null) { |
||||
var isVanguard = Entity.Vanguard() != null ? " vanguard" : ""; |
||||
|
||||
<div class="enititiesContainer @isVanguard"> |
||||
<EntityHeaderComponent Entity=Entity></EntityHeaderComponent> |
||||
|
||||
<div class="entityPartsContainer"> |
||||
<EntityVanguardComponent Entity=Entity></EntityVanguardComponent> |
||||
<EntityInfoComponent Entity=Entity></EntityInfoComponent> |
||||
<EntityVanguardsComponent Entity=Entity></EntityVanguardsComponent> |
||||
<EntityProductionComponent Entity=Entity></EntityProductionComponent> |
||||
<EntityStatsComponent Entity=Entity></EntityStatsComponent> |
||||
<EntityMechanicsComponent Entity=Entity></EntityMechanicsComponent> |
||||
<EntityPassivesComponent Entity=Entity></EntityPassivesComponent> |
||||
<EntityPyreSpellsComponent Entity=Entity></EntityPyreSpellsComponent> |
||||
<EntityUpgradesComponent Entity=Entity></EntityUpgradesComponent> |
||||
<EntityWeaponsComponent Entity=Entity></EntityWeaponsComponent> |
||||
<EntityAbilitiesComponent Entity=Entity></EntityAbilitiesComponent> |
||||
</div> |
||||
</div> |
||||
} |
||||
|
||||
<style> |
||||
.enititiesContainer { |
||||
margin-bottom: 12px; |
||||
width: 100%; |
||||
overflow-y: auto; |
||||
overflow-x: hidden; |
||||
padding: 30px; |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
} |
||||
|
||||
.vanguard { |
||||
border: 4px solid var(--accent); |
||||
border-radius: 8px; |
||||
} |
||||
|
||||
.entityPartsContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
flex-wrap: wrap; |
||||
width: 100%; |
||||
} |
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.enititiesContainer { |
||||
padding: 0px; |
||||
} |
||||
|
||||
.entityPartsContainer { |
||||
margin: 0px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,43 @@
|
||||
@if (Entity.IdAbilities().Count > 0) { |
||||
<EntityDisplayComponent Title="Abilities"> |
||||
@foreach (var idAbility in Entity.IdAbilities()) { |
||||
var spell = EntityModel.Get(idAbility.Id); |
||||
|
||||
var info = spell.Info(); |
||||
var production = spell.Production(); |
||||
|
||||
<div> |
||||
<div> |
||||
<b>Name:</b> @info.Name |
||||
</div> |
||||
<div style="max-width: 600px;"> |
||||
<b>Description:</b> @((MarkupString)info.Description) |
||||
</div> |
||||
<div> |
||||
@if (production != null) { |
||||
if (production.Energy != 0) { |
||||
<b> Energy: </b> |
||||
@production.Energy |
||||
} |
||||
if (production.BuildTime != 0) { |
||||
<b> BuildTime: </b> |
||||
@production.BuildTime |
||||
} |
||||
if (production.Cooldown != 0) { |
||||
<b> Cooldown: </b> |
||||
@production.Cooldown |
||||
} |
||||
} |
||||
</div> |
||||
</div> |
||||
} |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,46 @@
|
||||
<div class="entityHeader"> |
||||
<div class="entityHeaderText"> |
||||
@Entity.Info().Name |
||||
</div> |
||||
<div style="font-size:1.4rem;"> |
||||
<b>@Entity.EntityType.Replace("_", " ")</b> |
||||
@if (Entity.Info().Descriptive != DescriptiveType.None) { |
||||
<span> |
||||
<b>:</b> @Entity.Info().Descriptive.Replace("_", " ") |
||||
</span> |
||||
} |
||||
</div> |
||||
</div> |
||||
|
||||
<style> |
||||
.entityHeader { |
||||
display: flex; |
||||
flex-direction: row; |
||||
gap: 4px; |
||||
justify-content: space-between; |
||||
margin-bottom: 22px; |
||||
width: 100%; |
||||
margin-left: -6px; |
||||
} |
||||
|
||||
.entityHeaderText { |
||||
font-size: 2rem; |
||||
font-weight: 900; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.entityHeader { |
||||
flex-direction: column; |
||||
justify-content: normal; |
||||
margin-left: 4px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,57 @@
|
||||
<EntityDisplayComponent Title="Info"> |
||||
@if (Entity.Info().Description != "") { |
||||
<div> |
||||
<b>Description:</b> @((MarkupString)Entity.Info().Description) |
||||
</div> |
||||
} |
||||
|
||||
<div class="infoDisplayContainer"> |
||||
<div> |
||||
@if (Entity.Faction() != null) { |
||||
<div> |
||||
<b>Faction:</b> @Entity.Faction().Faction |
||||
</div> |
||||
} |
||||
@if (Entity.Tier() != null) { |
||||
<div> |
||||
<b>Tier:</b> @Entity.Tier().Tier |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
@if (Entity.Hotkey() != null) { |
||||
<div> |
||||
<div> |
||||
<b>Hotkey Group:</b> @Entity.Hotkey().HotkeyGroup |
||||
</div> |
||||
<div> |
||||
<b>Hotkey:</b> @Entity.Hotkey().Hotkey |
||||
</div> |
||||
<div> |
||||
<b>Hold Space:</b> @(Entity.Hotkey().HoldSpace ? "Yes" : "No") |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</EntityDisplayComponent> |
||||
|
||||
<style> |
||||
.infoDisplayContainer { |
||||
display: flex; |
||||
gap: 32px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.infoDisplayContainer { |
||||
flex-direction: column; |
||||
gap: 4px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
@if (Entity.Mechanics().Count > 0) { |
||||
<EntityDisplayComponent Title="Mechanics"> |
||||
<div> |
||||
@foreach (var data in Entity.Mechanics()) { |
||||
<div> |
||||
<div> |
||||
<span> |
||||
<b>Name:</b> @data.Name |
||||
</span> |
||||
</div> |
||||
<div> |
||||
<b>Description:</b> @data.Description |
||||
</div> |
||||
<br/> |
||||
</div> |
||||
} |
||||
</div> |
||||
|
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,26 @@
|
||||
@if (Entity.IdPassives().Count > 0) { |
||||
<EntityDisplayComponent Title="Passives"> |
||||
@foreach (var idPassive in Entity.IdPassives()) { |
||||
var passive = EntityModel.Get(idPassive.Id); |
||||
|
||||
var info = passive.Info(); |
||||
|
||||
<div> |
||||
<div> |
||||
<b>Name:</b> @info.Name |
||||
</div> |
||||
<div style="max-width: 600px;"> |
||||
<b>Description:</b> @((MarkupString)info.Description) |
||||
</div> |
||||
</div> |
||||
} |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,94 @@
|
||||
@{ |
||||
var production = Entity.Production(); |
||||
var supply = Entity.Supply(); |
||||
var requirements = Entity.Requirements(); |
||||
} |
||||
|
||||
@if (production != null || supply != null || requirements.Count > 0) { |
||||
<EntityDisplayComponent Title="Production"> |
||||
<div class="productionContainer"> |
||||
@if (requirements.Count() > 0) { |
||||
<div> |
||||
@foreach (var requirement in requirements) { |
||||
<div> |
||||
|
||||
<span> |
||||
<b>@requirement.Requirement.Replace("_", " "):</b> @requirement.Name |
||||
</span> |
||||
</div> |
||||
} |
||||
</div> |
||||
} |
||||
|
||||
@if (production != null && (!production.Alloy.Equals(0) |
||||
|| !production.Ether.Equals(0) |
||||
|| !production.BuildTime.Equals(0) |
||||
|| !production.Cooldown.Equals(0))) { |
||||
<div> |
||||
@if (!production.Alloy.Equals(0)) { |
||||
<div> |
||||
<b>Alloy:</b> @production.Alloy |
||||
</div> |
||||
} |
||||
@if (!production.Ether.Equals(0)) { |
||||
<div> |
||||
<b>Ether:</b> @production.Ether |
||||
</div> |
||||
} |
||||
@if (!production.Pyre.Equals(0)) { |
||||
<div> |
||||
<b>Pyre:</b> @production.Pyre |
||||
</div> |
||||
} |
||||
|
||||
@if (!production.BuildTime.Equals(0)) { |
||||
<div> |
||||
<b>Build Time:</b> @production.BuildTime.ToString()s |
||||
</div> |
||||
} |
||||
|
||||
@if (!production.Cooldown.Equals(0)) { |
||||
<div> |
||||
<b>Cooldown:</b> @production.Cooldown.ToString()s |
||||
</div> |
||||
} |
||||
</div> |
||||
} |
||||
@if (supply != null) { |
||||
<div> |
||||
@if (!supply.Grants.Equals(0)) { |
||||
<div> |
||||
<b>Grants:</b> @supply.Grants |
||||
</div> |
||||
} |
||||
@if (!supply.Takes.Equals(0)) { |
||||
<div> |
||||
<b>Takes:</b> @supply.Takes Supply |
||||
</div> |
||||
} |
||||
</div> |
||||
} |
||||
</div> |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
<style> |
||||
.productionContainer { |
||||
display: flex; |
||||
gap: 32px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.productionContainer { |
||||
flex-direction: column; |
||||
gap: 4px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,43 @@
|
||||
@if (Entity.IdPyreSpells().Count > 0) { |
||||
<EntityDisplayComponent Title="Pyre Spells"> |
||||
@foreach (var pyreSpell in Entity.IdPyreSpells()) { |
||||
var spell = EntityModel.Get(pyreSpell.Id); |
||||
|
||||
var info = spell.Info(); |
||||
var production = spell.Production(); |
||||
|
||||
<div> |
||||
<div> |
||||
<b>Name:</b> @info.Name |
||||
</div> |
||||
<div> |
||||
<b>Description:</b> @((MarkupString)info.Description) |
||||
</div> |
||||
<div> |
||||
@if (production != null) { |
||||
if (production.Pyre != 0) { |
||||
<b> Pyre: </b> |
||||
@production.Pyre |
||||
} |
||||
if (production.BuildTime != 0) { |
||||
<b> BuildTime: </b> |
||||
@production.BuildTime |
||||
} |
||||
if (production.Cooldown != 0) { |
||||
<b> Cooldown: </b> |
||||
@production.Cooldown |
||||
} |
||||
} |
||||
</div> |
||||
</div> |
||||
} |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,86 @@
|
||||
@{ |
||||
var vitality = Entity.Vitality(); |
||||
var movement = Entity.Movement(); |
||||
} |
||||
|
||||
@if (vitality != null || movement != null) { |
||||
<EntityDisplayComponent Title="Stats"> |
||||
<div class="statContainer"> |
||||
@if (vitality != null) { |
||||
<div> |
||||
@if (!vitality.DefenseLayer.Equals(0)) { |
||||
<div> |
||||
<b>Shield:</b> @vitality.DefenseLayer |
||||
</div> |
||||
} |
||||
@if (!vitality.Health.Equals(0)) { |
||||
<div> |
||||
<b>Health:</b> @vitality.Health |
||||
</div> |
||||
} |
||||
@if (!vitality.Energy.Equals(0)) { |
||||
<div> |
||||
<b>Energy:</b> @vitality.Energy |
||||
</div> |
||||
} |
||||
@if (vitality.Armor != "") { |
||||
<div> |
||||
<b>Armor:</b> @vitality.Armor |
||||
</div> |
||||
} |
||||
|
||||
@if (vitality.IsEtheric) { |
||||
<div> |
||||
<b> + Etheric</b> |
||||
</div> |
||||
} |
||||
@if (vitality.IsStructure) { |
||||
<div> |
||||
<b> + Structure</b> |
||||
</div> |
||||
} |
||||
</div> |
||||
} |
||||
|
||||
|
||||
@if (movement != null) { |
||||
<div> |
||||
@if (!movement.Speed.Equals(0)) { |
||||
<div> |
||||
<b>Speed:</b> @movement.Speed |
||||
</div> |
||||
} |
||||
else { |
||||
<div> |
||||
<b>Speed:</b> Immobile |
||||
</div> |
||||
} |
||||
<div> |
||||
<b>Move Type:</b> @movement.Movement |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
<style> |
||||
.statContainer { |
||||
display: flex; |
||||
gap: 32px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.statContainer { |
||||
flex-direction: column; |
||||
gap: 4px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,38 @@
|
||||
@if (Entity.IdUpgrades().Count > 0) { |
||||
<EntityDisplayComponent Title="Upgrades"> |
||||
<div class="upgradesContainer"> |
||||
@foreach (var upgradeId in Entity.IdUpgrades()) { |
||||
var entity = EntityModel.Get(upgradeId.Id); |
||||
<div> |
||||
<div> |
||||
<b>Name:</b> @entity.Info().Name |
||||
</div> |
||||
<div> |
||||
<b>Description:</b> @entity.Info().Description |
||||
</div> |
||||
</div> |
||||
} |
||||
</div> |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
<style> |
||||
.upgradesContainer { |
||||
display: flex; |
||||
gap: 32px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.upgradesContainer { |
||||
flex-direction: column; |
||||
gap: 4px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@
|
||||
@if (Entity.Vanguard() != null) { |
||||
<EntityDisplayComponent Title="Vanguard"> |
||||
<div> |
||||
<div> |
||||
<b>Immortal:</b> @Entity.Vanguard().Immortal.Replace("_", " ") |
||||
</div> |
||||
@if (Entity.Vanguard().Replaces != "") { |
||||
<div> |
||||
<b>Replaces:</b> @Entity.Vanguard().Replaces.Replace("_", " ") |
||||
</div> |
||||
} |
||||
</div> |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,35 @@
|
||||
@if (Entity.IdVanguards().Count > 0) { |
||||
<EntityDisplayComponent Title="Vanguards"> |
||||
@foreach (var data in Entity.IdVanguards()) { |
||||
var entity = EntityModel.Get(data.Id); |
||||
|
||||
var info = entity.Info(); |
||||
var production = entity.Production(); |
||||
var requirements = entity.Requirements(); |
||||
var vanguard = entity.Vanguard(); |
||||
var productionBuilding = (from building in requirements |
||||
where building.Requirement == RequirementType.Production_Building |
||||
select building).First().Name; |
||||
|
||||
<div> |
||||
<div> |
||||
<b>Name:</b> @info.Name |
||||
</div> |
||||
<div> |
||||
<b>Replaces:</b> @vanguard.Replaces |
||||
</div> |
||||
|
||||
<div> |
||||
<b>Built From:</b> @productionBuilding |
||||
</div> |
||||
</div> |
||||
} |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,114 @@
|
||||
@if (Entity.Weapons().Count > 0) { |
||||
<EntityDisplayComponent Title="Weapons"> |
||||
<div class="weaponsContainer"> |
||||
@foreach (var data in Entity.Weapons()) { |
||||
<div> |
||||
<div> |
||||
<div class="damageContainer"> |
||||
<div> |
||||
<b>Damage:</b> @data.Damage |
||||
</div> |
||||
@if (data.LightDamage != 0) { |
||||
<div class="alternateDamage"> |
||||
<i>vs Light: @data.LightDamage</i> |
||||
</div> |
||||
} |
||||
@if (data.MediumDamage != 0) { |
||||
<div class="alternateDamage"> |
||||
<i>vs Medium: @data.MediumDamage</i> |
||||
</div> |
||||
} |
||||
@if (data.HeavyDamage != 0) { |
||||
<div class="alternateDamage"> |
||||
<i>vs Heavy: @data.HeavyDamage</i> |
||||
</div> |
||||
} |
||||
@if (data.EthericDamageBonus != 0) { |
||||
<div class="alternateDamage"> |
||||
<i>vs Etheric +@data.EthericDamageBonus</i> |
||||
</div> |
||||
} |
||||
@if (data.StructureDamageBonus != 0) { |
||||
<div class="alternateDamage"> |
||||
<i>vs Structure: +@data.StructureDamageBonus</i> |
||||
</div> |
||||
} |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<b>Range:</b> @data.Range |
||||
</div> |
||||
@if (data.SecondsBetweenAttacks > 0) { |
||||
<div> |
||||
<b>AttacksPerSecond:</b> @(1 / data.SecondsBetweenAttacks) |
||||
</div> |
||||
<div> |
||||
(or <b>SecondsBetweenAttacks:</b> @data.SecondsBetweenAttacks) |
||||
</div> |
||||
} |
||||
else if (data.AttacksPerSecond > 0) { |
||||
<div> |
||||
<b>AttacksPerSecond:</b> @data.AttacksPerSecond |
||||
</div> |
||||
<div> |
||||
(or <b>SecondsBetweenAttacks:</b> @(1 / data.AttacksPerSecond)) |
||||
</div> |
||||
} |
||||
|
||||
<div> |
||||
<b>Targets:</b> @data.Targets |
||||
</div> |
||||
@if (data.AttacksPerSecond != 0) { |
||||
<span> |
||||
<b>DPS:</b> @(Math.Round(data.Damage * data.AttacksPerSecond)) |
||||
</span> |
||||
@if (data.LightDamage != 0) { |
||||
<span> |
||||
<i>L: @(Math.Round(data.LightDamage * data.AttacksPerSecond))</i> |
||||
</span> |
||||
} |
||||
@if (data.MediumDamage != 0) { |
||||
<span> |
||||
<i>M: @(Math.Round(data.MediumDamage * data.AttacksPerSecond))</i> |
||||
</span> |
||||
} |
||||
@if (data.HeavyDamage != 0) { |
||||
<span> |
||||
<i>H: @(Math.Round(data.HeavyDamage * data.AttacksPerSecond))</i> |
||||
</span> |
||||
} |
||||
} |
||||
</div> |
||||
} |
||||
</div> |
||||
</EntityDisplayComponent> |
||||
} |
||||
|
||||
<style> |
||||
.weaponsContainer { |
||||
display: flex; |
||||
gap: 32px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.weaponsContainer { |
||||
flex-direction: column; |
||||
gap: 4px; |
||||
} |
||||
} |
||||
|
||||
.alternateDamage { |
||||
margin-left: 18px; |
||||
} |
||||
|
||||
.damageContainer { |
||||
margin-bottom: 6px; |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
|
||||
[Parameter] |
||||
public EntityModel Entity { get; set; } |
||||
|
||||
} |
||||
@ -0,0 +1,235 @@
|
||||
<div class="desktopFilters"> |
||||
<div class="desktopFiltersContainer"> |
||||
<div class="filtersContainer"> |
||||
<div class="filterContainer"> |
||||
@foreach (var choice in EntityFilterService.GetFactionChoices()) { |
||||
var styleClass = ""; |
||||
if (choice.Equals(EntityFilterService.GetFactionType())) { |
||||
styleClass = "selected"; |
||||
} |
||||
<button @onclick="@(e => OnChangeFaction(choice))" class="choiceButton @styleClass">@choice</button> |
||||
} |
||||
</div> |
||||
|
||||
@if (EntityFilterService.GetFactionType() != "Any" && EntityFilterService.GetFactionType() != "None") { |
||||
<div class="filterContainer"> |
||||
@foreach (var choice in EntityFilterService.GetImmortalChoices()) { |
||||
var styleClass = ""; |
||||
if (choice.Equals(EntityFilterService.GetImmortalType())) { |
||||
styleClass = "selected"; |
||||
} |
||||
<button class="choiceButton @styleClass" @onclick="@(e => OnChangeImmortal(choice))">@choice</button> |
||||
} |
||||
</div> |
||||
} |
||||
</div> |
||||
<div class="filterContainer"> |
||||
@foreach (var choice in EntityFilterService.GetEntityChoices()) { |
||||
var styleClass = ""; |
||||
if (choice.Equals(EntityFilterService.GetEntityType())) { |
||||
styleClass = "selected"; |
||||
} |
||||
|
||||
<button class="choiceButton @styleClass" @onclick="@(e => OnChangeEntity(choice))">@choice.Replace("_", " ")</button> |
||||
} |
||||
</div> |
||||
<FormTextComponent Label="Search Label" Placeholder="Throne..." OnChange="@(e => EntityFilterService.EnterSearchText(e.Value.ToString()))"/> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="mobileFilters"> |
||||
<FormLayoutComponent> |
||||
<FormSelectComponent OnChange="@OnFactionChanged"> |
||||
<FormLabelComponent>Faction</FormLabelComponent> |
||||
<ChildContent> |
||||
<option value="@FactionType.Any" selected>Any</option> |
||||
<option value="@FactionType.Aru">Aru</option> |
||||
<option value="@FactionType.QRath">Q'Rath</option> |
||||
</ChildContent> |
||||
</FormSelectComponent> |
||||
|
||||
<FormSelectComponent OnChange="@OnImmortalChanged"> |
||||
<FormLabelComponent>Immortal</FormLabelComponent> |
||||
<ChildContent> |
||||
<option value="@ImmortalType.Any" selected>Any</option> |
||||
<option value="@ImmortalType.Mala">Mala</option> |
||||
<option value="@ImmortalType.Xol">Xol</option> |
||||
<option value="@ImmortalType.Orzum">Orzum</option> |
||||
<option value="@ImmortalType.Ajari">Ajari</option> |
||||
</ChildContent> |
||||
</FormSelectComponent> |
||||
|
||||
<FormSelectComponent OnChange="@OnEntityChanged"> |
||||
<FormLabelComponent>Entity</FormLabelComponent> |
||||
<ChildContent> |
||||
<option value="@EntityType.Any">Any</option> |
||||
<option value="@EntityType.Ability">Ability</option> |
||||
<option value="@EntityType.Army" selected>Army</option> |
||||
<option value="@EntityType.Building">Building</option> |
||||
<option value="@EntityType.Building_Upgrade">Building Upgrade</option> |
||||
<option value="@EntityType.Command">Command</option> |
||||
<option value="@EntityType.Faction">Faction</option> |
||||
<option value="@EntityType.Immortal">Immortal</option> |
||||
<option value="@EntityType.Pyre_Spell">Spell</option> |
||||
<option value="@EntityType.Passive">Passive</option> |
||||
<option value="@EntityType.Tech">Tech</option> |
||||
<option value="@EntityType.Worker">Worker</option> |
||||
</ChildContent> |
||||
</FormSelectComponent> |
||||
|
||||
|
||||
<FormTextComponent Label="Search Label" Placeholder="Throne..." OnChange="OnSearchTextChanged"/> |
||||
</FormLayoutComponent> |
||||
|
||||
</div> |
||||
|
||||
<style> |
||||
|
||||
.desktopFilters { |
||||
display: flex; |
||||
gap: 12px; |
||||
flex-direction: column; |
||||
justify-content: flex-start; |
||||
justify-items: flex-start; |
||||
top: 50px; |
||||
padding: 12px; |
||||
width: 100%; |
||||
left: 0px; |
||||
} |
||||
|
||||
.desktopFiltersContainer { |
||||
width: 75%; |
||||
min-width: 1000px; |
||||
margin: auto; |
||||
display: flex; |
||||
gap: 16px; |
||||
flex-direction: column; |
||||
justify-content: flex-start; |
||||
justify-items: flex-start; |
||||
} |
||||
|
||||
.filtersContainer { |
||||
display: flex; |
||||
gap: 16px; |
||||
} |
||||
|
||||
.filterContainer { |
||||
display: flex; |
||||
background-color: var(--background); |
||||
gap: 2px; |
||||
margin-right: auto; |
||||
border-radius: 8px; |
||||
} |
||||
|
||||
.choiceButton { |
||||
background-color: var(--primary); |
||||
color: white; |
||||
padding: 12px; |
||||
border: 1px solid var(--primary); |
||||
} |
||||
|
||||
.choiceButton:hover { |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
} |
||||
|
||||
.selected { |
||||
background-color: var(--secondary); |
||||
color: white; |
||||
font-style: normal; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.selected:hover { |
||||
background-color: var(--secondary-hover); |
||||
border-color: var(--secondary-border-hover); |
||||
} |
||||
|
||||
|
||||
.filterContainer .choiceButton:first-child { |
||||
border-top-left-radius: 8px; |
||||
border-bottom-left-radius: 8px; |
||||
} |
||||
|
||||
|
||||
.filterContainer .choiceButton:last-child { |
||||
border-top-right-radius: 8px; |
||||
border-bottom-right-radius: 8px; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.desktopNavContainer { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
@@media only screen and (max-width: 480px) { |
||||
.filtersContainer { |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.filterContainer { |
||||
flex-direction: column; |
||||
} |
||||
} |
||||
|
||||
.mobileFilters { |
||||
display: none; |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1024px) { |
||||
.mobileFilters { |
||||
display: block; |
||||
} |
||||
|
||||
.desktopFilters { |
||||
display: none; |
||||
} |
||||
|
||||
.desktopSpacer { |
||||
display: none; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[Inject] |
||||
public IEntityFilterService EntityFilterService { get; set; } |
||||
|
||||
protected override void OnInitialized() { } |
||||
|
||||
void OnChangeFaction(string clickedFaction) { |
||||
EntityFilterService.SelectFactionType(clickedFaction); |
||||
|
||||
StateHasChanged(); |
||||
} |
||||
|
||||
void OnChangeImmortal(string clickedImmortal) { |
||||
EntityFilterService.SelectImmortalType(clickedImmortal); |
||||
} |
||||
|
||||
void OnChangeEntity(string clickedEntity) { |
||||
EntityFilterService.SelectEntityType(clickedEntity); |
||||
} |
||||
|
||||
void OnFactionChanged(ChangeEventArgs e) { |
||||
EntityFilterService.SelectFactionType(e.Value.ToString()); |
||||
} |
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e) { |
||||
EntityFilterService.SelectImmortalType(e.Value.ToString()); |
||||
} |
||||
|
||||
|
||||
void OnEntityChanged(ChangeEventArgs e) { |
||||
EntityFilterService.SelectEntityType(e.Value.ToString()); |
||||
} |
||||
|
||||
|
||||
void OnSearchTextChanged(ChangeEventArgs e) { |
||||
EntityFilterService.EnterSearchText(e.Value.ToString()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,106 @@
|
||||
|
||||
.desktopFilters { |
||||
display: flex; |
||||
gap: 12px; |
||||
flex-direction: column; |
||||
justify-content: flex-start; |
||||
justify-items: flex-start; |
||||
top: 50px; |
||||
padding: 12px; |
||||
width: 100%; |
||||
left: 0px; |
||||
} |
||||
|
||||
.desktopFiltersContainer { |
||||
width: 75%; |
||||
min-width: 1000px; |
||||
margin: auto; |
||||
display: flex; |
||||
gap: 16px; |
||||
flex-direction: column; |
||||
justify-content: flex-start; |
||||
justify-items: flex-start; |
||||
} |
||||
|
||||
.filtersContainer { |
||||
display: flex; |
||||
gap: 16px; |
||||
} |
||||
|
||||
.filterContainer { |
||||
display: flex; |
||||
background-color: var(--background); |
||||
gap: 2px; |
||||
margin-right: auto; |
||||
border-radius: 8px; |
||||
} |
||||
|
||||
.choiceButton { |
||||
background-color: var(--primary); |
||||
color: white; |
||||
padding: 12px; |
||||
border: 1px solid var(--primary); |
||||
} |
||||
|
||||
.choiceButton:hover { |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
} |
||||
|
||||
.selected { |
||||
background-color: var(--secondary); |
||||
color: white; |
||||
font-style: normal; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.selected:hover { |
||||
background-color: var(--secondary-hover); |
||||
border-color: var(--secondary-border-hover); |
||||
} |
||||
|
||||
|
||||
.filterContainer .choiceButton:first-child { |
||||
border-top-left-radius: 8px; |
||||
border-bottom-left-radius: 8px; |
||||
} |
||||
|
||||
|
||||
.filterContainer .choiceButton:last-child { |
||||
border-top-right-radius: 8px; |
||||
border-bottom-right-radius: 8px; |
||||
} |
||||
|
||||
@media only screen and (max-width: 1025px) { |
||||
.desktopNavContainer { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
@media only screen and (max-width: 480px) { |
||||
.filtersContainer { |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.filterContainer { |
||||
flex-direction: column; |
||||
} |
||||
} |
||||
|
||||
.mobileFilters { |
||||
display: none; |
||||
} |
||||
|
||||
@media only screen and (max-width: 1024px) { |
||||
.mobileFilters { |
||||
display: block; |
||||
} |
||||
|
||||
.desktopFilters { |
||||
display: none; |
||||
} |
||||
|
||||
.desktopSpacer { |
||||
display: none; |
||||
} |
||||
} |
||||
@ -0,0 +1,272 @@
|
||||
@layout PageLayout |
||||
|
||||
@page "/harass-calculator" |
||||
|
||||
<LayoutMediumContentComponent> |
||||
<WebsiteTitleComponent>Harass Calculator</WebsiteTitleComponent> |
||||
|
||||
<PaperComponent> |
||||
Credit to Zard for deriving the formula. |
||||
</PaperComponent> |
||||
|
||||
<PaperComponent> |
||||
<LayoutRowComponent> |
||||
<LayoutColumnComponent> |
||||
<FormLayoutComponent> |
||||
<FormDisplayComponent Label="Cost of worker"> |
||||
<Display>@CostOfWorker</Display> |
||||
</FormDisplayComponent> |
||||
|
||||
<FormDisplayComponent Label="Alloy mined per second by worker"> |
||||
<Display>@AlloyMinedPerSecondByWorker</Display> |
||||
</FormDisplayComponent> |
||||
|
||||
<FormDisplayComponent Label="Time to produce worker"> |
||||
<Display>@TimeToProduceWorker</Display> |
||||
</FormDisplayComponent> |
||||
</FormLayoutComponent> |
||||
</LayoutColumnComponent> |
||||
|
||||
<LayoutColumnComponent> |
||||
<FormLayoutComponent> |
||||
<FormNumberComponent Min="0" |
||||
Value="@((int)NumberOfWorkersLostToHarass)" |
||||
OnChange="@(e => { NumberOfWorkersLostToHarass = int.Parse(e.Value.ToString()); Calculate();})"> |
||||
<FormLabelComponent>Number of workers lost to harass</FormLabelComponent> |
||||
</FormNumberComponent> |
||||
|
||||
<FormNumberComponent Min="0" |
||||
Value="@((int)NumberOfTownHallsExisting)" |
||||
OnChange="@(e => { NumberOfTownHallsExisting = int.Parse(e.Value.ToString()); Calculate();})"> |
||||
<FormLabelComponent>Number of townhalls existing</FormLabelComponent> |
||||
</FormNumberComponent> |
||||
|
||||
<FormNumberComponent Min="0" |
||||
Value="@((int)TravelTime)" |
||||
OnChange="@(e => { TravelTime = int.Parse(e.Value.ToString()); Calculate();})"> |
||||
<FormLabelComponent>Travel time</FormLabelComponent> |
||||
</FormNumberComponent> |
||||
|
||||
<FormDisplayComponent Label="Total alloy lost"> |
||||
<Display> |
||||
<div style="font-size: 1.5rem; font-weight: 800;"> |
||||
@TotalAlloyHarassment |
||||
</div> |
||||
</Display> |
||||
</FormDisplayComponent> |
||||
|
||||
|
||||
</FormLayoutComponent> |
||||
|
||||
<br/> |
||||
<div> |
||||
(<b>Worker replacement costs:</b> @WorkerReplacementCost()) |
||||
</div> |
||||
<div> |
||||
|
||||
(<b>Delayed mining time:</b> @DelayedMiningCost()) |
||||
</div> |
||||
|
||||
|
||||
</LayoutColumnComponent> |
||||
|
||||
|
||||
</LayoutRowComponent> |
||||
</PaperComponent> |
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
<PaperComponent> |
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What is this tool? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
The Harass Calculator allows you to calculate damage done to an enemy alloy line. For example, if you were to attack with Ichors, and kill 6 enemy workers, you can set the <b>Number of workers lost to harass</b> to 6. This would determine a loss of 741 alloy. Quite the large number. |
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
What can I learn from this? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
Well, let's assume you lost a full alloy line of workers, and have to take that 741 alloy cost (300 to rebuy the workers, and 441 in lost mining time.) |
||||
<br/><br/> |
||||
If you were to set the <b>Number of townhalls existing</b> to 2, the calculator will consider worker transfer micro. Allowing you to cut the total cost by roughly 315 alloy. However, that number isn't entirely accurate, you are also going to have to bump up the <b>Travel time</b> to account for the time it takes the transferred workers to arrive at the decimated alloy line. |
||||
<br/><br/> |
||||
Let's say it takes 10 seconds for workers to transfer from your second base. We can divide that number by 2, to represent our bases, and add those 5 additional seconds to <b>Travel time</b>, for the more accurate loss of 456 alloy (saving you 285 alloy.) <i>Which is much better than not transferring workers!</i> |
||||
|
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
Can I see the formula for the calculation? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
<br/> |
||||
<div class="mathContainer"> |
||||
<div> =c*m+r*g*(t+l) + </div> |
||||
|
||||
<MathLoopSumComponent> |
||||
<LoopStart><i>x</i> =1</LoopStart> |
||||
<LoopEnd> |
||||
⌊ |
||||
<MathDivisionComponent> |
||||
<Dividee>m</Dividee><Divider>a</Divider> |
||||
</MathDivisionComponent>⌋ |
||||
</LoopEnd> |
||||
<IndexSymbol> |
||||
<i>x</i> |
||||
</IndexSymbol> |
||||
</MathLoopSumComponent> |
||||
|
||||
<div style="width: 132px">g*<i>x</i>*(t+l)</div> |
||||
</div> |
||||
<br/> |
||||
<div style="font-family:monospace;"> |
||||
<div>c is CostOfWorker </div> |
||||
<div>m is NumberOfWorkersLostToHarass, <i>m for [M]otes</i></div> |
||||
<div>a is NumberOfTownHallsExisting, <i>a for [A]cropolis</i></div> |
||||
<div>r is m mod a is LeftOverWorkersToProduceCount()</div> |
||||
<div>g is AlloyMinedPerSecondByWorker</div> |
||||
<div>t is TimeToProduceWorker</div> |
||||
<div>l is TravelTime</div> |
||||
<div><i>x</i> is workerProductionIndex</div> |
||||
</div> |
||||
<br/><br/> |
||||
|
||||
</InfoAnswerComponent> |
||||
</InfoBodyComponent> |
||||
|
||||
|
||||
<InfoBodyComponent> |
||||
<InfoQuestionComponent> |
||||
Can I see the code for the calculation? |
||||
</InfoQuestionComponent> |
||||
<InfoAnswerComponent> |
||||
|
||||
<CodeComponent> |
||||
<div style="color: green;">//TotalAlloyHarassment is set after Calculate() function is called</div> |
||||
<div> |
||||
float TotalAlloyHarassment; |
||||
|
||||
float CostOfWorker = 50; |
||||
float AlloyMinedPerSecondByWorker = 1; |
||||
float TimeToProduceWorker = 20; |
||||
float TravelTime = 1; |
||||
float NumberOfWorkersLostToHarass = 1; |
||||
float NumberOfTownHallsExisting = 1; |
||||
|
||||
float SimultaneousProductionFloor() { |
||||
if (NumberOfTownHallsExisting <= 0 || NumberOfWorkersLostToHarass <= 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return (float)Math.Floor(NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass)); |
||||
} |
||||
float LeftOverWorkersToProduceCount() { |
||||
return NumberOfWorkersLostToHarass % (Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass)); |
||||
} |
||||
|
||||
float WorkerReplacementCost() { |
||||
return CostOfWorker * NumberOfWorkersLostToHarass; |
||||
} |
||||
|
||||
|
||||
float DelayedMiningCost() { |
||||
return TotalAlloyHarassment - WorkerReplacementCost(); |
||||
} |
||||
|
||||
void Calculate() { |
||||
TotalAlloyHarassment = WorkerReplacementCost(); |
||||
|
||||
for (var workerProductionIndex = 0; workerProductionIndex < SimultaneousProductionFloor(); workerProductionIndex++) { |
||||
TotalAlloyHarassment += AlloyMinedPerSecondByWorker * (TimeToProduceWorker + TravelTime) * (workerProductionIndex + 1); |
||||
} |
||||
|
||||
TotalAlloyHarassment += LeftOverWorkersToProduceCount() * (TimeToProduceWorker + TravelTime) * AlloyMinedPerSecondByWorker; |
||||
} |
||||
|
||||
|
||||
</div> |
||||
|
||||
</CodeComponent> |
||||
</InfoAnswerComponent> |
||||
|
||||
</InfoBodyComponent> |
||||
</PaperComponent> |
||||
|
||||
|
||||
</LayoutMediumContentComponent> |
||||
|
||||
<style> |
||||
.mathContainer { |
||||
font-family: monospace; |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: flex-start; |
||||
border: 1px black solid; |
||||
padding: 32px; |
||||
background-color: #1A1B1E |
||||
} |
||||
|
||||
@@media only screen and (max-width: 1025px) { |
||||
.mathContainer { |
||||
padding-left: 2px; |
||||
padding-right: 2px; |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
@code { |
||||
float TotalAlloyHarassment; |
||||
|
||||
readonly float CostOfWorker = 50; |
||||
readonly float AlloyMinedPerSecondByWorker = 1; |
||||
readonly float TimeToProduceWorker = 20; |
||||
float TravelTime = 1; |
||||
float NumberOfWorkersLostToHarass = 1; |
||||
float NumberOfTownHallsExisting = 1; |
||||
|
||||
float SimultaneousProductionFloor() { |
||||
if (NumberOfTownHallsExisting <= 0 || NumberOfWorkersLostToHarass <= 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return (float)Math.Floor(NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass)); |
||||
} |
||||
|
||||
float LeftOverWorkersToProduceCount() { |
||||
return NumberOfWorkersLostToHarass % Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass); |
||||
} |
||||
|
||||
float WorkerReplacementCost() { |
||||
return CostOfWorker * NumberOfWorkersLostToHarass; |
||||
} |
||||
|
||||
|
||||
float DelayedMiningCost() { |
||||
return TotalAlloyHarassment - WorkerReplacementCost(); |
||||
} |
||||
|
||||
void Calculate() { |
||||
TotalAlloyHarassment = WorkerReplacementCost(); |
||||
|
||||
for (var workerProductionIndex = 0; workerProductionIndex < SimultaneousProductionFloor(); workerProductionIndex++) { |
||||
TotalAlloyHarassment += AlloyMinedPerSecondByWorker * (TimeToProduceWorker + TravelTime) * (workerProductionIndex + 1); |
||||
} |
||||
|
||||
TotalAlloyHarassment += LeftOverWorkersToProduceCount() * (TimeToProduceWorker + TravelTime) * AlloyMinedPerSecondByWorker; |
||||
} |
||||
|
||||
protected override void OnInitialized() { |
||||
Calculate(); |
||||
} |
||||
|
||||
void ValueChanged(float test) { |
||||
Calculate(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,149 @@
|
||||
@layout PageLayout; |
||||
|
||||
@page "/immortal-home" |
||||
|
||||
<LayoutMediumContentComponent> |
||||
<div class="mainContainer"> |
||||
<div class="mainTitle"> |
||||
Fan Reference |
||||
</div> |
||||
|
||||
<div> |
||||
Refer to various aspects of "IMMORTAL: Gates of Pyre" from this external reference! |
||||
</div> |
||||
</div> |
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
<div class="herosContainer"> |
||||
<div class="hero"> |
||||
<div class="heroTitle"> |
||||
Database |
||||
</div> |
||||
<img src="image/hero/Database.png" class="heroImage"/> |
||||
<NavLink Href="/database" class="heroCallToAction"> |
||||
Review the units! |
||||
</NavLink> |
||||
</div> |
||||
|
||||
|
||||
<div class="hero"> |
||||
<div class="heroTitle"> |
||||
Build Calculator |
||||
</div> |
||||
<img src="image/hero/Build.png" class="heroImage"/> |
||||
<NavLink Href="/build-calculator" class="heroCallToAction"> |
||||
Make a build! |
||||
</NavLink> |
||||
</div> |
||||
|
||||
|
||||
<div class="hero"> |
||||
<div class="heroTitle"> |
||||
Notes |
||||
</div> |
||||
<img src="image/hero/Notes.png" class="heroImage"/> |
||||
<NavLink Href="/notes" class="heroCallToAction"> |
||||
Read some notes! |
||||
</NavLink> |
||||
</div> |
||||
|
||||
|
||||
<div class="hero"> |
||||
<div class="heroTitle"> |
||||
Streams |
||||
</div> |
||||
<img src="image/hero/Streams.png" class="heroImage"/> |
||||
<NavLink Href="/streams" class="heroCallToAction"> |
||||
Watch live development! |
||||
</NavLink> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<ContentDividerComponent></ContentDividerComponent> |
||||
|
||||
<AlertComponent> |
||||
<Title>Under Construction</Title> |
||||
<Message>Website is still being made. Check out <NavLink Href="/immortal-roadmap">Road Map</NavLink> for future plans, <NavLink Href="/immortal-agile">Agile</NavLink> for present tasks, and <NavLink Href="/immortal-changelog">Change Log</NavLink> for past changes.</Message> |
||||
|
||||
</AlertComponent> |
||||
|
||||
</LayoutMediumContentComponent> |
||||
|
||||
<style> |
||||
.mainContainer { |
||||
padding-bottom: 32px; |
||||
} |
||||
|
||||
.mainTitle { |
||||
font-size: 2.2rem; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.quoteContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 8px; |
||||
max-width: 600px; |
||||
margin: auto; |
||||
} |
||||
|
||||
|
||||
|
||||
.quoteTitle { |
||||
font-weight: 800; |
||||
margin-bottom: 8px; |
||||
} |
||||
|
||||
.quoteText { |
||||
margin: auto; |
||||
font-style: italic; |
||||
} |
||||
|
||||
.herosContainer { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
gap: 64px; |
||||
justify-content: center; |
||||
} |
||||
|
||||
.hero { |
||||
padding: 32px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 32px; |
||||
} |
||||
|
||||
|
||||
.heroTitle { |
||||
font-weight: 800; |
||||
font-size: 1.3rem; |
||||
margin: auto; |
||||
} |
||||
|
||||
.heroImage { |
||||
border: 1px solid rgba(0,0,0,0.5); |
||||
box-shadow: 2px 2px 2px rgba(0,0,0,0.5); |
||||
height: 400px; |
||||
width: 400px; |
||||
margin: auto; |
||||
} |
||||
|
||||
.heroCallToAction { |
||||
font-weight: 700; |
||||
font-size: 1.1rem; |
||||
margin: auto; |
||||
background-color: var(--primary); |
||||
border: 1px solid var(--primary); |
||||
padding: 16px; |
||||
cursor: pointer; |
||||
color: white; |
||||
} |
||||
|
||||
.heroCallToAction:hover { |
||||
background-color: var(--primary-hover); |
||||
border-color: var(--primary-border-hover); |
||||
} |
||||
|
||||
</style> |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue