diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Layout/MainLayout.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Layout/MainLayout.razor index 433431d7..acb5b2d4 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Layout/MainLayout.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Layout/MainLayout.razor @@ -1,8 +1,15 @@ -@using EnvelopeGenerator.Server.Client.Services; +@using EnvelopeGenerator.Server.Client.Services @inherits LayoutComponentBase +@implements IDisposable -
-
+@inject ThemeService ThemeService + + + + + +
+
@Body
@@ -11,18 +18,73 @@ © SignFlow 2023-2024 Digital Data GmbH | Datenschutz + +
@code { [Inject] IHttpClientFactory HttpClientFactory { get; set; } = default!; - - List RequiredFonts = new() { - "opensans.ttf" - }; - protected async override Task OnInitializedAsync() { - await FontLoader.LoadFonts(HttpClientFactory, RequiredFonts); + private Action? _themeChangeHandler; + + protected override async Task OnInitializedAsync() + { + await FontLoader.LoadFonts(HttpClientFactory, ["opensans.ttf"]); + _themeChangeHandler = () => InvokeAsync(StateHasChanged); + ThemeService.OnChange += _themeChangeHandler; await base.OnInitializedAsync(); } -} \ No newline at end of file + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await ThemeService.InitializeAsync(); + } + + private async Task OnToggleDarkMode() + => await ThemeService.ToggleDarkModeAsync(); + + private async Task OnThemeChanged(ChangeEventArgs e) + { + var value = e.Value?.ToString(); + if (!string.IsNullOrEmpty(value)) + await ThemeService.SetThemeAsync(value); + } + + public void Dispose() + => ThemeService.OnChange -= _themeChangeHandler; +} diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor index 2936a900..25de4614 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor @@ -5,11 +5,6 @@ @using EnvelopeGenerator.Server.Client.Models @using DevExpress.Blazor @using EnvelopeGenerator.Server.Client.Services -@inject EnvelopeGenerator.Server.Client.Services.EnvelopeService EnvelopeService -@inject EnvelopeGenerator.Server.Client.Services.AuthService AuthService -@inject NavigationManager Navigation -@inject IJSRuntime JSRuntime -@inject AppVersionService AppVersion @using EnvelopeGenerator.Application.Common.Dto @inject EnvelopeGenerator.Server.Client.Services.EnvelopeService EnvelopeService @inject EnvelopeGenerator.Server.Client.Services.AuthService AuthService @@ -17,7 +12,6 @@ @inject IJSRuntime JSRuntime @inject AppVersionService AppVersion - diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/IndexPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/IndexPage.razor index c8d170cb..710474f7 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/IndexPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/IndexPage.razor @@ -3,8 +3,6 @@ @inject NavigationManager Navigation @rendermode InteractiveWebAssembly - -
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginReceiverPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginReceiverPage.razor index de390551..b3f39ddd 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginReceiverPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginReceiverPage.razor @@ -4,8 +4,6 @@ @inject AuthService AuthService @inject NavigationManager Navigation - -

- Bitte geben Sie den Zugangscode ein, den Sie per E-Mail erhalten haben, um das Dokument sicher zu öffnen. + Bitte geben Sie den Zugangscode ein, den Sie per E-Mail erhalten haben, um das Dokument sicher zu öffnen.

@if (LoginResult == EnvelopeLoginResult.NotFound) @@ -33,7 +31,7 @@
Dokument nicht gefunden.
- Der angegebene Zugangscode konnte keinem Dokument zugeordnet werden. Bitte prüfen Sie den Link in Ihrer E-Mail. + Der angegebene Zugangscode konnte keinem Dokument zugeordnet werden. Bitte prüfen Sie den Link in Ihrer E-Mail.
} @@ -44,7 +42,7 @@
- Ungültiger Zugangscode.
+ Ungültiger Zugangscode.
Der eingegebene Code ist falsch. Bitte versuchen Sie es erneut.
@@ -58,7 +56,7 @@
Serverfehler.
- Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut. + Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.
} @@ -115,14 +113,14 @@ @if (IsLoading) { - Überprüfen … + Überprüfen … } else { - Dokument öffnen + Dokument öffnen } diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginSenderPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginSenderPage.razor index 32d74e97..150fbc65 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginSenderPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginSenderPage.razor @@ -4,8 +4,6 @@ @inject AuthService AuthService @inject NavigationManager Navigation - - } @@ -120,7 +118,7 @@ disabled="@(IsLoading || string.IsNullOrWhiteSpace(Username) || string.IsNullOrWhiteSpace(Password))"> @if (IsLoading) { - Anmelden … + Anmelden … } else { diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs index c0fa7a2e..fc25e496 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs @@ -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(); + builder.Services.AddScoped(); + // Business Services (Server specific) builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css index 562b15b3..d8bc6ad3 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css @@ -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; } \ No newline at end of file