Replace Home with Samples in menu; add ReceiverLayout
- Update NavMenu to show "Samples" instead of "Home" - Add ReceiverLayout.razor for receiver-facing pages: - Includes main content, sticky footer, and privacy link - Implements cookie consent banner using localStorage - Adds language switcher with LocalizationService integration - Handles event disposal and JS interop for SSR/client scenarios
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<div>
|
||||
<DxMenu Orientation="@Orientation.Vertical" CssClass="menu">
|
||||
<Items>
|
||||
<DxMenuItem NavigateUrl="/" Text="Home" CssClass="@MenuItemCssClass("/")" IconCssClass="icon icon-home"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/samples" Text="Samples" CssClass="@MenuItemCssClass("/samples")" IconCssClass="icon icon-home"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/counter" Text="Counter" CssClass="@MenuItemCssClass("/counter")" IconCssClass="icon icon-counter"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/weather" Text="Weather" CssClass="@MenuItemCssClass("/weather")" IconCssClass="icon icon-weather"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/pdfviewer" Text="PDF Viewer" CssClass="@MenuItemCssClass("/pdfviewer")" IconCssClass="icon icon-pdf-viewer"></DxMenuItem>
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
@inherits LayoutComponentBase
|
||||
@implements IDisposable
|
||||
@inject LocalizationService Loc
|
||||
@inject NavigationManager Nav
|
||||
@inject IJSRuntime JS
|
||||
|
||||
@*
|
||||
Layout for the receiver-facing pages migrated from EnvelopeGenerator.Web.
|
||||
Mirrors the legacy MVC <body> structure: page content + sticky footer
|
||||
with copyright link, language switcher and privacy link.
|
||||
|
||||
Cookie consent is reimplemented in Blazor (localStorage-backed) because
|
||||
ASP.NET Core's <ITrackingConsentFeature> only works on the server side
|
||||
and is awkward to integrate with InteractiveAuto rendering.
|
||||
*@
|
||||
|
||||
<div class="receiver-shell">
|
||||
|
||||
@* Main page content *@
|
||||
<main role="main" class="flex-grow-1">
|
||||
@Body
|
||||
</main>
|
||||
|
||||
@* Cookie consent banner (Blazor counterpart of _CookieConsentPartial). *@
|
||||
@if (_consentVisible)
|
||||
{
|
||||
<div class="receiver-cookie-banner" role="alertdialog" aria-live="polite">
|
||||
<span>@Loc["CookieConsentMessage"]</span>
|
||||
<DxButton Text="@Loc["Accept"]"
|
||||
RenderStyle="ButtonRenderStyle.Primary"
|
||||
Click="AcceptCookiesAsync" />
|
||||
</div>
|
||||
}
|
||||
|
||||
@* Footer (copyright + language switcher + privacy). *@
|
||||
<footer class="receiver-footer">
|
||||
<span>
|
||||
© SignFlow 2023-@DateTime.Now.Year
|
||||
<a href="https://digitaldata.works" target="_blank" rel="noopener">Digital Data GmbH</a>
|
||||
</span>
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<select class="language-switcher" value="@_currentLang" @onchange="OnLanguageChangedAsync">
|
||||
@foreach (var (lang, native, _) in LocalizationService.SupportedLanguages)
|
||||
{
|
||||
<option value="@lang" selected="@(lang == _currentLang)">@native</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<a href="@($"/privacy-policy.{_currentLang}.html")" target="_blank" rel="noopener">
|
||||
@Loc["Privacy"]
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string _currentLang = "de";
|
||||
private bool _consentVisible;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Loc.Changed += OnLocChanged;
|
||||
await Loc.EnsureLoadedAsync();
|
||||
_currentLang = Loc.CurrentLanguage ?? "de";
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender) return;
|
||||
// Probe localStorage on the client only — InteractiveAuto means
|
||||
// the server prerender runs without a browser, so JS interop is
|
||||
// unavailable until the first client render.
|
||||
try
|
||||
{
|
||||
var accepted = await JS.InvokeAsync<string?>("localStorage.getItem", "receiver.cookie-consent");
|
||||
_consentVisible = accepted != "1";
|
||||
StateHasChanged();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op: server prerender (JS unavailable) keeps the banner hidden.
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AcceptCookiesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await JS.InvokeVoidAsync("localStorage.setItem", "receiver.cookie-consent", "1");
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
_consentVisible = false;
|
||||
}
|
||||
|
||||
private async Task OnLanguageChangedAsync(ChangeEventArgs e)
|
||||
{
|
||||
var code = e.Value?.ToString();
|
||||
if (string.IsNullOrEmpty(code) || code == _currentLang)
|
||||
return;
|
||||
|
||||
_currentLang = code;
|
||||
await Loc.ChangeLanguageAsync(code);
|
||||
// Force a full reload so ASP.NET Core localization middleware
|
||||
// picks up the new culture for any subsequent SSR / API calls.
|
||||
Nav.NavigateTo(Nav.Uri, forceLoad: true);
|
||||
}
|
||||
|
||||
private void OnLocChanged()
|
||||
{
|
||||
_currentLang = Loc.CurrentLanguage ?? _currentLang;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose() => Loc.Changed -= OnLocChanged;
|
||||
}
|
||||
Reference in New Issue
Block a user