Files
maraphon-app/plans/initial-implementation/phase-5-host-theme-i18n.md
T

6.0 KiB

Phase 5: Blazor Hybrid Host + Theme + Localization

Status: Not Started Parent plan: PLAN.md Domain: frontend Implementer: Opus + frontend-design skill

Objective

Create the WPF + BlazorWebView host that loads Marathon.UI (Razor Class Library), establish the design system / theme using MudBlazor, set up bilingual (RU/EN) localization end-to-end, and wire up DI to compose Application + Infrastructure layers.

Tasks

  • In src/Marathon.Hosts.WpfBlazor/Marathon.Hosts.WpfBlazor.csproj:
    • Set <UseWPF>true</UseWPF>, <UseWindowsForms>false</UseWindowsForms>
    • SDK: Microsoft.NET.Sdk.Razor (so Razor + WPF interop works)
    • Add packages:
      • Microsoft.AspNetCore.Components.WebView.Wpf
      • MudBlazor
      • Microsoft.Extensions.Hosting
      • Serilog.Extensions.Hosting
      • Serilog.Sinks.File
      • Serilog.Sinks.Console
  • In src/Marathon.UI/Marathon.UI.csproj:
    • SDK: Microsoft.NET.Sdk.Razor
    • <TargetFramework>net8.0</TargetFramework> with WebView for Razor Components
    • Add MudBlazor (so components in this RCL can use MudBlazor)
  • Create Marathon.UI/_Imports.razor with namespace and component imports (Microsoft.AspNetCore.Components.*, MudBlazor, project namespaces).
  • Create Marathon.UI/wwwroot/index.html (Blazor host HTML for the WebView).
  • Create Marathon.UI/MainLayout.razor with MudBlazor MudLayout + MudAppBar + MudDrawer navigation. Include locale switcher (RU/EN) in the AppBar.
  • Create Marathon.UI/Pages/Home.razor placeholder dashboard.
  • Create Marathon.UI/Pages/Settings.razor — bound to all appsettings.json options (ScrapingOptions, WorkerOptions, StorageOptions, AnomalyOptions, LocalizationOptions). Live save via IOptionsMonitor + writing back to appsettings.Local.json.
  • Establish theme tokens in Marathon.UI/Theme/MarathonTheme.cs — distinctive palette per frontend-design guidance, NOT generic AI-default. Include:
    • Primary, secondary, accent
    • Surface tones for light + dark mode
    • Typography stack (RU-friendly font for Cyrillic — e.g., Inter or Manrope which have full Cyrillic coverage)
    • Spacing scale, radius scale, shadow scale as CSS variables in a app.css
  • Wire MudBlazor theme via MudThemeProvider in MainLayout.razor.
  • Localization:
    • Add Microsoft.Extensions.Localization to Marathon.UI
    • Create Marathon.UI/Resources/SharedResource.cs (marker class for IStringLocalizer)
    • Add Marathon.UI/Resources/SharedResource.ru.resx and SharedResource.en.resx with all UI strings used in this phase + placeholders for later phases
    • Configure supported cultures in host: ru-RU, en-US
    • Locale switcher persists choice to appsettings.Local.json and reloads UI
  • In src/Marathon.Hosts.WpfBlazor/MainWindow.xaml:
    • Single BlazorWebView filling the window
    • HostPage="wwwroot/index.html"
    • RootComponents add <RootComponent Selector="#app" ComponentType="{x:Type ui:MainLayout}" />
  • In src/Marathon.Hosts.WpfBlazor/App.xaml.cs:
    • Build IHost via Host.CreateApplicationBuilder()
    • Call services.AddMarathonInfrastructure(config)
    • Call services.AddMarathonApplication(config)
    • Call services.AddWpfBlazorWebView()
    • Add MudBlazor: services.AddMudServices()
    • Configure Serilog (rolling file at ./logs/marathon-.log, console)
    • Start the host on OnStartup, stop on OnExit
  • Add appsettings.json to Marathon.Hosts.WpfBlazor/ (move from Phase 3 if placed there) with all sections. Add appsettings.Development.json template.
  • Tests in Marathon.UI.Tests (using bUnit):
    • Test: MainLayout renders without errors
    • Test: locale switcher changes culture
    • Test: theme tokens are applied (CSS variables present in DOM)

Files to Modify/Create

  • src/Marathon.UI/_Imports.razor
  • src/Marathon.UI/MainLayout.razor
  • src/Marathon.UI/Pages/Home.razor, Pages/Settings.razor
  • src/Marathon.UI/Theme/MarathonTheme.cs, Theme/app.css
  • src/Marathon.UI/wwwroot/index.html
  • src/Marathon.UI/Resources/SharedResource.{cs,ru.resx,en.resx}
  • src/Marathon.UI/Components/LocaleSwitcher.razor
  • src/Marathon.Hosts.WpfBlazor/App.xaml, App.xaml.cs
  • src/Marathon.Hosts.WpfBlazor/MainWindow.xaml, MainWindow.xaml.cs
  • src/Marathon.Hosts.WpfBlazor/appsettings.json, appsettings.Development.json
  • src/Marathon.Hosts.WpfBlazor/Properties/AssemblyInfo.cs
  • tests/Marathon.UI.Tests/MainLayoutTests.cs, LocaleSwitcherTests.cs

Acceptance Criteria

  • Host project compiles (Big Bang smoke check).
  • Marathon.UI is a clean RCL — usable from any host (verifies portability).
  • Theme is distinct, not generic — implementer should follow frontend-design skill guidance for typography, color, motion, spatial composition.
  • Locale switcher works (toggles between RU and EN strings on the same page).
  • Settings page surfaces every configurable parameter from appsettings.json.

Notes

  • This phase is parallelizable with Phases 2 and 3 (only depends on Phase 1 Domain, but the orchestrator can run all three after Phase 1 completes).
  • The frontend-design skill content is provided to the agent in FRONTEND_DESIGN_SKILL context block. Follow it precisely.
  • Use Cyrillic-friendly fonts (Inter, Manrope, IBM Plex Sans, JetBrains Mono).
  • For BlazorWebView in WPF, the project SDK MUST be Microsoft.NET.Sdk.Razor and the OutputType set to WinExe with WPF enabled.

Review Checklist

  • Compiles
  • Marathon.UI references no host-specific code (BlazorWebView, WPF)
  • Theme not generic — distinctive palette + typography
  • All appsettings.json keys reachable via the Settings page
  • RU + EN both renderable (placeholder strings ok for later phases)
  • Accessibility: keyboard navigation in nav drawer, focus indicators

Handoff to Next Phase