Initial Commit
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# .NET
|
||||
bin/
|
||||
obj/
|
||||
*.user
|
||||
*.suo
|
||||
*.sln.docstates
|
||||
*.userprefs
|
||||
packages/
|
||||
*.nupkg
|
||||
|
||||
# .NET Aspire
|
||||
AppHost/
|
||||
|
||||
# IDE - Rider
|
||||
.idea/
|
||||
*.sln.ide/
|
||||
|
||||
# IDE - VS
|
||||
.vs/
|
||||
*.csproj.user
|
||||
*.dbmdl
|
||||
*.jfm
|
||||
|
||||
# IDE - VS Code
|
||||
.vscode/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# NuGet
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Node
|
||||
node_modules/
|
||||
|
||||
# Coverlet
|
||||
*.coverage
|
||||
*.coverage.xml
|
||||
|
||||
# Publish
|
||||
*.pubxml
|
||||
publish/
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DefineConstants>TRACE;NO_SQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>TRACE;NO_SQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.28.1"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.14"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.14"/>
|
||||
</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,26 @@
|
||||
<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; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
@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; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
bool isOnDev;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
isOnDev = NavigationManager.BaseUri.Contains("https://localhost");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<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; } = default!;
|
||||
|
||||
[Parameter] public string Title { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<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;
|
||||
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
padding-bottom: 20px;
|
||||
padding-top: 20px;
|
||||
white-space: break-spaces;
|
||||
z-index: 2147483647;
|
||||
|
||||
background-color: var(--info-secondary);
|
||||
border: 1px solid var(--info-secondary-border);
|
||||
border-radius: 2px;
|
||||
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
|
||||
.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; } = default!;
|
||||
|
||||
[Parameter] public string InfoText { get; set; } = default!;
|
||||
|
||||
[Parameter] public int? Margin { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<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; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment Description { get; set; } = default!;
|
||||
|
||||
|
||||
[Parameter] public RenderFragment Example { get; set; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment Usage { get; set; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment Code { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<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; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<div class="panelDisplay">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.panelDisplay {
|
||||
border: 2px solid var(--paper-border);
|
||||
padding: 20px;
|
||||
background-color: var(--paper);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="paperDisplay">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.paperDisplay {
|
||||
padding-top: 24px;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
padding-bottom: 24px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border: 4px solid var(--paper-border);
|
||||
background-color: var(--paper);
|
||||
box-shadow: 0px 6px var(--paper-border);
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
[Parameter] public string Title { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<div class="alertContainer @Type.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.ToLower() {
|
||||
background-color: var(--severity-warning-color);
|
||||
border-color: var(--severity-warning-border-color);
|
||||
}
|
||||
|
||||
.alertContainer.@SeverityType.Error.ToLower() {
|
||||
background-color: var(--severity-error-color);
|
||||
border-color: var(--severity-error-border-color);
|
||||
}
|
||||
|
||||
.alertContainer.@SeverityType.Information.ToLower() {
|
||||
background-color: var(--severity-information-color);
|
||||
border-color: var(--severity-information-border-color);
|
||||
}
|
||||
|
||||
.alertContainer.@SeverityType.Success.ToLower() {
|
||||
background-color: var(--severity-success-color);
|
||||
border-color: var(--severity-success-border-color);
|
||||
}
|
||||
|
||||
.alertTitle {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment? Title { get; set; }
|
||||
|
||||
[Parameter] public RenderFragment? Message { get; set; }
|
||||
|
||||
[Parameter] public string 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,100 @@
|
||||
@inject IToastService toastService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
@if (Toast == null)
|
||||
{
|
||||
<div>Add toast object...</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div onclick="@Dismiss" style="opacity: @Opacity()" class="toastContainer @Toast.SeverityType.ToLower()">
|
||||
<div class="toastTitle">
|
||||
@Toast.Title
|
||||
</div>
|
||||
<div>
|
||||
@Toast.Message
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<style>
|
||||
.toastContainer {
|
||||
border: 4px solid;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-items: stretch;
|
||||
width: 250px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.@SeverityType.Warning.ToLower() {
|
||||
background-color: var(--severity-warning-color);
|
||||
border-color: var(--severity-warning-border-color);
|
||||
}
|
||||
|
||||
.@SeverityType.Error.ToLower() {
|
||||
background-color: var(--severity-error-color);
|
||||
border-color: var(--severity-error-border-color);
|
||||
}
|
||||
|
||||
.@SeverityType.Information.ToLower() {
|
||||
background-color: var(--severity-information-color);
|
||||
border-color: var(--severity-information-border-color);
|
||||
}
|
||||
|
||||
.@SeverityType.Success.ToLower() {
|
||||
background-color: var(--severity-success-color);
|
||||
border-color: var(--severity-success-border-color);
|
||||
}
|
||||
|
||||
.toastTitle {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public ToastModel? Toast { get; set; }
|
||||
|
||||
private readonly float removalTime = 1300;
|
||||
private readonly float fadeoutTime = 1200;
|
||||
|
||||
private float Opacity()
|
||||
{
|
||||
if (Toast!.Age < fadeoutTime)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1.0f - (Toast.Age - fadeoutTime) / (removalTime - fadeoutTime);
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
toastService.Subscribe(OnUpdate);
|
||||
}
|
||||
|
||||
void Dismiss()
|
||||
{
|
||||
toastService.RemoveToast(Toast!);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
toastService.Unsubscribe(OnUpdate);
|
||||
}
|
||||
|
||||
void OnUpdate()
|
||||
{
|
||||
if (Toast!.Age > removalTime)
|
||||
{
|
||||
toastService.RemoveToast(Toast);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<div class="formContainer">
|
||||
<div class="formTextContainer">
|
||||
<div class="formLabel">
|
||||
@Label:
|
||||
</div>
|
||||
<input readonly="@ReadOnly"
|
||||
class="formCheckboxInput"
|
||||
type="checkbox"
|
||||
id="@labelId"
|
||||
checked="@Value"
|
||||
@onchange="OnChange"
|
||||
@oninput="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()
|
||||
{
|
||||
base.OnInitialized();
|
||||
labelId = Label.ToLower().Replace(" ", "_");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<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; } = default!;
|
||||
|
||||
[Parameter] public string Info { get; set; } = default!;
|
||||
|
||||
[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,30 @@
|
||||
@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,163 @@
|
||||
@using Model.MemoryTester
|
||||
@using Services.Immortal
|
||||
@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 ?? string.Empty) == 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; } = default!;
|
||||
|
||||
[Parameter] public bool IsSubmitted { get; set; }
|
||||
|
||||
|
||||
private string? guess = "";
|
||||
|
||||
|
||||
private string labelId = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.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,11 @@
|
||||
<div style="font-size:0.8rem; font-style:italic;">
|
||||
<i>
|
||||
@ChildContent
|
||||
</i>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<div style="font-weight:800">
|
||||
@ChildContent:
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<div style="display: flex; gap: 16px; width: 100%; flex-direction: column;">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<div class="formNumberContainer">
|
||||
@if (FormLabelComponent != null)
|
||||
{
|
||||
<FormLabelComponent>@FormLabelComponent</FormLabelComponent>
|
||||
}
|
||||
<div>
|
||||
<input readonly="@ReadOnly"
|
||||
id="@Id"
|
||||
class="numberInput"
|
||||
type="number"
|
||||
min="@Min"
|
||||
max="@Max"
|
||||
value="@Value"
|
||||
@onchange="OnInputChanged"/>
|
||||
</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 string Id { get; set; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment? FormInfoComponent { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<ChangeEventArgs> OnChange { get; set; }
|
||||
|
||||
void OnInputChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
var valueWas = Value;
|
||||
var newValue = int.Parse(changeEventArgs.Value!.ToString()!);
|
||||
|
||||
if (newValue > Max)
|
||||
{
|
||||
newValue = Max;
|
||||
}
|
||||
|
||||
if (newValue < Min)
|
||||
{
|
||||
newValue = Min;
|
||||
}
|
||||
|
||||
if (valueWas != newValue)
|
||||
{
|
||||
Value = newValue;
|
||||
changeEventArgs.Value = newValue;
|
||||
OnChange.InvokeAsync(changeEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter] public bool ReadOnly { get; set; }
|
||||
|
||||
[Parameter] public int Value { get; set; }
|
||||
|
||||
[Parameter] public int Min { get; set; }
|
||||
|
||||
[Parameter] public int Max { get; set; } = 2048;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<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,85 @@
|
||||
<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()
|
||||
{
|
||||
base.OnInitialized();
|
||||
labelId = Label.ToLower().Replace(" ", "_");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<div class="formContainer">
|
||||
@if (Label != "")
|
||||
{
|
||||
<div class="formLabel">
|
||||
@Label
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<input readonly="@ReadOnly"
|
||||
class="formTextInput"
|
||||
placeholder="@Placeholder"
|
||||
type="text"
|
||||
value="@Value"
|
||||
id="@Id"
|
||||
@onfocus="OnFocus"
|
||||
@oninput="OnInput"
|
||||
@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 Id { get; set; } = "";
|
||||
|
||||
[Parameter] public string Label { get; set; } = "";
|
||||
|
||||
[Parameter] public string Info { get; set; } = "";
|
||||
|
||||
[Parameter] public string Placeholder { get; set; } = "";
|
||||
|
||||
[Parameter] public EventCallback<ChangeEventArgs> OnInput { get; set; }
|
||||
|
||||
|
||||
[Parameter] public EventCallback<ChangeEventArgs> OnChange { get; set; }
|
||||
|
||||
[Parameter] public EventCallback OnFocus { get; set; }
|
||||
|
||||
|
||||
[Parameter] public bool ReadOnly { get; set; }
|
||||
|
||||
[Parameter] public string Value { get; set; } = "";
|
||||
|
||||
private string labelId = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
labelId = Label.ToLower().Replace(" ", "_");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<div class="formContainer">
|
||||
<div class="formTextContainer">
|
||||
<div class="formLabel">
|
||||
@Label:
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input readonly="@ReadOnly"
|
||||
type="checkbox"
|
||||
id="@labelId"
|
||||
class="@ClassStyle"
|
||||
checked="@Value"
|
||||
@oninput="OnChange"/>
|
||||
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</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;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--paper-border);
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.checked + .slider {
|
||||
background-color: #7838df;
|
||||
}
|
||||
|
||||
.checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
</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 = "";
|
||||
|
||||
private string ClassStyle => Value ? "checked" : "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.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,50 @@
|
||||
<button class="buttonContainer @MyButtonType.ToString().ToLower()" @onclick="ButtonClicked">@ChildContent</button>
|
||||
|
||||
<style>
|
||||
.buttonContainer {
|
||||
padding: 16px;
|
||||
border: 1px solid;
|
||||
border-radius: 8px;
|
||||
font-weight: 800;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.@(MyButtonType.Primary.ToString().ToLower()) {
|
||||
border-color: var(--primary);
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
.@MyButtonType.Secondary.ToString().ToLower() {
|
||||
border-color: var(--secondary);
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
||||
.@MyButtonType.Primary.ToString().ToLower():hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.@MyButtonType.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; } = default!;
|
||||
|
||||
[Parameter] public EventCallback<EventArgs> OnClick { get; set; }
|
||||
|
||||
[Parameter] public MyButtonType MyButtonType { get; set; }
|
||||
|
||||
private void ButtonClicked(EventArgs eventArgs)
|
||||
{
|
||||
OnClick.InvokeAsync(eventArgs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<div class="groupButtonContainerContainer">
|
||||
<div class="groupButtonContainer">
|
||||
@foreach (var choice in Choices)
|
||||
{
|
||||
var styleClass = "";
|
||||
if (choice.Equals(Choice))
|
||||
{
|
||||
styleClass = "selected";
|
||||
}
|
||||
|
||||
<button @onclick="@(e => OnChangeChoice(choice))" class="groupChoiceButton @styleClass">@choice</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
|
||||
.groupButtonContainerContainer {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
justify-items: flex-start;
|
||||
}
|
||||
|
||||
.groupButtonContainer {
|
||||
display: flex;
|
||||
background-color: var(--background);
|
||||
gap: 2px;
|
||||
margin-right: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.groupChoiceButton {
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--primary);
|
||||
}
|
||||
|
||||
.groupChoiceButton: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);
|
||||
}
|
||||
|
||||
|
||||
.groupButtonContainer .groupChoiceButton:first-child {
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
.groupButtonContainer .groupChoiceButton:last-child {
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public string Choice { get; set; } = default!;
|
||||
|
||||
[Parameter] public List<string> Choices { get; set; } = default!;
|
||||
|
||||
[Parameter] public EventCallback<string> OnClick { get; set; }
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
void OnChangeChoice(string choice)
|
||||
{
|
||||
Choice = choice;
|
||||
OnClick.InvokeAsync(choice);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<a href="@Href" target="_blank" class="codeLinkButton">
|
||||
View on GitHub <i class="fa-brands fa-github" style="font-size: 24px; margin-left: 5px;"></i>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.codeLinkButton {
|
||||
color: white;
|
||||
background-color: var(--info);
|
||||
border: 2px solid var(--info-border);
|
||||
padding: 16px;
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.codeLinkButton:hover {
|
||||
color: white;
|
||||
background-color: var(--info-hover);
|
||||
border: 2px solid var(--info-border-hover);
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public string Href { get; set; } = "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<a href="@Href" target="_blank" class="editLinkButton">
|
||||
Edit on GitHub
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.editLinkButton {
|
||||
color: white;
|
||||
background-color: var(--info);
|
||||
border: 1px solid var(--info-border);
|
||||
padding: 16px;
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
width: 180px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.editLinkButton:hover {
|
||||
color: white;
|
||||
background-color: var(--info-hover);
|
||||
border: 2px solid var(--info-border-hover);
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public string Href { get; set; } = "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
@using Model.Entity
|
||||
@using Model.Entity.Data
|
||||
@inject IEntityDialogService entityDialogService
|
||||
|
||||
|
||||
@if (EntityId == null)
|
||||
{
|
||||
<div>Add a entity</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="entityLabel @Entity.Descriptive.ToLower()" @onclick="EntityLabelClicked">@Entity.Info().Name</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public string EntityId { get; set; } = default!;
|
||||
|
||||
private EntityModel Entity => EntityData.Get()[EntityId];
|
||||
|
||||
void EntityLabelClicked()
|
||||
{
|
||||
entityDialogService.AddDialog(EntityId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
.entityLabel {
|
||||
font-weight: bolder;
|
||||
box-shadow: 1px 1px 0 0 rgba(0, 0, 0, 0.2);
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.entityLabel:hover {
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
.army {
|
||||
color: cyan;
|
||||
}
|
||||
|
||||
.building {
|
||||
color: greenyellow;
|
||||
}
|
||||
|
||||
.ability {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.passive {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<a href="@Href" class="linkButtonContainer">
|
||||
@ChildContent
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.linkButtonContainer {
|
||||
padding: 16px;
|
||||
border: 1px solid;
|
||||
border-radius: 8px;
|
||||
font-weight: 800;
|
||||
font-size: 1.2rem;
|
||||
border-color: var(--primary);
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
.linkButtonContainer:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
color: white;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
|
||||
[Parameter] public string Href { get; set; } = "";
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Components.Inputs;
|
||||
|
||||
public enum MyButtonType
|
||||
{
|
||||
Primary, // Positive Actions
|
||||
Secondary // Destruction Action
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
@inject ISearchService SearchService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
<button id="@Id" class="searchButtonContainer" @onclick="ButtonClicked">
|
||||
<div class="searchText">
|
||||
<i class="fa-solid fa-magnifying-glass" style="margin-left: 3px; margin-right: 6px;"></i> Search...
|
||||
</div>
|
||||
<div class="searchHotkey">
|
||||
@if (IsMac)
|
||||
{
|
||||
<span><i class="fa-solid fa-command"></i>K</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>CTRL + K</span>
|
||||
}
|
||||
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
.searchButtonContainer {
|
||||
background-color: var(--primary);
|
||||
border: 2px solid var(--primary-border);
|
||||
border-radius: 8px;
|
||||
font-weight: 800;
|
||||
width: 350px;
|
||||
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.searchHotkey {
|
||||
padding: 4px;
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
[Parameter] public string Id { get; set; } = default!;
|
||||
|
||||
private string _userAgent = "";
|
||||
|
||||
bool IsMac => _userAgent.Contains("Mac OS");
|
||||
|
||||
private void ButtonClicked(EventArgs eventArgs)
|
||||
{
|
||||
SearchService.Show();
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_userAgent = await JsRuntime.InvokeAsync<string>("getUserAgent");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
@inject ISearchService SearchService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
<button id="@Id" class="searchIconButtonContainer" @onclick="ButtonClicked">
|
||||
<div class="searchIcon">
|
||||
<i class="fa-solid fa-magnifying-glass"></i>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
.searchIconButtonContainer {
|
||||
border-radius: 8px;
|
||||
font-weight: 800;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.searchIcon {
|
||||
font-size: 28px;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
[Parameter] public string Id { get; set; } = default!;
|
||||
|
||||
private void ButtonClicked(EventArgs eventArgs)
|
||||
{
|
||||
SearchService.Show();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,17 @@
|
||||
<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,38 @@
|
||||
<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,38 @@
|
||||
<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,34 @@
|
||||
<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,26 @@
|
||||
<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,56 @@
|
||||
<div class="layoutWithSidebar">
|
||||
<div class="layoutSidebar">
|
||||
@Sidebar
|
||||
</div>
|
||||
<div class="layoutContent">
|
||||
@Content
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style scoped>
|
||||
.layoutWithSidebar {
|
||||
display: grid;
|
||||
|
||||
gap: 16px;
|
||||
width: 65%;
|
||||
min-width: 1000px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 30px;
|
||||
|
||||
grid-template-columns: 412px 1fr;
|
||||
}
|
||||
|
||||
.layoutSidebar {
|
||||
background: var(--paper);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.layoutContent {
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.layoutWithSidebar {
|
||||
flex-direction: column-reverse;
|
||||
width: 100%;
|
||||
min-width: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@media only screen and (min-width: 1024px) {
|
||||
.layoutWithSidebar {
|
||||
margin-top: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment Sidebar { get; set; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment Content { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<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; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<h1 class="title">
|
||||
@ChildContent
|
||||
</h1>
|
||||
|
||||
|
||||
<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,17 @@
|
||||
@using Markdig
|
||||
@((MarkupString)MarkdownText)
|
||||
|
||||
@code {
|
||||
|
||||
[Inject] protected HttpClient Http { get; set; } = default!;
|
||||
|
||||
[Parameter] public string MarkdownFileName { get; set; } = default!;
|
||||
|
||||
private string MarkdownText { get; set; } = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
MarkdownText = Markdown.ToHtml(await Http.GetStringAsync($"markdown/{MarkdownFileName}.md"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
@inherits LayoutComponentBase
|
||||
@inject INavigationService NavigationService
|
||||
@implements IDisposable
|
||||
|
||||
@{
|
||||
var visibleStyle = NavigationService.GetNavigationSectionId() > 0 ? "clickOffVisible" : "";
|
||||
}
|
||||
|
||||
<div onclick="@MenuClosed" class="clickOffBackground @visibleStyle">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="desktopNavContainer">
|
||||
<div class="menuHeader">
|
||||
<NavLink id="desktop-homeLink" href="/" class="websiteTitle">
|
||||
<i class="fa-solid fa-house" style="margin-right: 4px;"></i> IGP Fan Reference
|
||||
</NavLink>
|
||||
|
||||
<div class="sectionNavs">
|
||||
@foreach (var webSection in WebSections)
|
||||
{
|
||||
var isSelected = NavigationService.GetNavigationSectionId().Equals(webSection.Id);
|
||||
var sectionButtonStyle = "sectionButton";
|
||||
if (isSelected)
|
||||
{
|
||||
sectionButtonStyle += " sectionButtonSelected";
|
||||
}
|
||||
|
||||
<div class="sectionNav">
|
||||
|
||||
<button onclick="@(() => { MenuClicked(webSection.Id); })" class="@sectionButtonStyle">
|
||||
<i class="fa-solid @webSection.Icon"></i>
|
||||
@if (!webSection.OnlyIcon)
|
||||
{
|
||||
<span style="margin-left: 12px">@webSection.Name</span>
|
||||
}
|
||||
</button>
|
||||
@if (isSelected)
|
||||
{
|
||||
<div class="navMenuPosition">
|
||||
<div class="navMenuContainer">
|
||||
<DesktopNavSectionComponent Section="@webSection"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<SearchButtonComponent Id="desktop-searchButton"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.clickOffBackground {
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.clickOffBackground.clickOffVisible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.sectionButton {
|
||||
cursor: pointer;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
z-index: 50000;
|
||||
}
|
||||
|
||||
.desktopNavContainer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 40px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.menuHeader {
|
||||
border-bottom: 4px solid black;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
|
||||
display: flex;
|
||||
background-color: var(--accent);
|
||||
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.sectionNavs {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sectionNav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.websiteTitle {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.navMenuPosition {
|
||||
position: relative;
|
||||
top: 18px;
|
||||
left: calc(-50% + -330px / 2);
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.navMenuContainer {
|
||||
width: 330px;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
background-color: rgba(22, 22, 24, 0.95);
|
||||
border: 1px solid black;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sectionButtonSelected {
|
||||
box-shadow: 0 2px 3px black;
|
||||
background-color: var(--info);
|
||||
transform: translateY(-1px) scale(1.08);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.desktopNavContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 480px) {
|
||||
.desktopNavContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public List<WebSectionModel> WebSections { get; set; } = default!;
|
||||
|
||||
[Parameter] public List<WebPageModel> WebPages { get; set; } = default!;
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
NavigationService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
NavigationService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void MenuClicked(int menuName)
|
||||
{
|
||||
NavigationService.ChangeNavigationSectionId(menuName);
|
||||
}
|
||||
|
||||
void MenuClosed()
|
||||
{
|
||||
NavigationService.ChangeNavigationSectionId(-1);
|
||||
}
|
||||
|
||||
void HoverOut(MouseEventArgs mouseEventArgs)
|
||||
{
|
||||
NavigationService.ChangeNavigationState(NavigationStateType.Default);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
@using Components.Utils
|
||||
@inject INavigationService NavigationService;
|
||||
@inject NavigationManager NavigationManager;
|
||||
|
||||
@if (isOnPage)
|
||||
{
|
||||
<NavLink href="@Page.Href" class="desktopNavLink navSelected">
|
||||
<div class="navName">
|
||||
@Page.Name
|
||||
</div>
|
||||
</NavLink>
|
||||
}
|
||||
else
|
||||
{
|
||||
<NavLink target="@Links.GetTarget(Page.Href)"
|
||||
@onclick="() => { NavigationService.ChangeNavigationState(NavigationStateType.Default); NavigationService.ChangeNavigationSectionId(-1); }"
|
||||
href="@Page.Href" class="desktopNavLink">
|
||||
<div class="navName">
|
||||
@Page.Name
|
||||
</div>
|
||||
</NavLink>
|
||||
}
|
||||
|
||||
<style>
|
||||
|
||||
.navName {
|
||||
margin: auto;
|
||||
color: white;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.desktopNavLink {
|
||||
cursor: pointer;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
background-color: var(--primary);
|
||||
border: 1px solid var(--primary);
|
||||
}
|
||||
|
||||
.desktopNavLink:first-of-type {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.desktopNavLink:last-of-type {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.desktopNavLink: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; } = default!;
|
||||
|
||||
bool isOnPage;
|
||||
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
var uri = NavigationManager.Uri.Remove(0, NavigationManager.BaseUri.Count()).ToLower();
|
||||
|
||||
isOnPage = Page.Href.ToLower().Equals(uri);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
void OnNavigationChanged()
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnBack()
|
||||
{
|
||||
NavigationService.Back();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<div class="sectionContainer">
|
||||
@foreach (var childPage in Section.WebPageModels)
|
||||
{
|
||||
if (childPage.IsPrivate.Equals("True"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
<DesktopNavLinkComponent Page=childPage></DesktopNavLinkComponent>
|
||||
}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sectionContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public WebSectionModel Section { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<div class="mobileFooter">
|
||||
<div class="mobileNavSectionsContainer">
|
||||
@foreach (var webSection in WebSections)
|
||||
{
|
||||
<div class="mobileNavSectionButton" @onclick="() => OnSectionClicked(webSection)"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true">
|
||||
<div class="mobileNavSectionButtonText">
|
||||
<i class="fa-solid @webSection.Icon" style="font-size: 28px;"></i>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<SearchIconButtonComponent/>
|
||||
</div>
|
||||
|
||||
<div class="fullPageButton @(selectedSection != null)" @onclick="OnPageClicked" @onclick:stopPropagation="false"
|
||||
@onclick:preventDefault="false">
|
||||
</div>
|
||||
|
||||
@if (selectedSection != null)
|
||||
{
|
||||
List<WebPageModel?> webPages = (from page in WebPages
|
||||
where page.WebSectionModelId == selectedSection.Id
|
||||
select page).ToList()!;
|
||||
|
||||
<div class="mobileNavPagesContainer">
|
||||
@foreach (var webPage in webPages)
|
||||
{
|
||||
if (webPage!.IsPrivate.Equals("True"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
<div class="mobileNavPageButton" @onclick="() => OnPageLinkClicked(webPage)"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true">
|
||||
<div class="mobileNavPageButtonText">
|
||||
@webPage.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;
|
||||
border-radius: 2px;
|
||||
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 {
|
||||
#if NO_SQL
|
||||
[Parameter] public List<WebSectionModel> WebSections { get; set; } = default!;
|
||||
|
||||
[Parameter] public List<WebPageModel> WebPages { get; set; } = default!;
|
||||
|
||||
#else
|
||||
[Parameter]
|
||||
public DbSet<WebSectionModel> WebSections { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public DbSet<WebPageModel> WebPages { get; set; }
|
||||
#endif
|
||||
|
||||
[Inject] public NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
|
||||
private WebSectionModel? selectedSection;
|
||||
private 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,184 @@
|
||||
@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="tabletButtons">
|
||||
|
||||
<SearchButtonComponent/>
|
||||
<div class="tabletButton">
|
||||
<div class="tabletMenuTitle">
|
||||
<i class="fa-solid fa-bars" style="font-size: 32px; margin:auto"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="fullPageButton @navOpen" @onclick="OnNavClicked" @onclick:stopPropagation="false"
|
||||
@onclick:preventDefault="false">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="tabletNav @navOpen">
|
||||
@foreach (var webSection in WebSections)
|
||||
{
|
||||
var pages = (from page in WebPages
|
||||
where page.WebSectionModelId == webSection.Id
|
||||
select page).ToList();
|
||||
|
||||
<div>
|
||||
<div>
|
||||
@webSection.Name
|
||||
</div>
|
||||
|
||||
<div class="tabletNavItems">
|
||||
@foreach (var webPage in pages)
|
||||
{
|
||||
if (webPage.IsPrivate.Equals("True"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
<NavLink href="@webPage.Href" class="tabletNavItem" @onclick="OnPageClicked">
|
||||
@webPage.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;
|
||||
}
|
||||
|
||||
.tabletButtons {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
|
||||
.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 {
|
||||
|
||||
#if NO_SQL
|
||||
[Parameter] public List<WebSectionModel> WebSections { get; set; } = default!;
|
||||
|
||||
[Parameter] public List<WebPageModel> WebPages { get; set; } = default!;
|
||||
|
||||
#else
|
||||
[Parameter]
|
||||
public DbSet<WebSectionModel> WebSections { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public DbSet<WebPageModel> WebPages { get; set; }
|
||||
#endif
|
||||
|
||||
|
||||
bool navOpen = true;
|
||||
|
||||
void OnNavClicked(EventArgs eventArgs)
|
||||
{
|
||||
navOpen = !navOpen;
|
||||
}
|
||||
|
||||
|
||||
void OnPageClicked(EventArgs eventArgs)
|
||||
{
|
||||
navOpen = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
@if (isDisplayable)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
[Parameter] public WebDeploymentType DeploymentType { get; set; }
|
||||
|
||||
[Inject] public NavigationManager MyNavigationManager { get; set; } = default!;
|
||||
|
||||
bool isDisplayable;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
isDisplayable = DeploymentType == WebDeploymentModel.DeploymentType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@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; } = default!;
|
||||
|
||||
[Inject] public NavigationManager MyNavigationManager { get; set; } = default!;
|
||||
|
||||
bool isDisplayable;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
var page = MyNavigationManager.Uri.Remove(0, MyNavigationManager.BaseUri.Length);
|
||||
isDisplayable = WebDeploymentModel.Get().Contains(page);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<div class="footerContainer" xmlns="http://www.w3.org/1999/html">
|
||||
<div class="footerDivider"></div>
|
||||
|
||||
<div class="footerDisclaimer">
|
||||
This website is fan-made and not affiliated with <b>SunSpear Games</b> in any way.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.footerIcon {
|
||||
font-size: 24px;
|
||||
padding: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 6px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.footerIcon:hover {
|
||||
color: #8fc5ff;
|
||||
background-color: rgba(200, 200, 255, 0.1);
|
||||
border: 2px solid rgba(140, 140, 255, 0.4);
|
||||
}
|
||||
|
||||
|
||||
.footerContainer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 102px;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.footerSocials {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.footerDivider {
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
height: 1px;
|
||||
width: 128px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
.footerLastUpdated {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.footerDisclaimer {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,4 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
|
||||
@Body
|
||||
@@ -0,0 +1,17 @@
|
||||
<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; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment Divider { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<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; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment LoopStart { get; set; } = default!;
|
||||
|
||||
[Parameter] public RenderFragment IndexSymbol { get; set; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<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; } = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Components.Utils;
|
||||
|
||||
public static class Links
|
||||
{
|
||||
public static string GetTarget(string link)
|
||||
{
|
||||
if (link.StartsWith("https://")) return "_blank";
|
||||
|
||||
return "_self";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@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 Model.Feedback
|
||||
@using Model.Website
|
||||
@using Model.Website.Enums
|
||||
@using Services
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using System.Text
|
||||
@using System.Text.Json
|
||||
@using System.Threading.Tasks;
|
||||
@using System.Timers;
|
||||
@using System;
|
||||
@using YamlDotNet.Serialization
|
||||
@using Components.Inputs;
|
||||
@@ -0,0 +1,91 @@
|
||||
@inject IStorageService StorageService
|
||||
@inject IPermissionService PermissionService
|
||||
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
@if (isLoaded)
|
||||
{
|
||||
<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>
|
||||
|
||||
<EntityDialogPortal/>
|
||||
<ToastPortal/>
|
||||
<SearchPortal/>
|
||||
<ConfirmationDialogPortal/>
|
||||
|
||||
|
||||
@if (PermissionService.GetIsDataCollectionEnabled())
|
||||
{
|
||||
<NavigationTracker/>
|
||||
}
|
||||
|
||||
|
||||
<style>
|
||||
a {
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #8fc5ff;
|
||||
text-decoration-thickness: 3px;
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
--severity-warning-color: #2a2000;
|
||||
--severity-warning-border-color: #755c13;
|
||||
--severity-error-color: #290102;
|
||||
--severity-error-border-color: #4C2C33;
|
||||
--severity-information-color: #030129;
|
||||
--severity-information-border-color: #2c3a4c;
|
||||
--severity-success-color: #042901;
|
||||
--severity-success-border-color: #2E4C2C;
|
||||
|
||||
--accent: #432462;
|
||||
--primary: #4308a3;
|
||||
--primary-border: #2c0b62;
|
||||
--primary-hover: #5e00f7;
|
||||
--primary-border-hover: #a168ff;
|
||||
--background: #161618;
|
||||
--secondary: #23133e;
|
||||
--secondary-hover: #2a0070;
|
||||
--secondary-border-hover: #a168ff;
|
||||
--paper: #252526;
|
||||
--paper-border: #151516;
|
||||
|
||||
--paper-hover: #52366f;
|
||||
--paper-border-hover: #653497;
|
||||
|
||||
--info: #451376;
|
||||
--info-border: #210b36;
|
||||
|
||||
--dialog-border-color: black;
|
||||
--dialog-border-width: 2px;
|
||||
--dialog-radius: 6px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private bool isLoaded;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await StorageService.Load();
|
||||
isLoaded = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
@implements IDisposable;
|
||||
@inject IMyDialogService MyDialogService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@if (MyDialogService.IsVisible)
|
||||
{
|
||||
<div class="confirmDialogBackground" onclick="@CloseDialog">
|
||||
<div class="confirmDialogContainer"
|
||||
@onclick:preventDefault="true"
|
||||
@onclick:stopPropagation="true">
|
||||
|
||||
<div class="confirmDialogHeader">
|
||||
@MyDialogService.GetDialogContents().Title
|
||||
</div>
|
||||
<div class="confirmDialogBody">
|
||||
@MyDialogService.GetDialogContents().Message
|
||||
</div>
|
||||
|
||||
<div class="confirmDialogFooter">
|
||||
<ButtonComponent MyButtonType="MyButtonType.Secondary"
|
||||
OnClick="MyDialogService.GetDialogContents().OnCancel">
|
||||
Cancel
|
||||
</ButtonComponent>
|
||||
<ButtonComponent MyButtonType="MyButtonType.Primary"
|
||||
OnClick="MyDialogService.GetDialogContents().OnConfirm">
|
||||
@MyDialogService.GetDialogContents().ConfirmButtonLabel
|
||||
</ButtonComponent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pageContents * {
|
||||
filter: blur(2px);
|
||||
}
|
||||
|
||||
.confirmDialogBackground {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
.confirmDialogContainer {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 64px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
|
||||
background-color: var(--background);
|
||||
border-width: var(--dialog-border-width);
|
||||
border-style: solid;
|
||||
border-color: var(--dialog-border-color);
|
||||
border-radius: var(--dialog-radius);
|
||||
|
||||
padding: 8px;
|
||||
|
||||
|
||||
box-shadow: 1px 2px 2px black;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
.confirmDialogHeader {
|
||||
font-size: 1.4em;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.confirmDialogBody {
|
||||
padding: 12px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.confirmDialogFooter {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
</style>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
MyDialogService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
MyDialogService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
|
||||
public void CloseDialog()
|
||||
{
|
||||
MyDialogService.Hide();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
@implements IDisposable;
|
||||
@inject IEntityDialogService entityDialogService
|
||||
|
||||
<div class="dialogBackground" onclick="@CloseDialog">
|
||||
|
||||
<div class="dialogContainer"
|
||||
@onclick:preventDefault="true"
|
||||
@onclick:stopPropagation="true">
|
||||
@if (entity == null)
|
||||
{
|
||||
<div>Entity is null</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="dialogHeader">
|
||||
@if (entityDialogService.HasHistory())
|
||||
{
|
||||
<button class="backButton" @onclick="entityDialogService.BackDialog">
|
||||
<div class="backButtonIcon"></div>
|
||||
</button>
|
||||
}
|
||||
|
||||
<div class="dialogTitle">
|
||||
@entity.Info().Name
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="dialogContent">
|
||||
<CascadingValue Value="@entity">
|
||||
<EntityVanguardAddedComponent/>
|
||||
<EntityInfoComponent/>
|
||||
<EntityVanguardsComponent/>
|
||||
<EntityProductionComponent/>
|
||||
<EntityStatsComponent/>
|
||||
<EntityMechanicsComponent/>
|
||||
<EntityPassivesComponent/>
|
||||
<EntityPyreSpellsComponent/>
|
||||
<EntityUpgradesComponent/>
|
||||
<EntityWeaponsComponent/>
|
||||
<EntityAbilitiesComponent/>
|
||||
</CascadingValue>
|
||||
|
||||
</div>
|
||||
<div class="dialogFooter"></div>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.pageContents * {
|
||||
filter: blur(2px);
|
||||
}
|
||||
|
||||
|
||||
.dialogBackground {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dialogContainer {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 64px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
|
||||
background-color: var(--background);
|
||||
border-width: var(--dialog-border-width);
|
||||
border-style: solid;
|
||||
border-color: var(--dialog-border-color);
|
||||
border-radius: var(--dialog-radius);
|
||||
|
||||
|
||||
box-shadow: 1px 2px 2px black;
|
||||
|
||||
}
|
||||
|
||||
.dialogHeader {
|
||||
width: 100%;
|
||||
background-color: var(--accent);
|
||||
border-top-left-radius: var(--dialog-radius);
|
||||
border-top-right-radius: var(--dialog-radius);
|
||||
border-bottom: 4px solid black;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.backButton {
|
||||
margin-left: 16px;
|
||||
padding: 12px;
|
||||
|
||||
border: 1px solid var(--accent);
|
||||
}
|
||||
|
||||
.backButton:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border: 1px solid var(--primary-border-hover);
|
||||
}
|
||||
|
||||
.backButtonIcon {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border: solid white;
|
||||
border-width: 0 9px 9px 0;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.dialogTitle {
|
||||
padding: 16px;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dialogContent {
|
||||
flex-grow: 1;
|
||||
padding: 6px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.dialogFooter {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background-color: var(--paper);
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
EntityModel entity = default!;
|
||||
|
||||
private int refresh;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
entity = EntityData.Get()[entityDialogService.GetEntityId() ?? string.Empty];
|
||||
|
||||
entityDialogService.Subscribe(OnUpdate);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
entityDialogService.Unsubscribe(OnUpdate);
|
||||
}
|
||||
|
||||
void OnUpdate()
|
||||
{
|
||||
entity = EntityData.Get()[entityDialogService.GetEntityId()];
|
||||
refresh++;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public void CloseDialog()
|
||||
{
|
||||
entityDialogService.CloseDialog();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
@implements IDisposable;
|
||||
@inject ISearchService searchService
|
||||
@inject IJSRuntime jsRuntime
|
||||
|
||||
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
@if (searchService.IsLoaded() && searchService.IsVisible)
|
||||
{
|
||||
<div id="searchBackground" class="searchBackground" onclick="@CloseDialog">
|
||||
<div class="searchContainer"
|
||||
@onclick:preventDefault="true"
|
||||
@onclick:stopPropagation="true">
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormTextComponent OnFocus="OnFocus" Id="searchInput" Placeholder="Search..."
|
||||
OnInput="SearchChanged"></FormTextComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
<div class="searchBox">
|
||||
@if (SearchText.Length > 0)
|
||||
{
|
||||
foreach (var searchSection in searchService.Searches)
|
||||
{
|
||||
var searchPoints = searchSection.Value.FindAll(x => x.Title.ToLower().Contains(SearchText.ToLower()));
|
||||
|
||||
@if (searchPoints.Count > 0)
|
||||
{
|
||||
<div>
|
||||
<div class="searchSectionTitle">
|
||||
@searchSection.Key
|
||||
</div>
|
||||
<div class="searchContents">
|
||||
@foreach (var searchPoint in searchPoints)
|
||||
{
|
||||
<div>
|
||||
<button class="searchLink @searchPoint.PointType.ToLower()"
|
||||
label="@searchPoint.Title"
|
||||
@onclick="() => OnSearch(searchPoint)">
|
||||
@searchPoint.Title
|
||||
</button>
|
||||
@if (!searchPoint.Summary.Trim().Equals(""))
|
||||
{
|
||||
<i> - @searchPoint.Summary</i>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pageContents * {
|
||||
filter: blur(2px);
|
||||
}
|
||||
|
||||
.searchBackground {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.searchBox {
|
||||
padding: 12px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 530px;
|
||||
border: 1px solid black;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.searchContents {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
align-items: flex-start;
|
||||
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
|
||||
.searchSectionTitle {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
|
||||
.searchContainer {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 64px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
|
||||
background-color: var(--background);
|
||||
border-width: var(--dialog-border-width);
|
||||
border-style: solid;
|
||||
border-color: var(--dialog-border-color);
|
||||
border-radius: var(--dialog-radius);
|
||||
|
||||
padding: 8px;
|
||||
|
||||
|
||||
box-shadow: 1px 2px 2px black;
|
||||
|
||||
}
|
||||
|
||||
.searchLink {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.searchContainer {
|
||||
height: 300px;
|
||||
|
||||
}
|
||||
|
||||
.searchBox {
|
||||
height: 230px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private ElementReference searchBox;
|
||||
|
||||
private string SearchText { get; set; } = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
searchService.Subscribe(OnSearchChanged);
|
||||
|
||||
timer = new Timer(200);
|
||||
timer.Elapsed += FocusTimer;
|
||||
timer.Enabled = false;
|
||||
}
|
||||
|
||||
|
||||
private void FocusTimer(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
jsRuntime.InvokeVoidAsync("SetFocusToElement", "searchInput");
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private Timer timer = null!;
|
||||
|
||||
private void OnSearchChanged()
|
||||
{
|
||||
if (timer.Enabled != searchService.IsVisible)
|
||||
{
|
||||
timer.Enabled = searchService.IsVisible;
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
searchService.Unsubscribe(OnSearchChanged);
|
||||
timer.Elapsed -= FocusTimer;
|
||||
}
|
||||
|
||||
|
||||
public void CloseDialog()
|
||||
{
|
||||
searchService.Hide();
|
||||
}
|
||||
|
||||
public void NavigateTo(string url)
|
||||
{
|
||||
if (url.Contains("#"))
|
||||
{
|
||||
navigationManager.NavigateTo(url,
|
||||
navigationManager.Uri.Split("#").First().Contains(url.Split("#").First()));
|
||||
}
|
||||
else
|
||||
{
|
||||
navigationManager.NavigateTo(url);
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchChanged(ChangeEventArgs obj)
|
||||
{
|
||||
SearchText = obj.Value!.ToString()!;
|
||||
}
|
||||
|
||||
private void OnSearch(SearchPointModel searchPoint)
|
||||
{
|
||||
NavigateTo(searchPoint.Href);
|
||||
searchService.Hide();
|
||||
}
|
||||
|
||||
private void OnFocus(object obj)
|
||||
{
|
||||
timer.Enabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
|
||||
<LangVersion>12</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DefineConstants>TRACE;NO_SQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>TRACE;NO_SQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazor-Analytics" Version="4.0.0" />
|
||||
<PackageReference Include="Markdig" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.5" />
|
||||
<PackageReference Include="MudBlazor" Version="9.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Components\Components.csproj" />
|
||||
<ProjectReference Include="..\Model\Model.csproj" />
|
||||
<ProjectReference Include="..\Services\Services.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\generated" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Localizations.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Localizations.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Localizations.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Example.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
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}") = "Services", "..\Services\Services.csproj", "{621178C8-4E8B-478E-80E5-7478F0E7B67E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAutomation", "..\TestAutomation\TestAutomation.csproj", "{8B49D038-D013-460D-9C4F-817CAFFEB06F}"
|
||||
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
|
||||
{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
|
||||
{8B49D038-D013-460D-9C4F-817CAFFEB06F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8B49D038-D013-460D-9C4F-817CAFFEB06F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8B49D038-D013-460D-9C4F-817CAFFEB06F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8B49D038-D013-460D-9C4F-817CAFFEB06F}.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,5 @@
|
||||
@page "/"
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
<HomePage/>
|
||||
Generated
+114
@@ -0,0 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace IGP {
|
||||
using System;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Localizations {
|
||||
|
||||
private static System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Localizations() {
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.Equals(null, resourceMan)) {
|
||||
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IGP.Localizations", typeof(Localizations).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Greeting {
|
||||
get {
|
||||
return ResourceManager.GetString("Greeting", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Chart_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Chart Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Filter_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Filter Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Entity_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Entity Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Bank_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Bank Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Army_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Army Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Highlights_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Highlights Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_BuildOrder_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip BuildOrder Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Timing_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Timing Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Hotkey_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Hotkey Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Tooltip_Options_Info {
|
||||
get {
|
||||
return ResourceManager.GetString("Tooltip Options Info", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<root>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
|
||||
id="root"
|
||||
xmlns="">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="Greeting" xml:space="preserve">
|
||||
<value>Hello</value>
|
||||
</data>
|
||||
|
||||
<data name="Tooltip Chart Info" xml:space="preserve">
|
||||
<value>Shows economy at each game interval. Use to determine if spending additional resources on harvesters will help or hinder overall timing attack.</value>
|
||||
</data>
|
||||
|
||||
<data name="Tooltip Filter Info" xml:space="preserve">
|
||||
<value>Select build details, such as Faction and Immortal.
|
||||
|
||||
Affects entities you can build.</value>
|
||||
</data>
|
||||
<data name="Tooltip Entity Info" xml:space="preserve">
|
||||
<value>Summary of the entity you just selected.</value>
|
||||
</data>
|
||||
<data name="Tooltip Bank Info" xml:space="preserve">
|
||||
<value>Bank at time of last requested action. Use this section to determine if your build is floating too much alloy or ether.</value>
|
||||
</data>
|
||||
<data name="Tooltip Army Info" xml:space="preserve">
|
||||
<value>Overview of current army, and when it will be ready to begin an attack.</value>
|
||||
</data>
|
||||
<data name="Tooltip Highlights Info" xml:space="preserve">
|
||||
<value>Timeline highlights of your build order. Shows when you start a new action and when the action is done.</value>
|
||||
</data>
|
||||
<data name="Tooltip BuildOrder Info" xml:space="preserve">
|
||||
<value>Some raw JSON data to represent your build order.</value>
|
||||
</data>
|
||||
<data name="Tooltip Timing Info" xml:space="preserve">
|
||||
<value>Enter build details.</value>
|
||||
</data>
|
||||
<data name="Tooltip Hotkey Info" xml:space="preserve">
|
||||
<value>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></value>
|
||||
</data>
|
||||
<data name="Tooltip Options Info" xml:space="preserve">
|
||||
<value>Misc calculator controls.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,143 @@
|
||||
@inherits LayoutComponentBase
|
||||
@inject ISearchService SearchService
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
@inject NavigationManager NavigationManager
|
||||
@using Model.Website.Data
|
||||
@using Services.Website
|
||||
@implements IDisposable
|
||||
|
||||
<MudThemeProvider @ref="@_mudThemeProvider" @bind-IsDarkMode="@_isDarkMode"/>
|
||||
<MudPopoverProvider/>
|
||||
<MudDialogProvider/>
|
||||
<MudSnackbarProvider/>
|
||||
|
||||
<MudLayout>
|
||||
<MudAppBar Elevation="1">
|
||||
<MudHidden Breakpoint="Breakpoint.SmAndDown" Invert="true">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start"
|
||||
OnClick="@(e => DrawerToggle())"/>
|
||||
</MudHidden>
|
||||
<MudButton Class="ml-3 mr-8"
|
||||
Href="/"
|
||||
Target="_self"
|
||||
Variant="Variant.Text"
|
||||
Color="Color.Default">
|
||||
<MudText Typo="Typo.h5"> IGP Fan Reference</MudText>
|
||||
</MudButton>
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||
@foreach (var page in WebsiteData.GetPages())
|
||||
{
|
||||
<MudButton Href="@(page.Href)"
|
||||
Variant="Variant.Text"
|
||||
Color="Color.Default"
|
||||
Class="mr-4">
|
||||
<MudIcon Icon="@(page.Icon)" Class="mr-2"/>
|
||||
@(page.Name)
|
||||
</MudButton>
|
||||
}
|
||||
</MudHidden>
|
||||
<MudSpacer/>
|
||||
<SearchButtonComponent Id="desktop-searchButton"/>
|
||||
</MudAppBar>
|
||||
<MudHidden Breakpoint="Breakpoint.SmAndDown" Invert="true">
|
||||
<MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2">
|
||||
<MudPaper Width="250px" Class="d-inline-flex py-3" Elevation="0">
|
||||
<MudNavMenu Class="mud-width-full flex-grow-1">
|
||||
@foreach (var page in WebsiteData.GetPages())
|
||||
{
|
||||
<MudNavLink Href="@(page.Href)" Icon="@(page.Icon)">@(page.Name)</MudNavLink>
|
||||
}
|
||||
</MudNavMenu>
|
||||
</MudPaper>
|
||||
</MudDrawer>
|
||||
</MudHidden>
|
||||
|
||||
<MudMainContent>
|
||||
<MudContainer Class="px-8" MaxWidth="MaxWidth.False">
|
||||
<div id="content" class="content">
|
||||
@Body
|
||||
</div>
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
|
||||
<FooterComponent></FooterComponent>
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private bool _isDarkMode = true;
|
||||
private MudThemeProvider _mudThemeProvider;
|
||||
|
||||
bool _drawerOpen = true;
|
||||
|
||||
void DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
CollectFirstPageLoaded();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
//TODO: Support light mode
|
||||
//_isDarkMode = await _mudThemeProvider.GetSystemPreference();
|
||||
//StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectFirstPageLoaded()
|
||||
{
|
||||
var skipBaseUri = NavigationManager.Uri.Substring(NavigationManager.BaseUri.Length,
|
||||
NavigationManager.Uri.Length - NavigationManager.BaseUri.Length);
|
||||
var rootUrl = skipBaseUri.Split("/").First();
|
||||
if (rootUrl.Trim().Equals(""))
|
||||
{
|
||||
rootUrl = "home";
|
||||
}
|
||||
|
||||
DataCollectionService.SendEvent(DataCollectionKeys.FirstPage,
|
||||
new Dictionary<string, string> { { "page", rootUrl } });
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await Focus();
|
||||
}
|
||||
|
||||
private async Task Focus()
|
||||
{
|
||||
// await jsRuntime.InvokeVoidAsync("SetFocusToElement", pageContents);
|
||||
}
|
||||
|
||||
protected override async void OnAfterRender(bool firstRender)
|
||||
{
|
||||
// await jsRuntime.InvokeVoidAsync("SetFocusToElement", pageContents);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
void HasChanged()
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void HandleKeyDown(KeyboardEventArgs keyboardEventArgs)
|
||||
{
|
||||
if ((keyboardEventArgs.CtrlKey || keyboardEventArgs.MetaKey) && keyboardEventArgs.Key.ToLower() == "k")
|
||||
{
|
||||
SearchService.Show();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.layoutContainer {
|
||||
height: 100vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-bottom: 64px;
|
||||
display: flex;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
@layout PageLayout
|
||||
|
||||
@inherits BasePage
|
||||
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
|
||||
|
||||
@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,37 @@
|
||||
@using Services.Website
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
CollectLoadedPage();
|
||||
}
|
||||
|
||||
private void CollectLoadedPage()
|
||||
{
|
||||
var skipBaseUri = NavigationManager.Uri.Substring(NavigationManager.BaseUri.Length,
|
||||
NavigationManager.Uri.Length - NavigationManager.BaseUri.Length);
|
||||
|
||||
var splitData = skipBaseUri.Split("/");
|
||||
|
||||
var rootUrl = splitData.First();
|
||||
if (rootUrl.Trim().Equals(""))
|
||||
{
|
||||
rootUrl = "home";
|
||||
}
|
||||
|
||||
var eventData = new Dictionary<string, string> { { "page", rootUrl } };
|
||||
if (splitData.Length > 1)
|
||||
{
|
||||
eventData["inner-page"] = splitData.Last();
|
||||
}
|
||||
|
||||
DataCollectionService.SendEvent(DataCollectionKeys.PageInitialized, eventData);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
@layout PageLayout
|
||||
|
||||
@inherits BasePage
|
||||
|
||||
@inject IStringLocalizer<Localizations> Locale
|
||||
|
||||
@inject IKeyService KeyService
|
||||
@inject IImmortalSelectionService FilterService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject IEconomyService EconomyService
|
||||
@inject IToastService ToastService
|
||||
@inject ITimingService TimingService
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
|
||||
@page "/build-calculator"
|
||||
@using Services.Website
|
||||
@implements IDisposable
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Build Calculator</WebsiteTitleComponent>
|
||||
|
||||
<AlertComponent Type="@SeverityType.Warning">
|
||||
<Title>Work In Progress and Not Fully Tested</Title>
|
||||
<Message>
|
||||
Build Calculator hasn't been thoroughly tested. Bugs and inaccurate results assumed.
|
||||
<br/>
|
||||
Currently not considering running out of alloy and ether to harvest.
|
||||
<br/>
|
||||
<br/>
|
||||
Build Calculator was built based on a much older version of the game and was only quickly modified for the
|
||||
June 2025 Playtest version, so the above disclaimer is only more true.
|
||||
<br/>
|
||||
Expect even more oddities and invalid data then the above warning implies.
|
||||
</Message>
|
||||
</AlertComponent>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<div class="calculatorGrid">
|
||||
<div class="gridItem" style="grid-area: timing;">
|
||||
<ButtonComponent MyButtonType="MyButtonType.Secondary" OnClick="OnResetClicked">Clear Build Order
|
||||
</ButtonComponent>
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Timing Info"]">
|
||||
<TimingComponent></TimingComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Filter Info"]">
|
||||
<FilterComponent></FilterComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Options Info"]">
|
||||
<OptionsComponent></OptionsComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="gridItem" style="grid-area: chart;">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Chart Info"]">
|
||||
<BuildChartComponent></BuildChartComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
<div class="gridItem" style="grid-area: view;">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Entity Info"]">
|
||||
<EntityClickViewComponent/>
|
||||
</InfoTooltipComponent>
|
||||
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
<div class="gridItem" style="grid-area: bank;">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Bank Info"]">
|
||||
<BankComponent></BankComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
<div class="gridItem" style="grid-area: army;">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Army Info"]">
|
||||
<ArmyComponent></ArmyComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
<div class="gridItem gridKeys">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Hotkey Info"]">
|
||||
<HotkeyViewerComponent Size="80"></HotkeyViewerComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
<div class="gridItem" style="grid-area: highlights;">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip Highlights Info"]">
|
||||
<HighlightsComponent></HighlightsComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</div>
|
||||
|
||||
<div class="gridItem" style="grid-area: buildorder;">
|
||||
<PanelComponent>
|
||||
<InfoTooltipComponent InfoText="@Locale["Tooltip BuildOrder Info"]">
|
||||
<BuildOrderComponent></BuildOrderComponent>
|
||||
</InfoTooltipComponent>
|
||||
</PanelComponent>
|
||||
</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>
|
||||
.gridItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.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'
|
||||
'timing bank army army'
|
||||
'keys keys highlights buildorder'
|
||||
'chart chart chart chart';
|
||||
}
|
||||
|
||||
.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'
|
||||
'keys'
|
||||
'bank'
|
||||
'army'
|
||||
'highlights'
|
||||
'buildorder'
|
||||
'chart';
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, 0);
|
||||
|
||||
KeyService.Subscribe(HandleClick);
|
||||
|
||||
DataCollectionService.SendEvent(
|
||||
DataCollectionKeys.PageInitialized,
|
||||
new Dictionary<string, string> { { "page", "build-calculator" } }
|
||||
);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
KeyService.Unsubscribe(HandleClick);
|
||||
}
|
||||
|
||||
private void OnResetClicked()
|
||||
{
|
||||
ToastService.AddToast(new ToastModel
|
||||
{
|
||||
SeverityType = SeverityType.Success,
|
||||
Message = "Build order has been cleared.",
|
||||
Title = "Reset"
|
||||
});
|
||||
|
||||
BuildOrderService.Reset();
|
||||
}
|
||||
|
||||
|
||||
private void HandleClick()
|
||||
{
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
|
||||
if (hotkey == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hotkey == "`")
|
||||
{
|
||||
BuildOrderService.RemoveLast();
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
return;
|
||||
}
|
||||
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFaction();
|
||||
var immortal = FilterService.GetImmortal();
|
||||
|
||||
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,156 @@
|
||||
@inject IJSRuntime jsRuntime
|
||||
|
||||
@inject IBuildOrderService buildOrder
|
||||
@inject ITimingService timingService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<div class="armyView">
|
||||
|
||||
<FormLayoutComponent>
|
||||
<div style="display: flex; gap: 24px;">
|
||||
<FormDisplayComponent Label="Army Completed At">
|
||||
<Display>@lastInterval | T @Interval.ToTime(lastInterval)</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Army Attacking At">
|
||||
<Display>@(lastInterval + timingService.GetTravelTime()) |
|
||||
T @Interval.ToTime(lastInterval + timingService.GetTravelTime())</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
<FormDisplayComponent Label="Army units built">
|
||||
<Display>
|
||||
<div class="armyCardsContainer">
|
||||
@foreach (var unit in armyCount)
|
||||
{
|
||||
<div class="armyCard">
|
||||
<div class="armyCountPosition">
|
||||
<div class="armyCount">@unit.Value.ToString()x</div>
|
||||
</div>
|
||||
<div>@unit.Key</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.armyView {
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.armyCardsContainer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.armyCard {
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.armyCountPosition {
|
||||
height: 0;
|
||||
top: -20px;
|
||||
left: -16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.armyCount {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private int lastInterval;
|
||||
|
||||
readonly Dictionary<string, int> armyCount = new();
|
||||
|
||||
List<EntityModel> army = new();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
buildOrder.Subscribe(OnBuildOrderChanged);
|
||||
timingService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
buildOrder.Unsubscribe(OnBuildOrderChanged);
|
||||
timingService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "ArmyComponent");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "ArmyComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged()
|
||||
{
|
||||
var armyCountWas = 0;
|
||||
foreach (var army in armyCount)
|
||||
{
|
||||
armyCountWas += army.Value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Better
|
||||
var armyCountIs = 0;
|
||||
foreach (var army in armyCount)
|
||||
{
|
||||
armyCountIs += army.Value;
|
||||
}
|
||||
|
||||
|
||||
if (armyCountWas != armyCountIs)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
|
||||
@inject IEconomyService economyService
|
||||
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<div class="bankContainer">
|
||||
<FormDisplayComponent Label="Time">
|
||||
<Display>@(BuildOrderService.GetLastRequestInterval() + 1) |
|
||||
T @Interval.ToTime(BuildOrderService.GetLastRequestInterval() + 1)</Display>
|
||||
</FormDisplayComponent>
|
||||
<div class="bankRow">
|
||||
<FormDisplayComponent Label="Alloy">
|
||||
<Display>@_economy.Alloy +@_economy.AlloyIncome</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Ether">
|
||||
<Display>@Math.Round(_economy.Ether) +@Math.Round(_economy.EtherIncome)</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
<div class="bankRow">
|
||||
<FormDisplayComponent Label="Pyre">
|
||||
<Display>@_economy.Pyre</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Supply">
|
||||
<Display>@_supplyTaken / @_supplyGranted (@(_supplyGranted / 16)@(_extraBuildings > 0 ? "+" + _extraBuildings : ""))</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="workerText">Workers</div>
|
||||
<div class="bankRow">
|
||||
<FormDisplayComponent Label="Current">
|
||||
<Display>@_economy.WorkerCount</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Busy">
|
||||
<Display>@_economy.BusyWorkerCount</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Creating">
|
||||
<Display>@_economy.CreatingWorkerCount</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bankContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.workerText {
|
||||
margin-bottom: -2px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.bankRow {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject] IBuildOrderService BuildOrderService { get; set; } = default!;
|
||||
|
||||
[Inject] IEconomyService EconomyService { get; set; } = default!;
|
||||
|
||||
EconomyModel _economy = new();
|
||||
int _supplyGranted;
|
||||
int _supplyTaken;
|
||||
int _extraBuildings;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
BuildOrderService.Subscribe(OnBuildOrderChanged);
|
||||
|
||||
|
||||
_economy = EconomyService.GetEconomy(BuildOrderService.GetLastRequestInterval() + 1);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "BankComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "BankComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
BuildOrderService.Unsubscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged()
|
||||
{
|
||||
_economy = EconomyService.GetEconomy(BuildOrderService.GetLastRequestInterval() + 1);
|
||||
|
||||
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,331 @@
|
||||
@inject IEconomyService EconomyService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject ITimingService TimingService
|
||||
@inject IJSRuntime JsRuntime;
|
||||
@implements IDisposable
|
||||
|
||||
@if (lastRequestedRefreshIndex != requestedRefreshIndex)
|
||||
{
|
||||
<LoadingComponent/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="chartsContainer">
|
||||
@foreach (var chart in charts)
|
||||
{
|
||||
var takenPixels = new Dictionary<int, bool>();
|
||||
|
||||
<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)
|
||||
{
|
||||
var x = int.Parse(point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax));
|
||||
if (takenPixels.ContainsKey(x)) continue;
|
||||
|
||||
takenPixels.Add(x, true);
|
||||
|
||||
<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 {
|
||||
|
||||
private readonly int width = 250;
|
||||
|
||||
List<int> valueList = new();
|
||||
|
||||
readonly List<ChartModel> charts = new();
|
||||
|
||||
|
||||
float highestAlloyPoint;
|
||||
float highestEtherPoint;
|
||||
float highestPyrePoint;
|
||||
float highestArmyPoint;
|
||||
|
||||
private Timer ageTimer = null!;
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
BuildOrderService.Subscribe(OnBuilderOrderChanged);
|
||||
TimingService.Subscribe(OnBuilderOrderChanged);
|
||||
|
||||
ageTimer = new Timer(1000);
|
||||
ageTimer.Elapsed += OnAge!;
|
||||
ageTimer.Enabled = true;
|
||||
|
||||
|
||||
GenerateChart();
|
||||
}
|
||||
|
||||
|
||||
int lastRequestedRefreshIndex;
|
||||
|
||||
void OnAge(object? sender, ElapsedEventArgs elapsedEventArgs)
|
||||
{
|
||||
if (requestedRefreshIndex > 0)
|
||||
{
|
||||
if (requestedRefreshIndex == lastRequestedRefreshIndex)
|
||||
{
|
||||
GenerateChart();
|
||||
requestedRefreshIndex = 0;
|
||||
lastRequestedRefreshIndex = 0;
|
||||
}
|
||||
|
||||
lastRequestedRefreshIndex = requestedRefreshIndex;
|
||||
}
|
||||
|
||||
ageTimer.Enabled = true;
|
||||
}
|
||||
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
|
||||
TimingService.Unsubscribe(OnBuilderOrderChanged);
|
||||
}
|
||||
|
||||
|
||||
int requestedRefreshIndex;
|
||||
|
||||
void OnBuilderOrderChanged()
|
||||
{
|
||||
requestedRefreshIndex++;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "ChartComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "ChartComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
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.HarvestPoints
|
||||
where harvester.Harvest() != null
|
||||
where harvester.Harvest().RequiresWorker
|
||||
where harvester.Harvest().Resource == ResourceType.Alloy
|
||||
select harvester;
|
||||
|
||||
var alloyAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints
|
||||
where harvester.Harvest() != null
|
||||
where harvester.Harvest().RequiresWorker == false
|
||||
where harvester.Harvest().Resource == ResourceType.Alloy
|
||||
select harvester;
|
||||
|
||||
var etherAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints
|
||||
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,43 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
|
||||
@inject IBuildOrderService buildOrderService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormTextAreaComponent Label="JSON Data"
|
||||
Rows="14"
|
||||
Value="@buildOrderService.AsJson()">
|
||||
</FormTextAreaComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
buildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
buildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "BuildOrderComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "BuildOrderComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject IKeyService KeyService
|
||||
@inject IImmortalSelectionService FilterService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject IStorageService StorageService
|
||||
@using Services.Website
|
||||
@implements IDisposable
|
||||
|
||||
@if (_entity != null)
|
||||
{
|
||||
<div class="entityClickView">
|
||||
<CascadingValue Value="_entity">
|
||||
<CascadingValue Value="@_viewType">
|
||||
<EntityViewComponent></EntityViewComponent>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
</div>
|
||||
}
|
||||
<style>
|
||||
.entityClickView {
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
height: 550px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private EntityModel? _entity;
|
||||
private string _viewType = EntityViewType.Detailed;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
KeyService.Subscribe(HandleClick);
|
||||
StorageService.Subscribe(RefreshDefaults);
|
||||
|
||||
RefreshDefaults();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
KeyService.Unsubscribe(HandleClick);
|
||||
|
||||
StorageService.Unsubscribe(RefreshDefaults);
|
||||
}
|
||||
|
||||
|
||||
void RefreshDefaults()
|
||||
{
|
||||
_viewType = StorageService.GetValue<bool>(StorageKeys.IsPlainView) ? EntityViewType.Plain : EntityViewType.Detailed;
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "EntityClickViewComponent");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "EntityClickViewComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
private void HandleClick()
|
||||
{
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFaction();
|
||||
var immortal = FilterService.GetImmortal();
|
||||
|
||||
var foundEntity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
|
||||
if (foundEntity != null && _entity != foundEntity)
|
||||
{
|
||||
_entity = foundEntity;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
@inject IJSRuntime JsRuntime;
|
||||
@inject IImmortalSelectionService FilterService
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormSelectComponent OnChange="@OnFactionChanged">
|
||||
<FormLabelComponent>Faction</FormLabelComponent>
|
||||
<ChildContent>
|
||||
<option value="@DataType.FACTION_Aru"
|
||||
selected="@(FilterService.GetFaction().Equals(DataType.FACTION_Aru))">
|
||||
Aru
|
||||
</option>
|
||||
<option value="@DataType.FACTION_QRath"
|
||||
selected="@(FilterService.GetFaction().Equals(DataType.FACTION_QRath))">
|
||||
Q'Rath
|
||||
</option>
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
|
||||
<FormSelectComponent OnChange="@OnImmortalChanged">
|
||||
<FormLabelComponent>Immortal</FormLabelComponent>
|
||||
<ChildContent>
|
||||
@if (FilterService.GetFaction() == DataType.FACTION_QRath)
|
||||
{
|
||||
<option value="@DataType.IMMORTAL_Orzum"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Orzum))">
|
||||
Orzum
|
||||
</option>
|
||||
<option value="@DataType.IMMORTAL_Ajari"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Ajari))">
|
||||
Ajari
|
||||
</option>
|
||||
}
|
||||
@if (FilterService.GetFaction() == DataType.FACTION_Aru)
|
||||
{
|
||||
<option value="@DataType.IMMORTAL_Atzlan"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Atzlan))">
|
||||
Atzlan
|
||||
</option>
|
||||
<option value="@DataType.IMMORTAL_Mala"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Mala))">
|
||||
Mala
|
||||
</option>
|
||||
<option value="@DataType.IMMORTAL_Xol"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Xol))">
|
||||
Xol
|
||||
</option>
|
||||
}
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
void OnFactionChanged(ChangeEventArgs e)
|
||||
{
|
||||
FilterService.SelectFaction(e.Value!.ToString()!);
|
||||
}
|
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e)
|
||||
{
|
||||
FilterService.SelectImmortal(e.Value!.ToString()!);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "FilterComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "FilterComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
@inject IEconomyService economyService
|
||||
@inject IBuildOrderService buildOrderService
|
||||
@inject ITimingService timingService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<div class="highlightsContainer">
|
||||
<div>
|
||||
<div>Requested</div>
|
||||
|
||||
@foreach (var ordersAtTime in buildOrderService.StartedOrders.Reverse())
|
||||
{
|
||||
foreach (var order in ordersAtTime.Value)
|
||||
{
|
||||
<div>
|
||||
@ordersAtTime.Key | T @Interval.ToTime(ordersAtTime.Key)
|
||||
</div>
|
||||
<div>
|
||||
@order.Info().Name
|
||||
</div>
|
||||
<br/>
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div>Finished</div>
|
||||
|
||||
@foreach (var ordersAtTime in buildOrderService.CompletedOrders.Reverse())
|
||||
{
|
||||
foreach (var order in ordersAtTime.Value)
|
||||
{
|
||||
<div>
|
||||
|
||||
@ordersAtTime.Key | T @Interval.ToTime(ordersAtTime.Key)
|
||||
</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 {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
economyService.Subscribe(StateHasChanged);
|
||||
buildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
economyService.Unsubscribe(StateHasChanged);
|
||||
buildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "HighlightsComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "HighlightsComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
@inject IJSRuntime JsRuntime;
|
||||
@using Services.Website
|
||||
@implements IDisposable
|
||||
@inject IKeyService KeyService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject IImmortalSelectionService FilterService
|
||||
|
||||
@inject IEconomyService EconomyService
|
||||
@inject ITimingService TimingService
|
||||
@inject IToastService ToastService
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
|
||||
|
||||
<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)
|
||||
? hotkey.GetColor()
|
||||
: hotkey.GetColor();
|
||||
|
||||
var x = hotkey.PositionX * Size;
|
||||
var y = hotkey.PositionY * Size + (hotkey.PositionY == 0 ? 5 : -50);
|
||||
|
||||
var width = Size * hotkey.Width;
|
||||
var height = hotkey.PositionY == 0 ? 50 : Size;
|
||||
|
||||
var borderRadius = hotkey.PositionY == 0 ? 12 : 0;
|
||||
|
||||
var border = "1px solid black";
|
||||
if (hotkey.KeyText.Equals(key))
|
||||
{
|
||||
border = "5px solid black";
|
||||
}
|
||||
|
||||
if (hotkey.KeyText.Equals(controlGroup))
|
||||
{
|
||||
color = "#257525";
|
||||
}
|
||||
|
||||
if (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace())
|
||||
{
|
||||
border = "5px solid green";
|
||||
}
|
||||
|
||||
var keyText = hotkey.KeyText.Equals("CAPSLOCK") ? "Caps"
|
||||
: hotkey.KeyText.Equals("CONTROL") ? "Ctrl"
|
||||
: hotkey.KeyText.Equals("SHIFT") ? "Shift"
|
||||
: hotkey.KeyText.Equals("X") ? "X"
|
||||
: hotkey.KeyText.Equals("SPACE") ? "Space" : hotkey.KeyText;
|
||||
|
||||
|
||||
var controlStyle = $"background-color:{color}; " +
|
||||
$"width: {width}px; " +
|
||||
"border-top: 1px solid black; " +
|
||||
"border-left: 1px solid black; " +
|
||||
"border-right: 1px solid black; " +
|
||||
$"border-top-left-radius: {borderRadius}px; " +
|
||||
$"border-top-right-radius: {borderRadius}px; " +
|
||||
"overflow: hidden; " +
|
||||
"text-align: center;";
|
||||
|
||||
var keyStyle = $"background-color:{color}; " +
|
||||
$"border: {border}; " +
|
||||
$"width: {width}px; " +
|
||||
$"height: {height}px; " +
|
||||
"overflow: hidden; " +
|
||||
"padding: 4px;";
|
||||
|
||||
var usedStyle = hotkey.PositionY == 0 ? controlStyle : keyStyle;
|
||||
|
||||
<div style="position:relative;
|
||||
cursor:pointer;
|
||||
top:@y.ToString()px;
|
||||
left:@x.ToString()px;
|
||||
width: 0px;
|
||||
height: 0px;">
|
||||
|
||||
<div @onclick="e => ButtonClicked(e, hotkey)" style="@usedStyle">
|
||||
@keyText
|
||||
@foreach (var entity in data.Values)
|
||||
{
|
||||
if (InvalidKey(entity, hotkey) || InvalidKeyGroup(entity, hotkey) || InvalidHoldSpace(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidFaction(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidVanguard(entity) || InvalidNonVanguard(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isVanguard = entity.VanguardAdded() != null;
|
||||
var style = isVanguard ? "font-weight: bold;" : "";
|
||||
|
||||
if (BuildOrderService.WillMeetRequirements(entity) == null)
|
||||
{
|
||||
style += "color:gray; font-style: italic;";
|
||||
}
|
||||
|
||||
|
||||
<div style="@style">@entity.Info()?.Name</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</InputPanelComponent>
|
||||
|
||||
<style>
|
||||
.keyContainer {
|
||||
width: 400px;
|
||||
max-width: 95vw;
|
||||
height: 350px;
|
||||
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: transparent;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public int Size { get; set; } = 100;
|
||||
|
||||
readonly Dictionary<string, EntityModel> data = EntityModel.GetDictionary();
|
||||
readonly List<HotkeyModel> hotkeys = HotkeyModel.GetAll();
|
||||
|
||||
private string controlGroup = "C";
|
||||
private string key = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
KeyService.Subscribe(OnKeyPressed);
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
BuildOrderService.Subscribe(OnBuilderOrderChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
KeyService.Unsubscribe(OnKeyPressed);
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
|
||||
}
|
||||
|
||||
int completedTimeCount;
|
||||
|
||||
void OnBuilderOrderChanged()
|
||||
{
|
||||
if (BuildOrderService.UniqueCompletedTimes.Count != completedTimeCount)
|
||||
{
|
||||
completedTimeCount = BuildOrderService.UniqueCompletedTimes.Count;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "HotKeyViewerComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "HotKeyViewerComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidFaction(EntityModel entity)
|
||||
{
|
||||
if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFaction() && FilterService.GetFaction() != DataType.Any)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidVanguard(EntityModel entity)
|
||||
{
|
||||
if (entity.VanguardAdded() != null
|
||||
&& entity.VanguardAdded()?.ImmortalId != FilterService.GetImmortal()
|
||||
&& FilterService.GetImmortal() != DataType.Any)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidNonVanguard(EntityModel entity)
|
||||
{
|
||||
if (entity.Replaceds().Count > 0)
|
||||
{
|
||||
foreach (var replaced in entity.Replaceds())
|
||||
{
|
||||
if (FilterService.GetImmortal() == replaced.ImmortalId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
var controlGroupWas = controlGroup;
|
||||
var keyWas = key;
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("Z"))
|
||||
{
|
||||
controlGroup = "Z";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("X"))
|
||||
{
|
||||
controlGroup = "X";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("C"))
|
||||
{
|
||||
controlGroup = "C";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("D"))
|
||||
{
|
||||
controlGroup = "D";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("V"))
|
||||
{
|
||||
controlGroup = "V";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("ALT"))
|
||||
{
|
||||
controlGroup = "ALT";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("SHIFT"))
|
||||
{
|
||||
controlGroup = "SHIFT";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("CONTROL"))
|
||||
{
|
||||
controlGroup = "CONTROL";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Count > 0)
|
||||
{
|
||||
key = KeyService.GetAllPressedKeys().First();
|
||||
}
|
||||
|
||||
if (controlGroupWas != controlGroup || keyWas != key)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void HandleClick()
|
||||
{
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
|
||||
if (hotkey is "`")
|
||||
HandleCancelEntity();
|
||||
|
||||
if (EntityFromKey(hotkey, out var entity))
|
||||
return;
|
||||
|
||||
if (BuildOrderService.Add(entity!, EconomyService))
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
|
||||
private void HandleCancelEntity()
|
||||
{
|
||||
BuildOrderService.RemoveLast();
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
|
||||
private bool EntityFromKey(string? hotkey, out EntityModel? entity)
|
||||
{
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFaction();
|
||||
var immortal = FilterService.GetImmortal();
|
||||
|
||||
entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
|
||||
return entity == null;
|
||||
}
|
||||
|
||||
private void ButtonClicked(MouseEventArgs mouseEventArgs, HotkeyModel hotkey)
|
||||
{
|
||||
DataCollectionService.SendEvent(
|
||||
DataCollectionKeys.BuildCalcInput,
|
||||
new Dictionary<string, string> { { "key", hotkey.KeyText.ToLower() }, { "input-source", "mouse" } }
|
||||
);
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
@using Services.Website
|
||||
@inject IKeyService KeyService
|
||||
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
|
||||
<div tabindex="0"
|
||||
style="margin: auto;"
|
||||
@onkeydown="HandleKeyDown"
|
||||
@onkeyup="HandleKeyUp"
|
||||
@onkeydown:preventDefault="true"
|
||||
@onkeydown:stopPropagation="true">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
private void HandleKeyDown(KeyboardEventArgs e)
|
||||
{
|
||||
DataCollectionService.SendEvent(
|
||||
DataCollectionKeys.BuildCalcInput,
|
||||
new Dictionary<string, string> { { "key", e.Key.ToLower() }, { "input-source", "keyboard" } }
|
||||
);
|
||||
|
||||
KeyService.AddPressedKey(e.Key);
|
||||
}
|
||||
|
||||
private void HandleKeyUp(KeyboardEventArgs e)
|
||||
{
|
||||
KeyService.RemovePressedKey(e.Key);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "InputPanelComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "InputPanelComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
@inject IJSRuntime JsRuntime;
|
||||
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject IEconomyService EconomyService
|
||||
@inject IToastService ToastService
|
||||
@inject ITimingService TimingService
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="600"
|
||||
Min="0"
|
||||
Value="BuildDelay"
|
||||
OnChange="@OnBuildingInputDelayChanged">
|
||||
<FormLabelComponent>Building Input Delay</FormLabelComponent>
|
||||
<FormInfoComponent>Add a input delay to constructing buildings for simulating worker movement and player
|
||||
micro.
|
||||
</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
<div class="optionRow">
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="600"
|
||||
Min="1"
|
||||
Value="WaitTime"
|
||||
OnChange="@OnWaitTimeChanged">
|
||||
<FormLabelComponent>Wait Time</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
<ButtonComponent OnClick="OnWaitClicked">Add Wait</ButtonComponent>
|
||||
</FormLayoutComponent>
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="2048"
|
||||
Min="1"
|
||||
Value="WaitTo"
|
||||
OnChange="@OnWaitToChanged">
|
||||
<FormLabelComponent>Wait To</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
<ButtonComponent OnClick="OnWaitToClicked">Add Wait</ButtonComponent>
|
||||
</FormLayoutComponent>
|
||||
</div>
|
||||
</FormLayoutComponent>
|
||||
|
||||
<style>
|
||||
.optionRow {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private int BuildDelay { get; set; } = 2;
|
||||
private int WaitTime { get; set; } = 30;
|
||||
private int WaitTo { get; set; } = 30;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
TimingService.Subscribe(RefreshDefaults);
|
||||
|
||||
RefreshDefaults();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
TimingService.Unsubscribe(RefreshDefaults);
|
||||
}
|
||||
|
||||
void RefreshDefaults()
|
||||
{
|
||||
BuildDelay = TimingService.BuildingInputDelay;
|
||||
WaitTime = TimingService.WaitTime;
|
||||
WaitTo = TimingService.WaitTo;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnBuildingInputDelayChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
TimingService.BuildingInputDelay = int.Parse(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
void OnWaitTimeChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
TimingService.WaitTime = (int)changeEventArgs.Value!;
|
||||
WaitTime = (int)changeEventArgs.Value!;
|
||||
}
|
||||
|
||||
void OnWaitToChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
TimingService.WaitTo = (int)changeEventArgs.Value!;
|
||||
WaitTo = (int)changeEventArgs.Value!;
|
||||
}
|
||||
|
||||
private void OnWaitClicked()
|
||||
{
|
||||
if (BuildOrderService.AddWait(WaitTime))
|
||||
{
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWaitToClicked()
|
||||
{
|
||||
if (BuildOrderService.AddWaitTo(WaitTo))
|
||||
{
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "TimingComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "TimingComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
@inject IJSRuntime jsRuntime
|
||||
@inject IEconomyService economyService
|
||||
@inject IBuildOrderService buildOrderService
|
||||
|
||||
@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>
|
||||
|
||||
@if (buildOrderService.StartedOrders.TryGetValue(economyAtSecond.Interval, out var ordersAtTime))
|
||||
{
|
||||
@foreach (var order in ordersAtTime)
|
||||
{
|
||||
<div>
|
||||
Requested: @order.Info().Name
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@if (buildOrderService.CompletedOrders.TryGetValue(economyAtSecond.Interval, out var ordersCompletedAtTime))
|
||||
{
|
||||
@foreach (var order in ordersCompletedAtTime)
|
||||
{
|
||||
<div>
|
||||
New: @order.Info().Name
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Virtualize>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
economyService.Subscribe(StateHasChanged);
|
||||
buildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
economyService.Unsubscribe(StateHasChanged);
|
||||
buildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "TimelineComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "TimelineComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
|
||||
@inject IBuildOrderService buildOrderService
|
||||
@inject IEconomyService economyService
|
||||
@inject IToastService toastService
|
||||
@inject ITimingService timingService
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="2048"
|
||||
Min="0"
|
||||
Value="@timingService.GetAttackTime()"
|
||||
OnChange="@OnAttackTimeChanged">
|
||||
<FormLabelComponent>Attack Time</FormLabelComponent>
|
||||
<FormInfoComponent>
|
||||
<i>  T @Interval.ToTime(timingService.GetAttackTime())</i>
|
||||
</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
<FormNumberComponent Max="2048"
|
||||
Min="0"
|
||||
Value="@timingService.GetTravelTime()"
|
||||
OnChange="@OnTravelTimeChanged">
|
||||
<FormLabelComponent>Travel Time</FormLabelComponent>
|
||||
<FormInfoComponent>
|
||||
<i>  T @Interval.ToTime(timingService.GetTravelTime())</i>
|
||||
</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
timingService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
timingService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void OnAttackTimeChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
timingService.SetAttackTime(int.Parse(changeEventArgs.Value!.ToString()!));
|
||||
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
|
||||
toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Attack Time",
|
||||
Message = "Attack Time has changed.",
|
||||
SeverityType = SeverityType.Success
|
||||
});
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnTravelTimeChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
timingService.SetTravelTime(int.Parse(changeEventArgs.Value!.ToString()!));
|
||||
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
|
||||
toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Travel Time",
|
||||
Message = "Travel Time has changed.",
|
||||
SeverityType = SeverityType.Success
|
||||
});
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnNameChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
buildOrderService.SetName(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
void OnColorChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
buildOrderService.DeprecatedSetColor(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
|
||||
void OnNotesChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
buildOrderService.SetNotes(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "TimingComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "TimingComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
@layout PageLayout
|
||||
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
@inherits BasePage
|
||||
|
||||
@page "/contact"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Contact</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
How do I contact you for feature requests and bug reports?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
You can message me at <b>JonathanMcCaffrey#3544</b> on my <a href="https://discord.gg/uMq8bMGeeN"
|
||||
target="_blank">Discord</a> channel.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
@@ -0,0 +1,24 @@
|
||||
@page "/data-collection"
|
||||
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
@inherits BasePage
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<AlertComponent>
|
||||
<Title>Not Implemented</Title>
|
||||
<Message></Message>
|
||||
</AlertComponent>
|
||||
|
||||
<PaperComponent>
|
||||
TODO
|
||||
</PaperComponent>
|
||||
|
||||
<ContentDividerComponent/>
|
||||
|
||||
<PaperComponent>
|
||||
|
||||
</PaperComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
@@ -0,0 +1,59 @@
|
||||
@layout PageLayout
|
||||
@using IGP.Pages.DataTables.Parts
|
||||
@inherits BasePage
|
||||
|
||||
@page "/data-tables"
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Data Tables</WebsiteTitleComponent>
|
||||
|
||||
<AlertComponent Type="@SeverityType.Warning">
|
||||
<Title>Errors Present</Title>
|
||||
<Message>
|
||||
Incomplete feature for easily comparing unit stats.
|
||||
</Message>
|
||||
</AlertComponent>
|
||||
|
||||
<MudTabs Elevation="2">
|
||||
<MudTabPanel Text="Attacks">
|
||||
<WeaponTable/>
|
||||
</MudTabPanel>
|
||||
<MudTabPanel Text="Production">
|
||||
<ProductionTable/>
|
||||
</MudTabPanel>
|
||||
<MudTabPanel Text="Health">
|
||||
<VitalityTable/>
|
||||
</MudTabPanel>
|
||||
<MudTabPanel Text="Movement">
|
||||
<MovementTable/>
|
||||
</MudTabPanel>
|
||||
</MudTabs>
|
||||
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this tool?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
This tool is a data table of all information belonging to a type of data. Such as viewing all weapons,
|
||||
so one can easily sort and see what weapon attack has the highest range, and what faction and unit that
|
||||
attack belongs to.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
</PaperComponent>
|
||||
|
||||
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<MudDataGrid T="EntityMovementModel" Items="@_data"
|
||||
SortMode="SortMode.Multiple"
|
||||
Filterable="true"
|
||||
Hideable="true">
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Parent.GetName()" Title="Entity"/>
|
||||
<PropertyColumn Property="x => x.Movement"/>
|
||||
<PropertyColumn Property="x => x.Speed"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetFaction()" Title="Faction"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetImmortal()" Title="Immortal"/>
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
|
||||
@code {
|
||||
|
||||
readonly IEnumerable<EntityMovementModel> _data = EntityData.Get()
|
||||
.SelectMany(e => e.Value.EntityParts)
|
||||
.OfType<EntityMovementModel>()
|
||||
.ToList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<MudDataGrid T="EntityProductionModel" Items="@data"
|
||||
SortMode="SortMode.Multiple"
|
||||
Filterable="true"
|
||||
Hideable="true">
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Parent.GetName()" Title="Entity"/>
|
||||
<PropertyColumn Property="x => x.Alloy"/>
|
||||
<PropertyColumn Property="x => x.BuildTime"/>
|
||||
<PropertyColumn Property="x => x.Ether"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetFaction()" Title="Faction"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetImmortal()" Title="Immortal"/>
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
|
||||
@code {
|
||||
|
||||
readonly IEnumerable<EntityProductionModel> data = EntityData.Get()
|
||||
.SelectMany(e => e.Value.EntityParts)
|
||||
.OfType<EntityProductionModel>()
|
||||
.ToList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<MudDataGrid T="EntityVitalityModel" Items="@_data"
|
||||
SortMode="SortMode.Multiple"
|
||||
Filterable="true"
|
||||
Hideable="true">
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Parent.GetName()" Title="Entity"/>
|
||||
<PropertyColumn Property="x => x.Health"/>
|
||||
<PropertyColumn Property="x => x.Armor"/>
|
||||
<PropertyColumn Property="x => x.Defense"/>
|
||||
<PropertyColumn Property="x => x.DefenseLayer"/>
|
||||
<PropertyColumn Property="x => x.IsStructure"/>
|
||||
<PropertyColumn Property="x => x.IsEtheric"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetFaction()" Title="Faction"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetImmortal()" Title="Immortal"/>
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
|
||||
@code {
|
||||
|
||||
readonly IEnumerable<EntityVitalityModel> _data = EntityData.Get()
|
||||
.SelectMany(e => e.Value.EntityParts)
|
||||
.OfType<EntityVitalityModel>()
|
||||
.ToList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<MudDataGrid T="EntityWeaponModel" Items="@_data"
|
||||
SortMode="SortMode.Multiple"
|
||||
Filterable="true"
|
||||
Hideable="true">
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Parent.GetName()" Title="Entity"/>
|
||||
<PropertyColumn Property="x => x.Range" Title="Range"/>
|
||||
<PropertyColumn Property="x => x.Targets" Title="Targets"/>
|
||||
<PropertyColumn Property="x => x.Damage" Title="Damage"/>
|
||||
<PropertyColumn Property="x => x.AttacksPerSecond" Title="Attacks Per Second"/>
|
||||
<PropertyColumn Property="x => x.DamagePerSecond()" Title="DPS"/>
|
||||
<PropertyColumn Property="x => x.HasSplash" Title="Has Splash"/>
|
||||
<PropertyColumn Property="x => x.DamagePerSecondLight()" Title="DPS (Light)"/>
|
||||
<PropertyColumn Property="x => x.DamagePerSecondMedium()" Title="DPS (Medium)"/>
|
||||
<PropertyColumn Property="x => x.DamagePerSecondHeavy()" Title="DPS (Heavy)"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetFaction()" Title="Faction"/>
|
||||
<PropertyColumn Property="x => x.Parent.GetImmortal()" Title="Immortal"/>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="EntityWeaponModel"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
|
||||
@code {
|
||||
|
||||
readonly IEnumerable<EntityWeaponModel> _data = EntityData.Get()
|
||||
.SelectMany(e => e.Value.EntityParts)
|
||||
.OfType<EntityWeaponModel>()
|
||||
.ToList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
@layout PageLayout
|
||||
@inherits BasePage
|
||||
@page "/database"
|
||||
@using Model
|
||||
@implements IDisposable
|
||||
|
||||
@inject IEntityDisplayService EntityDisplayService
|
||||
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Database</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<FormDisplayComponent Label="Patch">
|
||||
<Display>
|
||||
Game Patch: @Variables.GamePatch
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
</PaperComponent>
|
||||
|
||||
<div style="margin-left: 8px">
|
||||
<ButtonGroupComponent OnClick="choice => { EntityDisplayService.SetDisplayType(choice); }"
|
||||
Choice="@EntityDisplayService.GetDisplayType()"
|
||||
Choices="@EntityDisplayService.DefaultChoices()"></ButtonGroupComponent>
|
||||
</div>
|
||||
|
||||
<PaperComponent>
|
||||
<EntityFilterComponent></EntityFilterComponent>
|
||||
|
||||
@if (searches != null)
|
||||
{
|
||||
<div class="databaseItems">
|
||||
@foreach (var entity in searches)
|
||||
{
|
||||
<CascadingValue Value="entity">
|
||||
<CascadingValue Value="@EntityDisplayService.GetDisplayType()">
|
||||
<EntityViewComponent></EntityViewComponent>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
}
|
||||
</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>@Variables.GamePatch</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>
|
||||
</PaperComponent>
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
<style>
|
||||
.databaseItems {
|
||||
height: 900px;
|
||||
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;
|
||||
}
|
||||
|
||||
.databaseInfoContainer {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Inject] public IEntityFilterService EntityFilterService { get; set; } = default!;
|
||||
|
||||
readonly List<EntityModel> defaults = (from entity in EntityModel.GetList()
|
||||
where entity.IsSpeculative == false
|
||||
select entity).ToList();
|
||||
|
||||
List<EntityModel> factions = default!;
|
||||
List<EntityModel> immortals = default!;
|
||||
List<EntityModel> entities = default!;
|
||||
List<EntityModel> searches = default!;
|
||||
|
||||
|
||||
string selectedFactionType = DataType.Any;
|
||||
string selectedImmortalType = DataType.Any;
|
||||
string selectedEntityType = EntityType.Army;
|
||||
string searchText = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
RefreshFactionSearch();
|
||||
|
||||
EntityFilterService.Subscribe(OnChange);
|
||||
EntityDisplayService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
EntityFilterService.Unsubscribe(OnChange);
|
||||
EntityDisplayService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
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 == DataType.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 == DataType.Any)
|
||||
{
|
||||
immortals = factions.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
immortals = (from entity in factions
|
||||
where entity.VanguardAdded() == null || entity.VanguardAdded().ImmortalId == 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,100 @@
|
||||
@layout PageLayout
|
||||
|
||||
@inherits BasePage
|
||||
|
||||
@page "/database/{text}"
|
||||
|
||||
@inject IEntityDisplayService EntityDisplayService
|
||||
@using Model
|
||||
@implements IDisposable
|
||||
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<FormDisplayComponent Label="Patch">
|
||||
<Display>
|
||||
Game Patch: @Variables.GamePatch
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
</PaperComponent>
|
||||
|
||||
<div style="margin-left: 8px">
|
||||
<ButtonGroupComponent OnClick="choice => { EntityDisplayService.SetDisplayType(choice); }"
|
||||
Choice="@EntityDisplayService.GetDisplayType()"
|
||||
Choices="@EntityDisplayService.DefaultChoices()"></ButtonGroupComponent>
|
||||
</div>
|
||||
|
||||
|
||||
@if (Text!.Trim().ToLower().Equals("walter"))
|
||||
{
|
||||
<PaperComponent>
|
||||
<CodeComponent>
|
||||
Unhandled Exception: EXCEPTION_MEMORY_SIZE_VIOLATION
|
||||
UNIT_WALTER too powerful to be displayed.
|
||||
|
||||
This SHOULD NEVER HAPPEN!
|
||||
</CodeComponent>
|
||||
</PaperComponent>
|
||||
}
|
||||
else if (_entity == null)
|
||||
{
|
||||
<PaperComponent>
|
||||
<div>Invalid entity name entered: <span id="invalidSearch">@Text</span></div>
|
||||
<div>No such entity. Did you mean <b>"<span id="validSearch">Throne</span>"</b>?</div>
|
||||
</PaperComponent>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<PaperComponent>
|
||||
<CascadingValue Value="_entity">
|
||||
<CascadingValue Value="@EntityDisplayService.GetDisplayType()">
|
||||
|
||||
<EntityViewComponent></EntityViewComponent>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
|
||||
</PaperComponent>
|
||||
}
|
||||
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public string? Text { get; set; }
|
||||
|
||||
private EntityModel? _entity;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
EntityDisplayService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
base.OnInitialized();
|
||||
|
||||
FocusEntity();
|
||||
}
|
||||
|
||||
private void FocusEntity()
|
||||
{
|
||||
foreach (var e in EntityData.Get().Values)
|
||||
{
|
||||
if (e.Info().Name.ToLower().Equals(Text!.ToLower()))
|
||||
{
|
||||
_entity = e;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
EntityDisplayService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@if (Entity != null)
|
||||
{
|
||||
var isVanguard = Entity.VanguardAdded() != null ? " vanguard" : "";
|
||||
|
||||
<div id="@Entity.EntityType.ToLower()-@Entity.Info().Name.ToLower()" class="entitiesContainer @isVanguard">
|
||||
<EntityHeaderComponent></EntityHeaderComponent>
|
||||
<div class="entityPartsContainer">
|
||||
<EntityVanguardAddedComponent></EntityVanguardAddedComponent>
|
||||
<EntityInfoComponent></EntityInfoComponent>
|
||||
<EntityVanguardsComponent></EntityVanguardsComponent>
|
||||
<EntityProductionComponent></EntityProductionComponent>
|
||||
<EntityStatsComponent></EntityStatsComponent>
|
||||
<EntityMechanicsComponent></EntityMechanicsComponent>
|
||||
<EntityPassivesComponent></EntityPassivesComponent>
|
||||
<EntityPyreSpellsComponent></EntityPyreSpellsComponent>
|
||||
<EntityUpgradesComponent></EntityUpgradesComponent>
|
||||
<EntityWeaponsComponent></EntityWeaponsComponent>
|
||||
<EntityAbilitiesComponent></EntityAbilitiesComponent>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<style>
|
||||
.entitiesContainer {
|
||||
margin-bottom: 12px;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 30px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.entityPartsContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.entitiesContainer {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[CascadingParameter] public EntityModel? Entity { get; set; }
|
||||
|
||||
[CascadingParameter] public string? StyleType { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
@if (Entity!.IdAbilities().Count > 0)
|
||||
{
|
||||
@if (StyleType.Equals("Plain"))
|
||||
{
|
||||
@foreach (var idAbility in Entity.IdAbilities())
|
||||
{
|
||||
var spell = EntityModel.Get(idAbility.Id);
|
||||
|
||||
var info = spell.Info();
|
||||
var production = spell.Production();
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<b>Ability Name:</b> @spell.Info().Name
|
||||
</div>
|
||||
<div>
|
||||
<b>- Description:</b> @((MarkupString)info.Description)
|
||||
</div>
|
||||
|
||||
@if (!info.Notes.Trim().Equals(""))
|
||||
{
|
||||
<div>
|
||||
<b>- Notes:</b> @((MarkupString)info.Notes)
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
@if (production != null)
|
||||
{
|
||||
if (production.Energy != 0)
|
||||
{
|
||||
<div>
|
||||
<b>- Energy: </b> @production.Energy
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!production.DefensiveLayer.Equals(0))
|
||||
{
|
||||
<div>
|
||||
<b>- Shields:</b> @production.DefensiveLayer
|
||||
</div>
|
||||
}
|
||||
|
||||
if (production.BuildTime != 0)
|
||||
{
|
||||
<div>
|
||||
<b>- BuildTime: </b> @production.BuildTime
|
||||
</div>
|
||||
}
|
||||
|
||||
if (production.Cooldown != 0)
|
||||
{
|
||||
<div>
|
||||
<b>- Cooldown: </b> @production.Cooldown
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<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>
|
||||
<EntityLabelComponent EntityId="@spell.DataType"/>
|
||||
</div>
|
||||
<div>
|
||||
<b>Description:</b> @((MarkupString)info.Description)
|
||||
</div>
|
||||
|
||||
@if (!info.Notes.Trim().Equals(""))
|
||||
{
|
||||
<div>
|
||||
<b>Notes:</b> @((MarkupString)info.Notes)
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
@if (production != null)
|
||||
{
|
||||
if (production.Energy != 0)
|
||||
{
|
||||
<div>
|
||||
<b> Energy: </b> @production.Energy
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!production.DefensiveLayer.Equals(0))
|
||||
{
|
||||
<div>
|
||||
<b>Shields:</b> @production.DefensiveLayer
|
||||
</div>
|
||||
}
|
||||
|
||||
if (production.BuildTime != 0)
|
||||
{
|
||||
<div>
|
||||
<b> BuildTime: </b> @production.BuildTime
|
||||
</div>
|
||||
}
|
||||
|
||||
if (production.Cooldown != 0)
|
||||
{
|
||||
<div>
|
||||
<b> Cooldown: </b> @production.Cooldown
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[CascadingParameter] public EntityModel? Entity { get; set; }
|
||||
|
||||
[CascadingParameter] public string StyleType { get; set; } = "Detailed";
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
@if (StyleType.Equals("Plain"))
|
||||
{
|
||||
<div>
|
||||
<b id="entityName">@Entity?.Info().Name</b>
|
||||
@if (Entity?.Info().Descriptive != DescriptiveType.None)
|
||||
{
|
||||
<span>, @Entity?.Info().Descriptive.Replace("_", " ")</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="entityHeader">
|
||||
<div id="entityName" 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>
|
||||
@if (Entity.Info().FlavorText != "")
|
||||
{
|
||||
<div>
|
||||
<i> @((MarkupString)Entity.Info().FlavorText)</i>
|
||||
</div>
|
||||
}
|
||||
|
||||
</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 {
|
||||
|
||||
[CascadingParameter] public EntityModel? Entity { get; set; }
|
||||
|
||||
|
||||
[CascadingParameter] public string StyleType { get; set; } = "Detailed";
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user