cmux NEXT sidebar: one leading icon column, header chevrons on the trailing column

Merged
TE
8d ago
+261-36

Leo, 2026-10-28, on a screenshot of the top of the sidebar (Search, a ⊘ row, "+ New…", then a workspace row with an app icon): "the alignment". Earlier the same day, on glyphs: "i feel like this is misaligned checkmark :( can we all audit the checkmarks and whatnot". Later, on two blue unread dots beside two red (i) marks: "eg look at this alignment :(".

What changes

One leading icon column. A new token, SidebarStyle.iconColumnCenterX(leading:), is the center of the one iconBox slot that starts at the row inset plus the pill inset. Every leading glyph centers what it draws on that column and on its row's center line:

  • band glyphs (Home and the other band rows)
  • a pinned workspace's pin
  • a pinned group's pin
  • a workspace row's icon, which already did

Before this PR, band glyphs and pins started their drawn ink at the inset instead of centering it. Measured on the fleet at the red commit, Home's glyph centered 2 pt and the pin 5 pt left of the workspace icons' center, at every density, in Minimal Mode on and off, and at both widths. Titles keep the one text column (SidebarStyle.leadingTextX).

Header chevrons on the trailing column. The status header, chat history, band section header and machine header (when it has no +) placed their chevrons with their own insets. Each one now centers on SidebarStyle.trailingColumnFrame, the column that every row's dot, spinner and error mark and the group header's chevron already share. The band section header gets its items' trailingTrim so that its chevron lands on its rows' column.

Trailing marks. On this base, the unread dot, the error (i) and Home's dot already share one center x in workspace and band rows. The new test confirms it, and also checks that each mark's art (dot, info, error, done) is centered in its box at 10, 20 and 30 px. The 2 pt drift on inner-tab dots that Leo's screenshot most likely shows was fixed by #26622 (landed 10-28), after which those dots share the trailing column.

Cloud mark. A machine mark already draws only while the sidebar lists more than one machine, and this Mac's rows draw none by default (sidebar.showLocalMachine is off). That matches the "only where it tells local from cloud apart" rule, so it is unchanged.

Audit, not changed here:

  • Color-swatch dots: they are color marks, not icons, and keep their own text offset.
  • The priority panel and the needs-you tray: they lay out their own action strips, outside the row column.
  • The Debug-only trailing badge style: its unread badge chains left of the column.

Takes back #23800 and Lawrence's 2026-10-28 "home and pinned are not aligned" commits (2cf09e1447b), in part. Their first-ink rule ("a pin's ink starts at the row inset") becomes "a leading glyph centers on the icon column", because Leo asked for one center x. Text columns are unchanged. plans/cmux-next/sidebar-owner.md is updated to the new rule.

Capture

State scripts/cmux-next/media/states/sidebar-icon-column.json: the showcase with the Debug row badge preview rows, so the sidebar shows unread dots (blue), needs-you dots (orange) and error (i) marks (red). These are the marks in Leo's "eg look at this alignment :(" screenshot. At this base they already share one trailing column, before and after. The showcase has no pinned rows, and the stills are at 1x, where Home's 2 pt move is 2 px. SidebarIconColumnTests carries the measured leading change.

Before at 698b3ef64cf0

LightDark
lightdark

After at 35226d0a9a40 (fleet build, capture mini, text checked for private data)

LightDark
lightdark

Review

Codex gpt-6-astra, high, fast, through the review-router route (lane-place found no working review box). At 35226d0a9a40 it returned BLOCK: in the card look, the band header took the trailing trim that its card's rows don't, so its chevron sat 4.5 pt right of their marks. Fixed in eea0ccbc3b95 (SidebarRegionLayout.itemTrailingTrim, one rule for the rows and the header, tested in every look). The re-review at eea0ccbc3b95 returned SHIP with no findings. After the fix, the 12 affected suites passed on the fleet at eea0ccbc3b95 (step 22d7327609954036e338ddcb).

Tests

  • SidebarIconColumnTests (new):
    • leading glyphs share one center x;
    • each glyph sits on its title's center line;
    • the unread, error and Home marks share one trailing center x and their rows' center lines;
    • the status art is centered in its box.
  • HomePinnedRowAlignmentTests and SidebarUniformRowSpacingTests.thePinCentersOnAnUnpinnedRowsIconColumn now check the icon column instead of the ink start.

Performance

No perf numbers: not a performance change. It adds no timers, observers or per-frame work, only layout math on the same layout passes.

Risk

risk:normal. A small, contained sidebar look change: leading glyphs and pins move by up to 5 pt to one center, and four header chevrons move onto the trailing column. Nothing changes in behavior, hit targets or state.

Changelog

  • Fixed: sidebar icons, pins and header chevrons line up on one leading column and one trailing column.

Observed / Not run

  • Red: cmux-ci run --class light --script scripts/ci/package-test-lane.sh --ref 80b6deec9c53 --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarIconColumnTests,HomePinnedRowAlignmentTests. SidebarIconColumnTests failed: Home 2 pt and the pin 5 pt off the icon column in all 12 cases. HomePinnedRowAlignmentTests passed.
  • Green: at d4c70d05133 (the head's Swift tree; the later commit adds only the capture state JSON), 20 of 21 suites passed (fleet step ea7e9ad73910b6820b78014c): SidebarIconColumnTests, HomePinnedRowAlignmentTests, SidebarUniformRowSpacingTests, PinnedRowsLookLikeRowsTests, SidebarTrailingColumnTests, GroupHeaderTrailingTests, SidebarChatHistoryTests, HostGroupHeaderStatusTests, MachineIconTests, SidebarGroupRailAlignmentTests, SidebarNestedGroupAlignmentTests, SidebarPinnedRowWidthTests, SidebarDragHeaderTests, SidebarLayoutFoldTests, HomeUnreadBlueDotTests, SidebarGroupMembersAlignTests, SidebarMinimalModeTests, HandSizedLabelClippingTests, SidebarGroupHeaderEveryDensityTests and SidebarRowTitleAndCloseTests. SidebarTrailingColumnGalleryTests ran no tests, as it also does at base 698b3ef64cf (fleet step 49e75c20bcc040df3a4e2bab, where the other 19 suites pass).
  • Captures: before at the base and after at the head, light and dark (above).

🤖 Generated with Claude Code

Agent session: agent session


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Aligns the sidebar's leading glyphs (band icons, pins, workspace icons) on one shared icon column and header chevrons on the shared trailing column, fixing the misalignment Leo reported in review.

  • Adds SidebarStyle.iconColumnCenterX; leading glyphs now center their ink on the column instead of starting at the row inset, and on their row's center line.
  • Status, chat history, band section and machine header chevrons move to the shared trailing column; a band section header uses the same trailing trim rule as its rows (SidebarRegionLayout.itemTrailingTrim) so the chevron lines up with its marks in every look, the card look included.
  • Adds SidebarIconColumnTests covering leading, trailing and header alignment across densities and looks, and updates the Home/pinned and pin-spacing tests to check the column instead of the ink start.