From 071f00dccaaf28599786f25fa64713dedc97dd13 Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Mon, 26 Oct 2026 16:09:01 -0300 Subject: [PATCH] layout: how wide a page grows is a token, and the three compositions are written down The dashboard decided its page widths in a file of its own; a composition rule that only one consumer holds is one the next consumer spells again. width_contained, width_detail and width_wide are palette.toml's now, as --spin-width-* in tokens.css and dashboard.css, and the laboratory says the three compositions - marketing, documentation, application - in words, each a page it draws above: where a token stops and a decision begins. Co-Authored-By: Claude Fable 5.1 --- cmd/palette/main.go | 3 +++ cmd/palette/outputs.go | 3 +++ dist/dashboard.css | 3 +++ dist/tokens.css | 3 +++ dist/tokens.json | 5 ++++- index.html | 13 +++++++++++++ palette.toml | 8 ++++++++ 7 files changed, 37 insertions(+), 1 deletion(-) diff --git a/cmd/palette/main.go b/cmd/palette/main.go index dc5a032..94bb555 100644 --- a/cmd/palette/main.go +++ b/cmd/palette/main.go @@ -54,6 +54,9 @@ type palette struct { Target int TargetTouch int `toml:"target_touch"` Phone, Tablet, Desktop int + WidthContained int `toml:"width_contained"` + WidthDetail int `toml:"width_detail"` + WidthWide int `toml:"width_wide"` } Motion struct { Fast, Base, Slow, Draw int diff --git a/cmd/palette/outputs.go b/cmd/palette/outputs.go index 89875e0..8f4848c 100644 --- a/cmd/palette/outputs.go +++ b/cmd/palette/outputs.go @@ -91,6 +91,7 @@ func tokensCSS(p palette, dark, light map[string]rgb) string { fmt.Fprintf(&b, "\t--spin-measure: %dch;\n\t--spin-sidebar: %drem;\n", p.Layout.Measure, p.Layout.Sidebar) fmt.Fprintf(&b, "\t--spin-radius-sm: %dpx;\n\t--spin-radius: %dpx;\n\t--spin-radius-lg: %dpx;\n", p.Layout.RadiusSm, p.Layout.Radius, p.Layout.RadiusLg) fmt.Fprintf(&b, "\t--spin-target: %dpx;\n\t--spin-target-touch: %dpx;\n", p.Layout.Target, p.Layout.TargetTouch) + fmt.Fprintf(&b, "\t--spin-width-contained: %dpx;\n\t--spin-width-detail: %dpx;\n\t--spin-width-wide: %dpx;\n", p.Layout.WidthContained, p.Layout.WidthDetail, p.Layout.WidthWide) fmt.Fprintf(&b, "\t--spin-duration-fast: %dms;\n\t--spin-duration: %dms;\n", p.Motion.Fast, p.Motion.Base) fmt.Fprintf(&b, "\t--spin-duration-slow: %dms;\n\t--spin-duration-draw: %dms;\n", p.Motion.Slow, p.Motion.Draw) fmt.Fprintf(&b, "\t--spin-ease: %s;\n", p.Motion.Ease) @@ -205,6 +206,8 @@ func dashboardCSS(p palette, dark, light map[string]rgb) string { // Its theme (dashboard/src/styles/globals.css) maps Tailwind's names onto these. b.WriteString(":root {\n") fmt.Fprintf(&b, "\t--radius: %gpx;\n", float64(p.Layout.RadiusSm)) + // How wide a page may grow, by what it shows (the dashboard's page-width.ts reads these). + fmt.Fprintf(&b, "\t--spin-width-contained: %dpx;\n\t--spin-width-detail: %dpx;\n\t--spin-width-wide: %dpx;\n", p.Layout.WidthContained, p.Layout.WidthDetail, p.Layout.WidthWide) // The dim behind a dialog: the mark's navy, in either theme, at the palette's scrim. navy, err := parseHex(p.Brand["navy"]) if err != nil { diff --git a/dist/dashboard.css b/dist/dashboard.css index 38f28af..65c2b95 100644 --- a/dist/dashboard.css +++ b/dist/dashboard.css @@ -51,6 +51,9 @@ } :root { --radius: 4px; + --spin-width-contained: 1200px; + --spin-width-detail: 1152px; + --spin-width-wide: 1600px; --scrim: rgb(17 24 39 / 0.6); --spin-wordmark: "Spinbox"; --spin-font-sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif; diff --git a/dist/tokens.css b/dist/tokens.css index 21f0f84..da312ec 100644 --- a/dist/tokens.css +++ b/dist/tokens.css @@ -61,6 +61,9 @@ --spin-radius-lg: 12px; --spin-target: 24px; --spin-target-touch: 44px; + --spin-width-contained: 1200px; + --spin-width-detail: 1152px; + --spin-width-wide: 1600px; --spin-duration-fast: 120ms; --spin-duration: 200ms; --spin-duration-slow: 400ms; diff --git a/dist/tokens.json b/dist/tokens.json index baeeb49..5e2427a 100644 --- a/dist/tokens.json +++ b/dist/tokens.json @@ -35,7 +35,10 @@ "TargetTouch": 44, "Phone": 390, "Tablet": 768, - "Desktop": 1280 + "Desktop": 1280, + "WidthContained": 1200, + "WidthDetail": 1152, + "WidthWide": 1600 }, "light": { "accent": "#0A6FA3", diff --git a/index.html b/index.html index 60456e9..3a446aa 100644 --- a/index.html +++ b/index.html @@ -285,6 +285,19 @@

Not

+
+ Compositions +
+

The same type and colours, three ways of laying a page out - each a page of this laboratory above, not a mock from the colours. Where the tokens stop and a decision begins: a token says how a border is drawn, these say where one is.

+

Marketing

+

The site's landing: a hero that says what to do before what it is, the story as one terminal, three capabilities as cards with their proof beside them and the rest as a list. The reading measure is --spin-measure; a section is a heading and what is under it, never a box.

+

Documentation

+

A Starlight page: one column at the reading measure, the sidebar at --spin-sidebar, headings in the mono. A claim links to the row of the status page that proves it.

+

Application

+

The dashboard, read for diagnosis. A page grows only as wide as what it shows: a document or a form to --spin-width-contained, one thing and what is around it to --spin-width-detail, a table of many to --spin-width-wide, an explorer to the viewport. A page is a header - the title, its state, its context and its one primary action on one row - and sections of rows between hairlines; the name beside the mark is --spin-wordmark, which the catalog audit holds the sidebar to.

+
+
+
Palette
diff --git a/palette.toml b/palette.toml index 94160b6..f38a98f 100644 --- a/palette.toml +++ b/palette.toml @@ -103,6 +103,14 @@ target_touch = 44 # px: a target on a coarse pointer (WCAG 2.5.5, Apple's phone = 390 # px: the narrow width every page is drawn at in preview.html tablet = 768 desktop = 1280 +# How wide a page grows, by what it shows: a document or a form stays a column one reads; one +# thing and what is around it - a workspace, a runner - is two columns of a few rows, which +# drift apart past this; a table of many takes what a wide screen gives. An explorer - logs, +# traces - takes the viewport. The dashboard's page-width.ts reads these; the October review +# read the workspace detail at 1400 px as two columns the eye crossed whitespace between. +width_contained = 1200 # px +width_detail = 1152 # px +width_wide = 1600 # px # Motion. A movement says what something does - a layer sealed on the one under it, a diff drawn # between two - or that it answered a hand; one that only decorates is left out. Each runs once: