[feature][editor] Кнопки блока кода поверх кода: язык + копирование в углу, селектор языка — по наведению #275
Reference in New Issue
Block a user
Delete Branch "%!s()"
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?
Проблема
В блоке кода панель управления (селектор языка + кнопка «копировать») занимает
отдельную строку над кодом и тратит на себя целую строку по вертикали. Нужно
перенести обе кнопки поверх кода, в правый верхний угол (в том же месте), а
селектор языка скрывать до наведения на блок.
Как работает сейчас
apps/client/src/features/editor/components/code-block/code-block-view.tsx.codeBlock(NodeViewWrapper) — flex-колонка. В DOM сначала идёт<pre>скодом, затем
<Group className={menuGroup}>с<Select>(язык) и<CopyButton>.order: -1, поэтому она —полноширинная строка сверху.
apps/client/src/features/editor/components/code-block/code-block.module.css→
.menuGroup { order: -1 }.apps/client/src/features/editor/styles/code.css→
.codeBlock { display: flex; flex-direction: column; … }.<pre>(редактируемый contentDOM) обязан идтипервым в DOM — иначе браузерный hit-testing клика уводит каретку на строку
выше. Поэтому панель рендерится после
<pre>, а «наверх» её поднимаетorder: -1.Что хотим
позиционирование), больше не отдельной строкой.
появляется при наведении на блок кода (а также при фокусе / открытом
дропдауне).
неактивен и бесполезен; остаётся только кнопка копирования.
Предлагаемая реализация
code.css: у.codeBlockдобавитьposition: relative;— якорь дляабсолютного оверлея. flex-колонку можно оставить: панель уйдёт из потока за
счёт
position: absolute.code-block.module.css→.menuGroup:order: -1;position: absolute; top: 8px; right: 8px; z-index: 1;+ уменьшитьgap;@media print { display: none; }.editor.isEditable(убрать текущийкостыль
disabled={!editor.isEditable}— в read-only селектора просто нет,остаётся только кнопка копирования).
Selectкласс-обёртку:classNames={{ root: classes.languageSelect, input: classes.selectInput }};.languageSelect { opacity: 0; pointer-events: none; transition: opacity 150ms ease; }:global(.codeBlock):hover .languageSelect, .languageSelect:focus-within { opacity: 1; pointer-events: auto; }.codeBlock— глобальный классNodeViewWrapper, поэтому через:global()).<pre>оставить первым в DOM (порядок не трогаем — критично для #146).Тонкости и edge-cases
<pre>первым) сохраняется; absolute-позиционированиедополнительно убирает панель из потока — каретка при клике не съезжает.
opacity: 0) сохраняет ширину внутриflex-
Group, поэтому кнопка «копировать» не прыгает при появлении/скрытииселектора.
pointer-events: noneв скрытом состоянии →выделение/клик по коду под ним работает; видимая кнопка «копировать»
перекрывает лишь маленький угол.
<pre>скрыт и рендерится диаграмма — оверлей ложится вправый верхний угол диаграммы, ок.
бесполезен) — на наведении показывать нечего; остаётся только кнопка
копирования, видимая всегда.
.codeBlock, а не кпрокручиваемому
<pre>→ остаётся в углу (как на GitHub).overflowблока.order: -1,который убираем), чтобы объяснение соответствовало новому подходу.
Критерии приёмки
углу поверх кода.
блок кода (или пока он не в фокусе); появление плавное.
воспроизводится).
артефактов.
@media print).Затрагиваемые файлы
apps/client/src/features/editor/components/code-block/code-block-view.tsxapps/client/src/features/editor/components/code-block/code-block.module.cssapps/client/src/features/editor/styles/code.css