Skip to content

Commit a134801

Browse files
authored
fix(site): correct light/dark diagrams, header title, contrast (#22)
- Pair diagram assets by ink colour (dark ink on light pages, light ink on dark pages); rewrite <picture> to CSS dual-imgs for Material toggle - Light theme: dark text on white; dark theme: light text on near-black - Header page title ALL CAPS; hide logo/icon in header and drawer - Simplify palette to explicit light/dark toggle (no auto media cycle)
1 parent 681f93a commit a134801

6 files changed

Lines changed: 197 additions & 75 deletions

File tree

SPECIFICATION.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,10 @@ A message is sent from the sender's host to each unique recipient host (i.e. eac
434434

435435
<p align="center">
436436
<picture>
437-
<source media="(prefers-color-scheme: dark)" srcset="pics/flow-dark.png">
438-
<source media="(prefers-color-scheme: light)" srcset="pics/flow-light.png">
439-
<img alt="fmsg protocol flow diagram" src="pics/flow-light.png">
437+
<!-- Asset names describe ink colour: dark ink on light pages, light ink on dark pages. -->
438+
<source media="(prefers-color-scheme: dark)" srcset="pics/flow-light.png">
439+
<source media="(prefers-color-scheme: light)" srcset="pics/flow-dark.png">
440+
<img alt="fmsg protocol flow diagram" src="pics/flow-dark.png">
440441
</picture>
441442
</p>
442443

STANDARDS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ The fmsg specification only describes host-to-host communication protocol semant
55
This page indexes common standards for a fmsg host to follow and services augmenting a host.
66

77
<picture>
8-
<source media="(prefers-color-scheme: dark)" srcset="pics/setup-example-dark-transparent.png">
8+
<!-- Dark pages need light-ink art; light pages use the light-theme diagram. -->
9+
<source media="(prefers-color-scheme: dark)" srcset="pics/setup-example-light-transparent.png">
910
<source media="(prefers-color-scheme: light)" srcset="pics/setup-example-light.png">
1011
<img alt="example fmsg setup" src="pics/setup-example-light.png">
1112
</picture>

docs/javascripts/scheme-images.js

Lines changed: 106 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,134 @@
11
/**
2-
* Prefer light/dark diagram assets from Material's color scheme toggle.
2+
* Show the diagram asset that matches Material's active palette.
33
*
4-
* Canonical docs keep <picture><source media="(prefers-color-scheme:…)">
5-
* for GitHub rendering. On the site, Material's palette can disagree with the
6-
* OS preference, so we set the <img> src from the matching source whenever
7-
* data-md-color-scheme changes.
4+
* After markdown fix-up, <source media="(prefers-color-scheme: …)"> points at
5+
* the asset meant for that *page* theme:
6+
* light page → dark-ink art (readable on white)
7+
* dark page → light-ink art (readable on near-black)
8+
*
9+
* Browsers re-resolve <source media> from the OS preference even when Material's
10+
* toggle disagrees, so we rewrite each <picture> into a dual-<img> pair driven
11+
* by data-md-color-scheme ("default" | "slate").
812
*/
913
(function () {
10-
function isDarkScheme() {
11-
return document.body.getAttribute("data-md-color-scheme") === "slate";
14+
function firstUrl(srcset) {
15+
if (!srcset) return null;
16+
return srcset.trim().split(/\s+/)[0] || null;
1217
}
1318

14-
function pickSrc(picture, dark) {
19+
function pairFromPicture(picture) {
1520
var sources = picture.querySelectorAll("source[srcset]");
16-
var light = null;
17-
var darkSrc = null;
21+
var img = picture.querySelector("img");
22+
var mediaDark = null;
23+
var mediaLight = null;
24+
var namedDarkInk = null;
25+
var namedLightInk = null;
1826
var i;
27+
1928
for (i = 0; i < sources.length; i++) {
20-
var media = sources[i].getAttribute("media") || "";
21-
var srcset = sources[i].getAttribute("srcset");
22-
if (!srcset) continue;
23-
// first URL token in srcset
24-
var src = srcset.trim().split(/\s+/)[0];
25-
if (media.indexOf("dark") !== -1) darkSrc = src;
26-
else if (media.indexOf("light") !== -1) light = src;
29+
var media = (sources[i].getAttribute("media") || "").toLowerCase().replace(/\s+/g, "");
30+
var src = firstUrl(sources[i].getAttribute("srcset"));
31+
if (!src) continue;
32+
var file = src.split("/").pop().toLowerCase();
33+
34+
if (media.indexOf("prefers-color-scheme:dark") !== -1) mediaDark = src;
35+
else if (media.indexOf("prefers-color-scheme:light") !== -1) mediaLight = src;
36+
37+
// Filename heuristics (ink colour), skipping ambiguous setup-example-light.png
38+
if (file.indexOf("dark") !== -1) namedDarkInk = src;
39+
if (file.indexOf("light") !== -1 && file.indexOf("transparent") !== -1) {
40+
namedLightInk = src;
41+
} else if (
42+
file.indexOf("light") !== -1 &&
43+
file.indexOf("setup-example-light.png") === -1
44+
) {
45+
namedLightInk = src;
46+
}
47+
}
48+
49+
// Media tags are authoritative once markdown is correct.
50+
var forLightPage =
51+
mediaLight || namedDarkInk || (img && img.getAttribute("src"));
52+
var forDarkPage = mediaDark || namedLightInk || forLightPage;
53+
54+
return { forLightPage: forLightPage, forDarkPage: forDarkPage };
55+
}
56+
57+
function rewritePicture(picture) {
58+
if (picture.getAttribute("data-fmsg-scheme") === "done") return;
59+
// Already rewritten wrapper
60+
if (
61+
picture.classList &&
62+
picture.classList.contains("fmsg-scheme-image")
63+
) {
64+
return;
65+
}
66+
67+
var img = picture.querySelector("img");
68+
if (!img) return;
69+
var alt = img.getAttribute("alt") || "";
70+
var pair = pairFromPicture(picture);
71+
if (!pair.forLightPage) return;
72+
73+
var wrap = document.createElement("span");
74+
wrap.className = "fmsg-scheme-image";
75+
wrap.setAttribute("data-fmsg-scheme", "done");
76+
77+
function make(cls, src) {
78+
var el = document.createElement("img");
79+
el.className = cls;
80+
el.setAttribute("src", src);
81+
el.setAttribute("alt", alt);
82+
el.setAttribute("loading", img.getAttribute("loading") || "lazy");
83+
return el;
84+
}
85+
86+
wrap.appendChild(make("fmsg-for-light", pair.forLightPage));
87+
wrap.appendChild(
88+
make("fmsg-for-dark", pair.forDarkPage || pair.forLightPage)
89+
);
90+
91+
if (picture.parentNode) {
92+
picture.parentNode.replaceChild(wrap, picture);
2793
}
28-
if (dark && darkSrc) return darkSrc;
29-
if (!dark && light) return light;
30-
if (darkSrc || light) return dark ? darkSrc || light : light || darkSrc;
31-
return null;
3294
}
3395

34-
function applySchemeImages() {
35-
var dark = isDarkScheme();
96+
function apply() {
3697
var pictures = document.querySelectorAll(".md-typeset picture");
3798
for (var i = 0; i < pictures.length; i++) {
38-
var picture = pictures[i];
39-
var img = picture.querySelector("img");
40-
if (!img) continue;
41-
var next = pickSrc(picture, dark);
42-
if (next && img.getAttribute("src") !== next) {
43-
img.setAttribute("src", next);
44-
}
99+
rewritePicture(pictures[i]);
45100
}
46101
}
47102

48-
function watchScheme() {
49-
applySchemeImages();
103+
function watch() {
104+
apply();
50105
if (typeof MutationObserver === "undefined") return;
51-
var observer = new MutationObserver(applySchemeImages);
52-
observer.observe(document.body, {
106+
var obs = new MutationObserver(function (mutations) {
107+
var i;
108+
for (i = 0; i < mutations.length; i++) {
109+
if (
110+
mutations[i].type === "attributes" &&
111+
mutations[i].attributeName === "data-md-color-scheme"
112+
) {
113+
// CSS handles visibility; nothing else required.
114+
continue;
115+
}
116+
}
117+
apply();
118+
});
119+
obs.observe(document.body, {
53120
attributes: true,
54121
attributeFilter: ["data-md-color-scheme"],
122+
childList: true,
123+
subtree: true,
55124
});
56125
}
57126

58-
// Material emits document$ on instant navigation; fall back to DOM ready.
59127
if (typeof document$ !== "undefined" && document$.subscribe) {
60-
document$.subscribe(watchScheme);
128+
document$.subscribe(watch);
61129
} else if (document.readyState === "loading") {
62-
document.addEventListener("DOMContentLoaded", watchScheme);
130+
document.addEventListener("DOMContentLoaded", watch);
63131
} else {
64-
watchScheme();
132+
watch();
65133
}
66134
})();

docs/show-hn.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ A full RFC style specification is hosted in this repository here: [SPECIFICATION
1414

1515
<div style="float: right; margin: 1em; max-width: 600px;">
1616
<picture>
17-
<source media="(prefers-color-scheme: dark)" srcset="fmsg-docker-dark.png">
18-
<source media="(prefers-color-scheme: light)" srcset="fmsg-docker-light.png">
19-
<img alt="fmsg-docker diagram" src="fmsg-docker-light.png">
17+
<!-- dark-ink art on light pages; light-ink art on dark pages -->
18+
<source media="(prefers-color-scheme: dark)" srcset="fmsg-docker-light.png">
19+
<source media="(prefers-color-scheme: light)" srcset="fmsg-docker-dark.png">
20+
<img alt="fmsg-docker diagram" src="fmsg-docker-dark.png">
2021
</picture>
2122
</div>
2223

@@ -79,9 +80,9 @@ To quote the spec:
7980
8081
<p align="center">
8182
<picture>
82-
<source media="(prefers-color-scheme: dark)" srcset="pics/flow-dark.png">
83-
<source media="(prefers-color-scheme: light)" srcset="pics/flow-light.png">
84-
<img alt="fmsg protocol flow diagram" src="pics/flow-light.png">
83+
<source media="(prefers-color-scheme: dark)" srcset="pics/flow-light.png">
84+
<source media="(prefers-color-scheme: light)" srcset="pics/flow-dark.png">
85+
<img alt="fmsg protocol flow diagram" src="pics/flow-dark.png">
8586
</picture>
8687
</p>
8788

docs/stylesheets/site.css

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* Brand colours for Material (primary/accent = custom). */
2-
:root {
2+
:root,
3+
[data-md-color-scheme="default"] {
34
--md-primary-fg-color: #102b3a;
45
--md-primary-fg-color--light: #185a7d;
56
--md-primary-fg-color--dark: #0a1c26;
@@ -8,6 +9,20 @@
89
--md-accent-fg-color--transparent: rgba(24, 90, 125, 0.1);
910
--md-typeset-a-color: #185a7d;
1011

12+
/* Light theme: dark text on white */
13+
--md-default-fg-color: #16202a;
14+
--md-default-fg-color--light: #3a4650;
15+
--md-default-fg-color--lighter: #5d6975;
16+
--md-default-fg-color--lightest: #d9e0e6;
17+
--md-default-bg-color: #ffffff;
18+
--md-default-bg-color--light: #f7f9fb;
19+
--md-default-bg-color--lighter: #ffffff;
20+
--md-default-bg-color--lightest: #ffffff;
21+
--md-code-bg-color: #f3f5f7;
22+
--md-code-fg-color: #16202a;
23+
--md-typeset-color: #16202a;
24+
--md-typeset-table-color: #16202a;
25+
1126
--fmsg-ink: #16202a;
1227
--fmsg-muted: #5d6975;
1328
--fmsg-line: #d9e0e6;
@@ -16,31 +31,56 @@
1631
--fmsg-code: #f3f5f7;
1732
}
1833

34+
/* Dark theme: light text on near-black */
1935
[data-md-color-scheme="slate"] {
20-
--md-primary-fg-color: #0e2430;
36+
--md-primary-fg-color: #0a1520;
2137
--md-primary-fg-color--light: #185a7d;
22-
--md-primary-fg-color--dark: #07141c;
38+
--md-primary-fg-color--dark: #050a0f;
39+
--md-primary-bg-color: #e8edf1;
2340
--md-accent-fg-color: #73b9dd;
2441
--md-accent-fg-color--transparent: rgba(115, 185, 221, 0.12);
2542
--md-typeset-a-color: #73b9dd;
2643

44+
--md-default-fg-color: #e8edf1;
45+
--md-default-fg-color--light: #b1bbc4;
46+
--md-default-fg-color--lighter: #8a96a1;
47+
--md-default-fg-color--lightest: #3a4650;
48+
--md-default-bg-color: #0b1218;
49+
--md-default-bg-color--light: #121a22;
50+
--md-default-bg-color--lighter: #182028;
51+
--md-default-bg-color--lightest: #222c35;
52+
--md-code-bg-color: #121a22;
53+
--md-code-fg-color: #e8edf1;
54+
--md-typeset-color: #e8edf1;
55+
--md-typeset-table-color: #e8edf1;
56+
--md-footer-bg-color: #050a0f;
57+
--md-footer-bg-color--dark: #000000;
58+
2759
--fmsg-ink: #e8edf1;
2860
--fmsg-muted: #b1bbc4;
29-
--fmsg-line: #3a4650;
30-
--fmsg-paper: #182028;
61+
--fmsg-line: #2a3540;
62+
--fmsg-paper: #0b1218;
3163
--fmsg-accent: #73b9dd;
32-
--fmsg-code: #222c35;
64+
--fmsg-code: #121a22;
3365
}
3466

3567
/* Slightly roomier reading column for long specifications. */
3668
.md-typeset {
3769
font-size: 0.78rem;
3870
line-height: 1.68;
71+
color: var(--md-typeset-color);
3972
}
4073

4174
.md-typeset h1 {
4275
font-weight: 700;
4376
letter-spacing: -0.025em;
77+
color: var(--fmsg-ink);
78+
}
79+
80+
.md-typeset h2,
81+
.md-typeset h3,
82+
.md-typeset h4 {
83+
color: var(--fmsg-ink);
4484
}
4585

4686
.md-typeset h2 {
@@ -49,22 +89,35 @@
4989

5090
.md-typeset table:not([class]) {
5191
font-size: 0.72rem;
92+
color: var(--fmsg-ink);
5293
}
5394

5495
.md-typeset code {
5596
word-break: break-word;
5697
}
5798

58-
/* Header brand */
59-
.md-header__button.md-logo img,
60-
.md-header__button.md-logo svg {
61-
height: 1.6rem;
62-
width: 1.6rem;
99+
/* Header: no logo icon; page title ALL CAPS */
100+
.md-header__button.md-logo {
101+
display: none;
63102
}
64103

65104
.md-header__title {
66105
font-weight: 700;
67106
letter-spacing: -0.02em;
107+
margin-left: 0.4rem;
108+
}
109+
110+
/* Active page title in the top bar (second topic slot). */
111+
.md-header__topic:nth-child(2) .md-ellipsis,
112+
.md-header__topic[data-md-component="header-topic"] .md-ellipsis {
113+
text-transform: uppercase;
114+
letter-spacing: 0.06em;
115+
font-size: 0.78em;
116+
}
117+
118+
/* Drawer: also hide logo mark next to site name */
119+
.md-nav__button.md-logo {
120+
display: none;
68121
}
69122

70123
/* Left nav: clearer section labels (Specification, Standards, …). */
@@ -216,9 +269,10 @@
216269
}
217270

218271
/*
219-
* Dual theme images (used when markup has both light and dark <img>s).
220-
* Material sets data-md-color-scheme to "default" (light) or "slate" (dark),
221-
* including after the header palette toggle — not only prefers-color-scheme.
272+
* Dual theme images.
273+
* fmsg-for-light = dark-ink asset (readable on white)
274+
* fmsg-for-dark = light-ink asset (readable on near-black)
275+
* Material: data-md-color-scheme = "default" | "slate"
222276
*/
223277
.md-typeset .fmsg-scheme-image {
224278
display: block;
@@ -227,17 +281,19 @@
227281

228282
.md-typeset .fmsg-scheme-image img {
229283
margin: 0;
284+
max-width: 100%;
285+
height: auto;
230286
}
231287

232-
.md-typeset .fmsg-scheme-image .fmsg-only-dark {
288+
.md-typeset .fmsg-scheme-image .fmsg-for-dark {
233289
display: none;
234290
}
235291

236-
[data-md-color-scheme="slate"] .md-typeset .fmsg-scheme-image .fmsg-only-light {
292+
[data-md-color-scheme="slate"] .md-typeset .fmsg-scheme-image .fmsg-for-light {
237293
display: none;
238294
}
239295

240-
[data-md-color-scheme="slate"] .md-typeset .fmsg-scheme-image .fmsg-only-dark {
296+
[data-md-color-scheme="slate"] .md-typeset .fmsg-scheme-image .fmsg-for-dark {
241297
display: inline-block;
242298
}
243299

0 commit comments

Comments
 (0)