Skip to main content

max / makenotwork

Use makeover-build's breakpoint check instead of a third copy static/ mixes generated, hand-written and bundled CSS, so the check takes the named-list form (check_breakpoints_files) rather than scanning a directory: a bundle's widths would otherwise read as drift. No tuning widths -- every threshold here is a shell boundary. The local guard's closing advice was better than the shared one's and has been carried up into makeover-build 0.19.0, so nothing is lost with the 90 lines that go.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-11 16:45 UTC
Signed with PGP, not checked
Commit: d44fee0e7e3a09deca74d20e15b363295d9bc586
Parent: 3c29f6f
3 files changed, +42 insertions, -102 deletions
M server/Cargo.lock +32 -13
@@ -2623,7 +2623,7 @@
2623 2623
2624 2624 [[package]]
2625 2625 name = "docengine"
2626 - version = "0.4.0"
2626 + version = "0.5.0"
2627 2627 dependencies = [
2628 2628 "ammonia",
2629 2629 "pulldown-cmark",
@@ -3594,7 +3594,7 @@
3594 3594 checksum = "1a791e6620676a875f362f3156ed213e73ca099a09bf992c18812abe65cc37b1"
3595 3595 dependencies = [
3596 3596 "bstr",
3597 - "hashbrown 0.15.5",
3597 + "hashbrown 0.17.1",
3598 3598 ]
3599 3599
3600 3600 [[package]]
@@ -5192,7 +5192,7 @@
5192 5192
5193 5193 [[package]]
5194 5194 name = "makenotwork"
5195 - version = "0.11.13"
5195 + version = "0.11.14"
5196 5196 dependencies = [
5197 5197 "ammonia",
5198 5198 "anyhow",
@@ -5232,6 +5232,7 @@
5232 5232 "hex",
5233 5233 "hmac 0.13.0",
5234 5234 "html5ever",
5235 + "http 1.4.2",
5235 5236 "http-body-util",
5236 5237 "infer",
5237 5238 "jsonwebtoken",
@@ -5240,6 +5241,7 @@
5240 5241 "makeover",
5241 5242 "makeover-build",
5242 5243 "makeover-geometry",
5244 + "makeover-layout 0.13.0",
5243 5245 "memmap2",
5244 5246 "metrics",
5245 5247 "metrics-exporter-prometheus",
@@ -5309,13 +5311,13 @@
5309 5311
5310 5312 [[package]]
5311 5313 name = "makeover-build"
5312 - version = "0.14.1"
5314 + version = "0.19.0"
5313 5315 source = "registry+https://github.com/rust-lang/crates.io-index"
5314 - checksum = "4fd18c4050ad28344da34329279baf092a560d5db087bf0e20e45ae2ef928a12"
5316 + checksum = "1afb7e3e1eba98f540b2e5dc4c1ead21120e4fa7feabb94126618c92638829a7"
5315 5317 dependencies = [
5316 5318 "makeover",
5317 5319 "makeover-geometry",
5318 - "makeover-webview",
5320 + "makeover-webview 0.23.0",
5319 5321 ]
5320 5322
5321 5323 [[package]]
@@ -5330,6 +5332,12 @@
5330 5332 source = "registry+https://github.com/rust-lang/crates.io-index"
5331 5333 checksum = "58edd16523115ed4c9ca6de016693300ac95cf1bb0bd8ccf7fd246213102a7ff"
5332 5334
5335 + [[package]]
5336 + name = "makeover-layout"
5337 + version = "0.13.0"
5338 + source = "registry+https://github.com/rust-lang/crates.io-index"
5339 + checksum = "3e503a11485fe2e17d9e7b0326cb7fef8a9ff0968e1d37d101b45ea08298b0b9"
5340 +
5333 5341 [[package]]
5334 5342 name = "makeover-touch"
5335 5343 version = "0.8.1"
@@ -5337,17 +5345,28 @@
5337 5345 checksum = "d9427a7a6890849f5c815a0e77a63faa4791d7a37e7efaff4802bcafa3b8235a"
5338 5346 dependencies = [
5339 5347 "makeover-geometry",
5340 - "makeover-layout",
5348 + "makeover-layout 0.12.0",
5341 5349 ]
5342 5350
5343 5351 [[package]]
5344 5352 name = "makeover-webview"
5345 - version = "0.22.1"
5353 + version = "0.23.0"
5346 5354 source = "registry+https://github.com/rust-lang/crates.io-index"
5347 - checksum = "9110b5a405a2378d2ef7d93efedc2b65f4bdd32a3de902ee8192b20a8dc3f7f5"
5355 + checksum = "0303225f8e8be6ef237ed268652e7fbfd501bd17843323680a18a9df30b38fe3"
5348 5356 dependencies = [
5349 5357 "makeover-geometry",
5350 - "makeover-layout",
5358 + "makeover-layout 0.12.0",
5359 + "makeover-touch",
5360 + ]
5361 +
5362 + [[package]]
5363 + name = "makeover-webview"
5364 + version = "0.24.0"
5365 + source = "registry+https://github.com/rust-lang/crates.io-index"
5366 + checksum = "6e88bf1eafa0806bbef3002435b91bfb28ce25a989fe484f19eb1e16c58eafc6"
5367 + dependencies = [
5368 + "makeover-geometry",
5369 + "makeover-layout 0.13.0",
5351 5370 "makeover-touch",
5352 5371 ]
5353 5372
@@ -6564,7 +6583,7 @@
6564 6583 name = "quasi-router"
6565 6584 version = "0.1.0"
6566 6585 dependencies = [
6567 - "makeover-layout",
6586 + "makeover-layout 0.13.0",
6568 6587 ]
6569 6588
6570 6589 [[package]]
@@ -6572,8 +6591,8 @@
6572 6591 version = "0.1.0"
6573 6592 dependencies = [
6574 6593 "docengine",
6575 - "makeover-layout",
6576 - "makeover-webview",
6594 + "makeover-layout 0.13.0",
6595 + "makeover-webview 0.24.0",
6577 6596 "quasi-http",
6578 6597 "quasi-router",
6579 6598 ]
@@ -236,10 +236,10 @@
236 236 # Emits static/geometry.css (makeover-geometry) and static/layout.css
237 237 # (makeover-webview). The same generator GO and BB run; only the output paths
238 238 # differ, since the server serves its stylesheets rather than bundling them.
239 - makeover-build = "0.16.0"
240 - # Read directly for SizeClass, which the breakpoint guard in build.rs compares
241 - # the stylesheets against. makeover-build does not re-export it, so the pin
242 - # lives here and has to track the one makeover-build resolves.
239 + makeover-build = "0.19.0"
240 + # Read directly for the embeds' own copy of the spacing layer, which they need
241 + # because an iframe cannot link a stylesheet. makeover-build does not re-export
242 + # it, so the pin lives here and has to track the one makeover-build resolves.
243 243 makeover-geometry = "0.7"
244 244
245 245 [dev-dependencies]
M server/build.rs +6 -85
@@ -48,7 +48,12 @@
48 48
49 49 println!("cargo::rerun-if-changed=build.rs");
50 50
51 - check_breakpoints();
51 + // The same check goingson and balanced_breakfast run, out of
52 + // makeover-build rather than a third copy of it. The named-list form:
53 + // static/ holds the generated stylesheets and a bundler's output beside
54 + // the hand-written ones, so there is no directory to scan. No tuning
55 + // widths -- every threshold here is a shell boundary.
56 + makeover_build::check_breakpoints_files(&HAND_WRITTEN_CSS, &[]);
52 57
53 58 // --- Static asset fingerprinting ---
54 59 // Hash the content of key static files to produce a version suffix.
@@ -134,90 +139,6 @@
134 139 "static/media-player.css",
135 140 ];
136 141
137 - /// Fail the build on any width breakpoint that is not a `SizeClass` boundary.
138 - ///
139 - /// A media condition cannot read a custom property and `@custom-media` has
140 - /// shipped nowhere, so every threshold in the stylesheets is a hand-typed
141 - /// literal and there is no generator path. The guard is the substitute: bump
142 - /// makeover-geometry to a release that moves a boundary and the build breaks
143 - /// here, rather than the layout breaking quietly in a browser.
144 - ///
145 - /// Only the numbers are checked, not the surrounding syntax. That accepts
146 - /// `(min-width: 600px) and (max-width: 839px)` without having to parse it, and
147 - /// still catches the thing worth catching: a number nobody can trace to the
148 - /// scale.
149 - fn check_breakpoints() {
150 - use makeover_geometry::SizeClass;
151 -
152 - let compact_max = SizeClass::Medium.min_px() - 1;
153 - let expanded_min = SizeClass::Expanded.min_px();
154 - let allowed = [
155 - compact_max,
156 - SizeClass::Medium.min_px(),
157 - expanded_min - 1,
158 - expanded_min,
159 - ];
160 -
161 - let mut strays: Vec<String> = Vec::new();
162 - for path in HAND_WRITTEN_CSS {
163 - println!("cargo::rerun-if-changed={path}");
164 - let Ok(css) = fs::read_to_string(path) else {
165 - continue;
166 - };
167 - for (n, line) in css.lines().enumerate() {
168 - for px in width_conditions(line) {
169 - if !allowed.contains(&px) {
170 - strays.push(format!("{path}:{}: (…-width: {px}px)", n + 1));
171 - }
172 - }
173 - }
174 - }
175 -
176 - assert!(
177 - strays.is_empty(),
178 - "stylesheet width breakpoints that are not SizeClass boundaries \
179 - ({}, {}, {}, {}px):\n {}\n\
180 - Either move the rule to a boundary, or make it dimensional so it \
181 - needs no threshold at all: a grid wants \
182 - repeat(auto-fit, minmax(<content floor>, 1fr)) and a size wants \
183 - clamp(). A threshold is for what appears and disappears.",
184 - allowed[0],
185 - allowed[1],
186 - allowed[2],
187 - allowed[3],
188 - strays.join("\n ")
189 - );
190 - }
191 -
192 - /// Every pixel value used as a `min-width` or `max-width` media feature on one
193 - /// line. Deliberately narrow: it reads `width` features and ignores the
194 - /// `width` property, `min-width`/`max-width` declarations, and every other
195 - /// number in the sheet.
196 - fn width_conditions(line: &str) -> Vec<u16> {
197 - let mut found = Vec::new();
198 - for (i, _) in line.match_indices("-width:") {
199 - let prefix = &line[..i];
200 - if !(prefix.ends_with("min") || prefix.ends_with("max")) {
201 - continue;
202 - }
203 - // A media feature is parenthesised; the property form never is.
204 - let opened = prefix.trim_end_matches(['m', 'i', 'n', 'a', 'x']);
205 - if !opened.ends_with('(') {
206 - continue;
207 - }
208 - let rest = &line[i + "-width:".len()..];
209 - let digits: String = rest
210 - .trim_start()
211 - .chars()
212 - .take_while(char::is_ascii_digit)
213 - .collect();
214 - if let Ok(px) = digits.parse::<u16>() {
215 - found.push(px);
216 - }
217 - }
218 - found
219 - }
220 -
221 142 /// Write `contents` to `path` only if it differs, to avoid needless rebuilds.
222 143 fn write_if_changed(path: &Path, contents: &str) {
223 144 let needs_write = fs::read_to_string(path).map_or(true, |existing| existing != contents);