Add dynamic theme and dark mode functionality
Introduced `ThemeService` to manage themes and dark mode, with a new footer UI for theme selection and toggling dark mode. Added dynamic CSS loading and Bootstrap theme support. Registered `UserPreferencesService` and `ThemeService` for SSR compatibility. Removed hardcoded DevExpress theme links. Fixed German localization issues in `LoginReceiverPage` and `LoginSenderPage`. Updated `app.css` with styles for the new footer controls. Simplified font loading in `MainLayout.razor`.
This commit is contained in:
@@ -321,6 +321,13 @@ try
|
||||
// User Preferences (theme, dark mode, grid layouts — stored in TBDD_CACHE)
|
||||
// Registration handled by Infrastructure DependencyInjection (AddEnvelopeGeneratorInfrastructureServices)
|
||||
|
||||
// Client-side services that MainLayout depends on must also be registered here
|
||||
// so that Blazor Auto prerender (SSR pass) can resolve them on the server.
|
||||
// ThemeService.InitializeAsync() uses IJSRuntime but is only called in OnAfterRenderAsync
|
||||
// (never during prerender), so registering it server-side is safe.
|
||||
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.UserPreferencesService>();
|
||||
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.ThemeService>();
|
||||
|
||||
// Business Services (Server specific)
|
||||
builder.Services.AddScoped<DocumentService>();
|
||||
builder.Services.AddScoped<AuthService>();
|
||||
|
||||
@@ -365,4 +365,63 @@ article {
|
||||
|
||||
.receiver-footer__sep {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* ── Footer: Theme & Dark Mode Controls ─────────────────────────────────── */
|
||||
/* Positioned at the right end of the fixed footer bar. */
|
||||
/* Styled to match the footer's gradient background — small, unobtrusive. */
|
||||
|
||||
.sf-footer-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-left: auto; /* push to the right */
|
||||
}
|
||||
|
||||
.sf-footer-select {
|
||||
height: 22px;
|
||||
padding: 0 5px;
|
||||
font-size: 0.68rem;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
/* Native select options use browser defaults — acceptable in a footer context */
|
||||
}
|
||||
|
||||
.sf-footer-select:hover,
|
||||
.sf-footer-select:focus {
|
||||
background: rgba(255, 255, 255, 0.20);
|
||||
border-color: rgba(255, 255, 255, 0.38);
|
||||
}
|
||||
|
||||
/* Force option text to be readable in browsers that support it */
|
||||
.sf-footer-select option {
|
||||
color: #1e2e3e;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.sf-footer-toggle {
|
||||
width: 24px;
|
||||
height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sf-footer-toggle:hover {
|
||||
background: rgba(255, 255, 255, 0.24);
|
||||
border-color: rgba(255, 255, 255, 0.40);
|
||||
color: #ffffff;
|
||||
}
|
||||
Reference in New Issue
Block a user