8.3 KiB
UI Theme — current state: MxAccessGateway
Repo: ~/Desktop/MxAccessGateway (Gitea mxaccessgw). Stack: .NET 10, Blazor SSR
(gateway x64) — UI in src/ZB.MOM.WW.MxGateway.Server/.
All paths below are relative to the repo root. Verified against source on 2026-06-01.
Summary: MxAccessGateway uses a sidebar nav layout and the Technical-Light tokens, but
the sidebar uses Bootstrap .sidebar / .nav-link classes rather than the canonical
.side-rail / .rail-link classes, and the overall structure diverges from the spec
target. Adoption has the highest effort and risk of the three apps — the shell
requires migration from its current sidebar idiom to the canonical ThemeShell pattern.
There is no dedicated login page (authentication gate is integrated into the Dashboard).
1. CSS / design tokens
theme.css — 379-line hand copy of the Technical-Light design system. Identical in
content to OtOpcUa's and ScadaBridge's copies except for the font-path prefix.
- Path:
src/ZB.MOM.WW.MxGateway.Server/wwwroot/css/theme.css - Font path:
url('/fonts/ibm-plex-sans-400.woff2')(lines 24, 29, 34) - Absolute path (
/fonts/…) is technically correct (resolves from root of the app), but differs from the canonicalurl('../fonts/…')in the RCL — a deployment path difference, not a loading bug. - Wired in
App.razorline 6:<link rel="stylesheet" href="/css/theme.css" />.
site.css — 592 lines of per-app page layout and Dashboard component styling.
- Path:
src/ZB.MOM.WW.MxGateway.Server/wwwroot/css/site.css - Wired in
App.razorline 7:<link rel="stylesheet" href="/css/site.css" />. - Contains:
.sidebarlayout (lines ~24–95),.dashboard-body,.agg-card, table styles, metric cards, event/alarm grids, and other domain-specific rules. - After adoption: the
.sidebarlayout section is superseded by RCLlayout.css. The domain-specific table/card/grid rules stay insite.css.
Note: MxGateway's App.razor loads assets from /css/… and /fonts/… (root-relative
paths to wwwroot/), not via _content/… static-web-asset paths — contrast with
OtOpcUa and ScadaBridge which use the RCL _content/ mechanism.
2. IBM Plex fonts
Three .woff2 files vendored into:
src/ZB.MOM.WW.MxGateway.Server/wwwroot/fonts/
ibm-plex-sans-400.woff2ibm-plex-sans-600.woff2ibm-plex-mono-500.woff2
After adoption: delete all three; the RCL serves them from
_content/ZB.MOM.WW.Theme/fonts/.
3. Layout shell
MainLayout.razor — 210-line combined layout + nav component. @implements IDisposable; @inject NavigationManager, @inject IJSRuntime. Interactive
(@rendermode InteractiveServer inherited from Routes).
- Path:
src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Layout/MainLayout.razor - Root element:
<div class="d-flex flex-column flex-lg-row" style="min-height: 100vh;">. Note: no.app-shellclass (unlike OtOpcUa and the spec target). - Brand:
<a class="brand" href="/"><span class="mark">▮</span> MXAccess Gateway</a>(line 24). - Nav structure:
<nav class="sidebar d-flex flex-column">with<ul class="nav flex-column">and<NavSection>groups ("Runtime", "Galaxy", "Admin", "Configuration") with<NavLink class="nav-link">children (not.rail-link). - No dedicated
RailFooter/ session block (auth state shown elsewhere or via API keys). - Nav state persisted via JS (
nav-state.js), same pattern as OtOpcUa.
NavSection.razor — 40-line component using EventCallback OnToggle + JS collapse.
- Path:
src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Layout/NavSection.razor - Structure:
<li class="nav-item"><button class="nav-section-toggle" @onclick="OnToggle">. Uses Bootstrap-style<ul>/<li>nav items, not.rail-linkanchor style.
4. Login / auth surface
MxAccessGateway has no dedicated Blazor login page. There is no Login.razor. The
dashboard is protected by ASP.NET Core cookie authentication; login is handled via an
ASP.NET Minimal API auth endpoint (outside the Blazor component tree). The MainLayout
includes a "Sign In" link (<a href="/login" class="btn …">Sign In</a> line 87) that
redirects to the server endpoint. The <LoginCard> component is not applicable until
a Blazor login page is added.
5. StatusBadge component
StatusBadge.razor — string-match–based chip component.
- Path:
src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Shared/StatusBadge.razor - Parameters:
string? Text. Maps known strings ("Ready", "Healthy", "Active", "Faulted", etc.) tochip-ok/chip-warn/chip-bad/chip-idleCSS classes. - After adoption: the string-matching logic is app-specific (based on gateway session
state strings). Migration to
StatusPillrequires the caller to map gateway state strings toStatusStatevalues, then passStateinstead ofText.
6. Divergences from spec
| Item | Current state | Spec |
|---|---|---|
theme.css |
Hand copy, 379 lines | Single canonical copy in RCL |
Font-path url() |
url('/fonts/…') (absolute, not a bug but non-canonical) |
url('../fonts/…') |
| IBM Plex fonts | Vendored 3× in wwwroot/fonts/ |
Single copy in RCL wwwroot/fonts/ |
| Asset wiring | Root-relative /css/…, /fonts/… |
_content/ZB.MOM.WW.Theme/… |
| Shell class | d-flex … (no .app-shell) |
ThemeShell + .app-shell |
| Nav class idiom | .sidebar + .nav-link + <ul>/<li> |
.side-rail + .rail-link + <a> |
| Nav items | <NavLink class="nav-link"> inside <li> |
<NavRailItem> |
| Nav sections | NavSection (button OnToggle + JS) |
NavRailSection (<details>, CSS-only) |
| Status chip | StatusBadge (string text → CSS class) |
StatusPill (StatusState enum) |
| Login page | None — server endpoint redirect only | <LoginCard> (if a Blazor login page is added) |
7. Adoption plan
Effort: High. Risk: High. The sidebar idiom (nav.sidebar + .nav-link + <ul><li>)
differs from the canonical rail idiom (.side-rail + .rail-link + <a>), requiring a
CSS and markup migration. No layout redesign (it already uses a side-panel pattern), but
class names, element structure, and the site.css sidebar block all change.
Steps:
-
Delete copies. Remove
wwwroot/css/theme.cssandwwwroot/fonts/ibm-plex-*.woff2fromsrc/ZB.MOM.WW.MxGateway.Server/. -
Reference RCL. Add
<PackageReference Include="ZB.MOM.WW.Theme" />toZB.MOM.WW.MxGateway.Server.csproj. Add@using ZB.MOM.WW.Themeto_Imports.razor. -
Wire
ThemeHead. InApp.razorreplace/css/theme.csslink with<ThemeHead />. Keep/css/site.cssfor domain-specific rules. Also change static asset paths from root-relative to_content/ZB.MOM.WW.Theme/…for fonts if any remain insite.css. -
Replace
MainLayout. Replace the 210-lineMainLayout.razorwith a thin wrapper around<ThemeShell Product="MXAccess Gateway">. Carry the nav sections and the sign-in link into theNavandRailFooterslots respectively. -
Port nav items. Migrate from
<NavLink class="nav-link">inside<li class="nav-item">to<NavRailItem Href="…" Text="…">. The four section groups ("Runtime", "Galaxy", "Admin", "Configuration") map to<NavRailSection Title="…">children. -
Clean
site.css. Remove the.sidebarlayout block (lines ~24–95) — superseded bylayout.css. Keep all dashboard/domain-specific rules (.agg-card, tables, metric cards, etc.). -
Replace
StatusBadge. Add a helper that maps gateway session-state strings toStatusStatevalues; replace<StatusBadge Text="…">call sites with<StatusPill State="…">. DeleteStatusBadge.razor. -
Login card (optional). No Blazor login page exists today. If one is added,
<LoginCard>is the canonical implementation. -
Keep: domain-specific
site.cssrules, scoped.razor.cssfiles (none currently), API-key authentication, all page components.
Flagged risk: This is the largest UX-visible change across the three apps. The sidebar
class migration (.sidebar → .side-rail, .nav-link → .rail-link) will visually
change the nav styling. Verify visually in the dashboard before merging. The nav expand
state persistence (JS-based) must be verified or replaced with CSS-only <details>.