20 Commits

Author SHA1 Message Date
JonathanMcCaffrey 358781affe Disabling slop features 2026-06-13 14:55:58 -04:00
6d486f49 90e321da48 ... 2026-06-11 17:04:04 -04:00
6d486f49 697eea20c0 ... 2026-06-11 16:36:25 -04:00
6d486f49 755aeb9901 ... 2026-06-11 16:23:05 -04:00
6d486f49 11ef727efe ... 2026-06-11 16:18:36 -04:00
JonathanMcCaffrey f98d37fae4 ... 2026-06-09 13:23:54 -04:00
JonathanMcCaffrey 1608328216 ... 2026-06-09 13:14:16 -04:00
JonathanMcCaffrey 362a070fc3 ... 2026-06-08 20:23:23 -04:00
JonathanMcCaffrey 7310e4ed71 Agent code and restructuring 2026-06-08 14:38:00 -04:00
JonathanMcCaffrey 0feac0f0a0 Agent Tests for API, MAUI, and Slop Features 2026-06-04 10:43:01 -04:00
JonathanMcCaffrey 46150d3a69 Converting Tests back to C# but still with Playwright 2026-06-03 16:04:39 -04:00
JonathanMcCaffrey 85834466f1 CLI and Publish Tests 2026-06-02 22:02:01 -04:00
JonathanMcCaffrey 7da6f554a8 Faction border code design and colour tweaks 2026-06-02 22:02:01 -04:00
6d486f49 dc0395c7d3 Updating .NET versions 2026-06-02 22:02:01 -04:00
JonathanMcCaffrey 026aebd5ad Clearing Entity Click View on Clear and other notes 2026-06-02 22:02:01 -04:00
JonathanMcCaffrey 3974fcfb91 Removing legacy test automation 2026-06-01 09:58:44 -04:00
JonathanMcCaffrey 410e7e23b7 Added current work plan 2026-06-01 09:57:15 -04:00
JonathanMcCaffrey 6655cdeee7 Console cleanup 2026-06-01 08:22:31 -04:00
JonathanMcCaffrey 1f7a0819fc Playwright start 2026-05-31 14:33:58 -04:00
6d486f49 73f29cea08 Updating version 2026-03-23 22:14:58 -04:00
612 changed files with 47212 additions and 122467 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_CALM_MUD_04916B210 }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "IGP"
app_location: "Web"
api_location: ""
output_location: "./wwwroot"
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_NICE_COAST_0F8B08010 }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "IGP"
app_location: "Web"
api_location: ""
output_location: "./wwwroot"
+4
View File
@@ -137,6 +137,7 @@ DocProject/Help/html
# Click-Once directory
publish/
publish_release/
# Publish Web Output
*.[Pp]ublish.xml
@@ -264,3 +265,6 @@ __pycache__/
**/.vs/
.DS_Store
publish_release/
View File
+1
View File
@@ -0,0 +1 @@
3.0
View File
+3 -3
View File
@@ -7,7 +7,7 @@
"type": "process",
"args": [
"build",
"${workspaceFolder}/IGP/IGP.csproj",
"${workspaceFolder}/Web/Web.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -19,7 +19,7 @@
"type": "process",
"args": [
"publish",
"${workspaceFolder}/IGP/IGP.csproj",
"${workspaceFolder}/Web/Web.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -33,7 +33,7 @@
"watch",
"run",
"--project",
"${workspaceFolder}/IGP/IGP.csproj"
"${workspaceFolder}/Web/Web.csproj"
],
"problemMatcher": "$msCompile"
}
+18
View File
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>API</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HotChocolate.AspNetCore" Version="16.1.2"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Model\Model.csproj"/>
</ItemGroup>
</Project>
+254
View File
@@ -0,0 +1,254 @@
using Model.Entity;
using Model.Entity.Parts;
namespace API.GraphQL.Types;
public class EntityGraphType : ObjectType<EntityModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityModel> descriptor)
{
descriptor.Name("Entity");
descriptor.Field(e => e.DataType).Name("id");
descriptor.Field(e => e.EntityType).Name("type");
descriptor.Field(e => e.IsSpeculative);
descriptor.Field(e => e.Descriptive).Name("descriptiveType");
descriptor.Ignore(e => e.EntityParts);
descriptor.Field("name")
.Resolve(ctx => ctx.Parent<EntityModel>().GetName());
descriptor.Field("factionName")
.Resolve(ctx => ctx.Parent<EntityModel>().GetFaction());
descriptor.Field("info")
.Type<EntityInfoGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Info());
descriptor.Field("production")
.Type<EntityProductionGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Production());
descriptor.Field("supply")
.Type<EntitySupplyGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Supply());
descriptor.Field("tier")
.Type<EntityTierGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Tier());
descriptor.Field("movement")
.Type<EntityMovementGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Movement());
descriptor.Field("vitality")
.Type<EntityVitalityGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Vitality());
descriptor.Field("requirements")
.Type<ListType<EntityRequirementGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().Requirements());
descriptor.Field("weapons")
.Type<ListType<EntityWeaponGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().Weapons());
descriptor.Field("hotkey")
.Type<EntityHotkeyGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Hotkey());
descriptor.Field("faction")
.Type<EntityFactionGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Faction());
descriptor.Field("harvest")
.Type<EntityHarvestGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().Harvest());
descriptor.Field("idAbilities")
.Type<ListType<EntityIdReferenceGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().IdAbilities());
descriptor.Field("idArmies")
.Type<ListType<EntityIdReferenceGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().IdArmies());
descriptor.Field("idPassives")
.Type<ListType<EntityIdReferenceGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().IdPassives());
descriptor.Field("idUpgrades")
.Type<ListType<EntityIdReferenceGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().IdUpgrades());
descriptor.Field("idVanguards")
.Type<ListType<EntityIdReferenceGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().IdVanguards());
descriptor.Field("idPyreSpells")
.Type<ListType<EntityIdReferenceGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().IdPyreSpells());
descriptor.Field("mechanics")
.Type<ListType<EntityMechanicGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().Mechanics());
descriptor.Field("passives")
.Type<ListType<EntityNamedDescGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().Passives());
descriptor.Field("strategies")
.Type<ListType<EntityStrategyGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().Strategies());
descriptor.Field("replaceds")
.Type<ListType<EntityVanguardReplacedGraphType>>()
.Resolve(ctx => ctx.Parent<EntityModel>().Replaceds());
descriptor.Field("vanguardAdded")
.Type<EntityVanguardAddedGraphType>()
.Resolve(ctx => ctx.Parent<EntityModel>().VanguardAdded());
}
}
public class EntityInfoGraphType : ObjectType<EntityInfoModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityInfoModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
descriptor.Field(e => e.Name);
descriptor.Field(e => e.Descriptive).Name("descriptiveType");
descriptor.Field(e => e.Description);
descriptor.Field(e => e.Notes);
descriptor.Field(e => e.FlavorText);
}
}
public class EntityProductionGraphType : ObjectType<EntityProductionModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityProductionModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntitySupplyGraphType : ObjectType<EntitySupplyModel>
{
protected override void Configure(IObjectTypeDescriptor<EntitySupplyModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityTierGraphType : ObjectType<EntityTierModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityTierModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityMovementGraphType : ObjectType<EntityMovementModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityMovementModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityVitalityGraphType : ObjectType<EntityVitalityModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityVitalityModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityRequirementGraphType : ObjectType<EntityRequirementModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityRequirementModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityWeaponGraphType : ObjectType<EntityWeaponModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityWeaponModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityHotkeyGraphType : ObjectType<EntityHotkeyModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityHotkeyModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityFactionGraphType : ObjectType<EntityFactionModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityFactionModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityHarvestGraphType : ObjectType<EntityHarvestModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityHarvestModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityIdReferenceGraphType : ObjectType<EntityIdAbilityModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityIdAbilityModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityMechanicGraphType : ObjectType<EntityMechanicModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityMechanicModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityNamedDescGraphType : ObjectType<EntityPassiveModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityPassiveModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityStrategyGraphType : ObjectType<EntityStrategyModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityStrategyModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityVanguardReplacedGraphType : ObjectType<EntityVanguardReplacedModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityVanguardReplacedModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
public class EntityVanguardAddedGraphType : ObjectType<EntityVanguardAddedModel>
{
protected override void Configure(IObjectTypeDescriptor<EntityVanguardAddedModel> descriptor)
{
descriptor.Ignore(e => e.Parent);
}
}
+32
View File
@@ -0,0 +1,32 @@
using API.GraphQL.Types;
using Model.Entity.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddGraphQLServer()
.AddQueryType(d =>
{
d.Name("Query");
d.Field("entities")
.Type<NonNullType<ListType<NonNullType<EntityGraphType>>>>()
.Resolve(ctx => EntityData.Get().Values.ToList());
d.Field("entity")
.Type<EntityGraphType>()
.Argument("id", a => a.Type<NonNullType<StringType>>())
.Resolve(ctx =>
{
var id = ctx.ArgumentValue<string>("id");
EntityData.Get().TryGetValue(id, out var entity);
return entity;
});
})
.AddType<EntityGraphType>();
var app = builder.Build();
app.MapGraphQL();
app.Run();
+12
View File
@@ -0,0 +1,12 @@
{
"profiles": {
"API": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:63192;http://localhost:63193"
}
}
}
+16
View File
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>IGP.Calculator.Cli</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Services\Services.csproj"/>
<ProjectReference Include="..\Model\Model.csproj"/>
</ItemGroup>
</Project>
+155
View File
@@ -0,0 +1,155 @@
using IGP.Calculator.Cli.Services;
using Model.Entity;
using Model.Entity.Data;
using Services.Immortal;
using Services.Website;
var faction = DataType.FACTION_QRath;
var immortal = DataType.IMMORTAL_Orzum;
var attackTime = 1500;
var entityNames = new List<string>();
for (var i = 0; i < args.Length; i++)
switch (args[i].ToLower())
{
case "--faction" when i + 1 < args.Length:
var f = args[++i].ToLower();
faction = f switch
{
"qrath" => DataType.FACTION_QRath,
"aru" => DataType.FACTION_Aru,
_ => throw new Exception($"Unknown faction '{args[i]}'. Use QRath or Aru.")
};
immortal = f switch
{
"qrath" => DataType.IMMORTAL_Orzum,
"aru" => DataType.IMMORTAL_Mala,
_ => immortal
};
break;
case "--immortal" when i + 1 < args.Length:
var im = args[++i];
immortal = im switch
{
nameof(DataType.IMMORTAL_Orzum) => DataType.IMMORTAL_Orzum,
nameof(DataType.IMMORTAL_Ajari) => DataType.IMMORTAL_Ajari,
nameof(DataType.IMMORTAL_Atzlan) => DataType.IMMORTAL_Atzlan,
nameof(DataType.IMMORTAL_Mala) => DataType.IMMORTAL_Mala,
nameof(DataType.IMMORTAL_Xol) => DataType.IMMORTAL_Xol,
_ => throw new Exception($"Unknown immortal '{im}'.")
};
break;
case "--attack-time" or "-a" when i + 1 < args.Length:
attackTime = int.Parse(args[++i]);
break;
default:
entityNames.Add(args[i]);
break;
}
var toastService = new ToastService();
var storageService = new NullStorageService();
var timingService = new TimingService(storageService);
timingService.SetAttackTime(attackTime);
var buildOrderService = new BuildOrderService(toastService, timingService);
var economyService = new EconomyService();
buildOrderService.Reset(faction);
economyService.Calculate(buildOrderService, timingService, 0);
Console.WriteLine($"Faction: {(faction == DataType.FACTION_QRath ? "Q'Rath" : "Aru")}");
Console.WriteLine($"Immortal: {immortal.Replace("IMMORTAL_", "")}");
Console.WriteLine($"Attack Time: {attackTime}s");
Console.WriteLine(new string('-', 50));
foreach (var name in entityNames)
{
if (name.StartsWith("wait ", StringComparison.OrdinalIgnoreCase))
{
var seconds = int.Parse(name[5..]);
buildOrderService.AddWait(seconds);
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
Console.WriteLine($" Wait {seconds}s -> now at interval {buildOrderService.GetLastRequestInterval()}");
continue;
}
if (name.StartsWith("waitto ", StringComparison.OrdinalIgnoreCase))
{
var interval = int.Parse(name[7..]);
buildOrderService.AddWaitTo(interval);
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
Console.WriteLine($" Wait to {interval}s -> now at interval {buildOrderService.GetLastRequestInterval()}");
continue;
}
var entity = FindEntity(name, faction, immortal);
if (entity == null)
{
Console.WriteLine($" ERROR: '{name}' not found for this faction/immortal.");
continue;
}
var beforeInterval = buildOrderService.GetLastRequestInterval();
var added = buildOrderService.Add(entity, economyService);
if (added)
{
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
var startedAt = buildOrderService.GetLastRequestInterval();
var production = entity.Production();
var completedAt = production != null ? startedAt + production.BuildTime : startedAt;
var cost = production != null
? $" [{production.Alloy}a/{production.Ether}e/{production.Pyre}p, {production.BuildTime}s]"
: "";
Console.WriteLine($" {entity.GetName(),-25} start={startedAt,4}s done={completedAt,4}s{cost}");
}
else
{
Console.WriteLine($" ERROR: Could not add '{name}'.");
var toasts = toastService.GetToasts();
if (toasts.Count > 0)
{
var lastToast = toasts[0];
Console.WriteLine($" Reason: {lastToast.Title} - {lastToast.Message}");
}
}
}
Console.WriteLine(new string('-', 50));
var lastInterval = buildOrderService.GetLastRequestInterval();
var finalEconomy = economyService.GetEconomy(timingService.GetAttackTime());
var lastEconomy = economyService.GetEconomy(lastInterval);
Console.WriteLine($"Army Attacking At: {timingService.GetAttackTime()}s");
Console.WriteLine("");
Console.WriteLine($"At attack time ({timingService.GetAttackTime()}s):");
Console.WriteLine($" Alloy: {finalEconomy.Alloy,10:F1}");
Console.WriteLine($" Ether: {finalEconomy.Ether,10:F1}");
Console.WriteLine($" Pyre: {finalEconomy.Pyre,10:F1}");
Console.WriteLine("");
Console.WriteLine($"At last build action ({lastInterval}s):");
Console.WriteLine($" Alloy: {lastEconomy.Alloy,10:F1}");
Console.WriteLine($" Ether: {lastEconomy.Ether,10:F1}");
Console.WriteLine($" Pyre: {lastEconomy.Pyre,10:F1}");
static EntityModel? FindEntity(string name, string faction, string immortal)
{
var candidates = EntityModel.GetList()
.Where(e => e.Info()?.Name?.Equals(name, StringComparison.OrdinalIgnoreCase) == true)
.Where(e => e.Faction()?.Faction == faction)
.ToList();
if (candidates.Count == 0)
candidates = EntityModel.GetList()
.Where(e => e.Info()?.Name?.Equals(name, StringComparison.OrdinalIgnoreCase) == true)
.Where(e => e.Faction() == null || e.Faction()!.Faction == DataType.FACTION_Neutral)
.ToList();
if (candidates.Count == 0) return null;
if (candidates.Count == 1) return candidates[0];
var vanguardMatch = candidates.FirstOrDefault(e => e.VanguardAdded()?.ImmortalId == immortal);
if (vanguardMatch != null) return vanguardMatch;
return candidates.FirstOrDefault(e => e.VanguardAdded() == null);
}
+33
View File
@@ -0,0 +1,33 @@
using Services;
namespace IGP.Calculator.Cli.Services;
public class NullStorageService : IStorageService
{
private readonly Dictionary<string, object?> _store = new();
public void Subscribe(Action action)
{
}
public void Unsubscribe(Action action)
{
}
public T GetValue<T>(string forKey)
{
if (_store.TryGetValue(forKey, out var value) && value is T typed)
return typed;
return default!;
}
public void SetValue<T>(string key, T value)
{
_store[key] = value;
}
public Task Load()
{
return Task.CompletedTask;
}
}
-16
View File
@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0" />
</ItemGroup>
</Project>
-5
View File
@@ -1,5 +0,0 @@
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
await builder.Build().RunAsync();
-9
View File
@@ -1,9 +0,0 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Client.Client
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
-15
View File
@@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Client.Client\Client.Client.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.0" />
</ItemGroup>
</Project>
-22
View File
@@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<ResourcePreloader />
<link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["Client.styles.css"]" />
<ImportMap />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</head>
<body>
<Routes />
<script src="@Assets["_framework/blazor.web.js"]"></script>
</body>
</html>
@@ -1,105 +0,0 @@
.navbar-toggler {
appearance: none;
cursor: pointer;
width: 3.5rem;
height: 2.5rem;
color: white;
position: absolute;
top: 0.5rem;
right: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
}
.navbar-toggler:checked {
background-color: rgba(255, 255, 255, 0.5);
}
.top-row {
min-height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
.navbar-brand {
font-size: 1.1rem;
}
.bi {
display: inline-block;
position: relative;
width: 1.25rem;
height: 1.25rem;
margin-right: 0.75rem;
top: -1px;
background-size: cover;
}
.bi-house-door-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}
.bi-plus-square-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}
.bi-list-nested-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}
.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep .nav-link {
color: #d7d7d7;
background: none;
border: none;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
width: 100%;
}
.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.37);
color: white;
}
.nav-item ::deep .nav-link:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
.nav-scrollable {
display: none;
}
.navbar-toggler:checked ~ .nav-scrollable {
display: block;
}
@media (min-width: 641px) {
.navbar-toggler {
display: none;
}
.nav-scrollable {
/* Never collapse the sidebar for wide screens */
display: block;
/* Allow sidebar to scroll for tall menus */
height: calc(100vh - 3.5rem);
overflow-y: auto;
}
}
@@ -1,36 +0,0 @@
@page "/Error"
@using System.Diagnostics
<PageTitle>Error</PageTitle>
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@code{
[CascadingParameter]
private HttpContext? HttpContext { get; set; }
private string? RequestId { get; set; }
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
protected override void OnInitialized() =>
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
}
-6
View File
@@ -1,6 +0,0 @@
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Client._Imports).Assembly }" NotFoundPage="typeof(Pages.NotFound)">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>
-12
View File
@@ -1,12 +0,0 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Client
@using Client.Client
@using Client.Components
@using Client.Components.Layout
-32
View File
@@ -1,32 +0,0 @@
using Client.Client.Pages;
using Client.Components;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveWebAssemblyComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
} else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(Client.Client._Imports).Assembly);
app.Run();
@@ -1,25 +0,0 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5029",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7182;http://localhost:5029",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
-60
View File
@@ -1,60 +0,0 @@
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
a, .btn-link {
color: #006bb7;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
.content {
padding-top: 1.1rem;
}
h1:focus {
outline: none;
}
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid #e50000;
}
.validation-message {
color: #e50000;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
.darker-border-checkbox.form-check-input {
border-color: #929292;
}
.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
color: var(--bs-secondary-color);
text-align: end;
}
.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
text-align: start;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,597 +0,0 @@
/*!
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #c4c8cb;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #fff;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: #6ea8fe;
--bs-secondary-text-emphasis: #a7acb1;
--bs-success-text-emphasis: #75b798;
--bs-info-text-emphasis: #6edff6;
--bs-warning-text-emphasis: #ffda6a;
--bs-danger-text-emphasis: #ea868f;
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #161719;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #41464b;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #087990;
--bs-warning-border-subtle: #997404;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #8bb9fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
--bs-form-valid-border-color: #75b798;
--bs-form-invalid-color: #ea868f;
--bs-form-invalid-border-color: #ea868f;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
border: 0;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.1875em;
color: var(--bs-highlight-color);
background-color: var(--bs-highlight-bg);
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: var(--bs-secondary-color);
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,594 +0,0 @@
/*!
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #c4c8cb;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #fff;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: #6ea8fe;
--bs-secondary-text-emphasis: #a7acb1;
--bs-success-text-emphasis: #75b798;
--bs-info-text-emphasis: #6edff6;
--bs-warning-text-emphasis: #ffda6a;
--bs-danger-text-emphasis: #ea868f;
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #161719;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #41464b;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #087990;
--bs-warning-border-subtle: #997404;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #8bb9fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
--bs-form-valid-border-color: #75b798;
--bs-form-invalid-color: #ea868f;
--bs-form-invalid-border-color: #ea868f;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
border: 0;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.1875em;
color: var(--bs-highlight-color);
background-color: var(--bs-highlight-bg);
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: var(--bs-secondary-color);
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>14</LangVersion>
<RootNamespace>Components</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -0,0 +1,87 @@
@inject IGlossaryService glossaryService
@if (TermId != null)
{
var term = glossaryService.GetTerm(TermId);
if (term != null)
{
<div class="glossaryTooltipWrapper">
<div class="glossaryTooltipContent">
<div class="glossaryTooltipHeader">
<span class="glossaryTooltipTerm">@term.Term</span>
<span class="glossaryTooltipCategory">@term.Category</span>
</div>
<div class="glossaryTooltipBody">
@term.ShortDefinition
</div>
</div>
@ChildContent
</div>
}
}
<style>
.glossaryTooltipWrapper {
position: relative;
display: inline-block;
}
.glossaryTooltipContent {
visibility: hidden;
position: absolute;
width: 400px;
max-width: 93vw;
bottom: 100%;
margin-bottom: 8px;
padding: 12px;
z-index: 2147483647;
background-color: var(--info-secondary);
border: 1px solid var(--info-secondary-border);
border-radius: 4px;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.5);
left: 50%;
transform: translateX(-50%);
}
.glossaryTooltipWrapper:hover .glossaryTooltipContent {
visibility: visible;
}
.glossaryTooltipHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.glossaryTooltipTerm {
font-weight: 800;
font-size: 1.1rem;
}
.glossaryTooltipCategory {
font-size: 0.8rem;
opacity: 0.7;
}
.glossaryTooltipBody {
font-size: 0.9rem;
line-height: 1.4;
}
@@media only screen and (max-width: 1025px) {
.glossaryTooltipContent {
margin: auto;
margin-bottom: 20px;
position: absolute;
}
}
</style>
@code {
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
[Parameter] public string TermId { get; set; } = default!;
}
@@ -1,79 +0,0 @@
@inject ITooltipService TooltipService
@implements IDisposable
@if (Tooltip == null)
{
<div>Add tooltip object...</div>
}
else
{
<div onclick="@Dismiss" class="tooltipContainer">
<div class="tooltip">
@Tooltip.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 TooltipModel? Tooltip { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
TooltipService.Subscribe(OnUpdate);
}
void Dismiss()
{
TooltipService.RemoveTooltip(Tooltip!);
}
void IDisposable.Dispose()
{
TooltipService.Unsubscribe(OnUpdate);
}
void OnUpdate()
{
}
}
+1 -2
View File
@@ -1,5 +1,4 @@
@using Model.MemoryTester
@using Services.Immortal
@implements IDisposable
@inject IMemoryTesterService MemoryTesterService
@@ -13,7 +12,7 @@
}
<div>
<input readonly="@MemoryQuestion.IsRevealed"
class="formTextInput @(MemoryQuestion.IsRevealed ? "revealed" : IsSubmitted == false ? "guess" : int.Parse(guess ?? string.Empty) == MemoryQuestion.Answer ? "correct" : "wrong")"
class="formTextInput @(MemoryQuestion.IsRevealed ? "revealed" : !IsSubmitted ? "guess" : int.Parse(guess ?? string.Empty) == MemoryQuestion.Answer ? "correct" : "wrong")"
placeholder="guess..."
type="number"
value="@guess"
@@ -0,0 +1,145 @@
@implements IDisposable
<div class="cooldown-wrap" style="--cooldown-size: @(Size)px">
<button class="cooldown-btn"
disabled="@_isCooldown"
@onclick="HandleClick"
@onclick:preventDefault="_isCooldown">
<span class="cooldown-btn-text">@ChildContent</span>
</button>
@if (_isCooldown)
{
<div class="cooldown-overlay" style="--angle: @(_elapsedAngle)deg">
<span class="cooldown-label">@_remainingSeconds</span>
</div>
}
</div>
<style>
.cooldown-wrap {
position: relative;
display: inline-flex;
width: var(--cooldown-size, 120px);
height: var(--cooldown-size, 120px);
}
.cooldown-btn {
width: 100%;
height: 100%;
border: 2px solid var(--primary);
border-radius: 12px;
background: var(--paper);
color: var(--text-primary, #eee);
font-weight: 700;
font-size: 0.9rem;
cursor: pointer;
padding: 12px;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s, border-color 0.15s;
line-height: 1.3;
font-family: inherit;
}
.cooldown-btn:hover:not(:disabled) {
background: var(--paper-hover);
border-color: var(--primary-hover);
}
.cooldown-btn:active:not(:disabled) {
transform: scale(0.97);
}
.cooldown-btn:disabled {
cursor: default;
}
.cooldown-btn-text {
pointer-events: none;
}
.cooldown-overlay {
position: absolute;
inset: 0;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
user-select: none;
}
.cooldown-overlay::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: rgba(22, 22, 24, 0.45);
mask-image: conic-gradient(transparent 0deg, transparent var(--angle), #000 var(--angle), #000 360deg);
-webkit-mask-image: conic-gradient(transparent 0deg, transparent var(--angle), #000 var(--angle), #000 360deg);
}
.cooldown-label {
font-size: 1.6rem;
font-weight: 900;
color: #999;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
pointer-events: none;
position: relative;
z-index: 1;
}
</style>
@code {
[Parameter] public RenderFragment? ChildContent { get; set; }
[Parameter] public EventCallback OnClick { get; set; }
[Parameter] public int CooldownSeconds { get; set; } = 12;
[Parameter] public int Size { get; set; } = 120;
private bool _isCooldown;
private int _elapsedAngle;
private int _remainingSeconds;
private DateTime _startTime;
private System.Timers.Timer? _timer;
private async Task HandleClick()
{
if (_isCooldown) return;
await OnClick.InvokeAsync(null);
StartCooldown();
}
private void StartCooldown()
{
_isCooldown = true;
_startTime = DateTime.UtcNow;
_elapsedAngle = 0;
_remainingSeconds = CooldownSeconds;
_timer = new System.Timers.Timer(33);
_timer.Elapsed += OnTick;
_timer.AutoReset = true;
_timer.Enabled = true;
}
private void OnTick(object? sender, System.Timers.ElapsedEventArgs e)
{
var elapsed = (DateTime.UtcNow - _startTime).TotalSeconds;
if (elapsed >= CooldownSeconds)
{
_isCooldown = false;
_timer?.Stop();
_timer?.Dispose();
_timer = null;
InvokeAsync(StateHasChanged);
return;
}
_elapsedAngle = (int)(elapsed / CooldownSeconds * 360);
_remainingSeconds = CooldownSeconds - (int)elapsed;
InvokeAsync(StateHasChanged);
}
public void Dispose()
{
if (_timer != null)
{
_timer.Stop();
_timer.Dispose();
_timer = null;
}
}
}
@@ -0,0 +1,29 @@
@inject IGlossaryService glossaryService
@inject IGlossaryDialogService glossaryDialogService
@if (TermId == null)
{
<span>Missing term</span>
}
else
{
var term = glossaryService.GetTerm(TermId);
if (term != null)
{
<button class="glossaryLabel @term.Category.ToLowerInvariant()" @onclick="TermLabelClicked"
title="@term.ShortDefinition">
@term.Term
</button>
}
}
@code {
[Parameter] public string TermId { get; set; } = default!;
void TermLabelClicked()
{
glossaryDialogService.AddDialog(TermId);
}
}
@@ -0,0 +1,33 @@
.glossaryLabel {
font-weight: bolder;
box-shadow: 1px 1px 0 0 rgba(0, 0, 0, 0.2);
padding-right: 4px;
border: none;
background: none;
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: underline;
text-decoration-style: dotted;
text-underline-offset: 2px;
}
.glossaryLabel:hover {
background-color: var(--primary-hover);
}
.resource {
color: gold;
}
.mechanic {
color: #8fc5ff;
}
.faction {
color: #da4e4e;
}
.role {
color: #87aa87;
}
+1 -11
View File
@@ -7,15 +7,7 @@
<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>
}
<span>/</span>
</div>
</button>
@@ -51,8 +43,6 @@
private string _userAgent = "";
bool IsMac => _userAgent.Contains("Mac OS");
private void ButtonClicked(EventArgs eventArgs)
{
SearchService.Show();
@@ -0,0 +1,180 @@
@inject IEntityDialogService entityDialogService
@inject NavigationManager NavigationManager
<div class="techTreeContainer" @ref="containerRef">
<svg class="techTreeSvg" width="@svgWidth" height="@svgHeight">
<!-- Edges -->
@foreach (var edge in Graph.Edges)
{
var source = Graph.Nodes.FirstOrDefault(n => n.Id == edge.SourceId);
var target = Graph.Nodes.FirstOrDefault(n => n.Id == edge.TargetId);
if (source != null && target != null)
{
var color = EdgeColor(edge.EdgeType);
var strokeWidth = edge.EdgeType == TechTreeEdgeType.Produces ? "2.5" : "1.5";
var strokeDash = edge.EdgeType == TechTreeEdgeType.RequiresProduction || edge.EdgeType == TechTreeEdgeType.RequiresResearch ? "6,3" : "";
strokeDash = edge.EdgeType == TechTreeEdgeType.Morph ? "2,2" : strokeDash;
<line x1="@(source.X + nodeWidth / 2)" y1="@(source.Y + nodeHeight / 2)"
x2="@(target.X + nodeWidth / 2)" y2="@(target.Y + nodeHeight / 2)"
stroke="@color" stroke-width="@strokeWidth"
stroke-dasharray="@strokeDash"
marker-end="url(#arrowhead-@(edge.EdgeType))"/>
}
}
<!-- Arrowhead markers -->
<defs>
@foreach (var edgeType in Graph.Edges.Select(e => e.EdgeType).Distinct())
{
<marker id="arrowhead-@edgeType" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="@EdgeColor(edgeType)"/>
</marker>
}
</defs>
<!-- Nodes -->
@foreach (var node in Graph.Nodes)
{
var color = NodeColor(node.Descriptive);
var isHighlighted = HighlightEntityId == node.Id;
<g class="techTreeNode" @onclick="() => OnNodeClick(node.Id)">
<rect x="@node.X" y="@node.Y" width="@nodeWidth" height="@nodeHeight" rx="6"
fill="var(--paper)" stroke="@color" stroke-width="@(isHighlighted ? 3 : 1.5)"
class="@(isHighlighted ? "highlighted" : "")"/>
<text x="@(node.X + nodeWidth / 2)" y="@(node.Y + nodeHeight / 2)"
text-anchor="middle" dominant-baseline="central"
fill="white" font-size="12" font-weight="600">
@TruncateText(node.Name, 20)
</text>
<title>@node.Name (@node.EntityType)</title>
</g>
}
</svg>
</div>
<style>
.techTreeContainer {
width: 100%;
overflow: auto;
border: 2px solid var(--paper-border);
border-radius: 8px;
background-color: var(--background);
}
.techTreeSvg {
display: block;
}
.techTreeNode {
cursor: pointer;
}
.techTreeNode rect {
transition: stroke-width 0.15s;
}
.techTreeNode rect.highlighted {
filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.5));
}
.techTreeNode:hover rect {
stroke-width: 3;
}
</style>
@code {
[Parameter] public TechTreeGraphModel Graph { get; set; } = new();
[Parameter] public string? HighlightEntityId { get; set; }
[Parameter] public EventCallback<string> OnEntitySelected { get; set; }
private ElementReference containerRef;
private const float nodeWidth = 140;
private const float nodeHeight = 36;
private const float horizontalSpacing = 60;
private const float verticalSpacing = 30;
private const float topPadding = 40;
private const float leftPadding = 40;
private float svgWidth = 800;
private float svgHeight = 600;
protected override void OnParametersSet()
{
ComputeLayout();
}
void ComputeLayout()
{
if (Graph.Nodes.Count == 0) return;
var layers = Graph.Nodes.GroupBy(n => n.Layer)
.OrderBy(g => g.Key)
.ToList();
// Simple layered layout: left to right (layers are columns)
for (var layerIdx = 0; layerIdx < layers.Count; layerIdx++)
{
var layerNodes = layers.ElementAt(layerIdx).OrderBy(n => n.Name).ToList();
var layerHeight = layerNodes.Count * (nodeHeight + verticalSpacing) - verticalSpacing;
for (var nodeIdx = 0; nodeIdx < layerNodes.Count; nodeIdx++)
{
var node = layerNodes[nodeIdx];
node.X = leftPadding + layerIdx * (nodeWidth + horizontalSpacing);
node.Y = topPadding + nodeIdx * (nodeHeight + verticalSpacing);
}
}
svgWidth = layers.Count * (nodeWidth + horizontalSpacing) + leftPadding + 100;
svgHeight = layers.Max(g => g.Count()) * (nodeHeight + verticalSpacing) + topPadding + 80;
if (svgWidth < 800) svgWidth = 800;
if (svgHeight < 400) svgHeight = 400;
}
void OnNodeClick(string entityId)
{
entityDialogService.AddDialog(entityId);
OnEntitySelected.InvokeAsync(entityId);
}
string NodeColor(string descriptive)
{
return descriptive.ToLowerInvariant() switch
{
"frontliner" => "#ff6b6b",
"skirmisher" => "#ffa502",
"support" => "#2ed573",
"generalist" => "#1e90ff",
"worker" => "#ffd43b",
"stronghold" => "#ff4757",
"upgrade" => "#a55eea",
"technology" => "#a55eea",
_ => "#8fc5ff"
};
}
string EdgeColor(string edgeType)
{
return edgeType switch
{
"Produces" => "#2ed573",
"RequiresProduction" => "#ffa502",
"RequiresResearch" => "#a55eea",
"Morph" => "#ff6b6b",
"Upgrades" => "#1e90ff",
_ => "#666"
};
}
string TruncateText(string text, int maxLength)
{
return text.Length <= maxLength ? text : text.Substring(0, maxLength - 3) + "...";
}
}
+4
View File
@@ -4,9 +4,13 @@
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Model.Feedback
@using Model.Glossary
@using Model.TechTree
@using Model.Website
@using Model.Website.Enums
@using Services
@using Services.Immortal
@using Services.Website
@using System.Net.Http
@using System.Net.Http.Json
@using System.Text
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Device.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
+14
View File
@@ -0,0 +1,14 @@
namespace Device;
public partial class App : Application
{
public App()
{
InitializeComponent();
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new AppShell());
}
}
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Shell
x:Class="Device.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Device"
Title="Device">
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Shell>
+9
View File
@@ -0,0 +1,9 @@
namespace Device;
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
+83
View File
@@ -0,0 +1,83 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>net10.0-android</TargetFrameworks>
<TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('linux'))">$(TargetFrameworks);net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net10.0-windows10.0.19041.0</TargetFrameworks>
<ProjectRuntimeIdentifier Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">win-x64</ProjectRuntimeIdentifier>
<!-- Note for MacCatalyst:
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifier>.
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->
<OutputType>Exe</OutputType>
<RootNamespace>Device</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Enable XAML source generation for faster build times and improved performance.
This generates C# code from XAML at compile time instead of runtime inflation.
To disable, remove this line.
For individual files, you can override by setting Inflator metadata:
<MauiXaml Update="MyPage.xaml" Inflator="Default" /> (reverts to defaults: Runtime for Debug, XamlC for Release)
<MauiXaml Update="MyPage.xaml" Inflator="Runtime" /> (force runtime inflation) -->
<MauiXamlInflator>SourceGen</MauiXamlInflator>
<!-- Display name -->
<ApplicationTitle>Device</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.companyname.device</ApplicationId>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
<WindowsPackageType>None</WindowsPackageType>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4"/>
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128"/>
<!-- Images -->
<MauiImage Include="Resources\Images\*"/>
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185"/>
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*"/>
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)"/>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.0"/>
<PackageReference Include="MudBlazor" Version="9.2.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Components\Components.csproj"/>
<ProjectReference Include="..\Model\Model.csproj"/>
<ProjectReference Include="..\Pages\Pages.csproj"/>
<ProjectReference Include="..\Services\Services.csproj"/>
</ItemGroup>
</Project>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Device"
x:Class="Device.MainPage">
<BlazorWebView x:Name="blazorWebView" HostPage="wwwroot/device.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app" ComponentType="{x:Type local:MainRazor}" />
</BlazorWebView.RootComponents>
</BlazorWebView>
</ContentPage>
+9
View File
@@ -0,0 +1,9 @@
namespace Device;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
+42
View File
@@ -0,0 +1,42 @@
@inject IGlossaryDialogService GlossaryDialogService
@inject IJSRuntime JsRuntime
<MudThemeProvider IsDarkMode="true"/>
<MudDialogProvider/>
<MudSnackbarProvider/>
<Router AppAssembly="@typeof(HomePage).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<EntityDialogPortal/>
<GlossaryDialogPortal/>
<ToastPortal/>
<SearchPortal/>
<ConfirmationDialogPortal/>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JsRuntime.InvokeVoidAsync("glossaryInterop.init", DotNetObjectReference.Create(this));
}
}
[JSInvokable]
public void OpenGlossaryTerm(string termId)
{
GlossaryDialogService.AddDialog(termId);
StateHasChanged();
}
}
+79
View File
@@ -0,0 +1,79 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Blazored.LocalStorage;
using Microsoft.Extensions.Logging;
using MudBlazor.Services;
using Services;
using Services.Development;
using Services.Immortal;
using Services.Website;
namespace Device;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#pragma warning disable CA1416 // BlazorWebView requires Android 23+, project targets 21+
builder.Services.AddMauiBlazorWebView();
#pragma warning restore CA1416
#if DEBUG
builder.Services.AddBlazorWebViewDeveloperTools();
builder.Logging.AddDebug();
#endif
builder.Services.AddLocalization();
builder.Services.AddBlazoredLocalStorage(config =>
{
config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
config.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
config.JsonSerializerOptions.WriteIndented = false;
});
builder.Services.AddScoped<INavigationService, NavigationService>();
builder.Services.AddScoped<IKeyService, KeyService>();
builder.Services.AddScoped<IImmortalSelectionService, ImmortalSelectionService>();
builder.Services.AddScoped<IBuildComparisonService, DeprecatedBuildComparisionService>();
builder.Services.AddScoped<IBuildOrderService, BuildOrderService>();
builder.Services.AddScoped<IEconomyService, EconomyService>();
builder.Services.AddScoped<ITimingService, TimingService>();
builder.Services.AddScoped<IMemoryTesterService, MemoryTesterService>();
builder.Services.AddScoped<IEntityFilterService, EntityFilterService>();
builder.Services.AddScoped<IEntityDisplayService, EntityDisplayService>();
builder.Services.AddScoped<IEntityDialogService, EntityDialogService>();
builder.Services.AddScoped<IGlossaryService, GlossaryService>();
builder.Services.AddScoped<IGlossaryDialogService, GlossaryDialogService>();
builder.Services.AddScoped<IToastService, ToastService>();
builder.Services.AddScoped<INoteService, NoteService>();
builder.Services.AddScoped<ISearchService, SearchService>();
builder.Services.AddScoped<IStorageService, StorageService>();
builder.Services.AddScoped<IPermissionService, PermissionService>();
builder.Services.AddScoped<IEconomyComparisonService, EconomyComparisionService>();
builder.Services.AddScoped<IDataCollectionService, DataCollectionService>();
builder.Services.AddScoped<IMyDialogService, MyDialogService>();
builder.Services.AddScoped<TechTreeService>();
builder.Services.AddMudServices();
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("https://0.0.0.0") });
return builder.Build();
}
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round"
android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+11
View File
@@ -0,0 +1,11 @@
using Android.App;
using Android.Content.PM;
namespace Device;
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode |
ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}
@@ -0,0 +1,18 @@
using Android.App;
using Android.Runtime;
namespace Device;
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp()
{
return MauiProgram.CreateMauiApp();
}
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>

Some files were not shown because too many files have changed in this diff Show More