From 3b093686690d6cc4f7a064919110c7193f63c805 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sun, 30 Aug 2026 15:51:25 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D1=82:=20=D0=B4=D0=B2=D0=B0=20=D0=BE=D1=81=D1=82=D0=B0=D0=B2?= =?UTF-8?q?=D1=88=D0=B8=D1=85=D1=81=D1=8F=20=D0=BD=D0=B0=D1=80=D1=83=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=B0=20=D0=B6=D0=B8=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B5?= =?UTF-8?q?=20+=20=D1=81=D1=82=D0=BE=D1=80=D0=BE=D0=B6=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D1=81=D0=B5=D0=BA=D1=86=D0=B8=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проверка axe-правилом по ОТРЕНДЕРЕННЫМ узлам прода дала 32 → 2. Обе оставшиеся показательны, и одну из них завёл мой же вчерашний батч. .tickerNote (3.06) — подпись под тикером. Её добавила одна ветка, токены чинила другая; каждая по отдельности была права, вместе дали дефект: подпись взяла --b2c-muted (токен для СВЕТЛОГО фона) и легла на тёмную плашку #121A1D, где шкала перевёрнута. Красится --b2c-muted-dark, 6.20. .stepsLabelAccent (4.48) — «ШАГ 3 · 150 ₽» на карточке #EAF5F7. Сторож знал эту поверхность, но проверял accentDeep только как ЗАЛИВКУ (белый по нему), а CSS использует его ещё и как ЦВЕТ ТЕКСТА. accentDeep #0C7B8B → #0B7382: минимальный шаг, проходит текстом на всех трёх светлых поверхностях (4.99/5.15/5.54) и заодно улучшает главную кнопку — белый по нему 4.97 → 5.54. Две правки сторожа, обе про механизм, а не про случай: 1. accentDeep проверяется и как текст: токен, используемый двумя способами, обязан проверяться обоими. 2. Новый тест «в тёмных секциях не используются светлофоновые токены». Он ловит промах в ВЫБОРЕ токена, а не в его значении — тот класс, который и прошёл мимо. Список тёмных секций явный, но это снимок СЕКЦИЙ, а не нарушений: новое правило внутри известной секции ловится без правки списка. Фальсификация обеих: возврат accentDeep даёт «4.4775 >= 4.5», возврат .tickerNote на muted даёт «.tickerNote → --b2c-muted». Первую попытку фальсификации засчитывать было нельзя — подмена не сработала из-за добавленного комментария, и тест остался зелёным по построению. --- .../__tests__/contrast-tokens.test.ts | 47 +++++++++++++++++++ .../src/app/mera-public/b2c-tokens.ts | 2 +- .../src/app/mera-public/landing-v3.module.css | 4 +- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/tradein-mvp/frontend/src/app/mera-public/__tests__/contrast-tokens.test.ts b/tradein-mvp/frontend/src/app/mera-public/__tests__/contrast-tokens.test.ts index 674d2e71..8bee478f 100644 --- a/tradein-mvp/frontend/src/app/mera-public/__tests__/contrast-tokens.test.ts +++ b/tradein-mvp/frontend/src/app/mera-public/__tests__/contrast-tokens.test.ts @@ -65,6 +65,11 @@ describe("контраст токенов b2c", () => { ["ink", b2c.ink], ["muted", b2c.muted], ["accentText", b2c.accentText], + // accentDeep — не только заливка кнопки. `.stepsLabelAccent` красит им + // ТЕКСТ, и на surfaceSoft он давал 4.48: сторож проверял его лишь как + // подложку под белым и этого не видел. Токен, используемый двумя + // способами, обязан проверяться обоими. + ["accentDeep (как текст)", b2c.accentDeep], ["success", b2c.success], ["danger", b2c.danger], ]; @@ -106,6 +111,48 @@ describe("контраст токенов b2c", () => { expect(contrast(b2c.accentText, b2c.surfaceDark)).toBeLessThan(AA_NORMAL); }); + /** + * Правила ПОД ТЁМНЫМИ СЕКЦИЯМИ не должны краситься светлофоновыми токенами. + * + * Так и появился `.tickerNote` (3.06): подпись добавили в одной ветке, токены + * чинили в другой, каждая по отдельности была права — а вместе дали дефект. + * Тест выше его не поймал бы: он проверяет ЗНАЧЕНИЯ токенов, а промах здесь + * в ВЫБОРЕ токена для конкретной поверхности. + * + * Подложку правила из текста CSS не вывести, поэтому список тёмных секций + * задан явно — но это снимок СЕКЦИЙ, а не снимок нарушений: секции заводят + * раз в несколько месяцев, а правила внутри них правят постоянно. Новое + * правило в уже известной тёмной секции ловится без обновления списка. + */ + it("в тёмных секциях не используются светлофоновые токены текста", () => { + const css = readFileSync( + join(__dirname, "..", "landing-v3.module.css"), + "utf8", + ); + + /** Префиксы классов, чьи правила лежат на тёмной подложке. */ + const DARK_SECTIONS = ["ticker", "gameRowDark", "pathCardDark", "artCta", "gameMapBottom"]; + /** Токены, чья шкала рассчитана на СВЕТЛЫЙ фон. */ + const LIGHT_ONLY = ["--b2c-muted", "--b2c-accent-text", "--b2c-ink"]; + + const нарушения: string[] = []; + for (const [, selector, body] of css.matchAll(/\.([A-Za-z0-9_-]+)\s*\{([^}]*)\}/g)) { + if (!DARK_SECTIONS.some((p) => selector.startsWith(p))) continue; + const color = body.match(/(?:^|;|\n)\s*color:\s*var\((--b2c-[a-z-]+)\)/); + if (!color) continue; + // `--b2c-muted-dark` начинается с `--b2c-muted` — сравниваем точно. + if (LIGHT_ONLY.includes(color[1])) { + нарушения.push(`.${selector} → ${color[1]}`); + } + } + + expect( + нарушения, + "Тёмная секция красится токеном для светлого фона. На surfaceDark шкала " + + "перевёрнута: берите --b2c-muted-dark или --b2c-accent.", + ).toEqual([]); + }); + it("accent не используется как текст на светлом: он и не может", () => { // Ради этого в палитре и живёт отдельный accentText. Ассерт фиксирует // причину, чтобы «упростить до одного акцента» нельзя было молча. diff --git a/tradein-mvp/frontend/src/app/mera-public/b2c-tokens.ts b/tradein-mvp/frontend/src/app/mera-public/b2c-tokens.ts index ccc2b690..383dbc1e 100644 --- a/tradein-mvp/frontend/src/app/mera-public/b2c-tokens.ts +++ b/tradein-mvp/frontend/src/app/mera-public/b2c-tokens.ts @@ -93,7 +93,7 @@ export const b2c = { /** Акцент — заливки/обводки/декор. НЕ для текста, см. шапку. */ accent: "#16A9BC", /** Акцент для заливки кнопок (под белым текстом). */ - accentDeep: "#0C7B8B", + accentDeep: "#0B7382", /** Акцент для ТЕКСТА — затемнён до AA. */ accentText: "#0B6B79", /** Текст на акцентной заливке. */ diff --git a/tradein-mvp/frontend/src/app/mera-public/landing-v3.module.css b/tradein-mvp/frontend/src/app/mera-public/landing-v3.module.css index 3e18e252..77568bc0 100644 --- a/tradein-mvp/frontend/src/app/mera-public/landing-v3.module.css +++ b/tradein-mvp/frontend/src/app/mera-public/landing-v3.module.css @@ -1414,7 +1414,9 @@ font-family: var(--b2c-font-mono); font-size: 10px; letter-spacing: 0.06em; - color: var(--b2c-muted); + /* Плашка тикера тёмная (#121A1D) — шкала здесь ПЕРЕВЁРНУТА, и `muted` + (светлофоновый токен) даёт на ней 3.06. Светлый конец палитры: 6.20. */ + color: var(--b2c-muted-dark); } .tickerBadge { position: absolute;