Skip to content

docs(read-diagrams): make crow's-foot ER diagrams dark-mode adaptive - #269

Open
dimitri-yatsenko wants to merge 2 commits into
mainfrom
docs/er-diagrams-dark-mode
Open

docs(read-diagrams): make crow's-foot ER diagrams dark-mode adaptive#269
dimitri-yatsenko wants to merge 2 commits into
mainfrom
docs/er-diagrams-dark-mode

Conversation

@dimitri-yatsenko

@dimitri-yatsenko dimitri-yatsenko commented Aug 20, 2026

Copy link
Copy Markdown
Member

Fixes the crow's-foot ER diagrams on how-to/read-diagrams not adapting to dark mode. (The dj.Diagram outputs on that page already adapt — this is only the four traditional-ERD comparison figures.)

Cause

er-one-to-one.svg, er-one-to-many.svg, er-reference.svg, er-many-to-many.svg are Mermaid erDiagram exports with baked-in light-only colors (fill:#eee/#f4f4f4/white, stroke:#999/#666, black text) and no prefers-color-scheme block — so they stayed light on a dark page, while the dj.Diagram SVGs adapt because they carry that block.

Fix

Inject a @media (prefers-color-scheme: dark) block into each SVG — the same mechanism the dj.Diagram outputs use — remapping every color the four files use (enumerated to be complete): entity panels and rows to navy-tinted darks, rules/relationship lines/crow's-foot markers to grey, text to light. Colors follow dj-brand V1.0 (navy structure, grey secondary) and match the sibling dj.Diagram dark theme. Light mode is byte-for-byte unchanged (block only inserted at the end of the <style> element).

Note

Like the dj.Diagram SVGs, this follows the OS prefers-color-scheme. The site's palette auto-selects the dark (slate) scheme under OS-dark, so they move together. A manual palette toggle that overrides the OS setting is a pre-existing limitation shared by all embedded SVGs here, out of scope for this fix.


Revised after review (@MilagrosMarin):

  • Values now come from dj-brand's ratified dark diagram table rather than being picked by eye: panel #242832, rules and borders #9DA0A4, lines, markers and edge labels #C9CFD9, body #E8EAF0. This keeps these four figures on the same dark theme as the dj.Diagram siblings instead of a second one that could drift. Thresholds all hold or improve: border 6.13:1 (was 5.19), text 10.28:1 on the slate and 9.41:1 on the panel, panel 1.09:1 against the page so it still reads as a panel.
  • The two row-stripe tints (#20263a, #1b2136) stay as they are — they sit between the panel and the page and have no ratified equivalent.
  • The !important on the dark stroke is kept deliberately: mermaid's own light rule is stroke:#666!important, so removing it would revert the markers to #666 at 2.80:1 in dark mode.
  • No fill added to .marker: mermaid's second .marker rule sets fill:none!important, so the crow's foot is an unfilled outline in both themes and the #666 fill declaration never renders.

The four er-*.svg crow's-foot diagrams (Mermaid erDiagram exports) had baked-in
light-only colors and no prefers-color-scheme block, so they stayed light on a
dark page — unlike the dj.Diagram SVGs, which adapt. Inject a
@media (prefers-color-scheme: dark) block into each (same mechanism as the
dj.Diagram outputs), remapping panels/rows/strokes/text to a brand-family dark
palette (navy-tinted panels, grey rules, light text) per dj-brand V1.0. Light
mode is unchanged.
@dimitri-yatsenko dimitri-yatsenko added the documentation Improvements or additions to documentation label Aug 20, 2026

@MilagrosMarin MilagrosMarin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the mechanism and the claims against main; the diagnosis is right and the approach is the correct one. One thing got missed in the enumeration.

Checks that hold:

  • The four ER SVGs carry no prefers-color-scheme block; the notebook's 19 inline dj.Diagram outputs carry exactly one each. The stated cause is the actual cause.
  • Light mode is untouched — all four files are a clean pure-insertion of the identical 610-byte block, every surrounding byte unchanged. (Minor: it's inserted at the end of the <style> element, not appended to the file — which is the right place; only the description says "appended.")
  • prefers-color-scheme is the only mechanism available, since these are <img src="/images/…"> and can't see the page's data-md-color-scheme. The note about the manual toggle is accurate.
  • Hues line up with the brand: grey 216° against --dj-grey 216°, navy 226–227° against --dj-navy 231°.
  • Against the slate background (hsl(225,15%,14%) = #1e2129): border 5.19:1, text 11.73:1, edge labels 7.87:1.

The crow's-foot markers keep their light-mode fill

Light mode sets both channels:

#my-svg .marker{fill:#666;stroke:#666;}

The dark block overrides only stroke. That would be harmless if the markers were stroke-only, but the crow's foot is a closed shape:

<marker class="marker oneOrMore er"><path d="M9,18 Q27,0 45,18 Q27,36 9,18"/></marker>

Two quadratics returning to the start point — a filled lens. The path carries no inline fill, so it inherits #666 from the marker element. In dark mode it renders as a #666 interior inside a #aeb6c2 outline, where light mode has the two matching.

Measured against #1e2129:

contrast
marker fill #666 (unchanged) 2.80:1 — below the 3:1 in WCAG 1.4.11 for graphical objects
marker stroke #aeb6c2 (new) 7.87:1
fill against its own outline 2.81:1

#666 is one of the enumerable colors in all four files, so this is the gap in "remapping every color the four files use." It also happens to land on the notation the page exists to explain.

One declaration fixes it:

#my-svg .marker{fill:#aeb6c2;stroke:#aeb6c2!important;}

The optionality circles are unaffected — <circle fill="white"> still resolves to #161a21, because [fill="white"] matches the circle directly and beats inheritance from the parent <marker>.

Two nits

  • "Match the sibling dj.Diagram dark theme" is true by family but not by value — the siblings use #242832 / #9DA0A4 / #C9CFD9 where this uses #242a3d / #8a93a1 / #aeb6c2. Fine as-is; worth knowing the two sets can drift apart.
  • The !important on stroke looks unnecessary: the dark block is later in the same stylesheet at equal specificity, so it already wins.

@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

Careful review, and the mechanism checks you ran are the right ones. Two of the three findings do not survive a look at the full cascade, and the reason is the same rule in both cases.

The markers are already unfilled — in both modes

Mermaid emits two .marker rules, and the second one is the operative one. On main, unchanged by this PR:

#my-svg .marker{fill:#666;stroke:#666;}                                  /* first  */
#my-svg .marker{fill:none!important;stroke:#666!important;stroke-width:1;}  /* second */

fill:none!important beats the earlier fill:#666, so the crow's foot renders as an unfilled outline in light mode too — the #666 interior never paints. Your 2.80:1 measurement is correct as a number for #666; there is just no surface carrying it. In dark mode the outline picks up #aeb6c2 at 7.87:1 and the interior stays none, which is why the enumeration skipped it: #666 appears in the file as a fill declaration but not as a rendered fill.

Adding fill:#aeb6c2 would change the rendering — filling the lens solid where both themes currently show an outline — so I'd rather leave it.

The !important on stroke is load-bearing

Same rule, other direction. The light .marker stroke is #666!important, so the dark block needs !important to win — equal specificity and later position are not enough against an !important declaration. Dropping it would silently revert the markers to #666 in dark mode, at 2.80:1 against the slate.

Which is the bug you described, arrived at from the other end: the marker fill can't cause it, but the "unnecessary" !important cleanup would.

Taking the other two

  • "Appended" is wrong in the description; the block is inserted at the end of the <style> element. Fixing the wording.
  • The value drift is real and worth closing now rather than noting. #242a3d / #8a93a1 / #aeb6c2 were picked by eye; dj-brand's ratified dark table gives #242832 / #9DA0A4 / #C9CFD9. Switching to the ratified set keeps every threshold: border #9DA0A4 6.13:1 (up from 5.19), text #C9CFD9 10.28:1 on slate and 9.41:1 on the panel, panel #242832 at 1.09:1 against the page — still reading as a panel rather than a plate. I'll push that so these four stop being a second dark theme.

Thanks for catching the wording and the drift, and for measuring rather than eyeballing the contrast — that part I'd have taken on faith.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants