diff --git a/Lieb.sln b/Lieb.sln index f38c7eb..9d2879d 100644 --- a/Lieb.sln +++ b/Lieb.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.32126.317 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lieb", "Lieb\Lieb.csproj", "{48554958-F16E-466A-B9B7-F17511FDA415}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lieb", "Lieb\Lieb.csproj", "{48554958-F16E-466A-B9B7-F17511FDA415}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Lieb/Data/DbInitializer.cs b/Lieb/Data/DbInitializer.cs index 95f050a..e8b974d 100644 --- a/Lieb/Data/DbInitializer.cs +++ b/Lieb/Data/DbInitializer.cs @@ -1,4 +1,6 @@ using Lieb.Models; +using Lieb.Models.GuildWars2; +using Lieb.Models.GuildWars2.Raid; using Microsoft.EntityFrameworkCore; namespace Lieb.Data @@ -29,12 +31,16 @@ namespace Lieb.Data return; // DB has been seeded } + GuildWars2Account linaith = new GuildWars2Account() { AccountName = "Linaith.2375" }; + GuildWars2Account sarah = new GuildWars2Account() { AccountName = "Sarah.3984" }; + GuildWars2Account hierpiepts = new GuildWars2Account() { AccountName = "hierpiepts.5241" }; + GuildWars2Account bloodseeker = new GuildWars2Account() { AccountName = "Bloodseeker.2043" }; var users = new LiebUser[] { - new LiebUser{DiscordUserId=194863625477816321, Name="Sarah", Birthday=DateTime.Parse("1992-01-15")}, - new LiebUser{DiscordUserId=1, Name="Lisa"}, - new LiebUser{DiscordUserId=2, Name="Simon"} + new LiebUser{DiscordUserId=194863625477816321, Name="Sarah", Birthday=DateTime.Parse("1992-01-15"), GuildWars2Accounts = new List(){ linaith} }, + new LiebUser{DiscordUserId=1, Name="Lisa", GuildWars2Accounts = new List(){ hierpiepts}}, + new LiebUser{DiscordUserId=2, Name="Simon", GuildWars2Accounts = new List(){ bloodseeker}} }; context.LiebUsers.AddRange(users); @@ -63,6 +69,45 @@ namespace Lieb.Data context.RoleAssignments.AddRange(assignments); context.SaveChanges(); + + PlannedRaidRole ele = new PlannedRaidRole() + { + Description = "Beste", + Name = "Heal Ele", + Spots = 2 + }; + PlannedRaidRole scourge = new PlannedRaidRole() + { + Description = "WupWup", + Name = "Scourge", + Spots = 8 + }; + + Raid raid = new Raid() + { + Title = "Testraid", + Description = "This is a test raid\nwith multiple lines?", + Guild = "LIEB", + Organizer = "Sarah", + RaidDuration = 2, + RaidType = RaidType.RandomClasses, + StartTime = DateTime.Now, + VoiceChat = "ts.lieb.games", + Roles = new [] { ele, scourge} + }; + context.Raids.Add(raid); + context.SaveChanges(); + + var signUps = new RaidSignUp[] + { + new RaidSignUp{GuildWars2AccountId = linaith.GuildWars2AccountId, LiebUserId = users[0].LiebUserId, PlannedRaidRoleId = ele.PlannedRaidRoleId, RaidId = raid.RaidId, SignUpType = SignUpType.SignedUp }, + new RaidSignUp{GuildWars2AccountId = hierpiepts.GuildWars2AccountId, LiebUserId = users[1].LiebUserId, PlannedRaidRoleId = scourge.PlannedRaidRoleId, RaidId = raid.RaidId, SignUpType = SignUpType.SignedUp }, + new RaidSignUp{GuildWars2AccountId = bloodseeker.GuildWars2AccountId, LiebUserId = users[2].LiebUserId, PlannedRaidRoleId = scourge.PlannedRaidRoleId, RaidId = raid.RaidId, SignUpType = SignUpType.Maybe } + }; + + context.RaidSignUps.AddRange(signUps); + context.SaveChanges(); + } } } diff --git a/Lieb/Data/GuildWars2AccountService.cs b/Lieb/Data/GuildWars2AccountService.cs new file mode 100644 index 0000000..4985eb7 --- /dev/null +++ b/Lieb/Data/GuildWars2AccountService.cs @@ -0,0 +1,84 @@ +using Lieb.Models; +using Lieb.Models.GuildWars2; +using Microsoft.EntityFrameworkCore; + +namespace Lieb.Data +{ + public class GuildWars2AccountService + { + private readonly IDbContextFactory _contextFactory; + + public GuildWars2AccountService(IDbContextFactory contextFactory) + { + _contextFactory = contextFactory; + } + + public async Task AddAccount(GuildWars2Account guildWars2Account, ulong discordId) + { + using var context = _contextFactory.CreateDbContext(); + LiebUser liebUser = await context.LiebUsers.FirstOrDefaultAsync(u => u.DiscordUserId == discordId); + if (liebUser != null) + { + liebUser.GuildWars2Accounts.Add(guildWars2Account); + await context.SaveChangesAsync(); + } + } + + public async Task UpdateAccount(int guildWars2AccountId, string accountName, string apiKey) + { + using var context = _contextFactory.CreateDbContext(); + GuildWars2Account account = await context.GuildWars2Accounts.FirstOrDefaultAsync(u => u.GuildWars2AccountId == guildWars2AccountId); + if (account != null) + { + account.ApiKey = apiKey; + if (!string.IsNullOrEmpty(accountName)) + { + account.AccountName = accountName; + } + await context.SaveChangesAsync(); + } + } + + public async Task RemoveAccount() + { + using var context = _contextFactory.CreateDbContext(); + + } + + public async Task AddBuildToAccount() + { + using var context = _contextFactory.CreateDbContext(); + + } + + public async Task RemoveBuildFromAccount() + { + using var context = _contextFactory.CreateDbContext(); + + } + + public async Task> GetBuilds() + { + using var context = _contextFactory.CreateDbContext(); + return context.GuildWars2Builds.ToList(); + } + + public async Task CreateBuild() + { + using var context = _contextFactory.CreateDbContext(); + await context.SaveChangesAsync(); + } + + public async Task UpdateBuild() + { + using var context = _contextFactory.CreateDbContext(); + await context.SaveChangesAsync(); + } + + public async Task DeleteBuild() + { + using var context = _contextFactory.CreateDbContext(); + await context.SaveChangesAsync(); + } + } +} diff --git a/Lieb/Data/LiebContext.cs b/Lieb/Data/LiebContext.cs index 6324c42..9585894 100644 --- a/Lieb/Data/LiebContext.cs +++ b/Lieb/Data/LiebContext.cs @@ -16,9 +16,9 @@ namespace Lieb.Data public DbSet LiebUsers { get; set; } public DbSet RoleAssignments { get; set; } public DbSet LiebRoles { get; set; } - public DbSet GuildWars2Account { get; set; } + public DbSet GuildWars2Accounts { get; set; } public DbSet Equipped { get; set; } - public DbSet RaidRoles { get; set; } + public DbSet GuildWars2Builds { get; set; } public DbSet PlannedRaidRoles { get; set; } public DbSet Raids { get; set; } public DbSet RaidReminders { get; set; } diff --git a/Lieb/Data/RaidService.cs b/Lieb/Data/RaidService.cs new file mode 100644 index 0000000..042e2af --- /dev/null +++ b/Lieb/Data/RaidService.cs @@ -0,0 +1,143 @@ +using Lieb.Models.GuildWars2.Raid; +using Microsoft.EntityFrameworkCore; + +namespace Lieb.Data +{ + public class RaidService + { + private readonly IDbContextFactory _contextFactory; + + public RaidService(IDbContextFactory contextFactory) + { + _contextFactory = contextFactory; + } + + public List GetRaids() + { + using var context = _contextFactory.CreateDbContext(); + return context.Raids + .Include(r => r.Roles) + .Include(r => r.SignUpHistory) + .Include(r => r.Reminders) + .Include(r => r.SignUps) + .ThenInclude(s => s.LiebUser) + .Include(r => r.SignUps) + .ThenInclude(s => s.GuildWars2Account) + .Include(r => r.SignUps) + .ThenInclude(s => s.PlannedRaidRole) + .ToList(); + } + + public Raid GetRaid(int raidId) + { + using var context = _contextFactory.CreateDbContext(); + return context.Raids + .Include(r => r.Roles) + .Include(r => r.SignUpHistory) + .Include(r => r.Reminders) + .Include(r => r.SignUps) + .ThenInclude(s => s.LiebUser) + .Include(r => r.SignUps) + .ThenInclude(s => s.GuildWars2Account) + .Include(r => r.SignUps) + .ThenInclude(s => s.PlannedRaidRole) + .FirstOrDefault(r => r.RaidId == raidId); + } + + public async Task CreateRaid(Raid raid) + { + if (raid == null) + { + using var context = _contextFactory.CreateDbContext(); + context.Raids.Add(raid); + await context.SaveChangesAsync(); + } + } + + public async Task> GetFreeRoles(int raidId) + { + using var context = _contextFactory.CreateDbContext(); + Raid? raid = await context.Raids + .Include(r => r.Roles) + .Include(r => r.SignUps) + .FirstOrDefaultAsync(r => r.RaidId == raidId); + + List freeRoles = new List(); + if (raid != null) + { + List plannedRolesIds = raid.SignUps.Select(s => s.PlannedRaidRoleId).ToList(); + Dictionary addedIds = new Dictionary(); + + foreach (RaidSignUp signUp in raid.SignUps) + { + if (signUp.SignUpType == SignUpType.SignedUp || signUp.SignUpType == SignUpType.Maybe) + { + int id = signUp.PlannedRaidRoleId; + if (addedIds.ContainsKey(id)) + { + addedIds[id] += 1; + } + else + { + addedIds.Add(id, 1); + } + } + } + foreach(PlannedRaidRole role in raid.Roles) + { + if(!addedIds.ContainsKey(role.PlannedRaidRoleId) || role.Spots > addedIds[role.PlannedRaidRoleId]) + { + freeRoles.Add(role); + } + } + } + return freeRoles; + } + + public async Task SignUp(int raidId, int liebUserId, int guildWars2AccountId, int plannedRoleId, SignUpType signUpType) + { + if ((await GetFreeRoles(raidId)).Where(r => r.PlannedRaidRoleId == plannedRoleId).Any()) + { + using var context = _contextFactory.CreateDbContext(); + context.RaidSignUps.Add(new RaidSignUp() + { + GuildWars2AccountId = guildWars2AccountId, + RaidId = raidId, + LiebUserId = liebUserId, + PlannedRaidRoleId = plannedRoleId, + SignUpType = signUpType + }); + await context.SaveChangesAsync(); + } + } + + public async Task SignOff(int raidId, int liebUserId) + { + using var context = _contextFactory.CreateDbContext(); + List signUps = context.RaidSignUps.Where(x => x.RaidId == raidId && x.LiebUserId == liebUserId).ToList(); + context.RaidSignUps.RemoveRange(signUps); + await context.SaveChangesAsync(); + } + + public async Task ChangeAccount(int raidId, int liebUserId, int guildWars2AccountId) + { + using var context = _contextFactory.CreateDbContext(); + List signUps = context.RaidSignUps.Where(x => x.RaidId == raidId && x.LiebUserId == liebUserId).ToList(); + foreach(RaidSignUp signUp in signUps) + { + signUp.GuildWars2AccountId = guildWars2AccountId; + } + await context.SaveChangesAsync(); + } + + public async Task ChangeSignUpType(int raidId, int liebUserId, int plannedRoleId, SignUpType signUpType) + { + using var context = _contextFactory.CreateDbContext(); + RaidSignUp signUp = await context.RaidSignUps.FirstOrDefaultAsync(x => x.RaidId == raidId && x.LiebUserId == liebUserId && x.SignUpType != SignUpType.SignedOff && x.SignUpType != SignUpType.Flex); + signUp.PlannedRaidRoleId = plannedRoleId; + signUp.SignUpType = signUpType; + await context.SaveChangesAsync(); + } + + } +} diff --git a/Lieb/Data/UserService.cs b/Lieb/Data/UserService.cs new file mode 100644 index 0000000..1a595a8 --- /dev/null +++ b/Lieb/Data/UserService.cs @@ -0,0 +1,56 @@ +using Lieb.Models; +using Microsoft.EntityFrameworkCore; + +namespace Lieb.Data +{ + public class UserService + { + private readonly IDbContextFactory _contextFactory; + + public UserService(IDbContextFactory contextFactory) + { + _contextFactory = contextFactory; + } + + public async Task GetLiebUser(ulong discordId) + { + if (discordId > 0) + { + using var context = _contextFactory.CreateDbContext(); + return await context.LiebUsers + .Include(u => u.GuildWars2Accounts) + .ThenInclude(a => a.EquippedBuilds) + .ThenInclude(b => b.GuildWars2Build) + .Include(u => u.RoleAssignments) + .ThenInclude(r => r.LiebRole) + .FirstOrDefaultAsync(u => u.DiscordUserId == discordId); + } + else + return new LiebUser(); + } + + public LiebUser GetLiebUserSmall(ulong discordId) + { + if (discordId > 0) + { + using var context = _contextFactory.CreateDbContext(); + return context.LiebUsers + .Include(u => u.GuildWars2Accounts) + .FirstOrDefault(u => u.DiscordUserId == discordId); + } + else + return new LiebUser(); + } + + public async Task GetLiebUserId(ulong discordId) + { + if (discordId > 0) + { + using var context = _contextFactory.CreateDbContext(); + return (await context.LiebUsers.FirstOrDefaultAsync(u => u.DiscordUserId == discordId)).LiebUserId; + } + else + return -1; + } + } +} diff --git a/Lieb/Lieb.csproj b/Lieb/Lieb.csproj index 5cfee68..e138465 100644 --- a/Lieb/Lieb.csproj +++ b/Lieb/Lieb.csproj @@ -6,10 +6,6 @@ enable - - - - diff --git a/Lieb/Models/GuildWars2/GuildWars2Account.cs b/Lieb/Models/GuildWars2/GuildWars2Account.cs index e4c228e..ff8e0a1 100644 --- a/Lieb/Models/GuildWars2/GuildWars2Account.cs +++ b/Lieb/Models/GuildWars2/GuildWars2Account.cs @@ -5,7 +5,7 @@ public int GuildWars2AccountId { get; set; } public string ApiKey { get; set; } = string.Empty; public string AccountName { get; set; } = string.Empty; - public ICollection EquippedRoles { get; set; } = new List(); + public ICollection EquippedBuilds { get; set; } = new List(); } } diff --git a/Lieb/Models/GuildWars2/Raid/PlannedRaidRole.cs b/Lieb/Models/GuildWars2/Raid/PlannedRaidRole.cs index ac13524..ece5e44 100644 --- a/Lieb/Models/GuildWars2/Raid/PlannedRaidRole.cs +++ b/Lieb/Models/GuildWars2/Raid/PlannedRaidRole.cs @@ -4,7 +4,7 @@ { public int PlannedRaidRoleId { get; set; } public string Name { get; set; } = String.Empty; - public int Spots { get; } + public int Spots { get; set; } public string Description { get; set; } = String.Empty; } } diff --git a/Lieb/Models/GuildWars2/Raid/Raid.cs b/Lieb/Models/GuildWars2/Raid/Raid.cs index 374cb9d..d833a73 100644 --- a/Lieb/Models/GuildWars2/Raid/Raid.cs +++ b/Lieb/Models/GuildWars2/Raid/Raid.cs @@ -16,11 +16,11 @@ public string Description { get; set; } = String.Empty; - public DateTimeOffset StartTime { get; set; } + public DateTime StartTime { get; set; } public double RaidDuration { get; set; } - public string Organisator { get; set; } = String.Empty; + public string Organizer { get; set; } = String.Empty; public string Guild { get; set; } = String.Empty; diff --git a/Lieb/Pages/Raids/RaidDetails.razor b/Lieb/Pages/Raids/RaidDetails.razor new file mode 100644 index 0000000..abbe173 --- /dev/null +++ b/Lieb/Pages/Raids/RaidDetails.razor @@ -0,0 +1,188 @@ +@using System.Security.Claims +@using Lieb.Data +@using Lieb.Models +@using Lieb.Models.GuildWars2.Raid +@inject UserService UserService +@inject RaidService RaidService + + +
@Raid.Title
+ +
@Raid.Description
+ +
+
+
Date
+

@Raid.StartTime.ToLongDateString()

+
+
+
Time
+

from: @Raid.StartTime.ToShortTimeString() to: @Raid.StartTime.AddHours(@Raid.RaidDuration).ToShortTimeString()

+
+
+ +
+
+
Organizer
+

@Raid.Organizer

+
+
+
Guild
+

@Raid.Guild

+
+
+
Voice chat
+

@Raid.VoiceChat

+
+
+ + + + @{ + ulong discordId = ulong.Parse(@context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value); + LiebUser user = UserService.GetLiebUserSmall(discordId); + RaidSignUp userRole = Raid.SignUps.Where(s => s.LiebUserId == user.LiebUserId).FirstOrDefault(); + bool isSignedUp = userRole != null; + + + + @foreach (var role in Raid.Roles) + { + Models.GuildWars2.Raid.RaidSignUp[] signUps = Raid.SignUps.Where(s => s.PlannedRaidRoleId == role.PlannedRaidRoleId).ToArray(); + int usedSpots = signUps.Where(s => s.SignUpType == SignUpType.SignedUp).Count(); + + + @if (@usedSpots < @role.Spots) + { + + + } + else + { + + + } + + + + + + @foreach (var signUp in signUps) + { + @if(signUp.SignUpType != SignUpType.SignedOff) + { + + + + @{bool isUser = isSignedUp && userRole.PlannedRaidRole.PlannedRaidRoleId == role.PlannedRaidRoleId && signUp.LiebUserId == user.LiebUserId;} + @if(isUser) + { + + } + else + { + + } + @{string signUpStatus = string.Empty;} + @if (signUp.SignUpType != SignUpType.SignedUp) signUpStatus = $" - {signUp.SignUpType}"; + + @if (isUser) + { + + } + else + { + + } + + } + } + } + +
@role.Name: @role.Description (@usedSpots /@role.Spots)
@signUp.LiebUser.Name + @signUpStatus @signUp.LiebUser.Name (@signUp.GuildWars2Account.AccountName) @signUpStatus
+ } +
+ + @foreach (var role in Raid.Roles) + { + Models.GuildWars2.Raid.RaidSignUp[] signUps = Raid.SignUps.Where(s => s.PlannedRaidRoleId == role.PlannedRaidRoleId).ToArray(); + int usedSpots = signUps.Where(s => s.SignUpType == SignUpType.SignedUp).Count(); + +
@role.Name: @role.Description (@usedSpots /@role.Spots)
+ @foreach (var signUp in signUps) + { + if(signUp.SignUpType != SignUpType.SignedOff) + { + string signUpStatus = string.Empty; + if (signUp.SignUpType != SignUpType.SignedUp) signUpStatus = $" - {signUp.SignUpType}"; +
@signUp.LiebUser.Name (@signUp.GuildWars2Account.AccountName) @signUpStatus
+ } + } + } +
+
+ + +@code { + + [Parameter] + public Raid Raid { get; set; } + + async Task SignUpClicked(PlannedRaidRole role, LiebUser liebUser, bool isSignedUp) + { + if(isSignedUp) + { + await RaidService.ChangeSignUpType(Raid.RaidId, liebUser.LiebUserId, role.PlannedRaidRoleId, SignUpType.SignedUp); + } + else + { + await RaidService.SignUp(Raid.RaidId, liebUser.LiebUserId, liebUser.GuildWars2Accounts.FirstOrDefault().GuildWars2AccountId, role.PlannedRaidRoleId, SignUpType.SignedUp); + } + Raid = RaidService.GetRaid(Raid.RaidId); + } + + async Task BackupClicked(PlannedRaidRole role, LiebUser liebUser, bool isSignedUp) + { + if(isSignedUp) + { + await RaidService.ChangeSignUpType(Raid.RaidId, liebUser.LiebUserId, role.PlannedRaidRoleId, SignUpType.Backup); + } + else + { + await RaidService.SignUp(Raid.RaidId, liebUser.LiebUserId, liebUser.GuildWars2Accounts.FirstOrDefault().GuildWars2AccountId, role.PlannedRaidRoleId, SignUpType.Backup); + } + Raid = RaidService.GetRaid(Raid.RaidId); + } + + async Task MaybeClicked(PlannedRaidRole role, LiebUser liebUser, bool isSignedUp) + { + if(isSignedUp) + { + await RaidService.ChangeSignUpType(Raid.RaidId, liebUser.LiebUserId, role.PlannedRaidRoleId, SignUpType.Maybe); + } + else + { + await RaidService.SignUp(Raid.RaidId, liebUser.LiebUserId, liebUser.GuildWars2Accounts.FirstOrDefault().GuildWars2AccountId, role.PlannedRaidRoleId, SignUpType.Maybe); + } + Raid = RaidService.GetRaid(Raid.RaidId); + } + + async Task SignOffClicked(PlannedRaidRole role, LiebUser liebUser) + { + await RaidService.SignOff(Raid.RaidId, liebUser.LiebUserId); + Raid = RaidService.GetRaid(Raid.RaidId); + } + + async Task ChangeAccount(LiebUser liebUser, ChangeEventArgs e) + { + int accountId = int.Parse(e.Value.ToString()); + await RaidService.ChangeAccount(Raid.RaidId, liebUser.LiebUserId, accountId); + Raid = RaidService.GetRaid(Raid.RaidId); + } +} diff --git a/Lieb/Pages/Raids/RaidDetails.razor.css b/Lieb/Pages/Raids/RaidDetails.razor.css new file mode 100644 index 0000000..37e2da0 --- /dev/null +++ b/Lieb/Pages/Raids/RaidDetails.razor.css @@ -0,0 +1,31 @@ +body { + background-color: rgb(38 38 38); + border-radius: 25px; + padding: 25px; + width: fit-content; + color: lightgray; +} + +h5 { + color: lightgrey; +} + +.times { + float: left; + display: inline; + width: 49%; + padding-top: 15px; +} + + +.details { + float: left; + display: inline; + width: 33%; + padding-top: 15px; +} + +table { + column-width: auto; + color: lightgray; +} \ No newline at end of file diff --git a/Lieb/Pages/Raids/RaidOverview.razor b/Lieb/Pages/Raids/RaidOverview.razor new file mode 100644 index 0000000..5b080a2 --- /dev/null +++ b/Lieb/Pages/Raids/RaidOverview.razor @@ -0,0 +1,22 @@ +@page "/raidoverview" +@using Lieb.Data +@inject RaidService RaidService + + +

RaidOverview

+ +@foreach (var raid in raids) { +

wupwup

+ +} + + + + @code { + private List raids; + + protected override async Task OnInitializedAsync() + { + raids = RaidService.GetRaids(); + } +} diff --git a/Lieb/Program.cs b/Lieb/Program.cs index b3c6eea..f321bcd 100644 --- a/Lieb/Program.cs +++ b/Lieb/Program.cs @@ -8,12 +8,26 @@ var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); -builder.Services.AddDbContext(options => - options.UseSqlServer(builder.Configuration.GetConnectionString("LiebContext"))); +//builder.Services.AddDbContext(options => +// options.UseSqlServer(builder.Configuration.GetConnectionString("LiebContext")), ServiceLifetime.Transient); +builder.Services.AddDbContextFactory(opt => + opt.UseSqlServer(builder.Configuration.GetConnectionString("LiebContext")), ServiceLifetime.Transient); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddServerSideBlazor(); + +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + + + + +//builder.Services.AddTransient(); +//builder.Services.AddTransient(); +//builder.Services.AddTransient(); + builder.Services.AddAuthentication(opt => { opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; diff --git a/Lieb/Shared/NavMenu.razor b/Lieb/Shared/NavMenu.razor index e2a51f5..29c0add 100644 --- a/Lieb/Shared/NavMenu.razor +++ b/Lieb/Shared/NavMenu.razor @@ -15,8 +15,8 @@