style(web): close control-system gaps found in the deep sweep

This commit is contained in:
chick
2026-09-08 08:02:01 +08:00
parent c0adbcbc8a
commit bfe5025943
7 changed files with 100 additions and 30 deletions
@@ -66,7 +66,7 @@ afterEach(() => {
});
describe('painted control contrast', () => {
it('keeps every rendered control at WCAG AA', { timeout: 30_000 }, async () => {
it('keeps every rendered control at WCAG AA', { timeout: 60_000 }, async () => {
const raw = await readFile(
new URL('file:///Users/chick/.local/opt/multi-simadmin/apps/web/src/styles.css'),
'utf8',
+53 -1
View File
@@ -196,10 +196,62 @@ describe('button system', () => {
'',
);
expect(css).not.toMatch(
/#8a6722|#fff8e8|#fffafa|rgba\(17,\s*119,\s*110|rgba\(170,\s*120,\s*35|rgba\(183,\s*77,\s*72/,
/#8a6722|#fff8e8|#fffafa|rgba\(17,\s*119,\s*110|rgba\(170,\s*120,\s*35|rgba\(182,\s*77,\s*72/,
);
});
it('keeps disabled and unavailable states legible without fading controls', async () => {
const { rules } = await loadStylesheet();
const stateSelectors = [
'.risk-confirm:has(input:disabled)',
'.fleet-messages-device-item[data-unavailable]',
'.fleet-log-retention-value:disabled',
'.fleet-notification-entry-button:disabled',
'[class*=animal-btn-]:disabled',
];
const faded = rules
.filter(
(rule) =>
stateSelectors.some((selector) => rule.selector.includes(selector)) &&
rule.declarations.opacity !== undefined &&
rule.declarations.opacity !== '1',
)
.map((rule) => rule.selector);
expect(faded).toEqual([]);
});
it('does not leave stale compact command-control sizes in later overrides', async () => {
const { rules } = await loadStylesheet();
const compactControls = [
'.global-navigation a',
'.fleet-sidebar-toggle',
'.fleet-cross-health-item',
'.fleet-select-all button',
'.batch-entry-actions button',
'.fleet-card-context-trigger',
'.fleet-group-tabs button',
'.fleet-subnavigation a',
'.automation-workspace .row-actions button',
'.fleet-log-retention-actions .primary-action',
];
const stale = rules
.filter((rule) =>
compactControls.some((selector) => rule.selector.replace(/\s+/g, ' ').includes(selector)),
)
.filter((rule) => {
const heights = [rule.declarations['min-height'], rule.declarations.height].filter(
(value): value is string => value !== undefined,
);
return heights.some((value) =>
['1.9rem', '2rem', '2.15rem', '2.2rem', '2.25rem'].includes(value),
);
})
.map((rule) => rule.selector);
expect(stale).toEqual([]);
});
it('keeps workbench text and focus indicators on the accessible brand scale', async () => {
const { tokens, resolve } = await loadStylesheet();