From 1dcddec9e1efb00d84a02ab4c3183098a64690fc Mon Sep 17 00:00:00 2001 From: bot-backend Date: Thu, 27 Aug 2026 14:37:05 +0300 Subject: [PATCH] =?UTF-8?q?fix(mera/v2):=20=D0=BF=D0=BB=D0=B0=D1=88=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B8=20=D0=BB=D0=B5?= =?UTF-8?q?=D0=B6=D0=B0=D0=BB=D0=B0=20=D0=BD=D0=B0=20=D0=B3=D0=BB=D0=B0?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=D0=B9=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B5?= =?UTF-8?q?=20=D0=B8=20=D1=81=D1=8A=D0=B5=D0=B4=D0=B0=D0=BB=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B8=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Замер на проде 27.08 (окно 1512×900): плашка стояла в левом нижнем углу (`left:16; bottom:16`), а туда же приходит липкая кнопка «ОЦЕНИТЬ КВАРТИРУ» из панели параметров. Прямоугольники: кнопка 59…484 по X и 859…904 по Y, плашка 16…284 и 859…884 — перекрытие по всей высоте плашки. Следствий два, и второе хуже первого. Надпись на кнопке читалась разорванной. И `document.elementFromPoint` в центре кнопки возвращал плашку: клик по левой трети главного действия продукта не доходил до кнопки вообще. Плашка переезжает в правый нижний угол, НАД кнопку поддержки (44px от низа, z-index 25). Там свободно: ниже только пассивная «Сводка объекта» без органов управления — перекрыть её краем ничего не стоит. Вдобавок плашка становится сквозной для указателя, а ссылка «История версий» внутри — нет. Это страхует от повторения: что бы под плашкой ни оказалось в будущем, клик достанется ему, а не ей. Три теста закрепляют оба следствия разбора: якорь не левый, указатель проходит насквозь, ссылка жива. Прогон: 68 тестов зелёные, tsc чист. --- .../src/components/trade-in/VersionFooter.tsx | 24 +++++++-- .../trade-in/__tests__/VersionFooter.test.tsx | 50 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tradein-mvp/frontend/src/components/trade-in/__tests__/VersionFooter.test.tsx diff --git a/tradein-mvp/frontend/src/components/trade-in/VersionFooter.tsx b/tradein-mvp/frontend/src/components/trade-in/VersionFooter.tsx index 426e46df..2ae5cc80 100644 --- a/tradein-mvp/frontend/src/components/trade-in/VersionFooter.tsx +++ b/tradein-mvp/frontend/src/components/trade-in/VersionFooter.tsx @@ -29,10 +29,12 @@ import { formatVersionLabel } from "@/lib/buildInfo"; const styles = ` .version-footer{opacity:.72;transition:opacity .15s;} .version-footer:hover{opacity:1;} -.version-footer a{color:${tokens.muted2};text-decoration:underline;text-underline-offset:2px;} +/* Плашка сквозная для указателя, ссылка внутри — нет. Даже когда она + что-то перекрывает, клик уходит вниз, а не пропадает в ней. */ +.version-footer a{color:${tokens.muted2};text-decoration:underline;text-underline-offset:2px;pointer-events:auto;} .version-footer a:hover{color:${tokens.ink};} @media (max-width: 480px){ - .version-footer{left:10px !important;bottom:10px !important;padding:3px 7px !important;font-size:9px !important;gap:6px !important;} + .version-footer{right:10px !important;bottom:72px !important;padding:3px 7px !important;font-size:9px !important;gap:6px !important;} } `; @@ -51,8 +53,22 @@ export function VersionFooter() { className="version-footer" style={{ position: "fixed", - left: 16, - bottom: 16, + // НЕ левый нижний угол. Там же стоит липкая кнопка «ОЦЕНИТЬ + // КВАРТИРУ» из панели параметров, и плашка ложилась ровно на её + // левую треть: надпись читалась разорванной, а клик по этой трети + // попадал в плашку, а не в кнопку — главное действие продукта + // частично не работало. Снято с прода 27.08. + // + // Правый край свободен: там только кнопка поддержки (z-index 25, + // высота 44 от низа), над ней и встаём. Ниже — пассивная панель + // «Сводка объекта» без органов управления, перекрыть её краем + // ничего не стоит. + right: 16, + bottom: 80, + // Указатель сквозь плашку проходит насквозь (ссылка внутри — + // исключение, см. стили выше): что бы под ней ни оказалось, + // клик достанется ему. + pointerEvents: "none", // Below SupportButton (25) and every v2 HUD overlay — hides under // modals/drawers instead of floating on top of them, mirrors the // z-index reasoning documented in SupportButton.tsx. diff --git a/tradein-mvp/frontend/src/components/trade-in/__tests__/VersionFooter.test.tsx b/tradein-mvp/frontend/src/components/trade-in/__tests__/VersionFooter.test.tsx new file mode 100644 index 00000000..2eab094e --- /dev/null +++ b/tradein-mvp/frontend/src/components/trade-in/__tests__/VersionFooter.test.tsx @@ -0,0 +1,50 @@ +/** + * Плашка версии не должна воровать клик у главной кнопки продукта. + * + * Замер на проде 27.08.2026 (`/trade-in/v2`, окно 1512×900): плашка стояла + * `position: fixed; left: 16; bottom: 16` и попадала ровно на левую треть + * липкой кнопки «ОЦЕНИТЬ КВАРТИРУ» (её прямоугольник — 59…484 по X, 859…904 + * по Y, плашки — 16…284 и 859…884). Надпись читалась разорванной, а + * `document.elementFromPoint` в центре кнопки возвращал плашку — то есть + * клик по этой трети в кнопку не попадал вовсе. + * + * Здесь закрепляются оба следствия разбора: плашка не якорится к левому + * нижнему углу (там живёт кнопка) и не перехватывает указатель, что бы под + * ней ни оказалось. Ссылка «История версий» — единственное исключение, + * иначе она стала бы недоступной. + */ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { VersionFooter } from "../VersionFooter"; + +function badge(): HTMLElement { + const el = document.querySelector(".version-footer"); + if (!(el instanceof HTMLElement)) throw new Error("плашка версии не отрисовалась"); + return el; +} + +describe("VersionFooter", () => { + it("не занимает левый нижний угол — там липкая кнопка «ОЦЕНИТЬ КВАРТИРУ»", () => { + render(); + const { left, right, bottom } = badge().style; + expect(left, "плашка снова прижата влево, к главной кнопке").toBe(""); + expect(right).not.toBe(""); + // Кнопка поддержки — 44px от низа; встаём НАД ней, а не на неё. + expect(Number.parseInt(bottom, 10)).toBeGreaterThan(60); + }); + + it("не перехватывает указатель, а ссылка внутри — остаётся живой", () => { + render(); + expect(badge().style.pointerEvents).toBe("none"); + // Возврат кликабельности ссылке живёт в