🐛 fix(driver-manager): 修复进度条越界与按钮对比度 (#773)

- 为驱动进度条增加稳定样式边界并允许控件收缩
- 优化设置中心嵌入布局的版本与进度网格轨道
- 将浅色主按钮调整为满足 AA 对比度的深绿底白字
- 增加嵌入布局和颜色对比度回归测试

Refs #773
This commit is contained in:
Syngnat
2026-07-30 16:01:42 +08:00
parent bf3f221857
commit 1a39d45011
5 changed files with 69 additions and 7 deletions

View File

@@ -2245,6 +2245,12 @@ body[data-platform='windows'] .titlebar-window-controls {
.driver-manager-control-block {
display: grid;
gap: 4px;
min-width: 0;
}
.driver-manager-progress.ant-progress-line {
width: 100%;
min-width: 0;
}
.driver-manager-control-label,
@@ -2466,7 +2472,7 @@ body[data-platform='windows'] .titlebar-window-controls {
.driver-manager-shell.is-embedded .driver-manager-card-controls {
display: grid;
grid-template-columns: minmax(150px, 1fr) minmax(110px, 0.7fr);
grid-template-columns: minmax(0, 1fr) minmax(96px, 0.7fr);
align-content: start;
gap: 7px 12px;
}

View File

@@ -0,0 +1,56 @@
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { readV2ThemeCss } from '../test/readV2ThemeCss';
const appCss = readFileSync(
fileURLToPath(new globalThis.URL('../App.css', import.meta.url)),
'utf8',
);
const v2ThemeCss = readV2ThemeCss();
const relativeLuminance = (hex: string): number => {
const channels = [1, 3, 5]
.map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16) / 255)
.map((channel) => (
channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4
));
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2];
};
const contrastRatio = (foreground: string, background: string): number => {
const light = Math.max(relativeLuminance(foreground), relativeLuminance(background));
const dark = Math.min(relativeLuminance(foreground), relativeLuminance(background));
return (light + 0.05) / (dark + 0.05);
};
const readHexToken = (cssBlock: string, token: string): string => {
const match = cssBlock.match(new RegExp(`${token}\\s*:\\s*(#[0-9a-f]{6})`, 'i'));
if (!match?.[1]) throw new Error(`Missing token ${token}`);
return match[1];
};
describe('DriverManagerModal embedded layout', () => {
it('keeps the version and progress controls shrinkable inside the settings panel', () => {
expect(appCss).toMatch(
/\.driver-manager-shell\.is-embedded \.driver-manager-card-controls\s*\{[^}]*grid-template-columns:\s*minmax\(0,\s*1fr\)\s+minmax\(96px,\s*0\.7fr\)/s,
);
expect(appCss).toMatch(
/\.driver-manager-control-block\s*\{[^}]*min-width:\s*0/s,
);
expect(appCss).toMatch(
/\.driver-manager-progress\.ant-progress-line\s*\{[^}]*width:\s*100%[^}]*min-width:\s*0/s,
);
});
it('keeps light-theme primary buttons at accessible contrast', () => {
const lightBlock = v2ThemeCss.match(
/body\[data-ui-version="v2"\]\[data-theme="light"\]\s*\{([^}]*)\}/s,
)?.[1];
expect(lightBlock).toBeTruthy();
const foreground = readHexToken(lightBlock || '', '--gn-on-accent');
const background = readHexToken(lightBlock || '', '--gn-accent-strong');
expect(contrastRatio(foreground, background)).toBeGreaterThanOrEqual(4.5);
});
});

View File

@@ -98,7 +98,7 @@ vi.mock('antd', () => {
})}
</select>
);
const Progress = () => <div data-progress="true" />;
const Progress = (props: any) => <div data-progress="true" {...props} />;
const Tag = ({ children }: any) => <span>{children}</span>;
const Switch = ({ checked, onChange, disabled }: any) => (
<button type="button" disabled={disabled} data-switch-checked={String(checked)} onClick={() => onChange?.(!checked)}>
@@ -245,6 +245,7 @@ describe('DriverManagerModal toolbar actions', () => {
background: 'transparent',
});
expect(findButton(embeddedRenderer!, t('driver.modal.card.action.install')).props.size).toBe('small');
expect(embeddedRenderer!.root.findByProps({ 'data-progress': 'true' }).props.className).toBe('driver-manager-progress');
let modalRenderer: ReactTestRenderer;
await act(async () => {

View File

@@ -1805,9 +1805,9 @@ const DriverManagerModal: React.FC<{ open: boolean; onClose: () => void; onBack?
{row.builtIn ? (
<Text type="secondary">{t('driver.modal.card.noInstallNeeded')}</Text>
) : hasActiveProgress ? (
<Progress percent={progress.percent} status={progress.status} size="small" />
<Progress className="driver-manager-progress" percent={progress.percent} status={progress.status} size="small" />
) : (
<Progress percent={0} size="small" />
<Progress className="driver-manager-progress" percent={0} size="small" />
)}
</div>
{renderDriverActions(row)}

View File

@@ -48,9 +48,8 @@ body[data-ui-version="v2"][data-theme="light"] {
--gn-accent: #15803d;
--gn-accent-2: #166534;
--gn-accent-soft: #dcfce7;
/* --gn-on-accent 此前未定义,所有 var(--gn-on-accent, #fff) 都回退成白字:
白字压在 #16a34a 上仅 3.30,不满足 WCAG AA 的 4.5。深绿可得 4.52。 */
--gn-on-accent: #052e16;
/* 浅色主题的主操作使用深绿填充,白色前景对 #15803d 的对比度为 5.02。 */
--gn-on-accent: #ffffff;
--gn-accent-strong: #15803d;
--gn-accent-strong-hover: #126634;
--gn-accent-strong-active: #0d4d27;