Skip to content

Make MLQT's look a reusable package: MLQT.UI.Theme - #29

Merged
mdempse1 merged 5 commits into
mainfrom
ui-theme-package
Oct 29, 2026
Merged

mdempse1 merged 5 commits into
mainfrom
ui-theme-package

Conversation

@mdempse1

Copy link
Copy Markdown
Owner

MLQT's look as a reusable Razor class library, so other internal tools can look like MLQT by referencing it from source, as they already do the parser and graph. MLQT builds on it itself, so the application and other tools take their look from one source.

What's in MLQT.UI.Theme

  • MlqtTheme: the default palettes, typography (0.75rem body text, monospace Body2) and layout sizes. The palette from a user's custom colours stays in MLQT.Shared as CustomPalette, because it reads UISettings.
  • mlqt-base.css: 16 --mlqt-* tokens (type sizes, the 4/8/16px spacing scale, control and icon sizes, colours, highlight washes, scrollbar), the WebKitGTK scrollbar fix (B140), and the split-pane and tab-host layout classes. It is loaded before MudBlazor's stylesheet.
  • mlqt-density.css: MudBlazor made small and dense, out of MainLayout's inline <style>. It is loaded after MudBlazor's stylesheet, because it only wins by coming later.
  • Moved without change: Roboto with its licence, mudBlazorWorkarounds.js and ProgressDialog.
  • ThemeAssetManifest: the load order as leading and trailing lists around a tool's own assets. HostAssetManifest is now built from it.
  • README.md: written for a tool using the theme.

The theme is the only project in the repository that references MudBlazor. Its public API is tracked like the six other assemblies built on outside this repository. Its CSS classes and tokens are listed in PublicCss.txt, and ThemeCssContractTests holds the stylesheets to that list. RS0041 is off for the project, because the Razor compiler generates BuildRenderTree outside any nullable context.

Commits

  1. Extract the theme with no visible change. This also deletes the unused Bootstrap stylesheet and the Bootstrap leftovers in app.css.
  2. Add the tokens and the CSS contract: PublicCss.txt, ThemeCssContractTests, and ThemeTokensJourney, which checks the token values in a real page and measures the scrollbar gutter (WebKit only, because headless Chromium hides scrollbars).
  3. Move McpTester onto the theme. It is the second consumer, and references nothing else of MLQT. McpTesterTheme (B124) and its MudBlazor reference go, and its app.css becomes an empty placeholder.
  4. Fix what a review found:
    • MLQT's 100vh/100vw window-shell rule had moved into the theme, where it made any page that scrolls overflow sideways by its scrollbar's width (measured). It is back in MainLayout, and a test now refuses viewport units in the theme.
    • Two tokens, the font and the link colour, could never take effect over MudBlazor's own body and a rules, so they are removed.
    • Comments that said otherwise are corrected, and the README is added.
  5. Make a plain MudAppBar match MLQT's. AppbarBackground is now the primary colour in both palettes. Before, McpTester's app bar was #6a93b1, a colour MLQT never showed.

Testing

  • CI=true dotnet build MLQT.slnx -c Release: no warnings.
  • Test suites: MLQT.Shared 1,078, Services 1,801, CLI 362. Journeys under Chromium: 112 pass, and the WebKit-only scrollbar check is skipped. ThemeTokensJourney also passes in full under WebKit locally.
  • Coverage gate: passes, with MLQT.UI.Theme at 98.9%.
  • Documentation screenshots: regenerated after every step and compared pixel by pixel with a baseline. They differ only where two baseline runs differ from each other: commit hashes and timestamps, the randomised graph layout, list order, and anti-aliasing (at most 9/255 off the noisy areas). No visible change to MLQT.
  • Guard tests: each new guard was confirmed to fail by breaking what it holds.
  • Published tester: a published McpTester serves every asset its page names, including the font files.

Not verified

  • The tester's window has not been opened. It should now look like MLQT, including the app bar.
  • The Photino self-test was not run locally. The desktop-selftest job covers it.
  • The scrollbar gutter on Linux is first measured by the nightly WebKit run.

Also recorded in the roadmap: B520, a small existing defect, not fixed here. The search-match highlight dims for the operating system's dark-mode preference, not MLQT's own Dark theme.

🤖 Generated with Claude Code

mdempse1 and others added 5 commits October 29, 2026 09:31
A new Razor class library that other Blazor tools can reference from source to look like MLQT.
MLQT.Shared builds on it, so there is one source of truth for the look:

- MlqtTheme: the default palettes, typography and layout sizes. The palette built from the
  user's custom colours stays in MLQT.Shared as CustomPalette, because it reads UISettings
- mlqt-base.css: the page font, the WebKitGTK scrollbar fix, the tab host and page-fill chain
  and the split-pane rules, out of MLQT.Shared's app.css, which keeps only MLQT's page rules
- mlqt-density.css: MudBlazor made small and dense, out of MainLayout's inline <style>
- Roboto, mudBlazorWorkarounds.js and ProgressDialog
- ThemeAssetManifest: the theme's assets as leading and trailing lists around a tool's own,
  because the density overrides must follow MudBlazor's stylesheet. HostAssetManifest and the
  Photino page are composed from it, and HostAssetManifestTests holds the order

The theme alone references MudBlazor, so a consumer gets the version its CSS was written for.
Its public API is tracked like the six other assemblies built on outside this repository,
with RS0041 off because Razor generates BuildRenderTree outside any nullable context. It joins
the coverage gate, measured from MLQT.Shared.Tests (98.9%).

The unused Bootstrap stylesheet and app.css's leftover Bootstrap template rules are deleted.

No visible change: the documentation screenshots regenerated after the move differ from the
baseline only where two baseline runs differ from each other (commit hashes, the randomised
graph layout, a placeholder caught mid-transition). The Shared, Services, CLI and journey suites
and a CI=true build pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p 2)

The values the theme's stylesheets repeated are now 18 custom properties at the top of
mlqt-base.css: type, the 4/8/16px spacing scale, control and icon sizes, the link and control
border colours, the divider, a selected-row and a search-match wash, and the scrollbar. Both theme
stylesheets and MLQT's app.css use them. A token is MudBlazor's own variable where the stylesheet
already used one or the value is MlqtTheme's typography; the control border stays its own colour,
because MudBlazor's lines-default turns white in dark mode and aliasing it would change the dark
theme. Optical one-offs (a 5px or 11px padding) stay literals.

The theme's classes and tokens are other tools' API, and no analyzer sees CSS. PublicCss.txt lists
them as PublicAPI.*.txt lists types, and ThemeCssContractTests fails on one defined and unlisted,
one listed and gone, or a var(--mlqt-*) anywhere in the repository's pages that the theme does not
define, which CSS would silently treat as the property's initial value. Each check was confirmed
to fail by breaking what it holds.

ThemeTokensJourney checks the tokenised rules come out at the theme's values in a real page, and
measures the scrollbar gutter that is the B140 fix: 4px under WebKit with var() inside
::-webkit-scrollbar. It skips under Chromium, which Playwright runs headless with no scrollbars.

No visible change: the regenerated documentation screenshots differ from the baseline only where
two baseline runs differ from each other, and by anti-aliasing (at most 9/255) on a few icons.

Found in passing and recorded as B520: the search-match wash dims for the operating system's dark
preference rather than MLQT's own Dark theme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tester is the theme's second consumer in the repository, and the first that takes nothing else
of MLQT: one project reference, which brings MudBlazor and none of the Modelica stack, so the tool
stays independent of MLQT's service layer. It builds its MudTheme with MlqtTheme.BuildTheme, and
its hand-written page loads the theme's assets in ThemeAssetManifest's order with its own app.css
between them. A new HostAssetManifestTests case holds the page to that order, and was confirmed to
fail with the density file moved ahead of MudBlazor's sheet.

McpTesterTheme goes: it existed only to ask for the platform's UI font rather than download Roboto
(B124), and the theme's bundled copy answers that. Its MudBlazor reference goes too, so MLQT.UI.Theme
is now the only project that references MudBlazor. The tester's app.css is now an empty placeholder,
like MLQT.Photino's. Its Bootstrap template rules and font are gone, and so are its #blazor-error-ui
rules: MudBlazor.min.css already hides and draws Blazor's error bar, and since app.css loads before
it, those rules lost on every property MudBlazor sets. The unused Bootstrap copy and the iOS
safe-area leftover from its MAUI days are deleted.

A published build serves every asset the page names, the font files included. The tester now looks
like MLQT: MLQT's palette and dense controls rather than MudBlazor's defaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- MLQT's window shell no longer goes to every tool. `.mud-layout { height: 100vh; width: 100vw }`
  and the `.mud-navmenu` rule moved into mlqt-density.css with the rest of MainLayout's inline
  style, but they describe MLQT's one-screen window, not density. On a page that scrolls, as
  McpTester's does, 100vw counts the vertical scrollbar and the layout overflows sideways by its
  width (measured in Chromium: 800px of layout in a 796px page). They are back in MainLayout, and
  ThemeCssContractTests now fails on any viewport unit in the theme's sheets (confirmed by adding
  one).
- Two public tokens that did nothing are gone. --mlqt-font-family and --mlqt-link-color drove
  `html, body` and `a` rules in mlqt-base.css, which loads before MudBlazor's sheet, and MudBlazor's
  own `body` and `a` rules beat them at the same specificity. Both rules were already dead in the
  old app.css. They are removed rather than moved after MudBlazor, which would change MLQT's look,
  and PublicCss.txt drops the two lines. That leaves 16 tokens.
- mlqt-base.css and ThemeAssetManifest said every base rule wins against MudBlazor, which was untrue.
  They now say which rules belong before MudBlazor's sheet, and every rule left was checked against
  MudBlazor 9.11's sheet.
- Stale wording fixed: the theme is one of seven tracked assemblies, not "like the six", and
  MudBlazor is referenced nowhere else in the repository, not just in MLQT.Shared's chain.
- MLQT.UI.Theme/README.md, for a tool using the theme: reference it and not MudBlazor, register
  MudBlazor's services, give MudThemeProvider MlqtTheme, load the assets in ThemeAssetManifest's
  order and why the order matters, and what PublicAPI.*.txt and PublicCss.txt let a tool rely on.

No visible change to MLQT: the regenerated documentation screenshots differ from the baseline only
by commit hashes and timestamps, the randomised graph layout, a list in a different order, and
anti-aliasing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MLQT's app bar and McpTester's were different blues. MLQT asks for <MudAppBar Color="Color.Primary">,
which MudBlazor paints in the palette's Primary, #6a70b1. The tester's plain <MudAppBar> takes
AppbarBackground, which MlqtTheme set to #6a93b1 in both palettes - a colour MLQT itself never
showed, since its own app bar ignores it and the custom palette has always made the two equal.

Both palettes now set AppbarBackground to the primary colour, which MlqtTheme names once, so any
tool's plain app bar matches MLQT's without being told to. MLQT does not change: the regenerated
documentation screenshots differ only by the usual commit hashes, graph layout and anti-aliasing,
and none of them in the app bar. MlqtThemeTests now holds AppbarBackground to Primary in both
palettes (confirmed to fail with the old colour back in the dark one), and the README no longer
tells a tool to ask for Color.Primary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mdempse1
mdempse1 merged commit 39265e2 into main Oct 29, 2026
14 checks passed
@mdempse1
mdempse1 deleted the ui-theme-package branch October 29, 2026 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant