web: scope each syntax palette to its color scheme !88
2 files changed, +21 −5
Layout: unified · split
e2e/diffweb_test.go +13 −1
| @@ -88,9 +88,21 @@ func TestDiffRendering(t *testing.T) { | |||
| 88 | if !strings.Contains(body, `<td class="src chroma">`) { | 88 | if !strings.Contains(body, `<td class="src chroma">`) { |
| 89 | t.Error("diff cell is not a chroma wrapper, so token classes go unstyled") | 89 | t.Error("diff cell is not a chroma wrapper, so token classes go unstyled") |
| 90 | } | 90 | } |
| 91 | if !strings.Contains(stylesheet(t, inst), ".chroma .k") { | 91 | css := stylesheet(t, inst) |
| 92 | if !strings.Contains(css, ".chroma .k") { | ||
| 92 | t.Error("stylesheet has no chroma token rules to match") | 93 | t.Error("stylesheet has no chroma token rules to match") |
| 93 | } | 94 | } |
| 95 | // Each palette is scoped to its own scheme. Unscoped, the light one | ||
| 96 | // leaks into dark mode for every token the dark palette does not name. | ||
| 97 | if !strings.Contains(css, "@media (prefers-color-scheme: light)") || | ||
| 98 | !strings.Contains(css, "@media (prefers-color-scheme: dark)") { | ||
| 99 | t.Error("chroma palettes are not both scheme-scoped") | ||
| 100 | } | ||
| 101 | if i := strings.Index(css, ".chroma .na"); i >= 0 { | ||
| 102 | if j := strings.LastIndex(css[:i], "prefers-color-scheme"); j < 0 { | ||
| 103 | t.Error("a chroma token rule sits outside any scheme scope") | ||
| 104 | } | ||
| 105 | } | ||
| 94 | // The +/- markers are CSS, so a copied selection is real source. | 106 | // The +/- markers are CSS, so a copied selection is real source. |
| 95 | if strings.Contains(body, `<td class="src">+`) { | 107 | if strings.Contains(body, `<td class="src">+`) { |
| 96 | t.Error("diff markers are in the markup, not the stylesheet") | 108 | t.Error("diff markers are in the markup, not the stylesheet") |
internal/httpd/web.go +8 −4
| @@ -829,13 +829,17 @@ func highlight(filePath string, data []byte) template.HTML { | |||
| 829 | return template.HTML(buf.String()) | 829 | return template.HTML(buf.String()) |
| 830 | } | 830 | } |
| 831 | 831 | ||
| 832 | // chromaCSS is both syntax palettes: light by default, dark under the same | 832 | // chromaCSS is both syntax palettes, each scoped to the scheme it is for. |
| 833 | // media query the rest of the stylesheet uses. The site's --code-bg stays | 833 | // The light one cannot be left unscoped: the two palettes do not name the |
| 834 | // the background either way. | 834 | // same token set, and every token github-dark omits would keep its |
| 835 | // light-theme colour on a black ground — NameAttribute landed at 2.97:1. | ||
| 836 | // Scoped, an unnamed token inherits the wrapper's colour instead, which is | ||
| 837 | // readable in both. The site's --code-bg stays the background either way. | ||
| 835 | var chromaCSS = func() []byte { | 838 | var chromaCSS = func() []byte { |
| 836 | var buf bytes.Buffer | 839 | var buf bytes.Buffer |
| 840 | buf.WriteString("@media (prefers-color-scheme: light) {\n") | ||
| 837 | chromaFormatter.WriteCSS(&buf, styles.Get("friendly")) | 841 | chromaFormatter.WriteCSS(&buf, styles.Get("friendly")) |
| 838 | buf.WriteString("\n@media (prefers-color-scheme: dark) {\n") | 842 | buf.WriteString("}\n@media (prefers-color-scheme: dark) {\n") |
| 839 | chromaFormatter.WriteCSS(&buf, styles.Get("github-dark")) | 843 | chromaFormatter.WriteCSS(&buf, styles.Get("github-dark")) |
| 840 | buf.WriteString("}\n.chroma, .bg { background: transparent !important; }\n") | 844 | buf.WriteString("}\n.chroma, .bg { background: transparent !important; }\n") |
| 841 | return buf.Bytes() | 845 | return buf.Bytes() |