Skip to main content

max / makenotwork

theme-common 0.7.0: add overlay intent; prune unused tokens (usage audit) Added: - `overlay` intent — a near-black, faintly theme-tinted modal scrim at 50% alpha (OKLab-anchored so it dims on light and dark themes). Fills the one role GoingsOn/MNW carried app-side. Pruned (usage audit found zero consumers across all four apps): - action-active, the four *-surface status tints, selection, row-stripe. Apps that need a selection/stripe colour derive it inline via the shared mix(); MNW keeps its hand-tuned *-bg literals. Emitted set 32 -> 25 tokens. - `info` kept but flagged (0 use; standard 4th status, authored in every theme). style.css drops the orphaned default lines; theming test updated. Full matrix + verdicts in _private docs (intent-usage-audit.md). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-13 02:06 UTC
Commit: 436c91c3c7b694b157676f9f6a0e88217ccd5dad
Parent: 4473c1f
6 files changed, +37 insertions, -29 deletions
@@ -7059,7 +7059,7 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
7059 7059
7060 7060 [[package]]
7061 7061 name = "theme-common"
7062 - version = "0.6.0"
7062 + version = "0.7.0"
7063 7063 dependencies = [
7064 7064 "serde",
7065 7065 "toml",
@@ -156,8 +156,9 @@ mod tests {
156 156 assert!(css.contains("--content: #3d3530;"));
157 157 assert!(css.contains("--action: #6c5ce7;"));
158 158 assert!(css.contains("--border: #d0cbb8;"));
159 - // A derived interactive state is present too.
160 - assert!(css.contains("--selection: "));
159 + // Derived states + the scrim are present too.
160 + assert!(css.contains("--action-hover: "));
161 + assert!(css.contains("--overlay: rgba("));
161 162 }
162 163
163 164 #[test]
@@ -157,20 +157,13 @@
157 157 --content-on-action: #ffffff;
158 158 --action: #6c5ce7;
159 159 --action-hover: #7a6cf8;
160 - --action-active: #5f4cd6;
161 160 --danger: #c0392b;
162 161 --success: #27ae60;
163 162 --warning: #f59e0b;
164 163 --info: #17a2b8;
165 - --danger-surface: #eacfc5;
166 - --success-surface: #d4e0cd;
167 - --warning-surface: #efdec9;
168 - --info-surface: #d3dedb;
169 164 --border: #d0cbb8;
170 165 --border-strong: #c0bba8;
171 166 --focus-ring: #6c5ce7;
172 - --selection: #d0cee6;
173 - --row-stripe: #f0ece6;
174 167 --hover-surface: #ddd7c5;
175 168 --category-one: #c0392b;
176 169 --category-two: #27ae60;
@@ -273,7 +273,7 @@ dependencies = [
273 273
274 274 [[package]]
275 275 name = "theme-common"
276 - version = "0.6.0"
276 + version = "0.7.0"
277 277 dependencies = [
278 278 "serde",
279 279 "tempfile",
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "theme-common"
3 - version = "0.6.0"
3 + version = "0.7.0"
4 4 edition = "2024"
5 5
6 6 [dependencies]
@@ -273,22 +273,18 @@ pub fn resolve(theme: &ThemeColors) -> SemanticTokens {
273 273 let mut derived: Vec<(String, Rgb)> = Vec::new();
274 274 if let Some(action) = get(&intents, "action") {
275 275 derived.push(("action-hover".into(), lighten(action, 0.05)));
276 - derived.push(("action-active".into(), darken(action, 0.05)));
277 276 derived.push(("content-on-action".into(), readable_on(action)));
278 277 derived.push(("focus-ring".into(), action));
279 - if let Some(page) = get(&intents, "surface-page") {
280 - derived.push(("selection".into(), mix(page, action, 0.2)));
281 - }
282 278 }
283 279 if let Some(page) = get(&intents, "surface-page") {
284 - if let Some(overlay) = get(&intents, "surface-overlay") {
285 - derived.push(("row-stripe".into(), mix(page, overlay, 0.5)));
286 - }
287 - for status in ["danger", "success", "warning", "info"] {
288 - if let Some(c) = get(&intents, status) {
289 - derived.push((format!("{status}-surface"), mix(page, c, 0.15)));
290 - }
291 - }
280 + // Modal scrim: a near-black tone carrying a faint hint of the theme's
281 + // hue, at 50% alpha. Anchored very dark (OKLab L=0.08) so it dims the
282 + // page on light *and* dark themes. Emitted as rgba (not a flat hex), so
283 + // it is inserted directly rather than through the hex loop below.
284 + let mut o = page.to_oklab();
285 + o.l = 0.08;
286 + let s = Rgb::from_oklab(o);
287 + intents.insert("overlay".into(), format!("rgba({}, {}, {}, 0.5)", s.r, s.g, s.b));
292 288 }
293 289 if let Some(sunken) = get(&intents, "surface-sunken") {
294 290 derived.push(("hover-surface".into(), sunken));
@@ -786,14 +782,32 @@ six = "#88c0d0"
786 782 let t = resolve(&theme);
787 783 let action = Rgb::from_hex("#81a1c1").unwrap();
788 784 let page = Rgb::from_hex("#2e3440").unwrap();
785 + let _ = page;
789 786 assert_eq!(t.hex("action-hover").unwrap(), lighten(action, 0.05).to_hex());
790 - assert_eq!(t.hex("action-active").unwrap(), darken(action, 0.05).to_hex());
791 787 assert_eq!(t.hex("content-on-action").unwrap(), readable_on(action).to_hex());
792 788 assert_eq!(t.hex("focus-ring"), Some("#81a1c1"));
793 - assert_eq!(t.hex("selection").unwrap(), mix(page, action, 0.2).to_hex());
794 789 assert_eq!(t.hex("hover-surface"), Some("#434c5e")); // = surface.sunken
795 - assert_eq!(t.hex("danger-surface").unwrap(),
796 - mix(page, Rgb::from_hex("#bf616a").unwrap(), 0.15).to_hex());
790 + // Pruned by the usage audit (0 consumers): action-active, the *-surface
791 + // tints, selection, row-stripe. Apps that need them derive inline via
792 + // the shared mix().
793 + assert!(t.hex("action-active").is_none());
794 + assert!(t.hex("danger-surface").is_none());
795 + assert!(t.hex("selection").is_none());
796 + assert!(t.hex("row-stripe").is_none());
797 + }
798 +
799 + #[test]
800 + fn resolve_overlay_is_dark_translucent_scrim() {
801 + let theme = parse_theme_str("nord", nord_toml(), false).unwrap();
802 + let t = resolve(&theme);
803 + let overlay = t.hex("overlay").unwrap();
804 + assert!(overlay.starts_with("rgba("), "overlay is translucent: {overlay}");
805 + assert!(overlay.ends_with(", 0.5)"));
806 + // The scrim tone is anchored very dark regardless of theme.
807 + let inner = overlay.trim_start_matches("rgba(").trim_end_matches(", 0.5)");
808 + let parts: Vec<u8> = inner.split(", ").map(|p| p.parse().unwrap()).collect();
809 + let scrim = Rgb { r: parts[0], g: parts[1], b: parts[2] };
810 + assert!(scrim.to_oklab().l < 0.2, "scrim must be near-black");
797 811 }
798 812
799 813 #[test]
@@ -829,7 +843,7 @@ six = "#88c0d0"
829 843 assert!(css.starts_with(":root {\n"));
830 844 assert!(css.contains(" --surface-page: #2e3440;\n"));
831 845 assert!(css.contains(" --danger: #bf616a;\n"));
832 - assert!(css.contains(" --selection: "));
846 + assert!(css.contains(" --action-hover: "));
833 847 assert!(css.trim_end().ends_with('}'));
834 848 }
835 849