162 lines
8.3 KiB
Markdown
162 lines
8.3 KiB
Markdown
# 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 canonical `url('../fonts/…')` in the RCL — a deployment path difference,
|
||
not a loading bug.
|
||
- Wired in `App.razor` line 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.razor` line 7: `<link rel="stylesheet" href="/css/site.css" />`.
|
||
- Contains: `.sidebar` layout (lines ~24–95), `.dashboard-body`, `.agg-card`, table
|
||
styles, metric cards, event/alarm grids, and other domain-specific rules.
|
||
- After adoption: the `.sidebar` layout section is superseded by RCL `layout.css`.
|
||
The domain-specific table/card/grid rules stay in `site.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.woff2`
|
||
- `ibm-plex-sans-600.woff2`
|
||
- `ibm-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-shell` class** (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-link` anchor 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.) to `chip-ok` / `chip-warn` / `chip-bad` / `chip-idle` CSS classes.
|
||
- After adoption: the string-matching logic is app-specific (based on gateway session
|
||
state strings). Migration to `StatusPill` requires the caller to map gateway state
|
||
strings to `StatusState` values, then pass `State` instead of `Text`.
|
||
|
||
---
|
||
|
||
## 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:**
|
||
|
||
1. **Delete copies.** Remove `wwwroot/css/theme.css` and `wwwroot/fonts/ibm-plex-*.woff2`
|
||
from `src/ZB.MOM.WW.MxGateway.Server/`.
|
||
|
||
2. **Reference RCL.** Add `<PackageReference Include="ZB.MOM.WW.Theme" />` to
|
||
`ZB.MOM.WW.MxGateway.Server.csproj`. Add `@using ZB.MOM.WW.Theme` to `_Imports.razor`.
|
||
|
||
3. **Wire `ThemeHead`.** In `App.razor` replace `/css/theme.css` link with `<ThemeHead />`.
|
||
Keep `/css/site.css` for domain-specific rules. Also change static asset paths from
|
||
root-relative to `_content/ZB.MOM.WW.Theme/…` for fonts if any remain in `site.css`.
|
||
|
||
4. **Replace `MainLayout`.** Replace the 210-line `MainLayout.razor` with a thin wrapper
|
||
around `<ThemeShell Product="MXAccess Gateway">`. Carry the nav sections and the sign-in
|
||
link into the `Nav` and `RailFooter` slots respectively.
|
||
|
||
5. **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.
|
||
|
||
6. **Clean `site.css`.** Remove the `.sidebar` layout block (lines ~24–95) — superseded by
|
||
`layout.css`. Keep all dashboard/domain-specific rules (`.agg-card`, tables, metric
|
||
cards, etc.).
|
||
|
||
7. **Replace `StatusBadge`.** Add a helper that maps gateway session-state strings to
|
||
`StatusState` values; replace `<StatusBadge Text="…">` call sites with
|
||
`<StatusPill State="…">`. Delete `StatusBadge.razor`.
|
||
|
||
8. **Login card (optional).** No Blazor login page exists today. If one is added,
|
||
`<LoginCard>` is the canonical implementation.
|
||
|
||
9. **Keep:** domain-specific `site.css` rules, scoped `.razor.css` files (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>`.
|