Files
Moonlight/Moonlight.Frontend/UI/Shared/Partials/AppSidebar.razor
2025-12-25 21:55:46 +01:00

140 lines
4.2 KiB
Plaintext

@using System.Diagnostics.CodeAnalysis
@using LucideBlazor
@using ShadcnBlazor.Sidebars
@inject NavigationManager Navigation
@implements IDisposable
@{
var url = new Uri(Navigation.Uri);
}
<Sidebar Variant="SidebarVariant.Sidebar" Collapsible="SidebarCollapsible.Icon">
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<a href="/" class="flex flex-row items-center">
<img alt="Logo" src="/_content/Moonlight.Frontend/logo.svg" class="size-6"/>
<span class="ms-2.5 text-lg font-semibold">Moonlight</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
@foreach (var group in Items.GroupBy(x => x.Group))
{
<SidebarGroup>
@if (!string.IsNullOrWhiteSpace(group.Key))
{
<SidebarGroupLabel>
@group.Key
</SidebarGroupLabel>
}
<SidebarGroupContent>
<SidebarMenu>
@foreach (var item in group)
{
var isActive = item.IsExactPath
? item.Path == url.LocalPath
: url.LocalPath.StartsWith(item.Path, StringComparison.OrdinalIgnoreCase);
<SidebarMenuItem @key="item">
<SidebarMenuButton IsActive="@isActive">
<Slot>
<a href="@item.Path" @attributes="context">
<DynamicComponent Type="item.IconType"/>
<span>@item.Name</span>
</a>
</Slot>
</SidebarMenuButton>
</SidebarMenuItem>
}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
}
</SidebarContent>
<SidebarFooter>
<NavUser/>
</SidebarFooter>
</Sidebar>
@code
{
private readonly List<SidebarItem> Items = new();
protected override void OnInitialized()
{
Items.AddRange([
new()
{
Name = "Overview",
IconType = typeof(LayoutDashboardIcon),
Path = "/",
IsExactPath = true
},
new()
{
Name = "Overview",
IconType = typeof(LayoutDashboardIcon),
Path = "/admin",
IsExactPath = true,
Group = "Admin"
},
new()
{
Name = "Users",
IconType = typeof(UsersRoundIcon),
Path = "/users",
IsExactPath = false,
Group = "Admin"
},
new()
{
Name = "Settings",
IconType = typeof(SettingsIcon),
Path = "/admin/settings",
IsExactPath = false,
Group = "Admin"
}
]);
Navigation.LocationChanged += OnLocationChanged;
}
private async void OnLocationChanged(object? sender, LocationChangedEventArgs e)
{
try
{
await InvokeAsync(StateHasChanged);
}
catch (Exception)
{
// Ignored
}
}
private record SidebarItem
{
public string Name { get; set; }
public string Path { get; set; }
public bool IsExactPath { get; set; }
public string? Group { get; set; }
// Used to prevent the IL-Trimming from removing this type as its dynamically assigned a type and we
// need it to work properly
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public Type IconType { get; set; }
}
public void Dispose()
{
Navigation.LocationChanged -= OnLocationChanged;
}
}