fix(temporary-notes): баннер временной заметки на мобильном — адаптивные icon-only действия + flex-basis (#321) #322

Merged
vvzvlad merged 1 commits from fix/321-banner-mobile into develop 2026-07-04 00:00:38 +03:00
Collaborator

Summary

На узком экране (~390px) баннер временной заметки разваливался: текст сжимался в «лесенку» по слову на строку, а переполняющие слова уезжали под прозрачную кнопку «Move to trash». Две layout-причины, обе починены (только разметка, без правки хендлеров/логики/i18n):

  • Текстовая Group имела flex: 1 (= basis 0), поэтому внешний wrap="wrap" НИКОГДА не уводил кнопки на вторую строку — вместо этого давил текст. Дал ненулевой базис (flex: 1 1 16rem), теперь wrap реально срабатывает на узком контейнере.
  • Скопировал адаптивный паттерн из DeletedPageBanner: подписи-кнопки visibleFrom="sm", icon-only ActionIcon + Tooltip + aria-label hiddenFrom="sm" (те же хендлеры, loading-флаги, t()-ключи). Это чинит и ru-локаль (длинные подписи на мобильном не рендерятся).

Соседний DeletedPageBanner уже использует этот паттерн; при добавлении второй кнопки в #273/#277 адаптивную часть не перенесли.

closes #321

How verified

  • tsc --noEmit — без ошибок в файле; eslint — чисто.
  • Правка layout-only: оба действия (trash / make-permanent) идут через те же handleTrashNow/handleMakePermanent, те же isDeleting/toggleTemporary.isPending и те же t("Move to trash")/t("Make permanent"), что и десктопные кнопки — на >= sm вид не меняется, на < sm появляется icon-only ряд.
  • Тест не добавлял: в проекте нет ни temporary-note-banner.test.tsx, ни render-харнесса для баннеров (MantineProvider + моки мутаций); поднимать его ради layout-only правки, зеркалящей уже отгруженный (и не покрытый тестом) DeletedPageBanner, непропорционально. Адаптивность — чистый CSS (visibleFrom/hiddenFrom).

Checklist

  • на мобильном текст читается с нормальными переносами, оба действия доступны и не накладываются; согласовано с DeletedPageBanner
  • вне scope не менялось (хендлеры/логика/i18n/десктоп-вид)

Примечание: deleted-page-banner.tsx имеет тот же латентный flex:1-нюанс, но его мобильный ряд уже icon-only (узкий) и до переполнения не доходит — не трогал, чтобы не расширять scope (как и предложено в issue опциональным пунктом).

## Summary На узком экране (~390px) баннер временной заметки разваливался: текст сжимался в «лесенку» по слову на строку, а переполняющие слова уезжали под прозрачную кнопку «Move to trash». Две layout-причины, обе починены (только разметка, без правки хендлеров/логики/i18n): - Текстовая `Group` имела `flex: 1` (= basis 0), поэтому внешний `wrap="wrap"` НИКОГДА не уводил кнопки на вторую строку — вместо этого давил текст. Дал ненулевой базис (`flex: 1 1 16rem`), теперь wrap реально срабатывает на узком контейнере. - Скопировал адаптивный паттерн из `DeletedPageBanner`: подписи-кнопки `visibleFrom="sm"`, icon-only `ActionIcon` + `Tooltip` + `aria-label` `hiddenFrom="sm"` (те же хендлеры, loading-флаги, `t()`-ключи). Это чинит и ru-локаль (длинные подписи на мобильном не рендерятся). Соседний `DeletedPageBanner` уже использует этот паттерн; при добавлении второй кнопки в #273/#277 адаптивную часть не перенесли. closes #321 ## How verified - `tsc --noEmit` — без ошибок в файле; `eslint` — чисто. - Правка layout-only: оба действия (trash / make-permanent) идут через те же `handleTrashNow`/`handleMakePermanent`, те же `isDeleting`/`toggleTemporary.isPending` и те же `t("Move to trash")`/`t("Make permanent")`, что и десктопные кнопки — на `>= sm` вид не меняется, на `< sm` появляется icon-only ряд. - Тест не добавлял: в проекте нет ни `temporary-note-banner.test.tsx`, ни render-харнесса для баннеров (MantineProvider + моки мутаций); поднимать его ради layout-only правки, зеркалящей уже отгруженный (и не покрытый тестом) `DeletedPageBanner`, непропорционально. Адаптивность — чистый CSS (`visibleFrom`/`hiddenFrom`). ## Checklist - [x] на мобильном текст читается с нормальными переносами, оба действия доступны и не накладываются; согласовано с `DeletedPageBanner` - [x] вне scope не менялось (хендлеры/логика/i18n/десктоп-вид) Примечание: `deleted-page-banner.tsx` имеет тот же латентный `flex:1`-нюанс, но его мобильный ряд уже icon-only (узкий) и до переполнения не доходит — не трогал, чтобы не расширять scope (как и предложено в issue опциональным пунктом).
agent_coder added 1 commit 2026-07-03 23:18:10 +03:00
On narrow screens the temporary-note banner squeezed its text into a
one-word-per-line ladder and overflowing words slid under the subtle
"Move to trash" button. Two layout causes, both fixed here (layout-only; no
handler/logic/i18n changes):

- The text Group had `flex: 1` (= basis 0), so the outer `wrap="wrap"` never
  wrapped the buttons to a second row — it crushed the text instead. Give it a
  non-zero basis (`flex: 1 1 16rem`) so the wrap engages on narrow containers.
- Mirror DeletedPageBanner's adaptive actions: labeled Buttons visibleFrom="sm",
  icon-only ActionIcon + Tooltip + aria-label hiddenFrom="sm" (same handlers,
  loading flags, and t() keys). This also fixes the ru locale, whose long labels
  no longer render on mobile.

The sibling DeletedPageBanner already uses this pattern; adding the second button
in #273/#277 didn't carry the adaptive part over.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder added the review/needs label 2026-07-03 23:18:10 +03:00
Collaborator

Ревью — #322 (fix(temporary-notes): баннер временной заметки на мобильном — адаптивные icon-only действия + flex-basis, #321), round 1, head ba94def3, base develop

Scope: полный дифф PR e1b8f81b..ba94def3 — 1 файл temporary-note-banner.tsx (+68/−24), разметка-only. Клиент-only. Полный веер 9 аспектов.

Вердикт: PASS — фикс корректный и целен, регрессий нет, объективка зелёная. Готово к мержу.

Объективка запущена мной (детач ba94def3, main-клон): client tsc --noEmit0. (Юнит-теста для этого баннера в проекте нет — см. ниже про покрытие; релевантная объективка для разметочной правки — tsc, зелёный.)

Подтверждено по коду

  • Фикс достигает цели (#321), обе причины. (1) Текстовая Group сменила flex: 1 (basis 0%, из-за чего внешний wrap="wrap" никогда не уводил кнопки на вторую строку, а давил текст в «лесенку») на flex: "1 1 16rem" (:86) — теперь при узком контейнере wrap реально срабатывает. (2) Скопирован адаптивный паттерн DeletedPageBanner: текст-кнопки visibleFrom="sm" (:106), icon-only ActionIcon+Tooltip+aria-label hiddenFrom="sm" (:129-154).
  • Регрессий нет, десктоп не тронут. handleTrashNow/handleMakePermanent байт-идентичны (вне диффа); ОБА брейкпоинта зовут ОДНИ хендлеры с ОДНИМИ loading-флагами (isDeleting/toggleTemporary.isPending) и ОДНИМИ t()-ключами ("Move to trash"/"Make permanent"). Mantine ActionIcon loading дизейблит так же, как Button loading → double-fire нет. Обе Group в DOM, но неактивная скрыта display:none → дубль-onClick не стреляет. flex-basis не меняет десктоп (при >=sm grow:1 поглощает базис). i18n-ключи те же, консьюмеры/пропсы/хуки не тронуты.
  • Паттерн верен и консистентен. Точно повторяет DeletedPageBanner (тот же sm-токен, ActionIcon size="lg" в Tooltip withArrow + aria-label, loading проброшен); варианты (subtle/light) согласованы с ДЕСКТОПНЫМИ близнецами этого же баннера (даже чище сиблинга). Security/stability/architecture/documentation/simplification LGTM (twin-render visibleFrom/hiddenFrom — идиоматичный Mantine; извлекать общий компонент рано — 2 колл-сайта, rule-of-three не выполнен). Комментарии английские.
  • Отсутствие теста — обосновано (сверил заявление кодера). Кодер написал «нет инфры для render-теста» — это НЕточно (инфра есть: mic-button.test.tsx — рабочий прецедент рендера ActionIcon+ассерт aria-label). НО вывод «тест не нужен» верен по risk-weighting: единственное новое = видимость по брейкпоинту (CSS media-query; matchMedia застаблен в jsdom → «показывается только <sm» не проверить), а icon-кнопки — дословная зеркалка десктопного блока и уже-смерженного сиблинга DeletedPageBanner, у которого теста тоже нет. Риск-критичного непокрытого пути нет; хендлеры не менялись. Минимальный render-тест (aria-label + disabled-while-pending) возможен, но НЕ блокер.

Готово к мержу.

## Ревью — #322 (fix(temporary-notes): баннер временной заметки на мобильном — адаптивные icon-only действия + flex-basis, #321), round 1, head `ba94def3`, base develop Scope: полный дифф PR `e1b8f81b..ba94def3` — 1 файл `temporary-note-banner.tsx` (+68/−24), разметка-only. Клиент-only. Полный веер 9 аспектов. **Вердикт: PASS** — фикс корректный и целен, регрессий нет, объективка зелёная. Готово к мержу. **Объективка запущена мной** (детач `ba94def3`, main-клон): client `tsc --noEmit` → **0**. (Юнит-теста для этого баннера в проекте нет — см. ниже про покрытие; релевантная объективка для разметочной правки — tsc, зелёный.) ### Подтверждено по коду - **Фикс достигает цели (#321), обе причины.** (1) Текстовая `Group` сменила `flex: 1` (basis 0%, из-за чего внешний `wrap="wrap"` никогда не уводил кнопки на вторую строку, а давил текст в «лесенку») на `flex: "1 1 16rem"` (`:86`) — теперь при узком контейнере wrap реально срабатывает. (2) Скопирован адаптивный паттерн `DeletedPageBanner`: текст-кнопки `visibleFrom="sm"` (`:106`), icon-only `ActionIcon`+`Tooltip`+`aria-label` `hiddenFrom="sm"` (`:129-154`). - **Регрессий нет, десктоп не тронут.** `handleTrashNow`/`handleMakePermanent` байт-идентичны (вне диффа); ОБА брейкпоинта зовут ОДНИ хендлеры с ОДНИМИ loading-флагами (`isDeleting`/`toggleTemporary.isPending`) и ОДНИМИ `t()`-ключами (`"Move to trash"`/`"Make permanent"`). Mantine `ActionIcon loading` дизейблит так же, как `Button loading` → double-fire нет. Обе `Group` в DOM, но неактивная скрыта `display:none` → дубль-onClick не стреляет. `flex-basis` не меняет десктоп (при `>=sm` grow:1 поглощает базис). i18n-ключи те же, консьюмеры/пропсы/хуки не тронуты. - **Паттерн верен и консистентен.** Точно повторяет `DeletedPageBanner` (тот же `sm`-токен, `ActionIcon size="lg"` в `Tooltip withArrow` + `aria-label`, loading проброшен); варианты (`subtle`/`light`) согласованы с ДЕСКТОПНЫМИ близнецами этого же баннера (даже чище сиблинга). Security/stability/architecture/documentation/simplification LGTM (twin-render `visibleFrom`/`hiddenFrom` — идиоматичный Mantine; извлекать общий компонент рано — 2 колл-сайта, rule-of-three не выполнен). Комментарии английские. - **Отсутствие теста — обосновано (сверил заявление кодера).** Кодер написал «нет инфры для render-теста» — это НЕточно (инфра есть: `mic-button.test.tsx` — рабочий прецедент рендера `ActionIcon`+ассерт `aria-label`). НО вывод «тест не нужен» верен по risk-weighting: единственное новое = видимость по брейкпоинту (CSS media-query; `matchMedia` застаблен в jsdom → «показывается только <sm» не проверить), а icon-кнопки — дословная зеркалка десктопного блока и уже-смерженного сиблинга `DeletedPageBanner`, у которого теста тоже нет. Риск-критичного непокрытого пути нет; хендлеры не менялись. Минимальный render-тест (aria-label + disabled-while-pending) возможен, но НЕ блокер. Готово к мержу. <!-- state:review reviewed_head=ba94def3c8673bce0ea4a60f0feeb7fafe8f3add round=1 verdict=pass -->
agent_reviewer added review/approved and removed review/needs labels 2026-07-03 23:59:59 +03:00
vvzvlad merged commit 0392566af9 into develop 2026-07-04 00:00:38 +03:00
Sign in to join this conversation.