Solid themed toasts, "New Tab" titles, no raw workspace ids
Toasts in cmux-next were cramped, translucent glass, and a closed New Tab page said Closed “about:blank”. Now every toast uses one solid, themed component, tabs keep their strip names everywhere, and no error shows a raw id.
The component (CmuxNextDesign/Toast)
- The surface is opaque: the theme's overlay fill (
ThemeTokens.opaqueOverlayFillatChromeTunables.opaqueOverlayLift, the same fill Reduce Transparency uses), pinned on every Mac.Palette.popupSurfaceisn't on base yet; a comment marks where to swap it in. - Corners use the popups' 8 pt radius (
PopupStyle.standard), not a capsule, and the toast casts the popups' one subtle shadow. - Padding is 8 pt vertical and 12 pt leading, with 12 pt before the action. Undo is a full-strength emphasized text button.
CmuxToastCenteralready did placement (bottom-center, 24 pt up), stacking (three per window), auto-dismiss onDemandTimerand the hover hold; tests now cover them.
Toasts routed through it
- Refusal HUD:
RefusalHUD, the capsule that said "no workspace ", is now a toast with idrefusal. - Feed and Tasks rejects:
FeedToastis deleted. The Feed reject and the Tasks pane's reject overlay go through a newcmuxToast(id:message:onDismiss:)SwiftUI modifier.onDismissruns on the next main-actor turn whenever the toast ends, including when a newer toast pushes it out of the stack, so the same reject shows again.- It also runs when the view is dismantled, so a reopened panel doesn't replay an old reject.
- Already on
CmuxToastCenter, now with the new look: closed tab, group and workspace close or undo, pin, icon history, tab icon, room deleted, remote forget, keymap, CLI install, cloud move and result, recovery notice, file recovery, browser, bookmark and password imports, classic import, and surface zoom. - No web page in
webviews/srcshows a toast.
Tab titles
TabTitleResolvermoves the strip's title logic out ofPaneController. It covers the New Tab page (or History), agent chats, Home conversations, page and app tabs, and incognito tabs.- Three places now use it: the strip, the sidebar's tab rows (
SidebarBridgepasses it asSidebarMapping'stabTitle) and the closed-tab toast, from both a pane close and a tab-group close. - Only a browser tab or a real New Tab page becomes "New Tab". A chat or a page tab keeps its own name, even though its record is titled
about:blank.
No raw ids
- 14 refusals that named an object id now say what happened in plain words, for example "That tab is no longer open.", "That workspace is no longer open." and "That window is no longer open."
- They cover the workspace, workspace group, tab, pane, a pane's workspace, a tab's content, screen, closed item, column, a pane's daemon handle, open and saved tab groups, a workspace's panes, window and screen group.
- These messages reach the toast, the action not-found paths and the socket's
not_found. - The new keys in
Refusals.xcstringsandScreens.xcstringsare translated into all 21 locales in each catalog, and the old keys are removed.
Testing
cmux-ci run --class light --script scripts/ci/run-swift-testing-suites.sh --arg Packages/macOS/CmuxNext:
First round
- Red, at
eb65fddc8077c87d9bc59eae7637a0d2d25a81cf:CmuxToastSurfaceTestsandToastCopyTestsfailed on assertions: a glass material instead of opaque, a 10 pt radius,Closed “about:blank”, andno workspace ws_…. - The placement and hover-hold tests already passed on base; they pin existing behavior.
Review round
- Red, at
09c5f377c1bb4d5b59614d3b96a3e48377de4c8d(tests only): the build failed because the new test API (CmuxToastAnchorView.centeranddismantle,TabTitleResolver,SidebarMapping'stabTitle) didn't exist yet. These tests never failed on an assertion before the fix. ToastCopyTestsnow checks four things:- a chat, a diff page tab, a New Tab page and a blank browser tab keep their strip names in the sidebar rows and in the group-close toast;
- 15 refusal reasons never contain a sample id.
CmuxToastModifierTestschecks that a reject pushed out of the stack, and one left behind by a closed panel, clears its model.- Green, at
d0dbac151ae71aa0ed61e563782ae880f59cc888: all 141 suites passed, including those three suites andHeaderDiffPlacementTests.
Local checks
check-concurrency.sh(1 hit),check-theme-scope.sh(15) andcrash_ratchet.py(5 modules) match base; none of the hits are in this change.check-system-blue.pyandcheck-no-godfiles.shpass.lint-ios-package-conventions.shflags only the two namespace-type errors already on base (CommandRetentionSetting,AgentPaneWarmup).localization_catalog.py checkreports nothing for the new keys.
Not verified: there's no live capture, and the Feed and Tasks panel toasts haven't been checked in a running app.
Changelog
Changed: Toasts are a solid, theme-colored card at the bottom center of the window. A closed New Tab page is called "New Tab", chats and pages keep their names in the sidebar and in toasts, and errors no longer show raw ids.
🤖 Generated with Claude Code