cmux-next: custom workspace sidebar (groups, machines, drag, tab drop)

Merged
LA
1mo ago
+5297-2

Summary

CmuxNextSidebar: a fully custom, layer-backed AppKit sidebar (no NSOutlineView/NSTableView/SwiftUI List). Machine sections (local, Cloud VMs), a pinned area, collapsible colored workspace groups, drag reorder with a lifted glass row and springs, an external tab-drop API with spring-loading, icons-only and hidden modes, live density tokens.

  • Model: @Observable @MainActor SidebarModel (sections -> groups -> workspaces, selection, filter, presentation, width) and SidebarIntent out (select, reorder(ids, to:), move(ids, toGroup:), reorderGroup, createGroup, renameGroup, setGroupColor, setGroupPinned, closeGroup, openGroup, ungroup, toggleCollapse, close, rename, setColor, setIcon, setPinned, newWorkspace). Without onIntent the model applies intents locally (mock and optimistic updates).
  • Pure logic with tests: SidebarLayout (flattening, per-row heights, live gap, O(1) key index, binary-search hit test), DropResolver (drop math in post-removal coordinates, gap feedback cancelled), KeyboardReorder (Cmd-Opt-Up/Down slots), SidebarEdits (tree edits), resolveTabDrop (external tab drag).
  • Views: only rows near the viewport have views (reuse pool), selection pill and drag gap are CALayers with CA springs, manual frame layout, no NSHostingView. Right-click goes through contextMenuProvider (App builds menus from the action registry).
  • SidebarContainerView owns the glass panel, width constraint, and resize handle.
  • SidebarMock.makeModel() (40 workspaces, 2 machines) and makeLargeModel(count:).
  • Package.swift: adds resources: [.process("Resources")] to the CmuxNextSidebar target for its Localizable.xcstrings (en, ja).

Testing

  • swift build --build-tests and swift test --filter CmuxNextSidebarTests (56 tests) in Packages/macOS/CmuxNext.
  • scripts/cmux-next/check-no-godfiles.sh passes for the module.
  • Throwaway demo executable driven by synthesized mouse events: single and multi-row drag, drop into group, cancel, tab-drop gap and spring-load, icons-only, comfortable density, filter. Screenshots were checked; not attached.
  • 1000 workspaces (release): full layout 0.14 ms, steady reload 0.5 ms, about 55 row views alive.

Changelog

none

🤖 Generated with Claude Code


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


Summary by cubic

Builds a fully custom AppKit sidebar for cmux-next, replacing the placeholder. It adds machine sections, a pinned area, collapsible colored workspace groups, spring-animated drag reorder, and an external tab-drop API with icons-only and hidden modes following live density tokens.

New Features

  • Layer-backed custom list (no NSOutlineView/NSTableView/List); only rows near the viewport get views, recycled through a per-class pool.
  • @Observable SidebarModel emits SidebarIntents; set onIntent to forward them to the daemon, otherwise they apply locally (optimistic).
  • External tab drags call SidebarView.externalDragMoved, which returns a proposal and highlight rect, opens a gap, and spring-loads workspace rows after a hover delay.
  • Adds 56 tests covering reorder, drop resolution, keyboard reorder, tab drops, and group verbs.