206 lines
7.2 KiB
Plaintext
206 lines
7.2 KiB
Plaintext
@inherits LayoutComponentBase
|
|
@inject AuthenticationStateProvider AuthStateProvider
|
|
@inject NavigationManager Nav
|
|
@inject IUserNotificationService UserNotificationService
|
|
@inject IJSRuntime JSRuntime
|
|
@inject HttpClient Http
|
|
@implements IDisposable
|
|
@using System.Security.Claims
|
|
|
|
<MudThemeProvider Theme="_theme" @bind-IsDarkMode="_isDarkMode" />
|
|
<MudPopoverProvider />
|
|
<MudDialogProvider />
|
|
<MudSnackbarProvider />
|
|
|
|
<MudLayout>
|
|
<MudAppBar Elevation="0" Style="background: color-mix(in srgb, var(--mud-palette-appbar-background) 85%, transparent); border-bottom: 1px solid rgba(255, 255, 255, 0.08); color: var(--mud-palette-appbar-text);">
|
|
<AuthorizeView>
|
|
<Authorized>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="ToggleDrawer" Class="d-flex d-md-none mr-2" />
|
|
</Authorized>
|
|
</AuthorizeView>
|
|
<MudSpacer />
|
|
<MudIconButton Icon="@(_isDarkMode ? Icons.Material.Filled.LightMode : Icons.Material.Filled.DarkMode)"
|
|
Color="Color.Inherit"
|
|
OnClick="ToggleDarkMode"
|
|
Class="mr-2" />
|
|
</MudAppBar>
|
|
|
|
<AuthorizeView>
|
|
<Authorized>
|
|
<MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Never" Elevation="0" Variant="DrawerVariant.Mini" OpenMiniOnHover="false" Class="modern-drawer">
|
|
<NavMenu OnToggleDrawer="ToggleDrawer" />
|
|
</MudDrawer>
|
|
</Authorized>
|
|
</AuthorizeView>
|
|
|
|
<MudMainContent>
|
|
<MudContainer MaxWidth="MaxWidth.Large" Class="mt-4 pb-8">
|
|
@Body
|
|
</MudContainer>
|
|
</MudMainContent>
|
|
|
|
<AuthorizeView>
|
|
<Authorized>
|
|
<ChatbotWidget />
|
|
</Authorized>
|
|
</AuthorizeView>
|
|
</MudLayout>
|
|
|
|
@code {
|
|
private bool _drawerOpen = true;
|
|
private bool _isDarkMode;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
UserNotificationService.OnUserDeleted += HandleUserDeleted;
|
|
|
|
try
|
|
{
|
|
var tenantInfo = await Http.GetFromJsonAsync<TenantInfo>("api/tenant/current");
|
|
if (tenantInfo?.IsTenant == true && !string.IsNullOrEmpty(tenantInfo.PrimaryColor))
|
|
{
|
|
var primaryColor = tenantInfo.PrimaryColor;
|
|
var secondaryColor = tenantInfo.SecondaryColor ?? tenantInfo.PrimaryColor;
|
|
|
|
_theme.PaletteLight.Primary = primaryColor;
|
|
_theme.PaletteLight.Secondary = secondaryColor;
|
|
_theme.PaletteDark.Primary = primaryColor;
|
|
_theme.PaletteDark.Secondary = secondaryColor;
|
|
|
|
// Dynamically apply background colors to navbar
|
|
_theme.PaletteLight.AppbarBackground = primaryColor;
|
|
_theme.PaletteLight.DrawerBackground = primaryColor;
|
|
_theme.PaletteDark.AppbarBackground = primaryColor;
|
|
_theme.PaletteDark.DrawerBackground = primaryColor;
|
|
|
|
// Adjust text/icon contrast based on background luminance
|
|
var isLight = IsLightColor(primaryColor);
|
|
var textCol = isLight ? "#0F172A" : "#FFFFFF";
|
|
var subTextCol = isLight ? "rgba(15, 23, 42, 0.70)" : "rgba(255, 255, 255, 0.70)";
|
|
|
|
_theme.PaletteLight.AppbarText = textCol;
|
|
_theme.PaletteLight.DrawerText = subTextCol;
|
|
_theme.PaletteLight.DrawerIcon = subTextCol;
|
|
_theme.PaletteLight.PrimaryContrastText = textCol;
|
|
|
|
_theme.PaletteDark.AppbarText = textCol;
|
|
_theme.PaletteDark.DrawerText = subTextCol;
|
|
_theme.PaletteDark.DrawerIcon = subTextCol;
|
|
_theme.PaletteDark.PrimaryContrastText = textCol;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Ignore background error
|
|
}
|
|
}
|
|
|
|
private bool IsLightColor(string hexColor)
|
|
{
|
|
if (string.IsNullOrEmpty(hexColor)) return false;
|
|
hexColor = hexColor.TrimStart('#');
|
|
if (hexColor.Length == 3)
|
|
{
|
|
hexColor = new string(new[] { hexColor[0], hexColor[0], hexColor[1], hexColor[1], hexColor[2], hexColor[2] });
|
|
}
|
|
if (hexColor.Length != 6) return false;
|
|
|
|
try
|
|
{
|
|
var r = Convert.ToInt32(hexColor.Substring(0, 2), 16);
|
|
var g = Convert.ToInt32(hexColor.Substring(2, 2), 16);
|
|
var b = Convert.ToInt32(hexColor.Substring(4, 2), 16);
|
|
|
|
var luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0;
|
|
return luminance > 0.6; // slightly conservative threshold for white text readability
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender)
|
|
{
|
|
try
|
|
{
|
|
var saved = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "darkMode");
|
|
if (!string.IsNullOrEmpty(saved))
|
|
{
|
|
_isDarkMode = bool.Parse(saved);
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Ignored during prerendering/SSR
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task ToggleDarkMode()
|
|
{
|
|
_isDarkMode = !_isDarkMode;
|
|
await JSRuntime.InvokeVoidAsync("localStorage.setItem", "darkMode", _isDarkMode.ToString().ToLower());
|
|
}
|
|
|
|
private async Task HandleUserDeleted(int deletedUserId)
|
|
{
|
|
var state = await AuthStateProvider.GetAuthenticationStateAsync();
|
|
var idClaim = state.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (idClaim != null && int.TryParse(idClaim, out var myId) && myId == deletedUserId)
|
|
{
|
|
await InvokeAsync(() => Nav.NavigateTo("/auth/logout", forceLoad: true));
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
UserNotificationService.OnUserDeleted -= HandleUserDeleted;
|
|
}
|
|
|
|
private readonly MudTheme _theme = new()
|
|
{
|
|
PaletteLight = new PaletteLight
|
|
{
|
|
Primary = "#1E293B",
|
|
PrimaryDarken = "#0F172A",
|
|
PrimaryLighten = "#475569",
|
|
Secondary = "#0EA5E9",
|
|
SecondaryDarken = "#0284C7",
|
|
AppbarBackground = "#0F172A",
|
|
Background = "#F8FAFC",
|
|
DrawerBackground = "#0F172A",
|
|
DrawerText = "#94A3B8",
|
|
DrawerIcon = "#94A3B8",
|
|
Surface = "#FFFFFF",
|
|
TextPrimary = "#0F172A",
|
|
TextSecondary = "#475569",
|
|
},
|
|
PaletteDark = new PaletteDark
|
|
{
|
|
Primary = "#0EA5E9",
|
|
PrimaryDarken = "#0284C7",
|
|
PrimaryLighten = "#38BDF8",
|
|
Secondary = "#0EA5E9",
|
|
SecondaryDarken = "#0284C7",
|
|
AppbarBackground = "#0F172A",
|
|
AppbarText = "#F8FAFC",
|
|
Background = "#0B0F19",
|
|
DrawerBackground = "#0F172A",
|
|
DrawerText = "#94A3B8",
|
|
DrawerIcon = "#94A3B8",
|
|
Surface = "#1E293B",
|
|
TextPrimary = "#F8FAFC",
|
|
TextSecondary = "#94A3B8",
|
|
ActionDefault = "#94A3B8",
|
|
Divider = "rgba(255, 255, 255, 0.08)",
|
|
}
|
|
};
|
|
|
|
private void ToggleDrawer() => _drawerOpen = !_drawerOpen;
|
|
}
|