Skip to main content

max / goingson

Take tab depth from the generated stylesheet makeover-layout 0.3.0 describes both halves of a selector, so the generated layout.css now carries the unchosen tab as well as the chosen one and this file's fills can go. Deleted: background from .ui-mode-desktop .tab (was --surface-sunken) and from its chosen state (was --surface-raised), plus the hover background. The generated rules supply the same two surface tokens, so the fills do not move. Hover does move, from --surface-overlay to --hover-surface, which is the same change button and card already took. Renamed the state class from active to chosen, matching what the crate emits. Five sites, all scoped to .tab-navigation .tab: index.html plus two loops each in navigation.js and projects.js. The mobile tab bar uses .mobile-tab and pill navigation uses .pill; both keep active and neither was touched. aria-selected is the accessible state and is unrelated, so it stays as it is. Kept deliberately, and it is not tidying: box-shadow: none on the chosen tab. The generated .tab.chosen carries Bevel::Raised, whose dark half lands on the bottom edge and would draw a line straight across the tab-to-pane join that the negative bottom margin exists to break. A folder tab needs its bottom edge open and a four-sided bevel cannot do that, which is why these tabs were drawn with a real border rather than a bevel to begin with. Whether Selector::Tabs should carry a bevel on its chosen state at all is a live question for the description.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-29 21:58 UTC
Signed with PGP, not checked
Commit: 914eec7e62dc93b2fdc08c873c5d30a3d57ec040
Parent: 325835d
5 files changed, +25 insertions, -14 deletions
M Cargo.lock +4 -4
@@ -3390,15 +3390,15 @@
3390 3390
3391 3391 [[package]]
3392 3392 name = "makeover-layout"
3393 - version = "0.2.0"
3393 + version = "0.3.0"
3394 3394 source = "registry+https://github.com/rust-lang/crates.io-index"
3395 - checksum = "a3ee0e7ee1b959eed5d3628ef7ca8901f00f5f62ae4c5601272fdd9a4d05052b"
3395 + checksum = "e220120a09f4ee3bf8e9a0959c3cde8bcb653827eda3f885f10671623b872252"
3396 3396
3397 3397 [[package]]
3398 3398 name = "makeover-webview"
3399 - version = "0.2.0"
3399 + version = "0.3.0"
3400 3400 source = "registry+https://github.com/rust-lang/crates.io-index"
3401 - checksum = "30a958bd1d5ba4e8d292d3c90f40dbcc59e9e1ebb96e03c97c3f7d30ed713199"
3401 + checksum = "d6c4dfda8103ba1abaeebd41c3fbb44678f3ab51a8e54a4002d3a76bc744e44c"
3402 3402 dependencies = [
3403 3403 "makeover-layout",
3404 3404 ]
@@ -41,7 +41,7 @@
41 41 <span class="mobile-view-title" id="mobile-view-title"></span>
42 42 </div>
43 43 <nav class="tab-navigation" role="tablist" aria-label="Main navigation">
44 - <a href="#" class="tab active" data-view="work" role="tab" aria-selected="true" aria-label="Work: tasks and projects">
44 + <a href="#" class="tab chosen" data-view="work" role="tab" aria-selected="true" aria-label="Work: tasks and projects">
45 45 <span class="tab-label">Work</span>
46 46 </a>
47 47 <a href="#" class="tab" data-view="time" role="tab" aria-selected="false" aria-label="Time: day planning, calendar, reviews">
@@ -490,6 +490,15 @@
490 490 gap: var(--gap-bound);
491 491 }
492 492
493 + /* Fills come from the generated layout.css: makeover-layout 0.3.0 describes
494 + both halves of a selector, so an unchosen tab is Depth::Sunken and the chosen
495 + one is Depth::Raised. Those are the same two tokens this file used to spell by
496 + hand, so nothing moves visually.
497 +
498 + The border stays here, and so does the bevel suppression below. A folder tab
499 + needs its bottom edge open to merge with the pane, and a four-sided bevel
500 + cannot do that -- which is why these tabs were drawn with a real border in the
501 + first place. */
493 502 .ui-mode-desktop .tab {
494 503 display: flex;
495 504 align-items: center;
@@ -497,7 +506,6 @@
497 506 padding: var(--gap-peer) var(--gap-section);
498 507 text-decoration: none;
499 508 color: var(--content-secondary);
500 - background: var(--surface-sunken);
501 509 border: var(--border-width) solid var(--border);
502 510 border-bottom: 0;
503 511 border-radius: var(--radius-sm) var(--radius-sm) 0 0;
@@ -505,7 +513,6 @@
505 513 }
506 514
507 515 .ui-mode-desktop .tab:hover {
508 - background: var(--surface-overlay);
509 516 color: var(--content);
510 517 }
511 518
@@ -513,11 +520,15 @@
513 520 strip's bottom line, breaking it: tab and pane become one shape. The
514 521 specimen writes the overlap as `top: 1px` on the unselected tabs; a
515 522 negative bottom margin says the same thing with the direction explicit,
516 - and the matching padding keeps every tab's label on one baseline. */
517 - .ui-mode-desktop .tab.active {
523 + and the matching padding keeps every tab's label on one baseline.
524 +
525 + box-shadow: none is load-bearing, not tidying. The generated .tab.chosen
526 + carries Bevel::Raised, whose dark half lands on the bottom edge and would
527 + draw a line straight across the join this rule exists to break. */
528 + .ui-mode-desktop .tab.chosen {
518 529 position: relative;
519 - background: var(--surface-raised);
520 530 color: var(--content);
531 + box-shadow: none;
521 532 margin-bottom: calc(-1 * var(--border-width));
522 533 padding-bottom: calc(var(--gap-peer) + var(--border-width));
523 534 }
@@ -120,13 +120,13 @@
120 120
121 121 // Update tab active state and aria-selected
122 122 document.querySelectorAll('.tab-navigation .tab').forEach(t => {
123 - t.classList.remove('active');
123 + t.classList.remove('chosen');
124 124 t.setAttribute('aria-selected', 'false');
125 125 });
126 126 if (parentTab) {
127 127 const activeTab = document.querySelector(`.tab-navigation [data-view="${parentTab}"]`);
128 128 if (activeTab) {
129 - activeTab.classList.add('active');
129 + activeTab.classList.add('chosen');
130 130 activeTab.setAttribute('aria-selected', 'true');
131 131 }
132 132 }
@@ -327,12 +327,12 @@
327 327
328 328 // Keep Work tab active in top nav
329 329 document.querySelectorAll('.tab-navigation .tab').forEach(t => {
330 - t.classList.remove('active');
330 + t.classList.remove('chosen');
331 331 t.setAttribute('aria-selected', 'false');
332 332 });
333 333 const workTab = document.querySelector('.tab-navigation [data-view="work"]');
334 334 if (workTab) {
335 - workTab.classList.add('active');
335 + workTab.classList.add('chosen');
336 336 workTab.setAttribute('aria-selected', 'true');
337 337 }
338 338