Skip to content

fix: keep selection highlight uniform across colored and uncolored workspaces (#3308) - #3310

Merged
austinywang merged 2 commits into
mainfrom
issue-3308-uniform-selection-color
Apr 30, 2026
Merged

austinywang merged 2 commits into
mainfrom
issue-3308-uniform-selection-color

Conversation

@austinywang

@austinywang austinywang commented Apr 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #3308.

This reverses #2565: workspace tab colors still identify unselected sidebar rows, but selected rows now always use the same standard selection background as uncolored workspaces.

Changes

Verification

Manual Verification

  • Launched the tagged dev build.
  • Created Colored and Plain workspaces.
  • Assigned #C0392B to Colored via workspace-action set-color.
  • Selected Colored: selected row used the standard blue selection highlight, with only the color rail retaining the assigned red.
  • Selected Plain: selected row used the same standard blue selection highlight, and the unselected Colored row retained its assigned red rail.

Note

Low Risk
UI-only color selection behavior change with limited scope, plus new unit tests; no security or data-handling impact.

Overview
Selected sidebar rows no longer derive their background from per-workspace custom tab colors; selection now always uses the standard configured selection color (or the default accent) regardless of workspace coloring.

This removes the contrast-adjustment/custom selected-background path from sidebarSelectedWorkspaceBackgroundNSColor/sidebarWorkspaceRowBackgroundStyle and adds SidebarWorkspaceSelectionColorTests to lock in the behavior across light/dark modes and with an explicit sidebarSelectionColorHex.

Reviewed by Cursor Bugbot for commit 64e098d. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Make selected sidebar rows use the same selection highlight across colored and uncolored workspaces. Unselected rows keep their workspace color for identity.

  • Bug Fixes
    • Reverted selected-state tinting by removing the custom color path in sidebarWorkspaceRowBackgroundStyle; selected rows now use the standard selection background or the configured sidebarSelectionColorHex in both light and dark modes.
    • Removed now-unused contrast/luminance helpers tied to selected-state custom colors.
    • Added SidebarWorkspaceSelectionColorTests to verify uniform selection for colored workspaces and preservation of custom color on unselected rows.

Written for commit 64e098d. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Resolved an issue where custom workspace colors could interfere with selection backgrounds in the sidebar across light and dark color schemes.
  • Tests

    • Added comprehensive tests to validate sidebar workspace selection color behavior.

Custom workspace colors currently bleed into the selected sidebar row, so this regression asserts that selected colored rows use the same background as uncolored selected rows while unselected colored rows retain their assigned fill.

Constraint: Direct local xcodebuild is prohibited for this branch; unit verification must run through GitHub Actions or the approved reload script.\nConfidence: high\nScope-risk: narrow\nTested: git diff --check -- cmuxTests/SidebarWidthPolicyTests.swift\nNot-tested: Unit test execution before the fix is pending GitHub Actions red-run verification
Workspace color remains an identity treatment for unselected sidebar rows, but selected rows now share the same configured selection background as uncolored workspaces. Removing the selected-state custom color branch restores a consistent focus cue across the sidebar.

Constraint: This intentionally reverses issue #2565 in favor of issue #3308.\nRejected: Keep darkened tab colors for selected rows | still makes the selection cue inconsistent across colored and uncolored workspaces.\nConfidence: high\nScope-risk: narrow\nTested: git diff --check -- Sources/Sidebar/SidebarAppearanceSupport.swift cmuxTests/SidebarWidthPolicyTests.swift\nNot-tested: Local unit tests not run because direct xcodebuild is prohibited; GitHub Actions unit run is used for verification
@vercel

vercel Bot commented Apr 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Apr 29, 2026 7:50pm
cmux-staging Ready Ready Preview, Comment Apr 29, 2026 7:50pm

@greptile-apps

greptile-apps Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Reverts the selected-state custom-colour behaviour introduced in #2565: sidebarSelectedWorkspaceBackgroundNSColor no longer accepts a customHex parameter, so all active workspace rows now resolve to the same standard accent/configured selection background regardless of their tab colour. The ~60-line luminance/contrast-adjustment block that darkened custom colours for contrast is removed entirely; the unselected custom-colour path in solidFill is unchanged. Two new unit tests are added to SidebarWidthPolicyTests.swift verifying the uniform selection background in both colour schemes and when a custom sidebarSelectionColorHex override is present.

Confidence Score: 4/5

Safe to merge; the code change is correct and pre-existing tests in WorkspaceUnitTests.swift already cover both indicator styles.

The implementation change is a clean, surgical removal with no logic surprises, and is backed by existing integration tests. Two P2-only findings (test-file placement and missing dark-mode coverage in one test case) prevent a perfect 5.

cmuxTests/SidebarWidthPolicyTests.swift — new test class could be relocated and dark-mode coverage added to the configured-hex test.

Important Files Changed

Filename Overview
Sources/Sidebar/SidebarAppearanceSupport.swift Removes the selected-state custom-colour branch (60+ lines of luminance/contrast helpers and the customHex parameter path) from sidebarSelectedWorkspaceBackgroundNSColor; selected rows now always return the standard accent/configured selection colour. Unselected custom-colour path is untouched. Change is correct and minimal.
cmuxTests/SidebarWidthPolicyTests.swift Adds SidebarWorkspaceSelectionColorTests with two test cases: cross-scheme equality of colored vs. plain selected rows, and configured-hex override. Tests are sound but the class belongs in a file closer to WorkspaceUnitTests.swift; the configured-hex test also only covers .light mode.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[sidebarWorkspaceRowBackgroundStyle] --> B{isActive?}
    B -- yes --> C[sidebarSelectedWorkspaceBackgroundNSColor]
    C --> D{sidebarSelectionColorHex set?}
    D -- yes --> E[Return configured hex colour]
    D -- no --> F[Return cmuxAccentNSColor for scheme]
    B -- no, solidFill --> G{customColorHex set?}
    G -- yes --> H[WorkspaceTabColorSettings.displayNSColor]
    H --> I[Return custom colour at opacity 0.7 / 0.35]
    G -- no --> J{isMultiSelected?}
    J -- yes --> K[Return accent at 0.25 opacity]
    J -- no --> L[Return .clear]
    B -- no, leftRail --> M{isMultiSelected?}
    M -- yes --> N[Return accent at 0.25 opacity]
    M -- no --> O[Return .clear]
Loading

Reviews (1): Last reviewed commit: "Keep colored workspace selection highlig..." | Re-trigger Greptile

Comment on lines +107 to +129
func testSelectedColoredWorkspaceUsesConfiguredSelectionBackground() {
let selectionHex = "#123456"
let coloredSelected = sidebarWorkspaceRowBackgroundStyle(
activeTabIndicatorStyle: .solidFill,
isActive: true,
isMultiSelected: false,
customColorHex: "#E85D75",
colorScheme: .light,
sidebarSelectionColorHex: selectionHex
)
let standardSelected = sidebarWorkspaceRowBackgroundStyle(
activeTabIndicatorStyle: .solidFill,
isActive: true,
isMultiSelected: false,
customColorHex: nil,
colorScheme: .light,
sidebarSelectionColorHex: selectionHex
)

XCTAssertEqual(coloredSelected.opacity, 1, accuracy: 0.001)
assertColor(coloredSelected.color, equals: standardSelected.color)
assertColor(coloredSelected.color, equals: NSColor(hex: selectionHex))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Configured-selection test is light-only

testSelectedColoredWorkspaceUsesConfiguredSelectionBackground passes colorScheme: .light exclusively, whereas the test above it iterates over both schemes in a loop. Because sidebarSelectedWorkspaceBackgroundNSColor uses cmuxAccentNSColor(for:) — which returns different sRGB values in light vs. dark — a sidebarSelectionColorHex-override test in dark mode would exercise the same code path but confirm there's no colour-scheme-specific conditional that could accidentally re-introduce the custom-colour branch for dark mode. Worth adding .dark coverage here to match the companion test.

}
}

final class SidebarWorkspaceSelectionColorTests: XCTestCase {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 New test class placed in the wrong file

SidebarWorkspaceSelectionColorTests is added to SidebarWidthPolicyTests.swift, a file that tests resize-range arithmetic and clamping logic. The existing parallel coverage lives in WorkspaceUnitTests.swift alongside SidebarSelectedWorkspaceColorTests. Moving the new class there (or into a new SidebarSelectionColorTests.swift) would keep test organisation consistent and make it easier to find all selection-colour tests in one place.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@coderabbitai

coderabbitai Bot commented Apr 29, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Removes custom hex color handling from sidebar selection background logic, ensuring selected workspace rows always display the standard system selection color. Custom colors now only apply to unselected rows, eliminating the custom hex resolution path and related luminance/contrast utilities.

Changes

Cohort / File(s) Summary
Sidebar Appearance Support
Sources/Sidebar/SidebarAppearanceSupport.swift
Removes customHex parameter from sidebarSelectedWorkspaceBackgroundNSColor, deletes custom hex resolution logic, and removes luminance/contrast transformation utilities. Function now only considers sidebarSelectionColorHex with fallback to system accent color.
Selection Color Tests
cmuxTests/SidebarWidthPolicyTests.swift
Adds new SidebarWorkspaceSelectionColorTests class with test cases validating that selected workspace rows use standard selection background regardless of custom color assignment, while unselected rows retain custom colors. Includes color comparison helper methods.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 No more orange glow when workspaces are chosen,
Selection stays true—system colors awoken!
Custom tabs rest, unselected and bright,
But chosen rows shine in standard light. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: making selection highlights uniform across colored and uncolored workspaces, matching the core objective of the PR.
Description check ✅ Passed The description includes a summary of changes, detailed verification steps (commits, local testing, manual checks), and organized notes but lacks specific sections from the template like explicit Testing subsection and checklist completion.
Linked Issues check ✅ Passed The PR fully implements issue #3308 requirements: removes custom color from selected state, adds regression tests for light/dark modes, and preserves custom colors for unselected rows.
Out of Scope Changes check ✅ Passed All changes are within scope of issue #3308: test additions, removal of custom-hex parameter, and updates to sidebar color selection logic directly address the requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3308-uniform-selection-color

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
cmuxTests/SidebarWidthPolicyTests.swift (1)

68-129: Expand the regression matrix to include .leftRail style.

The new tests currently assert only .solidFill. Please add .leftRail coverage too, so selection-color uniformity is guarded across both sidebar indicator styles.

Suggested test matrix tweak
-        for colorScheme in [ColorScheme.light, .dark] {
+        for colorScheme in [ColorScheme.light, .dark] {
+            for style in [SidebarActiveTabIndicatorStyle.solidFill, .leftRail] {
             let coloredSelected = sidebarWorkspaceRowBackgroundStyle(
-                activeTabIndicatorStyle: .solidFill,
+                activeTabIndicatorStyle: style,
                 isActive: true,
                 isMultiSelected: false,
                 customColorHex: "#E85D75",
                 colorScheme: colorScheme,
                 sidebarSelectionColorHex: nil
             )
             let standardSelected = sidebarWorkspaceRowBackgroundStyle(
-                activeTabIndicatorStyle: .solidFill,
+                activeTabIndicatorStyle: style,
                 isActive: true,
                 isMultiSelected: false,
                 customColorHex: nil,
                 colorScheme: colorScheme,
                 sidebarSelectionColorHex: nil
             )
@@
             let unselectedColored = sidebarWorkspaceRowBackgroundStyle(
-                activeTabIndicatorStyle: .solidFill,
+                activeTabIndicatorStyle: style,
                 isActive: false,
                 isMultiSelected: false,
                 customColorHex: "#E85D75",
                 colorScheme: colorScheme,
                 sidebarSelectionColorHex: nil
             )
-            XCTAssertEqual(unselectedColored.opacity, 0.7, accuracy: 0.001)
+            if style == .solidFill {
+                XCTAssertEqual(unselectedColored.opacity, 0.7, accuracy: 0.001)
+            }
             XCTAssertFalse(
                 colorsAreEqual(coloredSelected.color, unselectedColored.color),
                 "Selected row should use the standard selection background, not the workspace tab color"
             )
+            }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxTests/SidebarWidthPolicyTests.swift` around lines 68 - 129, Tests only
cover activeTabIndicatorStyle .solidFill; expand the matrix to also test
.leftRail so selection-color behavior is validated for both indicator styles.
Update both
testSelectedColoredWorkspaceUsesStandardSelectionBackgroundInLightAndDark and
testSelectedColoredWorkspaceUsesConfiguredSelectionBackground to either loop
over [.solidFill, .leftRail] for the activeTabIndicatorStyle parameter passed to
sidebarWorkspaceRowBackgroundStyle or duplicate assertions for .leftRail,
ensuring you call sidebarWorkspaceRowBackgroundStyle with
activeTabIndicatorStyle: .leftRail and verify the same opacity and color
equality checks as currently done for .solidFill.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cmuxTests/SidebarWidthPolicyTests.swift`:
- Around line 68-129: Tests only cover activeTabIndicatorStyle .solidFill;
expand the matrix to also test .leftRail so selection-color behavior is
validated for both indicator styles. Update both
testSelectedColoredWorkspaceUsesStandardSelectionBackgroundInLightAndDark and
testSelectedColoredWorkspaceUsesConfiguredSelectionBackground to either loop
over [.solidFill, .leftRail] for the activeTabIndicatorStyle parameter passed to
sidebarWorkspaceRowBackgroundStyle or duplicate assertions for .leftRail,
ensuring you call sidebarWorkspaceRowBackgroundStyle with
activeTabIndicatorStyle: .leftRail and verify the same opacity and color
equality checks as currently done for .solidFill.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 24a7dbc7-b593-4ca7-bf77-5877e4d4e0d8

📥 Commits

Reviewing files that changed from the base of the PR and between e181f99 and 64e098d.

📒 Files selected for processing (2)
  • Sources/Sidebar/SidebarAppearanceSupport.swift
  • cmuxTests/SidebarWidthPolicyTests.swift
💤 Files with no reviewable changes (1)
  • Sources/Sidebar/SidebarAppearanceSupport.swift

@austinywang
austinywang merged commit d0b699d into main Apr 30, 2026
25 checks passed

This branch was successfully deployed

1 active deployment
Preview – cmux — 64e098d9 Deployed Apr 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sidebar selection background should always be the standard selected color, not the workspace tab color

1 participant