Files
Joseph Doherty 3070169e5d docs(ui-theme): record post-adoption site.css prune + reconfirm 0.2.0 on feed
Audit follow-up: the deferred 'dead .sidebar/.nav-link residual' was broader than
logged (OtOpcUa's site.css duplicated and overrode the whole kit shell). Pruned
across all 3 apps on chore/theme-css-prune branches (-167/-95/-106 lines, builds
clean). Note the remaining deferred items (kit layout.css calc review; ScadaBridge
Host transitive kit ref) and reconfirm the Theme 0.2.0 publish is genuine.
2026-06-03 04:38:24 -04:00

8.1 KiB
Raw Permalink Blame History

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.

ADOPTED 2026-06-03 (local-only). Backlog #2#4 implemented across all three apps on each repo's feat/adopt-zb-theme branch — full canonical cutover (SPEC §7): <ThemeHead/>/<ThemeScripts/>, thin MainLayout<ThemeShell> + NavRailItem/NavRailSection, per-app theme.css/IBM-Plex fonts/ nav-state.js deleted, <LoginCard> sign-in, and StatusPill (OtOpcUa's dead StatusBadge deleted; MxGateway's StatusBadge redirected to a thin StatusPill adapter; inline domain .chip-* kept as page content per §6). Library first enhanced to 0.2.0 — nav-expand persistence promoted INTO the kit (NavRailSection.Keydata-nav-key + a localStorage nav-state.js enhancer emitted by a new <ThemeScripts/>), so all three apps get uniform persistence from one source (OtOpcUa's bespoke cookie/JS-interop nav island retired). 0.2.0 published to the Gitea feed; 44 bUnit tests. MxGateway additionally gained a net-new Blazor <LoginCard> /login page reusing its existing hardened POST /login endpoint (antiforgery + SanitizeReturnUrl + SignInAsync preserved). Every task spec+code reviewed (high-risk via serial spec→code; the MxGateway login via an Opus security review), then fast-forward-merged into each repo's local default and PUSHED to origin (gitea) 2026-06-03 (in sync; feat/* kept locally): OtOpcUa master@11de14d, ScadaBridge main@58352a6, MxGateway main@73e54e2. Plan: docs/plans/2026-06-03-ui-theme-adoption*.md. The /🟡 cells below describe the PRE-adoption divergence (kept for history).

Post-adoption CSS prune (2026-06-03, branch chore/theme-css-prune per app). An audit found each app's kept site.css still carried the old shell CSS the kit now owns — broader than first logged. Pruned: OtOpcUa shed a near-verbatim copy of the kit's layout.css (.app-shell/.side-rail/.rail-link/ .rail-foot/.login-*) plus dead #sidebar-collapse (kit emits #theme-rail) and .rail-eyebrow-chevron (167 lines), keeping only app-only .rail-eyebrow + .chip-alert/.chip-caution; ScadaBridge shed the dead .sidebar/.nav-link/.nav-section-toggle block (95), keeping #reconnect-modal/.script-editor-modal; MxGateway shed the dead .sidebar block + orphaned .dashboard-login/.login-card (106), keeping .app-bar (still used by /denied) + the .chip override. Each verified unreferenced before removal; all three build clean (0 warn/0 err). OtOpcUa's copy was the notable one — it overrode the kit, not just dead code. Still deferred: a kit-side layout.css calc(100vh - 3.3rem) review; and ScadaBridge's Host consumes the kit only transitively via CentralUI (no direct PackageReference) — builds green, but an implicit dependency.

Feed note: the same audit re-confirmed ZB.MOM.WW.Theme 0.2.0 is genuinely on the Gitea feed (registration count:1, package base versions:["0.2.0"], search totalHits:1) — the publish was real, not optimism.


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 DONE0.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.