feat(client): сноски — рендер без сдвига (номер инлайн через ::before) и шрифтом sm #421
Reference in New Issue
Block a user
Delete Branch "feat/420-footnote-render"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Блок сносок внизу страницы рендерился с висячим отступом (номер
N.жил в отдельном узком столбце.definitionMarkerчерезorder:-1; min-width:1.5em, текст и переносы уезжали вправо) и кеглем как у тела (16px).Реализован рекомендованный вариант: столбец-маркер удалён, номер рисуется инлайн в начале первого параграфа контента через
.definitionContent > :first-child::beforeиз CSS-переменной--footnote-number(она по-прежнему проставляется на обёртке.definition). Кегль сносок снижен доvar(--mantine-font-size-sm)(14px, как.listHeading).closes #420
How verified
cd apps/client && pnpm exec vitest run src/features/editor/components/footnote/→ 7 passed (7),footnote-definition-view.tsx100% покрытие. Ненулевой код возврата — только глобальный порог branch-coverage при прогоне подмножества, не падение теста.NodeViewContentтеперь буквально первый ребёнок (chrome-маркера перед ним больше нет),::before— псевдоэлемент, в DOM не входит, ProseMirror его не видит → каретка/hit-testing не ломаются. Структурный тестfootnote-views.structure.test.tsxне менялся и остаётся невакуумным (single-ref бэклинкcontentEditable=false→nonEditable.length > 0).↩ a b c) не тронут;.backLink/.backLinkArrowв относительныхem— унаследовали меньший кегль.::before, в модель документа и маркдаун не попадает — регрессий экспорта нет.Внутренний цикл: 1 проход coder + 1 внутреннее ревью (read-only) → замечаний нет (fallback-вариант со
<span>не понадобился, инвариант каретки сохранён рекомендованным путём).Checklist
Ревью — #421 · feat(client): сноски — рендер без сдвига (номер инлайн через ::before) и шрифтом sm
Вердикт: OK (PASS). Чистое презентационное изменение (клиент, 2 файла, +25/-30): столбец-маркер
.definitionMarkerудалён, номер рисуется инлайн через.definitionContent > :first-child::beforeиз CSS-var--footnote-number; кегль сносок снижен доsm. Висячий отступ устранён, инвариант #146 сохранён (даже усилён). closes #420.Как проверено (гейт, clean-room
/home/claude/gm-ci)apps/clienttsc (tsconfig.json) — PASS (0 ошибок), workspace-пакеты собраны.src/features/editor/components/footnote/c--coverage.enabled=false— 7/7 PASS, exit 0. (Ненулевой код возврата в PR-описании — только глобальный branch-threshold при прогоне подмножества, не падение теста; подтверждено.)NodeViewContentв DOM, влево черезorder:-1) удалён →NodeViewContentтеперь буквально первый ребёнок, число — псевдоэлемент::before(в DOM/модель ProseMirror не входит) → каретка/hit-testing целы. Структурный гвардfootnote-views.structure.test.tsxне менялся и остаётся невакуумным: single-ref бэклинк по-прежнемуcontentEditable={false}→nonEditable.length > 0.style --footnote-number = "1"+content: var(...) ". "→1.; фолбэк"?"совпадает сgetFootnoteNumber(...) ?? "?". Дангл-ссылок на.definitionMarkerв кодовой базе нет.::before(user-select:none), в модель/маркдаун не попадает — регрессий нет.Отдельно проверено: a11y (снятие
aria-hidden) — НЕ регрессияСтарый маркер был
aria-hidden="true",::before— нет, и его контент попадает в AX-дерево → скринридер теперь озвучивает номер. Разобрано против кода: референс-сторона.reference::afterуже рендерит номер псевдоэлементом БЕЗaria-hidden— озвучивание номеров сносок уже штатное поведение проекта. Старыйaria-hiddenна дефиниции стоял потому, что DOM-маркер читался НЕ ПО ПОРЯДКУ (после текста, т.к. в DOM он шёл после контента, влево — через flexorder);::beforeставит номер в правильную позицию чтения (перед текстом → «1. текст»). То есть снятиеaria-hidden— согласование дефиниции с уже принятым паттерном референса, а не регрессия. Escalate снят.⛔ DROP — кодеру НЕ делать (лог калибровки)
[below-threshold]medium/high [regressions] «a11y: номер теперь озвучивается скринридером» —footnote-definition-view.tsx:59— проверено НЕ регрессией:.reference::afterуже озвучивает номер безaria-hidden(штатно); старыйaria-hiddenкомпенсировал out-of-order чтение DOM-маркера,::beforeчитается по порядку → согласование, а не регресс. Escalate снят.[below-threshold]medium [documentation] JSDoc «a decorative number marker» —footnote-definition-view.tsx:21-28— прежний текст, «маркер» визуально всё ещё есть; PR-комментарий ниже уже поясняет CSS-::before. Код верен.[below-threshold]low [documentation] коммент говорит «.definitionContent ::before», селектор —.definitionContent > :first-child::before—footnote-definition-view.tsx:55— неточность в тексте, смысл ясен; не дефект.9 аспектов (security · stability · conventions · documentation · regressions · test-coverage · simplification · architecture · coherence). Security:
number— всегда положительный int или"?", CSS-инъекции нет. Simplification/Architecture/Coherence: изменение усиливает #146 (меньше не-редактируемых DOM-узлов у contentDOM), скоуп-крипа нет (кегльsm= часть визуального фикса, «как.listHeading»). Escalate нет.