fix(client): compact page tree + fix selection highlight alignment

Reduce DocTree row stride from 32px to 26px for a denser sidebar tree,
and fix the selection/hover highlight that looked unbalanced at the
tighter spacing.

Root causes:
- The virtualized <li> had no explicit height, so `.node`'s height:100%
  collapsed to content height; combined with the asymmetric
  `[role="treeitem"] { padding-bottom: 2px }` rule, row content was
  pushed to the top of the highlight pill (icon glued to the top edge).
- NodeMenu / CreateNode action icons used the default Mantine ActionIcon
  size (md = 28px), overflowing the tighter 26px row stride onto
  neighbouring rows.

Changes:
- doc-tree.tsx: rowHeight 32 -> 26; give each row <li> a definite
  height = rowHeight.
- tree.module.css: rowWrapper fills the slot (height:100%); node pill is
  inset and vertically centered (height: calc(100% - 4px)); drop the
  asymmetric [role="treeitem"] padding-bottom.
- space-tree-node-menu.tsx / space-tree-row.tsx: action icons size={20}.
- share.module.css: drop now-dead .treeNode padding-bottom override.

Verified in an isolated browser harness: highlight content is centered
(2.8/2.8px) and nothing overflows the row stride.
This commit is contained in:
vvzvlad
2026-06-18 23:08:42 +03:00
parent 53b7314705
commit b1d48d9d9a
5 changed files with 16 additions and 6 deletions

View File

@@ -510,6 +510,12 @@ function DocTreeInner<T extends object>(
top: 0,
left: 0,
width: '100%',
// Give the row slot the exact virtualizer stride height so the
// inner highlight can fill and vertically center within it.
// Without a definite height here, `.node`'s `height: 100%`
// collapses to content height and the selection pill ends up
// top-aligned (asymmetric) inside the stride.
height: rowHeight,
transform: `translateY(${virtualItem.start}px)`,
}}
>

View File

@@ -124,6 +124,7 @@ export function NodeMenu({ node, canEdit }: NodeMenuProps) {
<Menu shadow="md" width={200}>
<Menu.Target>
<ActionIcon
size={20}
variant="subtle"
color="gray"
className={classes.actionIcon}

View File

@@ -273,6 +273,7 @@ function CreateNode({
return (
<ActionIcon
size={20}
variant="subtle"
color="gray"
className={classes.actionIcon}

View File

@@ -17,7 +17,11 @@
border-radius: 4px;
display: flex;
align-items: center;
height: 100%;
/* Inset the highlight pill by 2px top + 2px bottom inside the full-height
row slot. rowWrapper (height: 100%, align-items: center) vertically
centers this pill in the stride, giving an even gap between rows and
symmetric padding around the row content. */
height: calc(100% - 4px);
width: 100%;
text-decoration: none;
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
@@ -77,10 +81,6 @@
display: flex;
}
[role="treeitem"] {
padding-bottom: 2px;
}
/* Strip the browser's default <ul> bullet + indent from the DocTree
<ul role="tree"> and nested <ul role="group"> nodes. The tree's own indent
is driven by paddingLeft on .rowWrapper. */
@@ -98,6 +98,9 @@
display: flex;
align-items: center;
border-radius: 4px;
/* Fill the full row slot (the <li> is sized to the virtualizer stride) so
align-items: center can vertically center the inset `.node` pill. */
height: 100%;
}
.node[data-dragging="true"] {

View File

@@ -10,7 +10,6 @@
.treeNode {
text-decoration: none;
user-select: none;
padding-bottom: 0;
}
.navbar,