| 1 |
# makeover-layout |
| 2 |
|
| 3 |
The renderer-agnostic half of the make-family design system. |
| 4 |
|
| 5 |
`makeover` answers *what colour*, and varies by theme. `makeover-geometry` |
| 6 |
answers *how much space*, and varies by density and surface. This crate answers |
| 7 |
*what the thing is*, and varies by nothing. |
| 8 |
|
| 9 |
## The deferral rule |
| 10 |
|
| 11 |
A description names intents and relationships, never values. Say `Fill::Raised`, |
| 12 |
never `#D9DDF4`. Say `Gap::Peer`, never `6px`. What is left once colour and |
| 13 |
spacing are deferred is composition: which edges are lit, what inverts on press, |
| 14 |
what nests in what. |
| 15 |
|
| 16 |
The constraint that shapes it: a renderer that can only paint rectangles has to |
| 17 |
be able to express the result. egui has no `box-shadow: inset` and one stroke per |
| 18 |
widget with no per-side control. A terminal has box-drawing characters and one |
| 19 |
cell of resolution, and cannot draw a two-tone lit edge at all. So this crate |
| 20 |
names the intent, and each renderer picks an expression it can produce, including |
| 21 |
dropping half of one. |
| 22 |
|
| 23 |
## What is here |
| 24 |
|
| 25 |
**Depth**: `Bevel`, `Edge`, `Fill`, `Depth`. Fill and bevel are named together, |
| 26 |
because naming them apart lets them disagree: a region can carry a raised bevel |
| 27 |
over a recessed fill. `Depth` makes that unrepresentable. |
| 28 |
|
| 29 |
**Components**: `Token` (a badge does not answer a click, a chip does), `Notice` |
| 30 |
(a toast is transient, a banner is persistent), `RowPart`, `Heading`, `Selector`, |
| 31 |
`Readiness`, and `Tone`, the one intent family they share. |
| 32 |
|
| 33 |
**Schemas**: `Field` for forms, `Column` for lists and tables. A column carries a |
| 34 |
drop priority, which is what replaces addressing columns by position. Addressing columns by |
| 35 |
`nth-child` means inserting a column silently hides the wrong one on a narrow |
| 36 |
screen. |
| 37 |
|
| 38 |
**Structure**: `Region` for the parts of a screen, `Arrangement` for how a screen |
| 39 |
is put together. Two arrangements, because the two apps have two. `Showing` says |
| 40 |
how many of a region's children are visible at once, which is what lets a |
| 41 |
renderer derive a tab strip or a prev/next row for itself instead of recognising |
| 42 |
a widget by name. |
| 43 |
|
| 44 |
The vocabulary was read off audiofiles, the only implementation written by a |
| 45 |
consumer with no CSS, then checked against both webview apps. |
| 46 |
|
| 47 |
## What is not here, on purpose |
| 48 |
|
| 49 |
Validation. `Field` describes fields, not constraints. A schema that describes |
| 50 |
fields without constraints acquires a constraint layer per app, which is the |
| 51 |
divergence this crate exists to end. |
| 52 |
|
| 53 |
## Where the description stops |
| 54 |
|
| 55 |
The bespoke widgets: a day-plan timeline, a kanban board, a calendar. A |
| 56 |
description expressive enough to produce those is not a description any more, it |
| 57 |
is a widget library with one app on top. Generate the boring 80% so the bespoke |
| 58 |
20% gets the attention. |
| 59 |
|
| 60 |
`Region::Bespoke` states that limit instead of hiding it. The description names |
| 61 |
the place, the app owns the contents, and a screen with a timeline in it is still |
| 62 |
a whole screen. Without that member the description would cover only the boring |
| 63 |
screens, and the interesting ones would need a second path beside the router. |
| 64 |
One opaque member, and `Region::described()` is how a renderer tells it from the |
| 65 |
rest. |
| 66 |
|
| 67 |
## Status |
| 68 |
|
| 69 |
On crates.io. A vocabulary correction ships as a major bump with a migration |
| 70 |
rather than as an edit. |
| 71 |
|
| 72 |
Design lives in the wiki note `makeover-layout`; the backlog is in GoingsOn under |
| 73 |
the project of the same name. |
| 74 |
|
| 75 |
## Licence |
| 76 |
|
| 77 |
MIT. |
| 78 |
|