fix(ui): improve financial text contrast

TD-010: use readable semantic text colors on financial surfaces while preserving signs
and state meanings.
This commit is contained in:
2026-09-21 21:10:10 +03:00
parent 6a87379813
commit c86be7bf73
4 changed files with 53 additions and 8 deletions
+45
View File
@@ -0,0 +1,45 @@
import { describe, expect, it } from "vitest";
import tokens from "./tokens.json";
function luminance(color: string) {
const channels = [1, 3, 5]
.map((index) => Number.parseInt(color.slice(index, index + 2), 16) / 255)
.map((value) =>
value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4,
);
return channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
}
describe("financial text contrast", () => {
it.each(["positive", "negative"] as const)(
"keeps %s readable on journal, position and tinted card surfaces",
(tone) => {
const role = tokens.color.roles[tone];
const palettes = tokens.color.palettes;
const foreground =
palettes[role.color as keyof typeof palettes][role.shade];
const surfaces = [
palettes.gray[0],
...Object.entries(palettes)
.filter(([name]) => name !== "dark")
.map(
([, palette]) =>
`#${[1, 3, 5]
.map((index) =>
Math.round(
Number.parseInt(palette[0].slice(index, index + 2), 16) *
0.45 +
255 * 0.55,
)
.toString(16)
.padStart(2, "0"),
)
.join("")}`,
),
];
for (const background of surfaces)
expect(
(luminance(background) + 0.05) / (luminance(foreground) + 0.05),
).toBeGreaterThanOrEqual(4.5);
},
);
});
+3 -3
View File
@@ -53,7 +53,7 @@
"#40c057",
"#37b24d",
"#2f9e44",
"#2b8a3e"
"#237032"
],
"red": [
"#fff5f5",
@@ -151,12 +151,12 @@
},
"positive": {
"color": "green",
"shade": 6,
"shade": 9,
"description": "Положительный результат; дополните знаком и текстом"
},
"negative": {
"color": "red",
"shade": 6,
"shade": 9,
"description": "Ошибка / отрицательный результат; дополните текстом"
},
"warning": {
+3 -3
View File
@@ -19,15 +19,15 @@
}
.positive {
color: var(--mantine-color-green-6);
color: var(--wl-color-positive);
}
.negative {
color: var(--mantine-color-red-6);
color: var(--wl-color-negative);
}
.neutral {
color: var(--mantine-color-dimmed);
color: var(--mantine-color-gray-7);
}
@media (max-width: 36em) {