diff --git a/tradein-mvp/frontend/src/app/mera-public/_components/v3/HeaderV3.tsx b/tradein-mvp/frontend/src/app/mera-public/_components/v3/HeaderV3.tsx index 88d71e80..71c747de 100644 --- a/tradein-mvp/frontend/src/app/mera-public/_components/v3/HeaderV3.tsx +++ b/tradein-mvp/frontend/src/app/mera-public/_components/v3/HeaderV3.tsx @@ -17,17 +17,41 @@ * которой выпадашку когда-то читали, теперь стоит текстом в герое (плашка * «полное покрытие / данных меньше», HeroV3), то есть видна без клика. * - * НА УЗКОМ ЭКРАНЕ ШАПКА — ОДНА СТРОКА: лого и «Для бизнеса». Навигация по - * секциям и CTA скрыты в CSS (`landing-v3.module.css`, блок шапки) и - * возвращаются с той ширины, на которой шапка макета замерена как + * НА УЗКОМ ЭКРАНЕ ШАПКА — ОДНА СТРОКА: лого, «Для бизнеса» и кнопка меню. + * Развёрнутый ряд навигации и CTA скрыты в CSS (`landing-v3.module.css`, блок + * шапки) и возвращаются с той ширины, на которой шапка макета замерена как * однострочная, — а не с общего для файла шага в 720px, где она всё ещё * переносится. На 375px переносилось всё, и липкая шапка занимала 29% - * экрана — эти проценты отъедались при любой прокрутке. Куда делись пункты: «Точность» - * и «Проверьте себя» — секции этой же страницы, до них доезжают прокруткой - * (ради чего на мобильном и скроллят); «Статьи» и «МЕРА для бизнеса» стоят - * ссылками в подвале (`FooterV3`); «Продажа под ключ» и на десктопе не - * ссылка, а заглушка. CTA не потерян: снизу висит `StickyCtaV3` — на экране - * остаётся ОДИН призыв вместо двух одинаковых. + * экрана — эти проценты отъедались при любой прокрутке. + * + * ПОЧЕМУ ПОЯВИЛОСЬ МЕНЮ (31.08.2026). Прежняя редакция этого докстринга + * объясняла, куда делись пункты: «Точность» и «Проверьте себя» — секции этой + * же страницы, до них доезжают прокруткой; «Статьи» и «МЕРА для бизнеса» + * стоят ссылками в подвале (`FooterV3`). Довод про высоту шапки верен и + * оставлен в силе — а вот замена не проверялась замером: страница на 800px + * имеет высоту 11 316px, то есть «доехать прокруткой» до `#accuracy` и + * `#game` значит листать половину лэндинга, а до подвала — весь. Навигации на + * узком экране не было вовсе (все четыре пункта и кнопка отдавали + * `getBoundingClientRect` нулевого размера). Поэтому пункты возвращены, но НЕ + * в строку шапки: `
` — родная разворачивалка браузера, без + * JavaScript и без клиентского острова. Закрытое меню — одна кнопка, то есть + * высота липкой шапки прежняя (замер, ради которого её и сужали, сохранён); + * открытая панель лежит ПОВЕРХ страницы (`position: absolute`), а не + * раздвигает шапку. CTA не потерян и на закрытой шапке: снизу висит + * `StickyCtaV3` — на экране по-прежнему ОДИН призыв вместо двух одинаковых, + * второй виден только когда человек сам открыл меню. + * + * ПОТОЛОК РОДНОГО `
`: после клика по пункту меню остаётся открытым — + * закрыть его без JavaScript браузер не умеет, а клик по якорю страницу не + * перезагружает. Человек видит, куда уехал, и закрывает той же кнопкой. + * Апгрейд, если этого окажется мало: клиентский остров с onClick на пунктах + * (`setOpen(false)`) — но это первый клиентский компонент в шапке, поэтому + * заводить его стоит по жалобе, а не заранее. + * + * ПУНКТЫ ОПИСАНЫ ОДИН РАЗ (`NAV_ITEMS`) и рендерятся дважды: в ряду для + * широкого экрана и в панели меню. Список в коде, а не две копии разметки, — + * чтобы пункт не мог появиться в одном месте и потеряться в другом (ровно + * этим и был дефект: на широком экране навигация есть, на узком её нет). * * НЕАКТИВНЫЕ ПУНКТЫ (29.08.2026). Осталась одна «Продажа под ключ» — * партнёрской формы нет ни в коде, ни у владельца, и пункт остаётся видимым, @@ -53,6 +77,47 @@ import { B2B_URL } from "../../content"; import styles from "../../landing-v3.module.css"; import { PublicLink } from "../PublicLink"; +/** + * Пункты навигации — один список на оба места вывода (ряд шапки и панель + * меню). `href: null` — пункт-заглушка: раздела нет ни в коде, ни у владельца, + * поэтому он видим, но некликабелен (см. блок «НЕАКТИВНЫЕ ПУНКТЫ» выше). + * `route` — ключ `PUBLIC_ROUTES`: короткие адреса публичного домена + * выразимы только через `PublicLink`, next/link подставил бы basePath. + */ +const NAV_ITEMS = [ + { label: "Точность", href: "#accuracy" }, + { label: "Проверьте себя", href: "#game" }, + { label: "Продажа под ключ", href: null }, + { label: "Статьи", route: "articles" }, +] as const; + +function renderNavItem(item: (typeof NAV_ITEMS)[number]) { + if ("route" in item) { + return ( + + {item.label} + + ); + } + if (item.href === null) { + return ( + + {item.label} + + ); + } + return ( + + {item.label} + + ); +} + export function HeaderV3() { return (
@@ -68,22 +133,7 @@ export function HeaderV3() {
@@ -93,6 +143,23 @@ export function HeaderV3() { Проверить квартиру +
+ + +
+ + + Проверить квартиру + +
+
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 77568bc0..408c3bd8 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 @@ -46,6 +46,9 @@ а не режим работы). Навигация и CTA возвращаются в @media-блоке в конце секции. */ .hdrInner { + /* `position: relative` — база для панели меню (`.hdrMenuPanel`): открытая + панель лежит ПОВЕРХ страницы и не увеличивает высоту липкой шапки. */ + position: relative; max-width: 1280px; margin-inline: auto; padding: 8px clamp(20px, 5vw, 56px); @@ -156,6 +159,7 @@ } .hdrCta, +.hdrMenuCta, .barBtn { display: inline-flex; align-items: center; @@ -183,10 +187,87 @@ } .hdrCta:hover, +.hdrMenuCta:hover, .barBtn:hover { filter: brightness(0.92); } +/* Меню узкого экрана (HeaderV3). Заменяет собой скрытые здесь `.hdrNav` и + `.hdrCta`: до этого на узком экране навигации не было ВООБЩЕ — ни ряда, ни + меню, — и «Точность»/«Проверьте себя»/«Статьи» отдавали нулевой + getBoundingClientRect. Разворачивалка — родной `
`: без JavaScript, + то есть шапка остаётся серверной. + + Закрытое меню — одна кнопка, поэтому довод, ради которого ряд навигации + отсюда убирали (липкая шапка в 29% экрана на 375px), остаётся соблюдён: + высота строки прежняя. Открытая панель позиционируется абсолютно — она + лежит ПОВЕРХ страницы, а не раздвигает шапку. */ +.hdrMenu { + font-size: 14px; +} + +.hdrMenuBtn { + display: inline-flex; + align-items: center; + gap: 8px; + /* Паддинг по вертикали — 6px, а не 8: с ним кнопка укладывается в ту же + высоту строки, что и логотип, и липкая шапка на 800px остаётся 53px — + ровно как до появления меню (замер до/после). */ + padding: 6px 12px; + border: 1px solid var(--b2c-line); + border-radius: 6px; + font-weight: 600; + color: var(--b2c-ink); + cursor: pointer; + /* Родной маркер-треугольник убран, рядом стоит своя иконка: `list-style` + закрывает Firefox, `::-webkit-details-marker` — Safari. */ + list-style: none; +} + +.hdrMenuBtn::-webkit-details-marker { + display: none; +} + +/* Три полосы гамбургера одним элементом: сам элемент — средняя полоса, две + крайние нарисованы тенями. Дешевле трёх в разметке. */ +.hdrMenuIcon { + width: 16px; + height: 2px; + background: currentColor; + box-shadow: + 0 -5px 0 currentColor, + 0 5px 0 currentColor; +} + +.hdrMenuPanel { + position: absolute; + left: 0; + right: 0; + top: 100%; + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px clamp(20px, 5vw, 56px) 20px; + /* Фон непрозрачный (не color-mix, как у самой шапки): под панелью едет + контент страницы, и полупрозрачный слой делал бы пункты нечитаемыми. */ + background: var(--b2c-page-bg); + border-bottom: 1px solid var(--b2c-line); +} + +.hdrMenuNav { + display: flex; + flex-direction: column; + gap: 14px; + font-size: 15px; + font-weight: 600; +} + +.hdrMenuCta { + justify-content: center; + padding: 12px 20px; + font-size: 14.5px; +} + /* Шапка макета целиком — с той ширины, на которой она РЕАЛЬНО влезает в одну строку (замерено: 1000px — лого, четыре пункта, «Для бизнеса» и кнопка; на 720px то же самое переносится в две строки и даёт 109px липкого хрома, @@ -205,6 +286,11 @@ .hdrCta { display: inline-flex; } + + /* Меню не нужно: с этой ширины все его пункты стоят в строке шапки. */ + .hdrMenu { + display: none; + } } /* ========================================================================== @@ -363,8 +449,15 @@ /* Компенсация fixed-позиционирования `.barRoot` (тот вырезан из потока документа): без спейсера панель легла бы поверх последних пикселей страницы при докрутке до конца (реквизиты в подвале, последний вопрос - FAQ). Высота одна на все ширины: панель везде в одну строку — на узком - экране за счёт того, что текст скрыт (см. `.barText`), а не переносится. */ + FAQ). + + ВЫСОТА НЕ ОДНА НА ВСЕ ШИРИНЫ (31.08.2026). Здесь стояло 68px «на все + ширины», и на узком экране это верно (замер на проде, 800px: панель + 66,5px). Но с 1000px у панели растёт вертикальный паддинг и появляется + строка текста — замерено 70,5px, то есть спейсер был на 2,5px КОРОЧЕ + панели, и нижние пиксели подвала уходили под неё ровно там, где спейсер и + заводили. Второе значение стоит в том же @media-блоке, что и паддинг, + который его меняет, — чтобы правки не разъезжались. */ .barSpacer { height: 68px; } @@ -416,6 +509,12 @@ padding-block: 12px; } + /* Ровно та высота, которую панель занимает с этими паддингами (замер на + проде: 70,5px) плюс запас на округление подпикселей. */ + .barSpacer { + height: 72px; + } + .barText { display: block; }