fix(tabs): state rows start under the brand, labels left-aligned (#426)

In the desktop header strip grouped by state, the brand leaves the flow
and sits over the strip's top-left corner, so every row after the first
starts at the left edge under "Codeman" instead of leaving that corner
empty. Labels are left-aligned in the measured column; the first row's
heading takes its natural width beside the brand (--tab-triage-brand,
kept by a ResizeObserver so no render pass reads layout for it).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-06 06:25:26 +02:00
parent bebf0db792
commit bb5fd5ee97
5 changed files with 95 additions and 14 deletions
+21
View File
@@ -283,6 +283,17 @@ describe('tab grouping in the render paths (app.js)', () => {
]);
});
it('marks the first row heading as the lead, in either state order', () => {
const app = makeApp();
app._fullRenderSessionTabs();
const lead = () =>
[...container().querySelectorAll<HTMLElement>(':scope > .tab-triage-head--lead')].map((h) => h.dataset.triageGroup);
expect(lead()).toEqual(['needs']);
document.documentElement.dataset.tabStateOrder = 'urgent-last';
app._renderSessionTabsImmediate();
expect(lead()).toEqual(['idle']);
});
it('keeps the DOM, and with it the Alt+N badges, in tab order', () => {
makeApp()._fullRenderSessionTabs();
const domOrder = [...container().querySelectorAll<HTMLElement>('.session-tab[data-id]')].map((t) => t.dataset.id);
@@ -431,6 +442,16 @@ describe('tab grouping wiring (static)', () => {
);
});
it('lets the rows after the first start under the brand, labels left-aligned', () => {
expect(css).toMatch(
/\.header:has\(> \.session-tabs-host > \.session-tabs\.tabs-triage:is\(\.tabs-auto-wrap, \.tabs-two-rows\)\) > \.header-brand \{\s*position: absolute;/
);
expect(css).toMatch(/> \.tab-triage-head \{\s*justify-content: flex-start;/);
expect(css).toMatch(
/> \.tab-triage-head--lead \{\s*width: auto;\s*margin-left: calc\(var\(--tab-triage-brand, 100px\) - var\(--tab-triage-gutter, 92px\)\);/
);
});
it('hides the headings on phones, whose strip stays one scrolling row', () => {
expect(mobileCss).toMatch(/:where\(\.header\) \.tab-triage-head \{\s*display: none;/);
});