docs(ui-theme): current-state ×3 + GAPS adoption backlog

This commit is contained in:
Joseph Doherty
2026-06-01 05:15:38 -04:00
parent 95975d0754
commit 029ac0719b
4 changed files with 579 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
# UI Theme — gaps & adoption backlog
Divergence of each project from [`spec/SPEC.md`](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_nav` cookie persistence
(keep bespoke interactive `NavSection` alongside `ThemeShell`'s `Nav` slot) or drop it
(CSS-only `NavRailSection` replaces it, losing expand-state persistence across page loads).
- **ScadaBridge `AuthorizeView` policy gating in nav:** Verify `<NavRailSection>` inside
`<AuthorizeView>` renders + hides correctly with the canonical SSR rendering model.