fix(tradein/v2): UI/UX аудит round 2 — AA-контраст, честность чисел, a11y (#2081) #2086

Merged
lekss361 merged 1 commit from fix/tradein-v2-audit-round2 into main 2026-06-28 22:03:39 +00:00
Owner

Закрывает FE-часть аудита #2081 (round 2) живого /trade-in/v2 (МЕРА). Правки только в tradein-mvp/frontend/src/{app/v2,components/trade-in/v2} — прод-фронт trade-in. tsc --noEmit и next build зелёные локально (это и есть деплой-гейт; ci.yml не покрывает tradein-mvp/**).

Что сделано (FE)

🔴 CRITICAL

  • C1 tokens.ts — шкала muted дотемнена до WCAG AA (≥4.5:1 против худшего стопа холста #e6eef7, HSV-оттенок сохранён; ratios в комментах). Первичные лейблы по всем компонентам переведены muted*→body2 (иерархия); muted4 оставлен для истинных hint. Хардкод-hex не добавлен.

🟠 HIGH

  • H1 mappers.ts — чип «Планировка N-к» теперь выводится из комнатности, реально присутствующей в наборе аналогов (гетерогенный набор → «Все планировки»). Ни одно число/медиана не сдвинуты.
  • H2 ResultPanel.tsx — «ОЖИДАЕМАЯ ЦЕНА СДЕЛКИ» сделана хедлайном (accent рамка/тинт/glow + крупнее), «ДКП·Росреестр» демоутнут в muted-плитку «СПРАВОЧНО». Все 3 цены и mapResultPanel целы.
  • H3 mappers.tsparseAddress больше не теряет номер дома у адресов без префикса «ул/пр» («Белинского, 86» → с «86»); префиксный путь не тронут. (Нет FE test-инфры в tradein-mvp/frontend — проверено standalone-харнессом 6/6.)

🟡 MEDIUM

  • M4 page/HeroBar/Footer — мёртвые контролы (КАК РАССЧИТАНО / PDF / ДЕЙСТВИТЕЛЕН ДО / footer-валидность) гейтятся на hasEstimate = mounted && estimate && !insufficient (SSR-парити).
  • M5 LocationDrawer.tsx — настоящий role=dialog + aria-modal + aria-labelledby + focus-trap + <button aria-label> вместо <div> + Esc preventDefault/stopPropagation (+ inert когда закрыт).
  • M6 ParamsPanel.tsx — автокомплит адреса: combobox-ARIA + клавиатура (Arrow/Home/End/Enter/Escape), по образцу Dd.
  • M7 Sources/Cache/Analytics/History — ARIA-семантика таблиц (table/row/columnheader/cell) поверх грида; скролл-область Аналитики стала focusable (закрывает единственный serious axe scrollable-region-focusable); чарт-SVG получили role=img+<title>+aria-label.
  • M8 CacheView.tsx — колонка ВРЕМЯ нормализована (normTime, единая минутная точность).
  • M9 LocationDrawer.tsx — честный список источников «как считаем»: Циан, Я.Недвижимость, Авито, N1.ru + Росреестр. Домклик/Restate убраны как dead — согласовано с свежим мерджем #1968 (drop dead domklik/restate).
  • M10 ParamsPanel.tsx + mappers.ts(mapMarkers) — пин субъекта показывает свою площадь; аналог-пины, налегающие на центр субъекта, отбрасываются (раньше читались как данные субъекта).
  • M11 ObjectSummary/SourcesView — безымянное число подписано «медиана объявлений»; колонки/строки целиком «—» скрываются.
  • M13 page.tsx — clamp scale ≥0.88 (микро-типографика не падает ниже ~8px физ.).

🟢 LOW

  • L1 Аналитика — фейк-диапазон «X–X дн» при n<2 скрыт. L2 — пустая серия (Avito без данных) убрана из подзаголовка истории цен. L7 TopNav — хардкод #6f8195tokens.muted.

Не входит в этот PR

  • Batch D (backend/data-contract, НЕ FE-баги): M1 (счётчик источников X/7 vs плитки), M2 (asking_to_sold_ratio vs медианы), M3 (базы «среднего торга» vs «ожидаемой»), H4 (кросс-source дедуп кросс-постинга, связано с #1772). Математика мапперов верна — это рассинхрон данных бэка; заводится отдельной дочерней к #2036.
  • L6 (вынос blueprint-grid из background-image) отложен: базовый градиент + glass-поверхности всё равно держат axe-contrast в incomplete, поэтому L6 в одиночку не возвращает CI-аудит контраста. Авторитетная проверка контраста — ручной computed-color sweep (будет в post-deploy QA).

Верификация

  • tsc --noEmit = 0, next build = 0 (роут /v2 собран).
  • Pre-push code-reviewer: ⚠️ MINOR, без блокеров; 3 замечания пофикшены в этом же коммите (M9 dead-источники, dangling aria-controls, stale-коммент).
  • Полный Playwright golden-path + контраст-sweep + axe + клавиатура + responsive 1366/1440 — после деплоя на проде (pilottest), отчёт в #2081.

Self-merge при зелёном build.

Закрывает FE-часть аудита **#2081** (round 2) живого `/trade-in/v2` (МЕРА). Правки только в `tradein-mvp/frontend/src/{app/v2,components/trade-in/v2}` — прод-фронт trade-in. `tsc --noEmit` и `next build` зелёные локально (это и есть деплой-гейт; `ci.yml` не покрывает `tradein-mvp/**`). ## Что сделано (FE) **🔴 CRITICAL** - **C1** `tokens.ts` — шкала `muted` дотемнена до WCAG AA (≥4.5:1 против худшего стопа холста `#e6eef7`, HSV-оттенок сохранён; ratios в комментах). Первичные лейблы по всем компонентам переведены `muted*→body2` (иерархия); `muted4` оставлен для истинных hint. Хардкод-hex не добавлен. **🟠 HIGH** - **H1** `mappers.ts` — чип «Планировка N-к» теперь выводится из комнатности, реально присутствующей в наборе аналогов (гетерогенный набор → «Все планировки»). Ни одно число/медиана не сдвинуты. - **H2** `ResultPanel.tsx` — «ОЖИДАЕМАЯ ЦЕНА СДЕЛКИ» сделана хедлайном (accent рамка/тинт/glow + крупнее), «ДКП·Росреестр» демоутнут в muted-плитку «СПРАВОЧНО». Все 3 цены и `mapResultPanel` целы. - **H3** `mappers.ts` — `parseAddress` больше не теряет номер дома у адресов без префикса «ул/пр» («Белинского, 86» → с «86»); префиксный путь не тронут. (Нет FE test-инфры в `tradein-mvp/frontend` — проверено standalone-харнессом 6/6.) **🟡 MEDIUM** - **M4** `page/HeroBar/Footer` — мёртвые контролы (КАК РАССЧИТАНО / PDF / ДЕЙСТВИТЕЛЕН ДО / footer-валидность) гейтятся на `hasEstimate = mounted && estimate && !insufficient` (SSR-парити). - **M5** `LocationDrawer.tsx` — настоящий `role=dialog` + `aria-modal` + `aria-labelledby` + focus-trap + `<button aria-label>` вместо `<div>` + Esc `preventDefault/stopPropagation` (+ `inert` когда закрыт). - **M6** `ParamsPanel.tsx` — автокомплит адреса: combobox-ARIA + клавиатура (Arrow/Home/End/Enter/Escape), по образцу `Dd`. - **M7** `Sources/Cache/Analytics/History` — ARIA-семантика таблиц (table/row/columnheader/cell) поверх грида; скролл-область Аналитики стала focusable (закрывает единственный **serious** axe `scrollable-region-focusable`); чарт-SVG получили `role=img`+`<title>`+`aria-label`. - **M8** `CacheView.tsx` — колонка ВРЕМЯ нормализована (`normTime`, единая минутная точность). - **M9** `LocationDrawer.tsx` — честный список источников «как считаем»: Циан, Я.Недвижимость, Авито, N1.ru + Росреестр. **Домклик/Restate убраны** как dead — согласовано с свежим мерджем #1968 (drop dead domklik/restate). - **M10** `ParamsPanel.tsx` + `mappers.ts(mapMarkers)` — пин субъекта показывает свою площадь; аналог-пины, налегающие на центр субъекта, отбрасываются (раньше читались как данные субъекта). - **M11** `ObjectSummary/SourcesView` — безымянное число подписано «медиана объявлений»; колонки/строки целиком «—» скрываются. - **M13** `page.tsx` — clamp scale ≥0.88 (микро-типографика не падает ниже ~8px физ.). **🟢 LOW** - **L1** Аналитика — фейк-диапазон «X–X дн» при n<2 скрыт. **L2** — пустая серия (Avito без данных) убрана из подзаголовка истории цен. **L7** `TopNav` — хардкод `#6f8195` → `tokens.muted`. ## Не входит в этот PR - **Batch D (backend/data-contract, НЕ FE-баги):** M1 (счётчик источников X/7 vs плитки), M2 (`asking_to_sold_ratio` vs медианы), M3 (базы «среднего торга» vs «ожидаемой»), H4 (кросс-source дедуп кросс-постинга, связано с #1772). Математика мапперов верна — это рассинхрон данных бэка; заводится отдельной дочерней к #2036. - **L6** (вынос blueprint-grid из `background-image`) отложен: базовый градиент + glass-поверхности всё равно держат axe-contrast в `incomplete`, поэтому L6 в одиночку не возвращает CI-аудит контраста. Авторитетная проверка контраста — ручной computed-color sweep (будет в post-deploy QA). ## Верификация - `tsc --noEmit` = 0, `next build` = 0 (роут `/v2` собран). - Pre-push `code-reviewer`: ⚠️ MINOR, без блокеров; 3 замечания пофикшены в этом же коммите (M9 dead-источники, dangling `aria-controls`, stale-коммент). - Полный Playwright golden-path + контраст-sweep + axe + клавиатура + responsive 1366/1440 — **после** деплоя на проде (pilottest), отчёт в #2081. Self-merge при зелёном build.
lekss361 added 1 commit 2026-06-28 22:02:34 +00:00
fix(tradein/v2): UI/UX audit round 2 — AA contrast, honesty, a11y (#2081)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
f5a7f9b437
C1 (tokens): darken muted scale to WCAG AA (>=4.5:1 vs worst-case canvas
  #e6eef7); reclassify primary labels muted->body2 across components.
H1 (mappers): planning chip derived from rooms actually present in the
  analog set («Все планировки» when heterogeneous) — no number shifted.
H2 (ResultPanel): make «ОЖИДАЕМАЯ ЦЕНА СДЕЛКИ» the headline (accent
  border/tint/glow + larger value); demote ДКП·Росреестр to a muted
  СПРАВОЧНО reference tile. All three values + mapResultPanel wiring intact.
H3 (mappers): parseAddress keeps the house number for prefix-less
  addresses («Белинского, 86»); prefixed path unchanged.
M4 (page/HeroBar/Footer): gate dead controls (КАК РАССЧИТАНО / PDF /
  ДЕЙСТВИТЕЛЕН ДО / footer validity) on hasEstimate (mounted && estimate && !insufficient).
M5 (LocationDrawer): real dialog — role=dialog/aria-modal/aria-labelledby
  + focus-trap + <button> close + Esc preventDefault/stopPropagation.
M6 (ParamsPanel): address autocomplete -> combobox ARIA + Arrow/Home/End/
  Enter/Escape keyboard nav (mirrors Dd listbox).
M7 (Sources/Cache/Analytics/History): ARIA table semantics over the grids;
  Analytics scroll region keyboard-focusable (clears the serious
  scrollable-region-focusable axe violation); chart SVGs get role=img+title+aria-label.
M8 (CacheView): normalize the ВРЕМЯ column (normTime) to consistent minute precision.
M9 (LocationDrawer): honest «как считаем» source list (Циан, Я.Недвижимость,
  Авито, N1.ru + Росреестр) — drop dead Домклик/Restate per #1968.
M10 (ParamsPanel/mapMarkers): subject pin shows the subject's own area; drop
  analog pins overlapping the subject center (was misread as subject data).
M11 (ObjectSummary/SourcesView): label «медиана объявлений»; hide all-«—» columns/rows.
M13 (page): clamp artboard scale >=0.88 so micro-type doesn't drop below ~8px.
L1 (Analytics): suppress fake «X–Y дн» range when n<2.
L2 (Analytics): drop zero-data series from price-history subtitle.
L7 (TopNav): replace hardcoded #6f8195 icon strokes with tokens.muted.

tsc + next build green. No FE test infra in tradein-mvp/frontend — parseAddress
verified via standalone harness (6/6). Backend data-contract items M1/M2/M3/H4
(source counter, ratio vs medians, bargain bases, cross-source dedup) filed
separately — not FE bugs. L6 (blueprint-grid axe-blindness) deferred: base
gradient + glass surfaces keep axe contrast «incomplete» regardless, so the
authoritative check stays the manual computed-color sweep.
lekss361 added the
scope/frontend
tradein
ux
labels 2026-06-28 22:03:37 +00:00
lekss361 merged commit 89fb666d88 into main 2026-06-28 22:03:39 +00:00
lekss361 deleted branch fix/tradein-v2-audit-round2 2026-06-28 22:03:39 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2086
No description provided.