clone

one developer profile for links and private tcp services, reached peer to peer over iroh with no open ports

Themes were never applying: fix the selector's specificity

Dami committed 8f35b41
Every theme set so far validated, stored, was served in the profile response,
and did nothing at all to the page.

applyTheme wrote its rule as `[data-profile="alice"]`, specificity (0,1,0). Pico
sets its palette on `:root:not([data-theme=dark])`, which is (0,2,0) — `:not()`
contributes the weight of its argument. Source order never came into it; the
theme lost on specificity and would have lost from anywhere in the document. The
comment in index.html asserted the opposite in as many words:

    landing last is all it needs to win: no user rule ever has to
    out-specify anything

The rule is now `:root[data-profile="alice"]`, which matches Pico's (0,2,0) and
wins on being last, and both the comment and docs/profile-template.md now explain
the arithmetic rather than assert the conclusion.

Worth naming how this survived: it failed silently in every direction. The
whitelist accepted the declarations, the canonical text round-tripped through
SQLite, the profile response carried them, applyTheme built the block and put it
in the document — and the page rendered exactly as if none of it existed. Every
test passed because every test asked whether the theme was *stored* correctly.
Nothing read a computed style out of a real browser, which is the only place the
question "did this change anything?" can actually be answered.

Also: .state now takes --pico-muted-color. Where a link goes and how a service is
shared are both secondary to the name, and were being drawn at full strength.
commit
8f35b413c930888152a3973a8d2c6372d289a1d9
parent
1a02e9fa0aa7f5ad9fa84984c3bfeaa56de0f761
author
Dami <dami.etoile@gmail.com>
4 files changed, +36 -11
Mdocs/profile-template.md22+++++++++++++++++++---
Mweb/app.js14++++++++++----
Mweb/index.html6++++--
Mweb/site.css5+++--
M docs/profile-template.md +19 -3
@@ -15,9 +15,25 @@ can answer mechanically, in `crates/devsite-server/src/theme.rs`.
1515 | Site | `web/site.css` | The typeface, and the few layout rules Pico has no opinion about. No colours. |1616 | Theme | `<style id="profile-theme">` | One rule, written at render time, holding only `--pico-*` assignments. |1717 18-They load in that order, so a theme wins ties on document order alone. No user19-declaration ever has to out-specify anything, and none of them can, because a20-theme contains no selectors.18+They load in that order, and the theme is written as one rule:19+20+```css21+:root[data-profile="alice"] { --pico-primary: #bc6c25; … }22+```23+24+The `:root` is not decoration. Pico sets its palette on25+`:root:not([data-theme=dark])`, which is specificity **(0,2,0)** — `:not()`26+contributes the weight of its argument. A bare `[data-profile="alice"]` is27+(0,1,0) and loses to that outright, however late it appears in the document.28+Matching (0,2,0) and coming last is what makes a theme win.29+30+This was wrong in the first implementation, and it failed silently: themes31+validated, stored, served in the profile response, and applied to a page that32+went on looking exactly the same. Nothing short of reading a computed style in a33+real browser would have caught it, which is now how it is checked.34+35+A theme still writes no selectors of its own — that one is supplied here, and the36+user supplies only the declarations inside it.2137 2238 **Type is fixed.** Open Sans, vendored at `web/vendor/fonts/`, at 400 and 700 and2339 no other weight. The file is a variable font, so it is declared twice at those two
M web/app.js +10 -4
@@ -123,9 +123,15 @@ async function completeSignIn() {
123123 ///124124 /// The server has already checked every property against its whitelist and every125125 /// value against a grammar, so this is only assembly: one rule, scoped to the126-/// profile, holding nothing but custom-property assignments. It is the last127-/// stylesheet in the document, so equal specificity is enough — no user rule128-/// ever has to out-rank Pico.126+/// profile, holding nothing but custom-property assignments.127+///128+/// The `:root` in the selector is load-bearing. Pico sets its palette on129+/// `:root:not([data-theme=dark])`, which is specificity (0,2,0) because `:not()`130+/// contributes its argument's weight. A bare `[data-profile="…"]` is (0,1,0) and131+/// loses to it outright — no matter how late in the document it appears. With132+/// `:root` in front we match that (0,2,0) and win on source order, being the last133+/// stylesheet in the page. This was wrong until it was tested in a browser, and134+/// the failure was silent: themes stored, served, and ignored.129135 function applyTheme(handle, declarations = []) {130136 const root = document.documentElement;131137 // Belt and braces: handles are already restricted to this alphabet server-side.
@@ -146,7 +152,7 @@ function applyTheme(handle, declarations = []) {
146152 .map((d) => ` ${d.property}: ${d.value};`)147153 .join('\n');148154 $('profile-theme').textContent = body149- ? `[data-profile="${scope}"] {\n${body}\n}\n`155+ ? `:root[data-profile="${scope}"] {\n${body}\n}\n`150156 : '';151157 }152158
M web/index.html +4 -2
M web/site.css +3 -2