Light theme legibility and top bar layout fixes¶
Motivation¶
A walk-through of every menu in light mode surfaced four classes of defect. None of them changed what the dashboard does; all of them made it hard or impossible to read.
- The theme preference was never applied.
useTheme(the only writer of thedata-themeattribute on<html>) was mounted exclusively by Settings → Appearance. Picking "Light" worked until the next reload, and a user whose OS is light and whose preference is the defaultsystemnever got the light palette at all unless they happened to open that panel. - The top bar overflowed the viewport at every common laptop width. The bar
is a single
nowrapflex row whose children do not shrink; it needed 1623 px of content, so at 1366 / 1440 / 1600 px the account, settings, and notification buttons were pushed off-screen and the whole document grew a horizontal scrollbar. - The
/blast/submitthree-column grid never collapsed in light mode.[data-theme="light"] .bsl-gridre-declaredgrid-template-columnsunconditionally, and being more specific than themax-width: 1100pxrule it overrode the collapse. Below 1100 px the stepper and summary rail were alreadydisplay: none, so the centre column rendered inside the ~210 px stepper track — the page looked shattered. - Assorted low-contrast text. A scripted WCAG contrast sweep of Dashboard,
New Search, BLAST Jobs, Results, Playground, Terminal, API Reference and
Diagnostics found code blocks rendering dark ink on a dark surface, API method
chips using dark-theme inks on light tints, and a set of
opacitymultipliers stacked on top of already-muted colour tokens.
User-facing change¶
- The stored theme (
light/dark/system) now applies on every screen, including sign-in and access-denied, and survives a reload. An inline script inindex.htmlresolves it before first paint so there is no dark flash for a light-theme user. - The top bar fits at every width from 420 px to 1920 px. Decorative chrome is shed widest-first as the viewport narrows: nav group labels and separators (≤1680), the build stamp (≤1400), the "Live" pill (≤1320), the latest-job chip (≤1180). The hamburger drawer now takes over at ≤940 px instead of ≤720 px — 940 px is the narrowest viewport where the horizontal bar still fits.
/blast/submitrenders full-width below 1100 px in light mode, and the five program tabs wrap to three columns on phones instead of clipping.- Code/sample panels (Service Bus Playground, Message Flow modal) use a light code canvas in light mode instead of dark text on a dark box.
- API Reference method chips (
GET/POST/DELETE/PUT/PATCH), the Core section accent, and the Result Passport parity verdict resolve through theme tokens, so light mode gets its darker AA-legible inks. Dark mode is byte-identical for the method chips (the tokens hold exactly the previous literals). - Disabled / dimmed controls (blocked BLAST programs, unavailable databases, unavailable sharding options, disabled buttons, the "last updated" whisper, locked terminal cockpit levels, "Coming soon" diagnostics) are still visibly dimmed but readable.
No route, API call, feature gate, or behaviour changed.
Diff summary¶
| File | Change |
|---|---|
web/index.html |
Pre-paint data-theme resolution script |
web/src/App.tsx |
Mount useTheme() at the root, above every auth branch |
web/src/components/Layout.css |
Shedding tiers (1680 / 1400 / 1320 / 1180), drawer 720 → 940, drop the 0.6 opacity on the build stamp and nav group labels |
web/src/components/Layout.tsx |
isMobileNav 720 → 940 to match the CSS |
web/src/components/LatestJobChip.css |
Chip shrink tier 1320 → 1680 |
web/src/theme/blast-submit-layout.css |
Light grid track override moved inside min-width: 1101px; program tabs wrap to 3 columns ≤768 px |
web/src/theme/glass.css |
New --bg-code token (dark #0d1117, light #f6f8fa); disabled/dimmed opacity raises |
web/src/pages/apiReference/{constants.ts,CoreApiSection.tsx,panelStates.tsx} |
Theme tokens instead of dark-theme literals |
web/src/pages/blastResults/analytics/ResultPassportCard.tsx |
Parity verdict colours via tokens |
web/src/pages/ServiceBusPlayground.tsx, components/cards/MessageFlow/MessageFlowModal.tsx |
var(--bg-code) + hairline border on code panels |
web/src/pages/blastSubmit/ComputeSection.tsx, components/cards/ClusterPulse/atoms.tsx, pages/diagnostics/DiagnosticsPage.tsx |
Inline disabled opacity raised off the muted token |
No backend, IaC, sidecar, or image change — nothing to redeploy beyond the normal frontend build.
Validation¶
cd web && npm run build— clean.cd web && npx eslint src— clean.cd web && npm test -- --run— 108 files, 978 tests passing.- Scripted WCAG 2.1 contrast + horizontal-overflow audit run in the browser
against the live deployment with the candidate CSS injected, on
/,/blast/submit,/blast/jobs,/blast/jobs/{id},/blast/playground,/terminal,/docs,/diagnostics: - Top bar width sweep at 420 / 600 / 700 / 800 / 900 / 945 / 960 / 1024 / 1100 /
1180 / 1200 / 1280 / 1320 / 1330 / 1366 / 1400 / 1440 / 1500 / 1600 / 1680 /
1700 / 1920 px —
document.scrollWidth === clientWidthat every step (previously overflowed by up to 193 px). /blast/submitat 1024 px: centre column measured 985 px (was 210 px).- Playground sample-code
<pre>:rgb(246,248,250)background withrgb(36,41,47)text (wasrgb(13,17,23)onrgb(36,41,47), 1.29:1). - Remaining sub-4.5:1 hits are all
:disabledcontrols, which WCAG 1.4.3 exempts; they now sit at 3.0–3.5:1 instead of 1.7–2.1:1.