Cap rail title size and keep compact type to launchers

The rail titles took the dock's rem type inside fixed 176px launchers, so a
larger browser font cut collapsed titles such as Recent Imagery short. Cap
the rail type at its 16px-root size.

The compact type for translated titles now skips Chinese and Japanese,
which fit at full size and keep their 9px floor, and reaches only the rail's
own launchers, so Radio inside Context keeps its type.

Tests now check the launcher divider, gap, toggle margin and flex-shrink
rules by their declarations, not only their selectors.
This commit is contained in:
Said Turksever committed 2026-10-30 15:26:21 +00:00
1 parent 47f3377d2b
commit ab1239d3ed
2 files changed
+81 -17

No files matched your search

+67 -10
View File
@@ -9,7 +9,10 @@ const clean = (selector) =>
.replace(/\s+/g, ' ')
.trim();
const rules = [...css.matchAll(/([^{}]+)\{([^{}]*)\}/g)].map(
([, selector, body]) => ({ selector: clean(selector), body }),
([, selector, body]) => ({
selector: clean(selector),
body: body.replace(/\/\*[\s\S]*?\*\//g, ''),
}),
);
const railRules = rules.filter(({ selector }) =>
selector.includes('#left-panel-stack, #right-context-rail'),
@@ -94,6 +97,47 @@ test('collapsed launchers on both rails keep titles inside the card', () => {
);
assert.ok(translated, 'translated collapsed titles must fit on both rails');
assert.match(translated.body, /font-size:\s*8px/);
// Chinese and Japanese titles fit at full size; 8px would put them under
// the 9px CJK floor in cjk.css.
assert.match(translated.selector, /:not\(:lang\(zh\)\):not\(:lang\(ja\)\)/);
// Only the rail's own launchers: Radio, nested in Context, keeps its type.
assert.match(
translated.selector,
/#right-context-rail\) > \.panel-collapsible\.collapsed > \[class\$='-panel-inner'\] > \.panel-header > \.panel-title$/,
);
});
test('a collapsed launcher drops its divider so English titles fit whole', () => {
const launcher = (tail) =>
railRules.filter(({ selector }) =>
selector
.split(/,(?![^(]*\))/)
.some((part) =>
part
.trim()
.endsWith(
`.collapsed > [class$='-panel-inner'] > .panel-header${tail}`,
),
),
);
const [header] = launcher('');
const [divider] = launcher(' > .panel-divider');
const [toggle] = launcher(' > .panel-collapse-btn');
assert.match(header?.body || '', /gap:\s*8px/, 'the launcher header gap');
assert.match(divider?.body || '', /display:\s*none/, 'the launcher divider');
assert.match(
toggle?.body || '',
/margin-left:\s*auto/,
'the launcher toggle',
);
const button = rules.find(
({ selector }) => selector === '.panel-collapse-btn',
);
assert.match(
button?.body || '',
/flex-shrink:\s*0/,
'a long title must not squeeze the toggle',
);
});
test('the default theme geometry change leaves cyber gutters alone', () => {
@@ -122,13 +166,21 @@ test('rail titles and dock labels share one set of label tokens', () => {
const rail = railRules.find(({ body }) =>
/--dock-label-font-size/.test(body),
);
for (const body of [dock?.body, rail?.body]) {
assert.match(body || '', /font-size:\s*var\(--dock-label-font-size\)/);
assert.match(
body || '',
/letter-spacing:\s*var\(--dock-label-letter-spacing\)/,
);
}
assert.match(dock?.body || '', /font-size:\s*var\(--dock-label-font-size\)/);
assert.match(
dock?.body || '',
/letter-spacing:\s*var\(--dock-label-letter-spacing\)/,
);
// The dock's rem type, capped at its 16px-root size: a collapsed launcher
// is a fixed 176px, so a larger browser font must not cut titles short.
assert.match(
rail?.body || '',
/font-size:\s*min\(var\(--dock-label-font-size\),\s*9\.28px\)/,
);
assert.match(
rail?.body || '',
/letter-spacing:\s*min\(var\(--dock-label-letter-spacing\),\s*2\.08px\)/,
);
});
test('default theme overrides never reach the cyber theme', () => {
@@ -165,8 +217,13 @@ test('default theme overrides never reach the cyber theme', () => {
});
test('launcher compaction and header colour stay on the rail panels themselves', () => {
const compact = railRules.filter(({ selector }) =>
/\.collapsed > \[class\$='-panel-inner'\] > \.panel-header/.test(selector),
// The divider, gap and toggle rules; the translated type rule is checked
// above.
const compact = railRules.filter(
({ selector }) =>
/\.collapsed > \[class\$='-panel-inner'\] > \.panel-header/.test(
selector,
) && !selector.startsWith('html:'),
);
assert.equal(compact.length, 3);
for (const { selector } of compact) {
+14 -7
View File
@@ -82,13 +82,16 @@
}
/* Side panel titles read like the command dock's labels: one type for every
panel, collapsed or open, and bright enough to read over the globe. */
panel, collapsed or open, and bright enough to read over the globe. The
dock's type is in rem, but a collapsed launcher is a fixed 176px, so the
rail caps it at its 16px-root size: a larger browser font must not cut
Recent Imagery short. */
:is(#left-panel-stack, #right-context-rail)
:is(.panel-header > .panel-title, .pp-header-label) {
font-family: var(--font-mono);
font-size: var(--dock-label-font-size);
font-size: min(var(--dock-label-font-size), 9.28px);
font-weight: var(--dock-label-font-weight);
letter-spacing: var(--dock-label-letter-spacing);
letter-spacing: min(var(--dock-label-letter-spacing), 2.08px);
text-transform: uppercase;
}
@@ -165,11 +168,15 @@
/* Translated titles run longer (Aktuelle Bilddaten), so a collapsed rail
launcher sets them in compact type rather than pushing the disclosure
button out of the card or cutting the word short. */
html:not([lang='en'])
button out of the card or cutting the word short. Chinese and Japanese
titles fit at full size and stay at or above their 9px floor (cjk.css);
Radio, nested in Context, is not a launcher. */
html:not([lang='en']):not(:lang(zh)):not(:lang(ja))
:is(#left-panel-stack, #right-context-rail)
.panel-collapsible.collapsed
.panel-title {
> .panel-collapsible.collapsed
> [class$='-panel-inner']
> .panel-header
> .panel-title {
font-size: 8px;
letter-spacing: 1px;
}