Sidebar: hide scrolled rows under the traffic lights (minimal titlebar)
With the default minimal titlebar, scrolling the left sidebar list slid rows up under the window's traffic lights, and they stayed visible there. On nightly 1.0.0-nightly.3965802926201 (3a63d6d9) the "Agents" group header pill sat beside the lights.
Cause: since 94f7db0 (minimal titlebar) the sidebar's header row is Metrics.tabStripHeight tall (28 in compact, WindowRootView.applyTokens), so the list starts level with the panes' content. The traffic lights reach about y=22 and the titlebar row ends at Metrics.titlebarHeight (32 in compact). The list's 18 pt top edge fade (ScrollEdgeFadeView) starts at the list's top, so a scrolled row from y=28 down was only partly faded, right below the lights.
Decision (claude-sr2), verbatim: "Miss 6: keep the list starting level with the panes at rest. When the list is scrolled, extend the top mask so content scrolling under the traffic lights is clipped and faded below the lights (y≈titlebarHeight). Don't use max(tabStripHeight, titlebarHeight) at rest."
Change:
ScrollEdgeFadeView(CmuxNextDesign) gets atopClipin points. Its gradient's first stop moves down totopClip. While content is hidden above, the top color is clear, so the mask hides everything from the list's top down totopClipand the usual 18 pt fade starts below it. At rest the top color is opaque, so the mask is the same as before.topClipdefaults to 0, so the other users (palette, extensions menu, priority panel) don't change.SidebarViewsets each scrolling band's clip (the list, and the top item band when it shows) to the part aboveMetrics.titlebarHeight, but only when the traffic lights are over this sidebar (headerHasWindowControls; a right sidebar gets 0). With the full titlebar the list already starts attitlebarHeight, so the clip is 0.- The list doesn't move. There are no sticky headers, the minimal titlebar is still the default, and no component is removed.
- Motion: no new animation. When the top edge starts hiding content, the clear band appears through the existing
Motion.feedbackhovercrossfade on the mask colors. With animation off it applies in one frame. Changing the geometry (topClip, locations) never animates. - Observers: none added. The scroll position comes from
ScrollEdgeFadeView's existing clip-view bounds/frame and document frame observers, which itsdeinitremoves. No per-row work: the clip is set inSidebarView.layout, and a scroll only changes the mask's colors, as before.
Test: SidebarTopMaskTests (CmuxNextAppTests), committed before the fix. It reads the mask's gradient the way Core Animation draws it and checks:
- At rest with a clip, the mask stays opaque at the top.
- Scrolled, it is clear down to the clip, half-faded in the middle of the fade, and opaque after it.
- With no clip, the fade still starts at the top.
- In the sidebar with the minimal header row, each band's clip ends at
max(bandTop, Metrics.titlebarHeight)and the band is not moved up. - With the full titlebar or no window controls, the clip is 0.
Changelog
Fixed: Sidebar rows no longer show under the window's traffic lights when the list is scrolled with the minimal titlebar.
Observed / Not run
- Ran
python3 scripts/cmux-next/prepush-gate.py: no new violations. - Focused suite on the fleet:
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarTopMaskTests. Red at 0ccf76674b75 (test only) and green at the head: results pending, to be added here when the steps finish. - Not run: the app itself. I didn't look at a scrolled sidebar in a build. The 4 pt clip in compact (28 to 32) comes from the token values, not from a measurement on screen.
No capture: the before/after capture follows from the next nightly (scrolled sidebar state).
Agent session: cmux16
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes sidebar rows staying visible under the window's traffic lights when scrolled with the minimal titlebar.
ScrollEdgeFadeViewgains atopClipthat hides content down to the titlebar's bottom and starts the top fade below it; at rest the mask is unchanged.- The sidebar sets each scrolling band's clip only when traffic lights are over it (
headerHasWindowControls); full titlebar and right sidebar behavior is unchanged. - Adds
SidebarTopMaskTestscovering the mask at rest, scrolled, with no clip, and with full titlebar or no window controls. - Logs the fix in the sidebar owner note, since the fix commit reached its branch without a
Sidebar-Looktrailer.