fix(web): action bar holds one row and compresses to the container width

The band was `flex-wrap: wrap` with a hard `min-width: 70px` per button, so
five controls (star + quick actions + children + backlinks + overflow) needed
~340px and wrapped to a second row in any pane narrower than that.

Replace the hard floor with `flex: 0 1 70px` scoped to `.meta-actions`: the
70px basis reproduces the old width when there is room, so nothing moves on a
wide container, and `min-width: auto` bounds the shrink at each button's own
label rather than clipping it. The graph drawer's `.action-btn`s keep the plain
floor — their labels are wider than 70px.

`.menu-anchor` and `.quick-actions-menu` become flex so the ⋯ /  triggers they
wrap participate in the compression instead of sitting at block min-content.

Below a 340px band a container query reclaims 4px of inline padding per side,
which covers the 312px pane minimum (the draggable floor) with the full control
set — measured 0 overflow there, and 0 with a 3-digit child count. Deliberately
not `overflow-x: auto`: an invisible scrollport is what made controls silently
unreachable in TASK-2328.

Also narrows the button `transition: all 0.1s` to the three hover properties.
Now that width is container-derived, `all` animated padding during a pane drag.

Measured in Chromium at 264-912px band widths: no wrap and no clipped label at
any width; anchored ⋯ menu still escapes the new container (panel renders 162px
below the band); mobile BottomSheet still resolves against the viewport
(390x844) rather than the container, for both the ⋯ and  menus.

Gates: svelte-check 0 errors, 490 vitest, 39 e2e across the five specs that
drive these controls.
This commit is contained in:
xarmian
2026-07-26 13:34:53 +00:00
parent 0b4d72aaa6
commit 92f8a6e242
+66 -2
View File
@@ -6427,7 +6427,20 @@
align-items: center;
gap: var(--space-2);
margin-bottom: var(--space-6);
flex-wrap: wrap;
/* Single row at every container width. The band lives in the docked
pane (user-draggable, 312-672px) as well as the full page, so the
old `wrap` gave back a whole row of vertical space the moment the
pane got narrow. Buttons compress instead — see the
`.meta-actions .action-btn` flex rule below. */
flex-wrap: nowrap;
/* Query container for the narrow-width padding tightening below. Keyed
off the BAND, not the viewport, because the docked pane's width is
user-dragged and decoupled from it (PLAN-2326 DR-2). Safe here per
DR-3: `inline-size` implies `contain: layout style inline-size` with
no PAINT containment, so the ⋯ / ⚡ anchored menus still escape the
band's box. Verified by measurement, not inference. */
container-type: inline-size;
container-name: item-action-bar;
}
.action-btn {
padding: var(--space-1) var(--space-3);
@@ -6439,7 +6452,14 @@
color: var(--text-secondary);
font-size: 0.85em;
cursor: pointer;
transition: all 0.1s;
/* Was `all 0.1s`, which is fine for a hover but wrong now that width
and padding are width-derived: dragging the pane animated every
button's padding, so the row visibly wobbled behind the drag and
settled ~100ms late. Enumerate the hover properties instead. */
transition:
background 0.1s,
color 0.1s,
border-color 0.1s;
white-space: nowrap;
}
.action-btn:hover {
@@ -6452,6 +6472,50 @@
color: #fff;
}
/* Fluid action-bar buttons. Scoped to `.meta-actions` on purpose: the
graph drawer's `.action-btn`s ("Close ✕", "Retry") are wider than 70px
and must keep the plain `min-width` floor, not a 70px flex basis.
`flex-basis: 70px` reproduces the old comfortable width when there is
room, so nothing moves on a wide container. `flex-shrink: 1` lets the
row compress when there isn't. `min-width: auto` (NOT 0) is what makes
this safe — a flex item's automatic minimum is its content size, so
shrinking stops at the label rather than clipping "🌳 12/34" down to
nothing. Overriding the 70px floor above is the whole point; without
this line the floor and the basis are the same number and nothing
shrinks. */
.meta-actions .action-btn {
flex: 0 1 70px;
min-width: auto;
}
/* Both of these wrap a button in a plain div, which would otherwise be a
block-layout flex item: the basis above only applies to a flex ITEM, so
without `display: flex` here the ⋯ and ⚡ triggers sit at their
block min-content width and refuse to participate in the compression.
`.menu-anchor` keeps `position: relative` — Menu's anchored mode
positions against it. */
.menu-anchor,
.meta-actions :global(.quick-actions-menu) {
display: flex;
}
/* Last resort before overflow. Once every control has shrunk to its own
label the row can still exceed a 264px band (a 312px pane — the draggable
minimum — with star + ⚡ + 🌳 + 📎 + ⋯ measured -3.4px, and -29.8px with a
3-digit child count). Reclaiming 4px of padding per side per control buys
~40px, which clears both. Deliberately NOT `overflow-x: auto` here: a
scrollport under `scrollbar-width: none` is what made controls silently
unreachable the first time round (DR-12).
Two-selector specificity (0,2,0) on purpose — `@container` contributes
none of its own, so a bare `.action-btn` here would tie with the base
rule above and be decided by source order. */
@container item-action-bar (max-width: 339.98px) {
.meta-actions .action-btn {
padding-inline: var(--space-2);
}
}
/* Per-item dependency graph drawer (PLAN-1780 / TASK-1784). Right-docked
panel with a dimming backdrop; on narrow viewports it fills the screen. */
.graph-drawer-backdrop {