Skip to main content

max / makenotwork

Derive the page's layout class from a described measure 69 of 72 templates carried `padded-page`, `centered-page` or `article-page` as a literal in `{% block body_attrs %}`, which made how wide a page runs a fact about the template rather than about the screen. 53, 13 and 3 of them, and the count comes out the same after the conversion because nothing about which page is which has changed. `shell::measure` maps `makeover_layout::Measure` to the three strings. The strings are unchanged and no rule in `style.css` is touched: what moved is where the choice is written down, from a class name in markup to a property the description layer names and every renderer has to answer. The old class names stay on the left-hand side of the rules because that is what the stylesheet matches, and renaming them is a separate change with no description in it. A test walks the templates and fails on a layout class still written by hand, so a new template pasted from an old one does not quietly reintroduce the literal. The four standalone tokens are screen identity rather than measure and are deliberately left alone.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-13 00:06 UTC
Signed with PGP, not checked
Commit: 5bd23ba771a72c3b32576285dc004a767ebea897
Parent: 6ac466b
72 files changed, +165 insertions, -71 deletions
@@ -5326,7 +5326,7 @@
5326 5326
5327 5327 [[package]]
5328 5328 name = "makeover-layout"
5329 - version = "0.17.0"
5329 + version = "0.18.0"
5330 5330
5331 5331 [[package]]
5332 5332 name = "makeover-touch"
@@ -10694,6 +10694,10 @@
10694 10694 name = "kberg"
10695 10695 version = "0.1.0"
10696 10696
10697 + [[patch.unused]]
10698 + name = "ops-status"
10699 + version = "0.1.0"
10700 +
10697 10701 [[patch.unused]]
10698 10702 name = "painhours"
10699 10703 version = "0.1.0"
@@ -159,7 +159,7 @@
159 159 # rather than reached through quasi-router's re-export because a described
160 160 # screen names FieldKind and Tone directly; it has to track what quasi-router
161 161 # resolves or the two `layout::` paths are different crates.
162 - makeover-layout = "0.17.0"
162 + makeover-layout = "0.18.0"
163 163 # For the request head the per-viewer state factory reads. axum re-exports it,
164 164 # but the factory's signature is quasi-axum's and names `http::request::Parts`.
165 165 http = "1.3.1"
@@ -87,6 +87,37 @@
87 87 &parts().body_attrs
88 88 }
89 89
90 + pub use makeover_layout::Measure;
91 +
92 + /// The body class for a screen's measure.
93 + ///
94 + /// `0eccff0d`. 69 of 72 templates carried one of these three strings as a
95 + /// literal, which made how wide a page runs a fact about the template rather
96 + /// than about the screen. The strings are unchanged and the rules in
97 + /// `style.css` are untouched: what moved is where the choice is written down,
98 + /// from a class name in markup to a described property with a name in every
99 + /// renderer's vocabulary.
100 + ///
101 + /// The old names stay on the left-hand side of the rules because they are what
102 + /// `style.css` matches, and renaming them is a separate change with no
103 + /// description in it. `padded-page` is [`Measure::Wide`] because a padded page
104 + /// is the full width with gutters, which is what the class always meant.
105 + ///
106 + /// The four standalone tokens -- `health-page`, `purchase-page`, `buy-page`,
107 + /// `stripe-disclaimer-page` -- are screen identity rather than measure, and are
108 + /// deliberately not here.
109 + #[must_use]
110 + pub const fn measure(measure: Measure) -> &'static str {
111 + match measure {
112 + Measure::Contained => "centered-page",
113 + Measure::Reading => "article-page",
114 + // The default, and the arm a member added upstream lands in. A measure
115 + // this server has not learned yet should render at the width every
116 + // other page does rather than unstyled.
117 + _ => "padded-page",
118 + }
119 + }
120 +
90 121 #[cfg(test)]
91 122 mod tests {
92 123 use super::*;
@@ -133,6 +164,65 @@
133 164 assert!(!attrs.contains("class="));
134 165 }
135 166
167 + #[test]
168 + fn every_measure_keeps_the_class_the_templates_used_to_write() {
169 + // `0eccff0d` moved where the choice is written down and changed no
170 + // rule in `style.css`, so the three strings have to come out exactly as
171 + // the 69 templates spelled them. A typo here renders 53 pages unstyled.
172 + assert_eq!(measure(Measure::Wide), "padded-page");
173 + assert_eq!(measure(Measure::Contained), "centered-page");
174 + assert_eq!(measure(Measure::Reading), "article-page");
175 + }
176 +
177 + #[test]
178 + fn no_template_still_writes_a_layout_class_by_hand() {
179 + // The done-condition, checked rather than remembered: the layout axis
180 + // is derived from the described property. A new template pasted from an
181 + // old one fails here instead of quietly reintroducing the literal.
182 + //
183 + // The four standalone tokens are screen identity rather than measure
184 + // and are deliberately left alone, so they are not looked for.
185 + let mut offenders = Vec::new();
186 + for entry in walk("templates") {
187 + let source = std::fs::read_to_string(&entry).expect("a template reads");
188 + for (at, line) in source.lines().enumerate() {
189 + if !line.contains("block body_attrs") {
190 + continue;
191 + }
192 + // The literal, as distinct from the call that produces it: the
193 + // rendered class still says `padded-page`, and should.
194 + let derived = line.contains("crate::shell::measure(");
195 + let literal = ["padded-page", "centered-page", "article-page"]
196 + .iter()
197 + .any(|name| line.contains(name));
198 + if literal && !derived {
199 + offenders.push(format!("{}:{}", entry.display(), at + 1));
200 + }
201 + }
202 + }
203 + assert!(offenders.is_empty(), "{offenders:?}");
204 + }
205 +
206 + /// Every `.html` under a directory.
207 + fn walk(root: &str) -> Vec<std::path::PathBuf> {
208 + let mut found = Vec::new();
209 + let mut stack = vec![std::path::PathBuf::from(root)];
210 + while let Some(at) = stack.pop() {
211 + let Ok(entries) = std::fs::read_dir(&at) else {
212 + continue;
213 + };
214 + for entry in entries.flatten() {
215 + let path = entry.path();
216 + if path.is_dir() {
217 + stack.push(path);
218 + } else if path.extension().is_some_and(|ext| ext == "html") {
219 + found.push(path);
220 + }
221 + }
222 + }
223 + found
224 + }
225 +
136 226 #[test]
137 227 fn morph_is_loaded_wherever_a_swap_can_ask_for_it() {
138 228 // The shell writes `hx-ext="morph"` onto every page's body, so the
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Appeals - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block head %}
7 7 {% endblock %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Comp codes - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block head %}
7 7 {% endblock %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Metrics - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block head %}
7 7 {% endblock %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Reports - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block content %}
7 7 {% include "partials/site_header.html" %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Scan Audit Log - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block content %}
7 7 {% include "partials/site_header.html" %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Signups - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block content %}
7 7 {% include "partials/site_header.html" %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Scan Pipeline - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block content %}
7 7 {% include "partials/site_header.html" %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Users - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block head %}
7 7 {% endblock %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Admin: Waitlist - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page admin-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} admin-page"{% endblock %}
5 5
6 6 {% block head %}
7 7 {% endblock %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}{% if editing %}Edit Post{% else %}New Post{% endif %} - {{ project_slug }} - Dashboard{% endblock %}
4 - {% block body_attrs %} class="padded-page blog-editor"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} blog-editor"{% endblock %}
5 5
6 6 {% block content %}
7 7 {% include "partials/site_header.html" %}
@@ -1,7 +1,7 @@
1 1 {% extends "base.html" %}
2 2
3 3 {% block title %}Delete Account - Makenotwork{% endblock %}
4 - {% block body_attrs %} class="padded-page delete-account-page"{% endblock %}
4 + {% block body_attrs %} class="{{ crate::shell::measure(crate::shell::Measure::Wide) }} delete-account-page"{% endblock %}
5 5
6 6 {% block head %}
7 7 {% endblock %}