Skip to main content

max / makeover-build

Hand the density policy back to makeover-geometry It sat here only because that crate is published and five consumers took it from the registry. Every product is internal, so that worry does not apply and the policy goes where Density is defined. What is left here is the banner and the write, which is what a build helper is for.
Author: Max Johnson <me@maxj.phd> · 2026-07-28 22:10 UTC
Signed with PGP, not checked
Commit: eabcdc5c57d712a86aa67f0c8817de6a3995c59c
Parent: 90541b1
2 files changed, +17 insertions, -68 deletions
M Cargo.toml +1 -1
@@ -9,7 +9,7 @@
9 9 [dependencies]
10 10 makeover = { path = "../makeover" }
11 11 makeover-webview = { path = "../makeover-webview" }
12 - makeover-geometry = "0.1.0"
12 + makeover-geometry = { path = "../makeover-geometry" }
13 13
14 14 [lints.rust]
15 15 unused = "warn"
M src/lib.rs +16 -67
@@ -77,52 +77,26 @@
77 77 std::fs::write(path, makeover_webview::stylesheet(opts)).expect("write layout css");
78 78 }
79 79
80 - /// Write `makeover-geometry`'s spacing layer to `path`, with the canonical
81 - /// density selection.
80 + /// Write `makeover-geometry`'s spacing layer, with its canonical density
81 + /// selection, to `path`.
82 82 ///
83 - /// **Density is a capability, not a device and not a width.** A narrow window
84 - /// on a desktop still has a pointer in it and a tablet at full width still has
85 - /// a finger, so the touch preset hangs off `(hover: none), (pointer: coarse)`
86 - /// rather than off a breakpoint or a user-agent string. That is the question
87 - /// the platform actually answers.
88 - ///
89 - /// `explicit_touch` names a selector an app sets when the *user* has chosen,
90 - /// which is emitted last and therefore wins at equal specificity. Detection is
91 - /// a default, not a verdict: a touchscreen laptop and someone who simply wants
92 - /// roomier targets are both real and neither is visible to a media query.
93 - ///
94 - /// This settles a policy the three consumers previously answered three ways:
95 - /// GoingsOn sniffed the user agent behind a class, Balanced Breakfast used
96 - /// `(hover: none)` alone, and audiofiles had no switch at all. It lives here
97 - /// rather than in `makeover-geometry` only because that crate is published at
98 - /// 0.1.0 and five consumers take it from the registry; it belongs there at its
99 - /// next release.
83 + /// The policy is the crate's, not this one's: touch hangs off
84 + /// `(hover: none), (pointer: coarse)` because density is a capability rather
85 + /// than a device or a width, and `explicit_touch` names a selector an app sets
86 + /// when the user has chosen. See [`makeover_geometry::density_css`]. All this
87 + /// adds is the generated-file banner and the write.
100 88 ///
101 89 /// # Panics
102 90 ///
103 91 /// If the file cannot be written.
104 92 pub fn geometry_css(path: impl AsRef<Path>, explicit_touch: Option<&str>) {
105 - use makeover_geometry::{Density, gap_css_overrides, geometry_css_vars};
106 -
107 93 let mut css = String::from(
108 94 "/* Generated by makeover-build from makeover-geometry. Do not edit.\n \
109 95 Spacing is named by relationship, not by size. Touch density is a\n \
110 96 capability question: a narrow desktop window still has a pointer, a\n \
111 97 full-width tablet still has a finger. */\n",
112 98 );
113 - css.push_str(&geometry_css_vars(Density::Pointer));
114 - css.push_str("\n@media (hover: none), (pointer: coarse) {\n");
115 - for line in gap_css_overrides(":root", Density::Touch).lines() {
116 - css.push_str(" ");
117 - css.push_str(line);
118 - css.push('\n');
119 - }
120 - css.push_str("}\n");
121 - if let Some(selector) = explicit_touch {
122 - css.push_str("\n/* An explicit user choice, last so it wins over detection. */\n");
123 - css.push_str(&gap_css_overrides(selector, Density::Touch));
124 - }
125 -
99 + css.push_str(&makeover_geometry::density_css(explicit_touch));
126 100 std::fs::write(path, css).expect("write geometry css");
127 101 }
128 102
@@ -205,42 +179,17 @@
205 179 }
206 180
207 181 #[test]
208 - fn density_is_selected_by_capability_not_by_width_or_agent() {
209 - let dir = scratch("density");
210 - let path = dir.join("geometry.css");
211 - geometry_css(&path, None);
212 - let css = std::fs::read_to_string(&path).unwrap();
213 - assert!(css.contains("@media (hover: none), (pointer: coarse)"));
214 - // The three things density must never be selected by.
215 - assert!(!css.contains("max-width"), "a breakpoint crept in");
216 - assert!(!css.contains("min-width"), "a breakpoint crept in");
217 - assert!(!css.contains("ui-mode"), "a device mode crept in");
218 - }
219 -
220 - #[test]
221 - fn an_explicit_choice_is_emitted_after_the_detection() {
222 - let dir = scratch("explicit");
182 + fn the_geometry_file_carries_the_crates_policy_and_a_banner() {
183 + // The policy itself is tested in makeover-geometry. What is this
184 + // crate's job is that the banner is there and the policy reached the
185 + // file at all.
186 + let dir = scratch("geometry");
223 187 let path = dir.join("geometry.css");
224 188 geometry_css(&path, Some(".ui-mode-mobile"));
225 189 let css = std::fs::read_to_string(&path).unwrap();
226 - let media = css.find("@media").expect("media query");
227 - let explicit = css.find(".ui-mode-mobile").expect("explicit selector");
228 - // Equal specificity, so order is the whole mechanism: the user's
229 - // choice has to come last or detection quietly overrides it.
230 - assert!(explicit > media, "the explicit selector must come last");
231 - }
232 -
233 - #[test]
234 - fn no_explicit_selector_means_no_extra_rule() {
235 - let dir = scratch("noexplicit");
236 - let path = dir.join("geometry.css");
237 - geometry_css(&path, None);
238 - let css = std::fs::read_to_string(&path).unwrap();
239 - assert_eq!(
240 - css.matches("--gap-peer").count(),
241 - 2,
242 - "pointer and touch, no more"
243 - );
190 + assert!(css.starts_with("/* Generated by makeover-build"));
191 + assert!(css.contains("@media (hover: none), (pointer: coarse)"));
192 + assert!(css.contains(".ui-mode-mobile"));
244 193 }
245 194
246 195 #[test]