Initial Commit

This commit is contained in:
2026-05-29 14:17:46 -04:00
commit b7d0676d5b
498 changed files with 30308 additions and 0 deletions
+38
View File
@@ -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; } = "";
}
+7
View File
@@ -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;">
&#8721;
</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!;
}
+11
View File
@@ -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";
}
}
+18
View File
@@ -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;