5.1 KiB
UI Theme — gaps & adoption backlog
Divergence of each project from spec/SPEC.md, and the ordered backlog to
reach adoption of the ZB.MOM.WW.Theme shared RCL. Status legend: ⛔ gap · 🟡 partial · ✅ matches.
Divergence vs spec
§1 Design tokens — theme.css
| Item | OtOpcUa | MxAccessGateway | ScadaBridge |
|---|---|---|---|
| Tokens identical to canonical | ✅ identical | ✅ identical | ✅ identical |
| File maintained in one place (RCL) | ⛔ own copy | ⛔ own copy | ⛔ own copy |
Font path url('../fonts/…') |
⛔ url('fonts/…') — latent 404 |
🟡 url('/fonts/…') — absolute, not portable |
✅ url('../fonts/…') — correct |
| IBM Plex fonts in one place | ⛔ own wwwroot/fonts/ |
⛔ own wwwroot/fonts/ |
⛔ own wwwroot/fonts/ |
→ Gap T1: All three apps maintain a copy of theme.css — the single-source guarantee
is broken today. Any token change must be applied in four places (three apps + the RCL)
once the RCL exists.
→ Gap T2: OtOpcUa url('fonts/…') is a latent 404 masked by system-font fallback.
Adoption fixes it automatically.
→ Gap T3: Each app vendors fonts — 3× duplication. The RCL eliminates it.
§2 Typography
All three apps reference IBM Plex via the token stacks. No typography divergence — the token values are identical. Gap is delivery (T3 above).
§3 Canonical side-rail layout
| Item | OtOpcUa | MxAccessGateway | ScadaBridge |
|---|---|---|---|
.app-shell root element |
✅ div.app-shell |
⛔ div.d-flex … (no .app-shell) |
⛔ div.d-flex … (no .app-shell) |
| Rail CSS class | ✅ .side-rail |
⛔ .sidebar |
⛔ .sidebar |
| Nav item CSS class | ✅ .rail-link |
⛔ .nav-link |
⛔ .nav-link |
| Nav item element | ✅ <a> (NavLink) |
⛔ <li><NavLink> inside <ul> |
⛔ <li><NavLink> inside <ul> |
| Shell component | ⛔ bespoke MainLayout + NavSidebar |
⛔ combined MainLayout (210 lines) |
⛔ MainLayout + NavMenu |
| Thin-MainLayout pattern | ⛔ not yet | ⛔ not yet | ⛔ not yet |
→ Gap L1: OtOpcUa already uses the right CSS classes but the component structure
doesn't use ThemeShell. Low-risk migration.
→ Gap L2: MxAccessGateway and ScadaBridge use .sidebar / .nav-link / <ul><li>.
Migration requires class name changes throughout their nav markup and site.css sidebar
blocks. Medium (ScadaBridge) to high (MxGateway combined layout) risk.
§4 Component contract
| Component | OtOpcUa | MxAccessGateway | ScadaBridge |
|---|---|---|---|
StatusPill (vs bespoke StatusBadge) |
⛔ StatusBadge (string CSS class) |
⛔ StatusBadge (string text → class) |
⛔ raw .chip-* classes inline |
LoginCard |
⛔ inline markup in Login.razor |
⛔ no Blazor login page | ⛔ Bootstrap .card markup in Login.razor |
NavRailItem / NavRailSection |
⛔ NavLink + NavSection (interactive) |
⛔ NavLink+<li> + NavSection |
⛔ NavLink+<li> + NavSection |
ThemeShell / thin MainLayout |
⛔ not yet | ⛔ not yet | ⛔ not yet |
ThemeHead |
⛔ manual <link> tags |
⛔ manual <link> tags |
⛔ manual <link> tags |
§5 Delivery
| Item | OtOpcUa | MxAccessGateway | ScadaBridge |
|---|---|---|---|
Asset via _content/ZB.MOM.WW.Theme/… |
⛔ _content/…AdminUI/css/… |
⛔ root-relative /css/… |
⛔ _content/…CentralUI/css/… |
<ThemeHead /> in <head> |
⛔ manual <link> tags |
⛔ manual <link> tags |
⛔ manual <link> tags |
Adoption backlog (ordered)
| # | Item | Projects | Priority | Effort | Risk | Notes |
|---|---|---|---|---|---|---|
| 1 | Build ZB.MOM.WW.Theme RCL |
scadaproj | High | M | Low | DONE — 0.1.0 built + tested in this repo |
| 2 | Adopt in OtOpcUa AdminUI | OtOpcUa | High | S | Low | Already rail; fix latent font 404; cookie nav-state optional retain |
| 3 | Adopt in ScadaBridge CentralUI + Host | ScadaBridge | Med | M | Med | Sidebar class migration + MainLayout replace; scoped .razor.css unchanged |
| 4 | Adopt in MxAccessGateway Dashboard | MxAccessGateway | Low | L | High | Combined MainLayout migration; sidebar idiom change; largest UX-visible change — verify visually |
Sequencing: #2 first (lowest risk, validates the adoption pattern); #3 next (medium effort, no design change); #4 last (highest risk — verify dashboard UX thoroughly before merging). Each adoption is a per-repo PR, independent.
Open questions
- MxGateway login: No Blazor login page today. If one is added during adoption (#4),
use
<LoginCard>. If the server-redirect pattern is kept,<LoginCard>is not needed. - OtOpcUa cookie nav state: Decide whether to retain
otopcua_navcookie persistence (keep bespoke interactiveNavSectionalongsideThemeShell'sNavslot) or drop it (CSS-onlyNavRailSectionreplaces it, losing expand-state persistence across page loads). - ScadaBridge
AuthorizeViewpolicy gating in nav: Verify<NavRailSection>inside<AuthorizeView>renders + hides correctly with the canonical SSR rendering model.