Evidence — Mermaid diagram figures (ZER0-013)¶
Proof for the Mermaid rework: _includes/components/mermaid.html (loader) + assets/js/mermaid-diagrams.js (behaviour) + _sass/components/_mermaid.scss (chrome), replacing the ~400-line inline <script>/<style> include. Generated by test/visual/mermaid-evidence.mjs; every number below is read off the live page, not asserted by eye.
Routes: /quickstart/ (the single flowchart the bug was reproduced on) and /docs/features/mermaid-diagrams/ (12 diagrams, 8 types, one intentionally broken).
Before → after¶
BEFORE is the old include on main (tracked changes stashed, site rebuilt, same script run with EVIDENCE_STATE=before). AFTER is this branch. Both states capture the same scenes so the montages compare like with like.
| # | Scene | Before | After |
|---|---|---|---|
| 01 | Light, 1280px | 01-before-light-1280.png — Mermaid's stock purple (#9370DB) borders on white nodes, "trebuchet ms". |
01-after-light-1280.png — bordered figure; node fill is a tint of the skin brand, border is the brand (--bs-primary), body font. Toolbar appears on hover. |
| 02 | Dark mode, after a live toggle | 02-before-dark-after-toggle-1280.png — the diagram is gone. The div shows a wall of #mermaid-… {font-family: …} text (its own leaked stylesheet) plus a permanent "Loading diagram…" label. |
02-after-dark-after-toggle-1280.png — re-rendered from source with a dark palette (node fill rgb(56, 76, 95), light ink). |
| 03 | Phone, 390px (touch) | 03-before-mobile-390.png — scaled to fit, no way to enlarge. |
03-after-mobile-390.png — same fit-to-width, plus a static toolbar row above the diagram (never covering it) with 36px tap targets; zoom or fullscreen enlarge it. |
| 04 | Skin neon |
04-before-skin-neon-1280.png — still the broken state from scene 02 (nothing recovers). |
04-after-skin-neon-1280.png — purple nodes: border rgb(131, 56, 236) = the skin's --bs-primary. |
| 05 | Syntax error (-> instead of -->) |
05-before-syntax-error.png — Mermaid's bomb icon, "Syntax error in text", the source discarded. |
05-after-syntax-error.png — error card with the parse message, a hint, and the source kept in an open <details>; only copy stays enabled. |
| 06 | Zoomed to 195 % | — | 06-after-zoomed-195.png — the SVG itself is resized (678 → 1325px) so the frame scrolls; page overflow stays 0. |
| 07 | Fullscreen | — | 07-after-fullscreen-1280.png — native <dialog> with title + toolbar + close; the same SVG node moved in (and back on Escape). |
| 08 | Series colours | — | 08-after-pie-light.png (12-colour series fanned out from the brand hue), 08-after-gantt-dark.png (done / active / crit bars from muted / accent / danger tokens; dark-ink text on the light brand bar). |
Metrics (metrics.json / metrics-before.json)¶
| Scene | SVG present | leaked CSS on screen | node fill | node border | toolbar | page overflow |
|---|---|---|---|---|---|---|
| light 1280 — before | yes | no | #ffffff |
#9370db (Mermaid default) |
— | 0 px |
| light 1280 — after | yes | no | rgb(226, 238, 248) |
rgb(111, 168, 220) (= --bs-primary) |
floating | 0 px |
| dark after toggle — before | no | yes | — | — | — | 0 px |
| dark after toggle — after | yes | no | rgb(56, 76, 95) |
rgb(111, 168, 220) |
floating | 0 px |
| back to light — before | no | yes | — | — | — | 0 px |
| back to light — after | yes | no | rgb(226, 238, 248) |
rgb(111, 168, 220) |
floating | 0 px |
| skin neon — before | no | yes | — | — | — | 0 px |
| skin neon — after | yes | no | rgb(238, 227, 252) |
rgb(131, 56, 236) |
floating | 0 px |
| mobile 390 — before | yes | no | #ffffff |
#9370db |
— | 0 px |
| mobile 390 — after | yes | no | rgb(226, 238, 248) |
rgb(111, 168, 220) |
static, above the diagram | 0 px |
| syntax error — before | bomb SVG | no | — | — | — | 0 px |
| syntax error — after | no (error card, source kept) | no | — | — | floating (copy only) | 0 px |
| zoomed 195 % — after | yes, 1325 px wide | no | frame scrolls | 0 px | ||
| fullscreen — after | in dialog | focus inside dialog, scroll locked, closed on Escape | ||||
| docs page — after | 11 of 12 rendered, 1 error card; types: flowchart, sequence, class, state, er, pie, gantt, git | 0 px |
Two things worth reading off that table:
- The toggle bug is a total loss, not a glitch. Before, one colour-mode switch leaves
hasSvg = falsefor the rest of the page's life — the "back to light" and "skin" rows never recover. After, every row has its SVG and the palette follows the mode and skin. - The palette really is the theme's. The after border colour equals
--bs-primaryin both skins (#6fa8dcair,#8338ecneon); no colour is hard-coded in the component.
A second bug this surfaced¶
While chasing grey pie slices, the culprit turned out to be assets/js/obsidian-wiki-links.js: it rewrites #hashtag-shaped tokens in text nodes and skips STYLE ancestors by nodeName — but SVG-namespace elements report style in lower case, so it walked into every rendered diagram's <style> and turned its #id selectors into tag links, unscoping the rules for the whole page. Fixed in the same PR (case-insensitive check, <svg> subtrees skipped, .zer0-diagram exempt), with a fixture in test/test_resolver.js and a pie-fill assertion in the spec.
Regression test¶
test/visual/features/mermaid.spec.js — 12 tests, green on Chromium: fences → figures for 8 types (+ no code-copy chrome, no stylesheet leak), toolbar/caption a11y, colour-mode toggle re-renders from source, skin recolour, error card keeps source, zoom resizes + scrolls, keyboard zoom, fullscreen dialog + focus return, clipboard copy, no overflow at 320/390 px, static toolbar on touch. test/test_resolver.js covers the wiki-link fix.