Skip to main content

Crate makeover_webview

Crate makeover_webview 

Source
Expand description

The webview renderer for makeover_layout.

§The renderer that needs no palette

makeover-immediate and makeover-tui both take a Palette, because egui and a terminal need an actual colour before they can put anything on screen. A webview does not: var(--surface-raised) is the late binding, and the browser resolves it against whatever themes.js last wrote onto :root.

So this crate emits text naming intents, and never learns a colour. It is the deferral rule with no adapter in the way, and it is why the webview was always the wrong renderer to derive a vocabulary from: it can express anything, so it never pushes back.

§Phase A: the stylesheet

This module emits component CSS and no markup, deliberately. GoingsOn has 145 innerHTML sites and Balanced Breakfast 175 createElement sites, so moving markup is a migration where adopting a generated stylesheet is not. The apps keep every line of their markup and gain the classes.

It is not a deletion either, which this header claimed until the measurement came in. Adoption across goingson removed 49 declarations net and added 25 lines: a rule loses its depth declarations and gains a variant selector next to it, so the file stays the same size. What phase A moves is where depth is defined, not how much CSS exists. Numbers and method in the wiki note under “The deletion test, run”.

The bevel properties are byte-identical to what both apps already hand-write, which is asserted below.

§Phase B: the markup, one description at a time

form renders makeover_layout::Field, which is the half of phase B whose description is settled. It emits strings, because both apps interpolate their fields into larger string-built forms and returning nodes would rewrite those too. It owns its own escaping, on the reasoning in that module: a Rust encoder can cover element text and attribute values with one function, where the apps need four and have to choose correctly at every call site.

Rows and tables are the other half and are not here yet.

§What phase A settled, and what it costs

Decided 2026-07-29 against goingson’s styles.css rather than against a component list. The useful finding there was that .btn (line 644), .card (768) and .tag, .badge (882) each hand-write the same composition, so three quarters of phase A is one rule with several names.

Two of the four decisions change how goingson looks, and adoption should not be described as a pure deletion:

  • Pressed carries its fill. interactive_rules emits Depth::pressed whole. goingson presses to --surface-sunken today and will press to --surface-well, and hovers to --surface-overlay today and will hover to --hover-surface. Since surface-well inverts by theme where surface-sunken does not, a dark theme presses lighter than it hovers. That falls out of makeover’s own derivation, which says outright that surface-sunken cannot serve as a well, so if it reads wrong the answer is there and not here.
  • Badges go flat. See [token_rules].

The other two: the progress trough is renderer-local and the scrollbar track was dropped (component_rules), and no class prefix ships by default, so adoption means deleting the app’s hand-written rule in the same commit that adds the generated one. .card, .badge and the tab classes all already exist in goingson, and while both rules exist the cascade order decides which wins. That is the one real risk in adopting this, and it is why the migration lands per component rather than in one commit.

§0.10.0: the states this crate used to leave to its consumers

interactive_rules emitted hover and pressed and stopped, because makeover-layout modelled no interaction state. Focus and disabled were therefore unsayable, and every app completed the primitive from outside the only way that works: by out-specifying a rule it does not own. goingson carries 19 such rules and the MNW server 21, and the three focus rings do not match each other.

That also blocked the cascade-layer work outright. An app that declares @layer puts its own rules in a named layer, and unlayered declarations outrank every named layer regardless of specificity, so all of those overrides lose in the commit that adopts layers. They cannot simply be deleted, because they are the only thing supplying the missing states. Emitting the states here is what turns that adoption into a deletion.

Four states now, in emission order, and the order is load-bearing: they are all specificity (0,2,0), so disabled beats hover by coming last and by nothing else. Nothing here reaches for :not(:disabled), which would raise a selector this crate will shortly be wrapping in its own layer.

Hover additionally sits inside a capability query now. makeover-touch answers whether a fingertip has hover and makeover-geometry spells the condition; this crate asks and does not decide. goingson’s section 60 exists solely to take the hover state back on touch, which is a fight it should never have been handed.

§Substitution, three ways

Fill::Well has no colour on makeover before 2.3.0, and each renderer answers that differently, which is the evidence that dropping Fill::fallback from the description was right:

  • makeover-immediate substitutes the page in Rust.
  • makeover-tui refuses to substitute and draws an edge instead, because a terminal would quantise the two together.
  • here, CSS already has the mechanism: var(--surface-well, var(--surface-page)) falls back in the browser, and nothing in Rust decides anything.

Modules§

form
Phase B, the forms half: makeover_layout::Field rendered to HTML.
list
Column layout and row structure for lists and tables.

Structs§

Emit
How the emitted CSS is shaped.

Functions§

bevel_properties
The custom properties both bevels resolve through.
bevel_shadow
The two-tone edge as a box-shadow value.
bevel_var
The CSS custom property holding a bevel’s composition.
component_rules
The component layer: every named thing phase A emits.
depth_class
The class name for a depth.
depth_declarations
The fill and edge declarations for a depth, as a rule body.
depth_rule
One rule giving a selector a depth, or nothing when the depth declares nothing.
depth_rules
One rule per depth: its fill and its edge, together.
disabled_rule
Present, visible, and not answering.
fill_var
A var() reference to a fill intent, with the browser’s own fallback where the intent may be absent.
focus_rule
The keyboard focus ring, placed by the depth it lands on.
interactive_rules
Every state a selector that answers a click implies: hover, pressed, focus and disabled, in that order.
stylesheet
The whole phase-A stylesheet: properties, depth rules and components, with a generated-file banner.