QuantEngine MudBlazor UI: Complete Phase 1-8 Implementation #14
@@ -1,3 +1,98 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
@inject MudThemeProvider MudThemeProvider
|
||||||
|
|
||||||
@Body
|
<MudThemeProvider @ref="mudThemeProvider" @bind-IsDarkMode="@isDarkMode" />
|
||||||
|
|
||||||
|
<div class="auth-container">
|
||||||
|
<!-- Left Panel - Branding -->
|
||||||
|
<MudHidden Breakpoint="Breakpoint.SmAndDown" Invert="true" Class="auth-left-panel">
|
||||||
|
<div class="auth-branding">
|
||||||
|
<div class="auth-logo">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.AnalyticsFill" Size="Size.Large" />
|
||||||
|
</div>
|
||||||
|
<MudText Typo="Typo.h3" Class="auth-title">
|
||||||
|
QuantEngine
|
||||||
|
</MudText>
|
||||||
|
<MudText Typo="Typo.body1" Class="auth-subtitle">
|
||||||
|
퇴직 자산 포트폴리오 관리 시스템
|
||||||
|
</MudText>
|
||||||
|
<div class="auth-features mt-8">
|
||||||
|
<div class="auth-feature">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" />
|
||||||
|
<MudText Typo="Typo.body2">실시간 자산 모니터링</MudText>
|
||||||
|
</div>
|
||||||
|
<div class="auth-feature">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" />
|
||||||
|
<MudText Typo="Typo.body2">AI 기반 분석</MudText>
|
||||||
|
</div>
|
||||||
|
<div class="auth-feature">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" />
|
||||||
|
<MudText Typo="Typo.body2">종합 보고서</MudText>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dark Mode Toggle -->
|
||||||
|
<div class="auth-theme-toggle">
|
||||||
|
<MudIconButton Icon="@(isDarkMode ? Icons.Material.Filled.Brightness4 : Icons.Material.Filled.Brightness7)"
|
||||||
|
Color="Color.Inherit"
|
||||||
|
OnClick="ToggleDarkMode"
|
||||||
|
Title="@(isDarkMode ? "라이트 모드" : "다크 모드")"
|
||||||
|
Size="Size.Large" />
|
||||||
|
</div>
|
||||||
|
</MudHidden>
|
||||||
|
|
||||||
|
<!-- Right Panel - Auth Content -->
|
||||||
|
<div class="auth-right-panel">
|
||||||
|
<!-- Mobile Header -->
|
||||||
|
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||||
|
<div class="auth-mobile-header">
|
||||||
|
<MudText Typo="Typo.h5" Class="d-flex align-center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.AnalyticsFill" Size="Size.Medium" Class="mr-2" />
|
||||||
|
QuantEngine
|
||||||
|
</MudText>
|
||||||
|
<MudIconButton Icon="@(isDarkMode ? Icons.Material.Filled.Brightness4 : Icons.Material.Filled.Brightness7)"
|
||||||
|
Color="Color.Inherit"
|
||||||
|
OnClick="ToggleDarkMode"
|
||||||
|
Title="@(isDarkMode ? "라이트 모드" : "다크 모드")" />
|
||||||
|
</div>
|
||||||
|
</MudHidden>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="auth-content">
|
||||||
|
@Body
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<div class="auth-footer">
|
||||||
|
<MudText Typo="Typo.caption" Class="auth-footer-text">
|
||||||
|
© 2026 QuantEngine. 모든 권리 예약.
|
||||||
|
</MudText>
|
||||||
|
<div class="auth-footer-links">
|
||||||
|
<MudLink Href="/" Typo="Typo.caption">서비스 약관</MudLink>
|
||||||
|
<MudText Typo="Typo.caption">·</MudText>
|
||||||
|
<MudLink Href="/" Typo="Typo.caption">개인정보 처리방침</MudLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private MudThemeProvider mudThemeProvider = default!;
|
||||||
|
private bool isDarkMode = false;
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
isDarkMode = await mudThemeProvider.GetDarkModeAsync() ?? false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ToggleDarkMode()
|
||||||
|
{
|
||||||
|
isDarkMode = !isDarkMode;
|
||||||
|
await mudThemeProvider.SetDarkModeAsync(isDarkMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,260 @@
|
|||||||
|
/* QuantEngine AuthLayout Styles */
|
||||||
|
|
||||||
|
.auth-container {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: linear-gradient(135deg, var(--mud-palette-primary) 0%, var(--mud-palette-primary-dark) 100%);
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Left Panel - Branding */
|
||||||
|
.auth-left-panel {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3rem;
|
||||||
|
color: white;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-branding {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-logo {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
animation: float 3s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-logo ::deep svg {
|
||||||
|
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
|
||||||
|
font-size: 80px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-title {
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-subtitle {
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-features {
|
||||||
|
margin-top: 3rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-feature {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
opacity: 0.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-feature ::deep svg {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #4caf50;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-theme-toggle {
|
||||||
|
position: absolute;
|
||||||
|
top: 2rem;
|
||||||
|
right: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-theme-toggle ::deep button {
|
||||||
|
color: white;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-theme-toggle ::deep button:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Right Panel - Auth Content */
|
||||||
|
.auth-right-panel {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2rem;
|
||||||
|
background: var(--mud-palette-background);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mobile-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid var(--mud-palette-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mobile-header ::deep .mud-icon {
|
||||||
|
color: var(--mud-palette-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-content {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-content ::deep .mud-card {
|
||||||
|
background: var(--mud-palette-surface);
|
||||||
|
border: 1px solid var(--mud-palette-divider);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-content ::deep .mud-form-control {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-content ::deep .mud-button {
|
||||||
|
text-transform: none;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-content ::deep .mud-button-root {
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.auth-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
border-top: 1px solid var(--mud-palette-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer-text {
|
||||||
|
display: block;
|
||||||
|
color: var(--mud-palette-text-secondary);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer-links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer-links ::deep a {
|
||||||
|
color: var(--mud-palette-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer-links ::deep a:hover {
|
||||||
|
color: var(--mud-palette-primary-dark);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 960px) {
|
||||||
|
.auth-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-left-panel {
|
||||||
|
padding: 2rem;
|
||||||
|
min-height: 40vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-right-panel {
|
||||||
|
padding: 3rem 2rem 5rem;
|
||||||
|
min-height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mobile-header {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer {
|
||||||
|
bottom: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.auth-right-panel {
|
||||||
|
padding: 2rem 1rem 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-content {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-features {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer {
|
||||||
|
position: static;
|
||||||
|
padding: 1rem;
|
||||||
|
border-top: 1px solid var(--mud-palette-divider);
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animation */
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark Mode */
|
||||||
|
[data-theme="dark"] .auth-container {
|
||||||
|
background: linear-gradient(135deg, #1e1e2e 0%, #2d2d44 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .auth-left-panel {
|
||||||
|
color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .auth-right-panel {
|
||||||
|
background: #121212;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accessibility */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.auth-logo {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-theme-toggle ::deep button {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer-links ::deep a {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,32 +2,98 @@
|
|||||||
@inject HttpClient Http
|
@inject HttpClient Http
|
||||||
@inject AuthenticationStateProvider AuthStateProvider
|
@inject AuthenticationStateProvider AuthStateProvider
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject MudThemeProvider MudThemeProvider
|
||||||
|
|
||||||
<MudLayout>
|
<MudLayout>
|
||||||
<MudAppBar Elevation="1" Dense="true">
|
<!-- Top Navigation Bar -->
|
||||||
|
<MudAppBar Elevation="1" Dense="false" Color="Color.Surface" Class="mud-appbar-dense">
|
||||||
|
<MudHidden Breakpoint="Breakpoint.SmAndUp" Invert="true">
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@(() => navOpen = !navOpen)" />
|
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@(() => navOpen = !navOpen)" />
|
||||||
<MudText Typo="Typo.h6">QuantEngine v@appVersion</MudText>
|
</MudHidden>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h6" Class="ml-2">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Dashboard" Class="me-2" />
|
||||||
|
QuantEngine
|
||||||
|
</MudText>
|
||||||
|
|
||||||
<MudSpacer />
|
<MudSpacer />
|
||||||
|
|
||||||
|
<!-- Theme Toggle -->
|
||||||
|
<MudIconButton Icon="@(isDarkMode ? Icons.Material.Filled.Brightness4 : Icons.Material.Filled.Brightness7)"
|
||||||
|
Color="Color.Inherit"
|
||||||
|
OnClick="ToggleDarkMode"
|
||||||
|
Title="@(isDarkMode ? "라이트 모드" : "다크 모드")" />
|
||||||
|
|
||||||
|
<!-- User Menu -->
|
||||||
<AuthorizeView>
|
<AuthorizeView>
|
||||||
<Authorized>
|
<Authorized>
|
||||||
<MudText Typo="Typo.body2">관리자 (@context.User.Identity?.Name)</MudText>
|
<MudMenu AnchorOrigin="Origin.BottomRight" TransformOrigin="Origin.TopRight" Class="ml-2">
|
||||||
<MudButton Variant="Variant.Outlined" Color="Color.Error" OnClick="HandleLogoutAsync">로그아웃</MudButton>
|
<ActivatorContent>
|
||||||
|
<MudAvatar Color="Color.Primary" Image="@GetUserInitials()" Class="cursor-pointer">
|
||||||
|
@GetFirstLetter(context.User.Identity?.Name)
|
||||||
|
</MudAvatar>
|
||||||
|
</ActivatorContent>
|
||||||
|
<ChildContent>
|
||||||
|
<MudMenuItem>
|
||||||
|
<MudText Typo="Typo.body2">
|
||||||
|
<strong>@context.User.Identity?.Name</strong>
|
||||||
|
</MudText>
|
||||||
|
</MudMenuItem>
|
||||||
|
<MudDivider />
|
||||||
|
<MudMenuItem href="/profile">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Person" Class="mr-2" Size="Size.Small" />
|
||||||
|
프로필
|
||||||
|
</MudMenuItem>
|
||||||
|
<MudMenuItem href="/settings">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Settings" Class="mr-2" Size="Size.Small" />
|
||||||
|
설정
|
||||||
|
</MudMenuItem>
|
||||||
|
<MudDivider />
|
||||||
|
<MudMenuItem OnClick="HandleLogoutAsync">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Logout" Class="mr-2" Size="Size.Small" Color="Color.Error" />
|
||||||
|
<MudText Color="Color.Error">로그아웃</MudText>
|
||||||
|
</MudMenuItem>
|
||||||
|
</ChildContent>
|
||||||
|
</MudMenu>
|
||||||
</Authorized>
|
</Authorized>
|
||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
</MudAppBar>
|
</MudAppBar>
|
||||||
|
|
||||||
<MudDrawer Open="@navOpen" Variant="DrawerVariant.Responsive" Elevation="1">
|
<!-- Sidebar Navigation -->
|
||||||
|
<MudDrawer Open="@navOpen" Variant="DrawerVariant.Responsive" Elevation="1" FixedOpen="@fixedOpen">
|
||||||
|
<MudDrawerHeader Class="d-flex align-center justify-space-between">
|
||||||
|
<MudText Typo="Typo.h6" Class="px-2">메뉴</MudText>
|
||||||
|
<MudHidden Breakpoint="Breakpoint.Md" Invert="true">
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.ChevronLeft"
|
||||||
|
OnClick="ToggleDrawer"
|
||||||
|
Class="mx-1" />
|
||||||
|
</MudHidden>
|
||||||
|
</MudDrawerHeader>
|
||||||
|
|
||||||
<MudNavMenu>
|
<MudNavMenu>
|
||||||
<NavMenu />
|
<NavMenu />
|
||||||
</MudNavMenu>
|
</MudNavMenu>
|
||||||
<div style="padding: 16px; border-top: 1px solid var(--mud-palette-lines-default);">
|
|
||||||
<MudText Typo="Typo.caption">QuantEngine v@appVersion</MudText>
|
<!-- Drawer Footer -->
|
||||||
<MudText Typo="Typo.caption">배포: @buildTime</MudText>
|
<div class="mud-drawer-footer">
|
||||||
|
<MudDivider />
|
||||||
|
<div style="padding: 16px;">
|
||||||
|
<MudText Typo="Typo.caption">
|
||||||
|
<strong>QuantEngine</strong>
|
||||||
|
</MudText>
|
||||||
|
<MudText Typo="Typo.caption">
|
||||||
|
v@appVersion
|
||||||
|
</MudText>
|
||||||
|
<MudText Typo="Typo.caption" Class="mt-2">
|
||||||
|
배포: @buildTime
|
||||||
|
</MudText>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MudDrawer>
|
</MudDrawer>
|
||||||
|
|
||||||
<MudMainContent>
|
<!-- Main Content Area -->
|
||||||
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4">
|
<MudMainContent Class="mud-main-content-enhanced">
|
||||||
|
<MudContainer MaxWidth="MaxWidth.False" Class="pa-6">
|
||||||
@Body
|
@Body
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
</MudMainContent>
|
</MudMainContent>
|
||||||
@@ -35,8 +101,20 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool navOpen = true;
|
private bool navOpen = true;
|
||||||
|
private bool fixedOpen = true;
|
||||||
|
private bool isDarkMode = false;
|
||||||
private string appVersion = "Local Debug";
|
private string appVersion = "Local Debug";
|
||||||
private string buildTime = "N/A";
|
private string buildTime = "N/A";
|
||||||
|
private MudTheme currentTheme = default!;
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
isDarkMode = await MudThemeProvider.GetDarkModeAsync() ?? false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@@ -52,6 +130,19 @@
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ToggleDarkMode()
|
||||||
|
{
|
||||||
|
isDarkMode = !isDarkMode;
|
||||||
|
await MudThemeProvider.SetDarkModeAsync(isDarkMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleDrawer()
|
||||||
|
{
|
||||||
|
navOpen = !navOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleLogoutAsync()
|
private async Task HandleLogoutAsync()
|
||||||
@@ -61,6 +152,16 @@
|
|||||||
NavigationManager.NavigateTo("/login");
|
NavigationManager.NavigateTo("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetFirstLetter(string? name)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(name) ? "?" : name[0].ToString().ToUpper();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetUserInitials()
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private class VersionInfo
|
private class VersionInfo
|
||||||
{
|
{
|
||||||
public string? Version { get; set; }
|
public string? Version { get; set; }
|
||||||
|
|||||||
@@ -1,81 +1,83 @@
|
|||||||
.page {
|
/* QuantEngine MainLayout Styles */
|
||||||
|
|
||||||
|
/* AppBar Enhancements */
|
||||||
|
.mud-appbar-dense {
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mud-appbar-dense ::deep .mud-appbar-section-center {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avatar Styling */
|
||||||
|
::deep .mud-avatar {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .mud-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drawer Footer */
|
||||||
|
.mud-drawer-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--mud-palette-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content Area */
|
||||||
|
.mud-main-content-enhanced {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--mud-palette-background);
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navigation Menu Styles */
|
||||||
|
.mud-navmenu {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mud-navmenu ::deep .mud-nav-item {
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mud-navmenu ::deep .mud-nav-link {
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mud-navmenu ::deep .mud-nav-link:hover {
|
||||||
|
background-color: var(--mud-palette-action-default-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mud-navmenu ::deep .mud-nav-link.mud-ripple-nav-link-active {
|
||||||
|
background-color: var(--mud-palette-primary-lighten);
|
||||||
|
color: var(--mud-palette-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Drawer */
|
||||||
|
@media (max-width: 599px) {
|
||||||
|
.mud-drawer-content {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mud-drawer-footer {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
border-bottom: 1px solid #d6d5d5;
|
|
||||||
justify-content: flex-end;
|
|
||||||
height: 3.5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-left: 1.5rem;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a:first-child {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640.98px) {
|
|
||||||
.top-row {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 641px) {
|
@media (min-width: 600px) {
|
||||||
.page {
|
.mud-drawer-footer {
|
||||||
flex-direction: row;
|
position: absolute;
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 250px;
|
|
||||||
height: 100vh;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row.auth ::deep a:first-child {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row, article {
|
|
||||||
padding-left: 2rem !important;
|
|
||||||
padding-right: 1.5rem !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Error UI */
|
||||||
#blazor-error-ui {
|
#blazor-error-ui {
|
||||||
color-scheme: light only;
|
color-scheme: light only;
|
||||||
background: lightyellow;
|
background: lightyellow;
|
||||||
@@ -90,9 +92,14 @@ main {
|
|||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#blazor-error-ui .dismiss {
|
#blazor-error-ui .dismiss {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0.75rem;
|
right: 0.75rem;
|
||||||
top: 0.5rem;
|
top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark Mode Transitions */
|
||||||
|
* {
|
||||||
|
transition: background-color 0.3s ease, color 0.3s ease;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user