max / makenotwork
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
10 files changed,
+69 insertions,
-72 deletions
| @@ -5311,9 +5311,9 @@ | |||
| 5311 | 5311 | ||
| 5312 | 5312 | [[package]] | |
| 5313 | 5313 | name = "makeover-build" | |
| 5314 | - | version = "0.23.1" | |
| 5314 | + | version = "0.24.0" | |
| 5315 | 5315 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 5316 | - | checksum = "09326dad8b7fdbf1ae4359f866e8f4432a86c837f5a8bf1576bf0c298afcd41b" | |
| 5316 | + | checksum = "12bcb5bc04026df9a5f4007e2a0f17ed34d8671573ea6445b4d17d7f44280d69" | |
| 5317 | 5317 | dependencies = [ | |
| 5318 | 5318 | "makeover", | |
| 5319 | 5319 | "makeover-geometry", | |
| @@ -5344,9 +5344,9 @@ | |||
| 5344 | 5344 | ||
| 5345 | 5345 | [[package]] | |
| 5346 | 5346 | name = "makeover-webview" | |
| 5347 | - | version = "0.30.1" | |
| 5347 | + | version = "0.31.0" | |
| 5348 | 5348 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 5349 | - | checksum = "d6f86fc082c5fc0d73192a3f3f5f74840848ba2cc815154ab207b1fc707f7c64" | |
| 5349 | + | checksum = "f9f97c1694d50160ed5c980a17c96b1c8d007dbdb2d6b9472a2a5270e28cb4fd" | |
| 5350 | 5350 | dependencies = [ | |
| 5351 | 5351 | "makeover-geometry", | |
| 5352 | 5352 | "makeover-layout", | |
| @@ -10682,6 +10682,14 @@ | |||
| 10682 | 10682 | "pkg-config", | |
| 10683 | 10683 | ] | |
| 10684 | 10684 | ||
| 10685 | + | [[patch.unused]] | |
| 10686 | + | name = "quasi-store" | |
| 10687 | + | version = "0.1.0" | |
| 10688 | + | ||
| 10689 | + | [[patch.unused]] | |
| 10690 | + | name = "quasi-tauri" | |
| 10691 | + | version = "0.1.0" | |
| 10692 | + | ||
| 10685 | 10693 | [[patch.unused]] | |
| 10686 | 10694 | name = "kberg" | |
| 10687 | 10695 | version = "0.1.0" | |
| @@ -10697,11 +10705,3 @@ | |||
| 10697 | 10705 | [[patch.unused]] | |
| 10698 | 10706 | name = "synckit-config" | |
| 10699 | 10707 | version = "0.2.0" | |
| 10700 | - | ||
| 10701 | - | [[patch.unused]] | |
| 10702 | - | name = "quasi-store" | |
| 10703 | - | version = "0.1.0" | |
| 10704 | - | ||
| 10705 | - | [[patch.unused]] | |
| 10706 | - | name = "quasi-tauri" | |
| 10707 | - | version = "0.1.0" |
| @@ -236,7 +236,7 @@ | |||
| 236 | 236 | # Emits static/geometry.css (makeover-geometry) and static/layout.css | |
| 237 | 237 | # (makeover-webview). The same generator GO and BB run; only the output paths | |
| 238 | 238 | # differ, since the server serves its stylesheets rather than bundling them. | |
| 239 | - | makeover-build = "0.23.1" | |
| 239 | + | makeover-build = "0.24.0" | |
| 240 | 240 | # Read directly for the embeds' own copy of the spacing layer, which they need | |
| 241 | 241 | # because an iframe cannot link a stylesheet. makeover-build does not re-export | |
| 242 | 242 | # it, so the pin lives here and has to track the one makeover-build resolves. |
| @@ -247,37 +247,42 @@ | |||
| 247 | 247 | /// need a selector matcher and a checker that guesses wrong about specificity | |
| 248 | 248 | /// fails correct builds, so the judgement is recorded here. | |
| 249 | 249 | /// | |
| 250 | - | /// **A deliberate pairing.** `.table-heading { content }` is the sort caret's | |
| 251 | - | /// reserved gap, declared on the unsorted arm precisely so it cannot blank the | |
| 252 | - | /// generated caret on the sorted one; `.table-heading { display }` and | |
| 253 | - | /// `.progress-fill { background }` are different elements rather than different | |
| 254 | - | /// arms -- the caret pseudo-element, and the media scrubber's fill, which lives | |
| 250 | + | /// **A deliberate pairing.** `.progress-fill { background }` is a different | |
| 251 | + | /// element rather than a different arm: the media scrubber's fill, which lives | |
| 255 | 252 | /// inside `.progress-bar` and never matches the generated | |
| 256 | - | /// `.progress > .progress-fill`. That last one already carried a `respec-ok` | |
| 257 | - | /// comment saying so. | |
| 253 | + | /// `.progress > .progress-fill`. It already carried a `respec-ok` comment | |
| 254 | + | /// saying so. | |
| 255 | + | /// | |
| 256 | + | /// `.tab { box-shadow }` and `.chosen { box-shadow }` are the third kind and the | |
| 257 | + | /// awkward one -- one rule, two entries, because the check reads every class in | |
| 258 | + | /// a selector and `.tab.chosen` is both. This file zeroes the base `button` | |
| 259 | + | /// shadow on a tab, and unlayered CSS outranks `@layer makeover` whatever the | |
| 260 | + | /// specificity, so the generated `.tab.chosen` bevel cannot apply on its own. | |
| 261 | + | /// The chosen arm takes `box-shadow: revert-layer`, which hands the property | |
| 262 | + | /// back to the layer rather than naming a value. Two arms, one of which is a | |
| 263 | + | /// deferral rather than an override, so both entries stay. | |
| 258 | 264 | /// | |
| 259 | 265 | /// **A divergence taken on purpose.** `.table-row { display }` is `grid` here | |
| 260 | 266 | /// against makeover's `table-row`, which is the same build-time grid story | |
| 261 | 267 | /// goingson is on. | |
| 262 | 268 | /// | |
| 263 | - | /// `.tab { background }` and `.tab { box-shadow }` are none of the above and | |
| 264 | - | /// should not stay. `.tab.is-selected` sets `--surface-raised` and | |
| 265 | - | /// `--bevel-raised`, which is byte for byte what the generated `.tab.chosen` | |
| 266 | - | /// sets: a second name for makeover's own state, which is the defect | |
| 267 | - | /// makeover-webview 0.27.0 exists to prevent. Removing it is a template change | |
| 268 | - | /// rather than a stylesheet one, so it is filed rather than done here. | |
| 269 | + | /// `.tab { background }` was here and is gone. `.tab.is-selected` set | |
| 270 | + | /// `--surface-raised` and `--bevel-raised`, byte for byte what the generated | |
| 271 | + | /// `.tab.chosen` sets: a second name for makeover's own state, which is the | |
| 272 | + | /// defect makeover-webview 0.27.0 exists to prevent. The tabs carry `chosen` | |
| 273 | + | /// now, in four templates and in `frontend/src/core/tabs.ts`, and the rule is | |
| 274 | + | /// deleted. The caret's two entries went the same way, one release later: | |
| 275 | + | /// makeover-webview 0.31.0 emits the leading space and the reserved box itself. | |
| 269 | 276 | /// | |
| 270 | 277 | /// An entry that stops colliding fails the build, so this list cannot outlive | |
| 271 | 278 | /// what it describes. | |
| 272 | 279 | const REVIEWED_OVERLAPS: &[(&str, &str)] = &[ | |
| 273 | 280 | ("badge", "color"), | |
| 274 | 281 | ("card", "color"), | |
| 282 | + | ("chosen", "box-shadow"), | |
| 275 | 283 | ("progress-fill", "background"), | |
| 276 | - | ("tab", "background"), | |
| 277 | 284 | ("tab", "box-shadow"), | |
| 278 | 285 | ("tab", "color"), | |
| 279 | 286 | ("tab", "cursor"), | |
| 280 | - | ("table-heading", "content"), | |
| 281 | - | ("table-heading", "display"), | |
| 282 | 287 | ("table-row", "display"), | |
| 283 | 288 | ]; |
| @@ -113,7 +113,7 @@ | |||
| 113 | 113 | | Upload status block | `.upload-status` + `-row` | `-msg.is-success`, `-msg.is-error` | — | | |
| 114 | 114 | | Status pill | `.field-status` / `.save-status` | `.success`, `.error`, `.saving` | — | | |
| 115 | 115 | | Table | `.data-table` + `.well` (rich), `.compact-table` (small mono) | `.minw-300..800` for horizontal scroll min-width | `.sortable.ascending`, `.sortable.descending` | | |
| 116 | - | | Tabs | `.tabs` + `.tab` | — | `.tab.is-selected` | | |
| 116 | + | | Tabs | `.tabs` + `.tab` | — | `.tab.chosen` (makeover's name, not the site's) | | |
| 117 | 117 | | Breadcrumb | `.breadcrumb` | — | — | | |
| 118 | 118 | | Pagination | `_ui.html` macro `pagination` → `.pagination` | — | `.active` | | |
| 119 | 119 | ||
| @@ -162,7 +162,7 @@ | |||
| 162 | 162 | ||
| 163 | 163 | Hover used to have three options picked by component type, and the second of them was a depth lift: the shadow grew from `var(--shadow-raised)` to `3px 3px var(--shadow-edge)`, reserved for controls that commit a write, so that pressing "Pay" looked different from pressing "Next". That signal is gone rather than moved, and it was spent deliberately. A bevel is an edge and not a distance, so it has no growth axis to extend along; keeping a commit-versus-navigate cue would have meant a local override on top of the `layout.css` every other make-family app takes unmodified. Decided 2026-07-31 (wiki `mnw-platinum`). A control that commits a write is distinguished by its label and its placement, the same way it is in GoingsOn and Balanced Breakfast. | |
| 164 | 164 | - **Focus**: `:focus-visible` shows the `--focus-ring` violet outline. Custom interactive containers (`.card--selectable`, sort headers) must opt in by adding `:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }`. A container the browser does not focus on its own also needs `tabindex="0"` in the markup, or the rule never matches and the outline is decoration for a state that cannot happen. The `data-action` dispatcher activates such a container on Enter and Space. | |
| 165 | - | - **Selected / active**: `.is-selected` modifier applies `background: var(--highlight-faint)` plus the focus-ring border. `.tab.active`, `.filter-item.active`, `.view-btn.active`, and the `:checked + .card--selectable-inner` recipe all read it. | |
| 165 | + | - **Selected / active**: `.is-selected` modifier applies `background: var(--highlight-faint)` plus the focus-ring border. `.filter-item.active`, `.view-btn.active`, and the `:checked + .card--selectable-inner` recipe all read it. A tab is the exception and takes `.tab.chosen` instead: makeover names that state and emits its rule, so spelling it `.is-selected` here as well made the site a second name for something the design system already named. Where makeover has a primitive, its name wins; the components it has none for keep `.is-selected`. | |
| 166 | 166 | - **Status**: a badge names the status it reports, and the colour follows from the status. The set is `data-tone="success"` (Active, Trialing, Completed, Approved, Published, Connected, Free), `data-tone="warning"` (Pending, Processing, Scheduled, Draft, Incomplete) and `data-tone="danger"` (Failed, Past due, Unpaid, Suspended, Spam). A terminal state nobody has to act on (Refunded, Canceled) takes the plain `.badge` with no tone, which already reads as neutral: colouring it red would ask for an action that does not exist. A badge reports data, not selection, so it never takes `.is-selected` and there is no `.badge.active`. A class that names a colour rather than a state is the same category error as `.mb-4` naming a number. | |
| 167 | 167 | ||
| 168 | 168 | The tone is an attribute rather than a class because that is makeover's spelling: `layout.css` carries `.badge[data-tone="…"]` and the four tone names are the design system's. The badge itself is coloured text, not a filled pill. It was a filled pill until wave 2 tier B2, painted per status by a local `.badge--live/pending/failed` set, and that fill was saying exactly what the generated colour says — keeping it meant the tone could never do anything. `.ai-tier-*` is the one thing that stays local, because makeover's four tones all read as alarm and a disclosure level is not alarm: a handmade item is not a "success". |
| @@ -55,7 +55,7 @@ | |||
| 55 | 55 | .field-status / .save-status + .success / .error / .saving | |
| 56 | 56 | .toast + .toast--success / --error / --warning | |
| 57 | 57 | .breadcrumb / .pagination | |
| 58 | - | .tabs + .tab.is-selected | |
| 58 | + | .tabs + .tab.chosen (chosen is makeover's) | |
| 59 | 59 | ||
| 60 | 60 | CONTROL MODIFIERS (compose onto buttons/inputs) | |
| 61 | 61 | .small / .btn-compact / .btn-link / .btn-tiny button sizes | |
| @@ -808,17 +808,25 @@ | |||
| 808 | 808 | flex-shrink: 0; | |
| 809 | 809 | } | |
| 810 | 810 | ||
| 811 | - | /* layout.css spells selection `.tab.chosen`; the site spells it | |
| 812 | - | `.is-selected`, and it spells it that way on git nav links, editor tabs, | |
| 813 | - | section tabs, issue tabs and filter buttons as well — one idiom across a | |
| 814 | - | dozen components that makeover has primitives for only some of. Renaming | |
| 815 | - | the tabs alone would split that idiom in two, so the name stays local and | |
| 816 | - | the VALUES are the generated ones: this is `.tab.chosen` under the site's | |
| 817 | - | own selection name. If the description layer ever emits the markup, the | |
| 818 | - | name goes with it and this rule goes away. */ | |
| 819 | - | .tab.is-selected { | |
| 820 | - | background: var(--surface-raised); | |
| 821 | - | box-shadow: var(--bevel-raised); | |
| 811 | + | /* A tab's selected state is `.tab.chosen` in layout.css and nowhere else now. | |
| 812 | + | This file used to carry a `.tab.is-selected` rule setting the same two | |
| 813 | + | declarations byte for byte, on the argument that `.is-selected` is the | |
| 814 | + | site's own idiom across git nav links, editor tabs, section tabs, issue tabs | |
| 815 | + | and filter buttons, so renaming the tabs alone would split it. That is true | |
| 816 | + | and it is still the wrong trade: a second name for a state the design system | |
| 817 | + | already names is invisible only while both say the same thing, and stops | |
| 818 | + | being invisible the moment makeover changes what a chosen tab looks like. | |
| 819 | + | The other components keep `.is-selected`, because makeover has no primitive | |
| 820 | + | for a git nav link; the tab has one. | |
| 821 | + | ||
| 822 | + | The chosen arm's box-shadow comes back through the layer rather than being | |
| 823 | + | restated. `.tab` below zeroes the base `button` shadow, and this file is | |
| 824 | + | unlayered, so it outranks @layer makeover whatever the specificity: without | |
| 825 | + | the revert, the generated bevel never applies and a chosen tab reads flat. | |
| 826 | + | `revert-layer` hands the property back instead of naming a value, which is | |
| 827 | + | the difference between deferring to the design system and copying it. */ | |
| 828 | + | .tab.chosen { | |
| 829 | + | box-shadow: revert-layer; | |
| 822 | 830 | } | |
| 823 | 831 | ||
| 824 | 832 | .tab-more-wrap { | |
| @@ -8694,25 +8702,6 @@ | |||
| 8694 | 8702 | outline-offset: 2px; | |
| 8695 | 8703 | } | |
| 8696 | 8704 | ||
| 8697 | - | /* makeover-tui and makeover-immediate emit their caret with a leading space; | |
| 8698 | - | the webview emitter appends the bare glyph, so the gap is the app's to put | |
| 8699 | - | back. Reserved on every sortable heading and not only the sorted one, or | |
| 8700 | - | pressing a header reflows the row it sits in. | |
| 8701 | - | ||
| 8702 | - | Box only, never `content`. This file outranks the `makeover` layer, so | |
| 8703 | - | declaring `content` on the sorted arm would win over the generated caret and | |
| 8704 | - | put the arrow back to nothing -- the same override this block deletes, one | |
| 8705 | - | property along. The empty box goes on the arm the generator does not match. */ | |
| 8706 | - | .table-heading[data-sortable]:not([aria-sort])::after { | |
| 8707 | - | content: ''; | |
| 8708 | - | } | |
| 8709 | - | ||
| 8710 | - | .table-heading[data-sortable]::after { | |
| 8711 | - | display: inline-block; | |
| 8712 | - | min-width: 1ch; | |
| 8713 | - | margin-left: var(--gap-bound); | |
| 8714 | - | } | |
| 8715 | - | ||
| 8716 | 8705 | /* Data-table column-width utilities (numeric width hints, | |
| 8717 | 8706 | kept as classes to avoid inline `style="width: NN%"`) */ | |
| 8718 | 8707 | .col-3 { width: 3%; } |
| @@ -38,7 +38,7 @@ | |||
| 38 | 38 | </header> | |
| 39 | 39 | ||
| 40 | 40 | <div class="tabs" role="tablist" aria-label="Item sections"> | |
| 41 | - | <button class="tab is-selected" | |
| 41 | + | <button class="tab chosen" | |
| 42 | 42 | role="tab" | |
| 43 | 43 | aria-selected="true" | |
| 44 | 44 | aria-controls="tab-content" |
| @@ -30,7 +30,7 @@ | |||
| 30 | 30 | </header> | |
| 31 | 31 | ||
| 32 | 32 | <div class="tabs" role="tablist" aria-label="Project sections"> | |
| 33 | - | <button class="tab is-selected" | |
| 33 | + | <button class="tab chosen" | |
| 34 | 34 | role="tab" | |
| 35 | 35 | aria-selected="true" | |
| 36 | 36 | aria-controls="tab-content" |
| @@ -74,7 +74,7 @@ | |||
| 74 | 74 | ||
| 75 | 75 | <div class="tabs" role="tablist" aria-label="Dashboard sections"> | |
| 76 | 76 | {% if deactivated %} | |
| 77 | - | <button class="tab is-selected" | |
| 77 | + | <button class="tab chosen" | |
| 78 | 78 | role="tab" | |
| 79 | 79 | aria-selected="true" | |
| 80 | 80 | aria-controls="tab-content" | |
| @@ -96,7 +96,7 @@ | |||
| 96 | 96 | </div> | |
| 97 | 97 | {% else %} | |
| 98 | 98 | {% if let Some(su) = session_user %}{% if su.can_create_projects %} | |
| 99 | - | <button class="tab is-selected" | |
| 99 | + | <button class="tab chosen" | |
| 100 | 100 | role="tab" | |
| 101 | 101 | aria-selected="true" | |
| 102 | 102 | aria-controls="tab-content" | |
| @@ -108,7 +108,7 @@ | |||
| 108 | 108 | hx-indicator="#tab-spinner" | |
| 109 | 109 | data-action="onSetActiveTab">Projects</button> | |
| 110 | 110 | {% endif %}{% endif %} | |
| 111 | - | <button class="tab{% if let Some(su) = session_user %}{% if !su.can_create_projects %} is-selected{% endif %}{% endif %}" | |
| 111 | + | <button class="tab{% if let Some(su) = session_user %}{% if !su.can_create_projects %} chosen{% endif %}{% endif %}" | |
| 112 | 112 | role="tab" | |
| 113 | 113 | aria-selected="{% if let Some(su) = session_user %}{% if !su.can_create_projects %}true{% else %}false{% endif %}{% endif %}" | |
| 114 | 114 | aria-controls="tab-content" |
| @@ -10,7 +10,7 @@ | |||
| 10 | 10 | <h1 class="page-title">Your Library</h1> | |
| 11 | 11 | ||
| 12 | 12 | <div class="tabs" role="tablist" aria-label="Library sections"> | |
| 13 | - | <button class="tab is-selected" | |
| 13 | + | <button class="tab chosen" | |
| 14 | 14 | role="tab" | |
| 15 | 15 | aria-selected="true" | |
| 16 | 16 | aria-controls="tab-content" |
| @@ -17,8 +17,11 @@ | |||
| 17 | 17 | const moreBtn = moreWrap.querySelector('.tab-more-btn'); | |
| 18 | 18 | const menu = moreWrap.querySelector('.tab-overflow-menu'); | |
| 19 | 19 | if (!moreBtn || !menu) return; | |
| 20 | - | const hasActive = menu.querySelector('.tab.is-selected'); | |
| 21 | - | moreBtn.classList.toggle('is-selected', !!hasActive); | |
| 20 | + | // `chosen` and not the site's `.is-selected`: the More button is built with | |
| 21 | + | // `className = 'tab tab-more-btn'`, so it is a tab and takes the tab's name | |
| 22 | + | // for the state. That name is makeover's, spelled once. | |
| 23 | + | const hasActive = menu.querySelector('.tab.chosen'); | |
| 24 | + | moreBtn.classList.toggle('chosen', !!hasActive); | |
| 22 | 25 | } | |
| 23 | 26 | ||
| 24 | 27 | function reflow(tabsEl: HTMLElement): void { | |
| @@ -113,10 +116,10 @@ | |||
| 113 | 116 | const container = btn.closest('.tabs'); | |
| 114 | 117 | if (!container) return; | |
| 115 | 118 | container.querySelectorAll('.tab').forEach((tab) => { | |
| 116 | - | tab.classList.remove('is-selected'); | |
| 119 | + | tab.classList.remove('chosen'); | |
| 117 | 120 | tab.setAttribute('aria-selected', 'false'); | |
| 118 | 121 | }); | |
| 119 | - | btn.classList.add('is-selected'); | |
| 122 | + | btn.classList.add('chosen'); | |
| 120 | 123 | btn.setAttribute('aria-selected', 'true'); | |
| 121 | 124 | const panel = document.getElementById('tab-content'); | |
| 122 | 125 | if (panel) panel.setAttribute('aria-labelledby', btn.id); |