feat(ui): a layout scale, and a guard that keeps files on it - #79
Merged
Conversation
Colour has been a system since M1 — twenty named slots, two hand-authored palettes, contrast asserted over both. Everything that is not colour was not a system at all. Measured before writing anything: 25 distinct `Padding` pairs across 68 sites, twelve `spacing` values, six border radii. `[3,6]`, `[3,8]`, `[3,10]` and `[3,12]` were all in use, each chosen a call site at a time. That is not a stylistic complaint — values picked one at a time drift, and nothing in the suite noticed. Spacing was the crate's largest blind spot: any number could change and all 890 tests still passed. So `metrics.rs` carries eight steps and three radii, and — more importantly — a guard. It holds the list of files already on the scale and reads each one, failing if a raw number has come back on a line that sets padding, spacing or a radius. A file joins that list in the change that converts it and cannot regress afterwards, which is what makes the rest of this migration testable one file at a time rather than trusted in bulk. The guard has its own test rather than being trusted because it passes over the files it is pointed at. It has to tell `.padding([3, 12])` from `.padding(metrics::SNUG)`, and both from `radius: iced::Border::default().radius` — a line that chooses no value is not choosing a wrong one. What the scale governs is deliberately narrow: space between things and corner radii, the numbers a reader compares without meaning to. A component's own dimensions stay local. `TAB_WIDTH` is a decision about how much room a repository name needs and reads better beside the tab than as a step on a shared ladder, so the guard leaves it alone. `widget/tabs.rs` is converted as the proof, being the smallest file with a representative spread. Two of its numbers move by a pixel: a 5 that no other padding in the crate used becomes the 4 that many do. The tab bar only appears with two repositories open, so none of the committed screenshots show it. Type sizes are not on a scale yet — six file-local constants duplicate each other, `ITEM_SIZE = 13.0` three times over — and that is its own step.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
T1 — the foundation the rest of the UI plan stands on.
The measurement
Colour has been a system since M1: twenty named slots, two hand-authored palettes, contrast asserted over both. Everything that is not colour was not a system at all.
Padding::from([v,h])pairs.spacing(n)[3,6],[3,8],[3,10]and[3,12]were all in use at once, each picked at its own call site.That is not a stylistic complaint. Spacing was the crate's largest blind spot — any number could change and all 890 tests still passed.
The guard is the actual deliverable
The scale is eight steps and three radii; that part is easy. What makes the rest of this migration possible is the guard:
metrics.rsholds the list of files already on the scale, reads each one, and fails if a raw number has come back on a line that sets padding, spacing or a radius. A file joins that list in the change that converts it and cannot regress afterwards — so the migration is testable one file at a time instead of trusted in bulk.It has its own test rather than being trusted because it happens to pass over the files it is pointed at. It must tell
.padding([3, 12])from.padding(metrics::SNUG), and both fromradius: iced::Border::default().radius— a line that chooses no value is not choosing a wrong one.Same shape as the bidirectional shortcut-reference test and
xtask bench-check: an assertion about the source, for an invariant no ordinary test can reach.What the scale deliberately does not govern
A component's own dimensions.
TAB_WIDTHis a decision about how much room a repository name needs; it belongs beside the tab as a named local constant, not as a step on a shared ladder. The guard leaves it alone, and a test pins that it does.Only the numbers a reader compares without meaning to are shared.
Proof, on the smallest file
widget/tabs.rs— 176 lines, eleven layout literals, a representative spread of padding, spacing and both radius spellings.Two numbers move by a pixel: a
5that no other padding in the crate used becomes the4that many do. The tab bar only appears with two repositories open, so none of the four committed screenshots show it — there is nothing to retake, and I am not attaching a before/after of a one-pixel change to a bar that is off screen in every one of them.Sabotage — four, all confirmed
migrated_files_carry_no_raw_layout_numbersthe_scale_climbs_and_never_repeats_itselfevery_step_is_a_whole_number_of_pixelsThe half-pixel one is worth its keep: a half-pixel gap renders as zero or one depending where it lands, which is how a scale quietly stops being one.
Docs
UI_SPEC.mdgains a Layout scale section beside Theming — the measurement, the eight steps, the boundary against component dimensions, and how the guard works. It also states plainly that type sizes are not on a scale yet, with theITEM_SIZE = 13.0-three-times duplication named, since that is the next step.Gate
cargo fmt --all -- --check,cargo clippy --workspace --all-targets --all-features --locked -- -D warnings,cargo test --workspace --all-features --locked— 894 tests, all green.