diff --git a/ui/src/components/DepthButtons.jsx b/ui/src/components/DepthButtons.jsx index ab3e2f3..d36e1d6 100644 --- a/ui/src/components/DepthButtons.jsx +++ b/ui/src/components/DepthButtons.jsx @@ -35,6 +35,9 @@ export default function DepthButtons({ label, levels, depth, onPick, totalLabel const known = depth != null const current = !known ? '—' : (depth === 0 ? totalLabel : levels[depth - 1]) const step = (d) => onPick(Math.min(max, Math.max(0, d))) + // Capped so one long field name cannot push the rest of the toolbar off; + // past the cap the label truncates, with the full name in the title. + const widest = Math.min(18, Math.max(...[totalLabel, ...levels].map(l => String(l).length))) // One joined control, in the style of the operation panel's // Scale | Recode | Clone. The arrows used to be separate outlined boxes a @@ -53,9 +56,13 @@ export default function DepthButtons({ label, levels, depth, onPick, totalLabel title={`Collapse ${label.toLowerCase()} by one level`} onClick={() => step((depth ?? 0) - 1)}>◂ + {/* Sized to the axis's longest level, not the current one. Sized to + its content it resized on every step, so the ▸ moved out from + under the cursor between clicks. */} diff --git a/ui/src/components/LayoutMenu.jsx b/ui/src/components/LayoutMenu.jsx index 7db8102..f79d85a 100644 --- a/ui/src/components/LayoutMenu.jsx +++ b/ui/src/components/LayoutMenu.jsx @@ -123,15 +123,22 @@ export default function LayoutMenu({ ${open ? 'border-blue-300 text-blue-700 bg-blue-50' : 'border-gray-200 text-gray-600 hover:border-gray-400'}`}> {active ? active.name : 'Unsaved'} - {dirty && •} + {/* Always rendered, hidden when clean, so the button does not widen + by a dot the moment the pivot changes. */} + • ▾ {/* Save is the common action and stays outside the menu, but only when - there is something to save it to and it is yours to overwrite. */} - {active?.can_edit && dirty && ( - )}