fix(header,tabs): tile-shaped header buttons beside the clustered stats, a bolder active ledger cell, one ledger row height (#426)

Header icon buttons next to the Tiles take the tile box (36px, border,
fill, 18px glyph) and turn into round chips beside the Compact pills;
the gear's quarter turn moves onto the glyph. The ledger's active cell
gets an inset second pixel and an accent bar (the skin's 1px !important
border was too quiet in a grid of look-alike cells), and every ledger
cell stretches to a 30px minimum so rows stay one height.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-06 04:08:02 +02:00
parent e3dfbf6591
commit bebf0db792
3 changed files with 97 additions and 0 deletions
+71
View File
@@ -20009,12 +20009,19 @@ html[data-session-list='sidebar'][data-sidebar='collapsed'] .session-sidebar .ta
display: grid;
grid-template-columns: repeat(auto-fill, minmax(176px, 1fr));
align-content: start;
/* The strip's own align-items: flex-start applies to grid items too; a
cell must stretch, or the active cell (taller with its actions) breaks
its row. */
align-items: stretch;
gap: 4px 6px;
}
.session-tabs-host > .session-tabs.tabs-ledger > .session-tab {
--ledger-bar: var(--green);
min-width: 0;
/* Tall enough for the active cell's actions, so every row is one height. */
min-height: 30px;
box-sizing: border-box;
gap: 7px;
padding: 4px 8px 4px 11px;
border: 1px solid var(--control-border);
@@ -20057,6 +20064,16 @@ html[data-session-list='sidebar'][data-sidebar='collapsed'] .session-sidebar .ta
.session-tabs-host > .session-tabs.tabs-ledger > .session-tab:is(.tab-agent-exited, .session-tab--web, :has(> .tab-status.stopped)) {
--ledger-bar: var(--text-muted);
}
/* The active cell has to win against a grid of look-alike cells. The skin's
active rule (1px accent border, no shadow, both !important) is too quiet
here, so an inset second pixel doubles the border without resizing the
cell, and the status bar turns accent. */
.session-tabs-host > .session-tabs.tabs-ledger > .session-tab.active {
background: rgba(var(--accent-rgb), 0.2) !important;
box-shadow: inset 0 0 0 1px var(--accent), inset 4px 0 0 var(--accent) !important;
color: var(--text) !important;
}
}
/* ============================================================
@@ -20355,6 +20372,60 @@ html[data-header-stats='tiles'] .header-plan-usage .pu-win-idle {
opacity: 0.55;
}
/* --- Header buttons next to the clustered stats ------------------------ */
/* Bare 16px glyphs beside 36px tiles read as a different design. In Tiles the
header's icon buttons take the tile box (same height, border and fill, a
larger icon); in Compact they become round chips the height of the pills.
Only the box changes: the marker classes still hide them, and the gear
keeps its quarter turn on hover, on the glyph rather than the whole box. */
html[data-header-stats='tiles'] .header-right > .btn-icon-header,
html[data-header-stats='compact'] .header-right > .btn-icon-header {
box-sizing: border-box;
background: var(--control-bg);
border: 1px solid var(--control-border);
color: var(--text-dim);
}
html[data-header-stats='tiles'] .header-right > .btn-icon-header {
width: 36px;
height: 36px;
border-radius: 7px;
}
html[data-header-stats='compact'] .header-right > .btn-icon-header {
width: 26px;
height: 26px;
border-radius: 13px;
}
html[data-header-stats='tiles'] .header-right > .btn-icon-header > svg {
width: 18px;
height: 18px;
}
html[data-header-stats='compact'] .header-right > .btn-icon-header > svg {
width: 15px;
height: 15px;
}
html[data-header-stats='tiles'] .header-right > .btn-icon-header:hover,
html[data-header-stats='compact'] .header-right > .btn-icon-header:hover {
background: var(--control-bg-hover);
border-color: var(--control-border-hover);
color: var(--text);
transform: none;
}
html[data-header-stats='tiles'] .header-right > .btn-icon-header > svg,
html[data-header-stats='compact'] .header-right > .btn-icon-header > svg {
transition: transform var(--transition-smooth);
}
html[data-header-stats='tiles'] .header-right > .btn-settings:hover > svg,
html[data-header-stats='compact'] .header-right > .btn-settings:hover > svg {
transform: rotate(45deg);
}
/* Before the first plan reading the chip holds a bare em dash; give it a tile
of its own so it does not read as a stray mark between the tiles. */
html[data-header-stats='tiles'] .header-plan-usage:not(:has(.pu-row)) {
+17
View File
@@ -205,6 +205,23 @@ describe('header stats wiring (static)', () => {
);
});
it('lays a tile out as three rows, so its height never depends on the font', () => {
// A bar laid over the bottom of a fixed-height tile is what let a taller
// system mono (SF Mono) push the value into it.
expect(css).toMatch(/grid-template-rows: 9px 14px 2px;\s*row-gap: 2px;/);
const tiles = css.slice(css.indexOf('/* --- Tiles: label over value'));
const bar = tiles.slice(tiles.indexOf("html[data-header-stats='tiles'] .header-system-stats .stat-bar,"));
expect(bar.slice(0, bar.indexOf('}'))).not.toContain('position: absolute');
expect(bar.slice(0, bar.indexOf('}'))).toContain('grid-row: 3;');
});
it('gives the header buttons the tile box beside the tiles', () => {
expect(css).toMatch(
/html\[data-header-stats='tiles'\] \.header-right > \.btn-icon-header \{\s*width: 36px;\s*height: 36px;/
);
expect(css).toMatch(/html\[data-header-stats='tiles'\] \.header-right > \.btn-icon-header > svg \{\s*width: 18px;/);
});
it('stamps data-header-stats before first paint, tiles by default and classic on narrow screens', () => {
expect(INDEX).toContain(
"dataset.headerStats=(window.innerWidth<768||solo)?'classic':(H==='classic'||H==='compact')?H:'tiles'"
+9
View File
@@ -287,6 +287,15 @@ describe('tab layouts by case and ledger (static)', () => {
expect(before).not.toContain('.tabs-ledger');
});
it('keeps every ledger row one height and makes the active cell stand out', () => {
const ledger = css.slice(css.indexOf('@media (min-width: 768px) {\n .session-tabs-host > .session-tabs.tabs-ledger {'));
expect(ledger).toContain('align-items: stretch;');
expect(ledger).toContain('min-height: 30px;');
expect(ledger).toMatch(
/\.tabs-ledger > \.session-tab\.active \{[^}]*box-shadow: inset 0 0 0 1px var\(--accent\), inset 4px 0 0 var\(--accent\) !important;/
);
});
it('dissolves the boxes into the one chip row on phones', () => {
expect(mobileCss).toMatch(
/:where\(\.header\) \.session-tabs-host > \.session-tabs\.tabs-clusters > \.tab-cluster \{\s*display: contents;/