Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 80 additions & 6 deletions Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,68 @@ func cmuxAccentColor() -> Color {
Color(nsColor: cmuxAccentNSColor())
}

private func sidebarSelectedWorkspaceRelativeLuminance(_ color: NSColor) -> CGFloat {
let rgbColor = color.usingColorSpace(.sRGB) ?? color
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
rgbColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)

func linearized(_ component: CGFloat) -> CGFloat {
if component <= 0.03928 {
return component / 12.92
}
return pow((component + 0.055) / 1.055, 2.4)
}

let linearRed = linearized(red)
let linearGreen = linearized(green)
let linearBlue = linearized(blue)
return (0.2126 * linearRed) + (0.7152 * linearGreen) + (0.0722 * linearBlue)
}

private func sidebarSelectedWorkspaceContrastRatio(
between first: NSColor,
and second: NSColor
) -> CGFloat {
let firstLuminance = sidebarSelectedWorkspaceRelativeLuminance(first)
let secondLuminance = sidebarSelectedWorkspaceRelativeLuminance(second)
let lighter = max(firstLuminance, secondLuminance)
let darker = min(firstLuminance, secondLuminance)
return (lighter + 0.05) / (darker + 0.05)
}

private func sidebarSelectedWorkspaceReadableBackgroundNSColor(_ color: NSColor) -> NSColor {
let minimumContrast: CGFloat = 4.5
var adjusted = color.usingColorSpace(.sRGB) ?? color
var iteration = 0
Comment on lines +109 to +113

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 forceBright omitted — potential visual inconsistency in leftRail mode

WorkspaceTabColorSettings.displayNSColor is called here without forceBright:

guard let color = WorkspaceTabColorSettings.displayNSColor(
    hex: hex,
    colorScheme: colorScheme
) else {

Every other call site in TabItemView passes forceBright: activeTabIndicatorStyle == .leftRail (lines 13437–13440, 13445–13448). This means the selection background in leftRail mode starts from the base (un-brightened) color, while the left-rail indicator and the color swatch both use the brightened version. The contrast-darkening loop will then operate on a dimmer starting color and may produce a slightly different shade than expected. If this is intentional (avoiding double-brightness before darkening), a comment explaining the decision would help.


// Keep the assigned hue, but darken overly bright custom colors until the
// existing white selected-state foreground remains readable.
while sidebarSelectedWorkspaceContrastRatio(between: adjusted, and: NSColor.white) < minimumContrast,
iteration < 12 {
guard let darkened = adjusted.blended(withFraction: 0.12, of: .black) else { break }
adjusted = darkened.usingColorSpace(.sRGB) ?? darkened
iteration += 1
}

return adjusted
}
Comment on lines +115 to +125

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.

P1 Hardcoded white foreground may produce wrong contrast in light mode

The readability loop always measures contrast against NSColor.white:

while sidebarSelectedWorkspaceContrastRatio(between: adjusted, and: NSColor.white) < minimumContrast,

This is only correct when the selected-row label text is actually white. In light-mode appearances, the sidebar's selected-state text is often rendered in a dark color (e.g., .labelColor, which resolves to near-black in light mode). Darkening a mid-range color to achieve 4.5:1 against white when the real foreground is dark would overshoot — making the background needlessly dark in light mode.

Consider passing colorScheme into sidebarSelectedWorkspaceReadableBackgroundNSColor and using NSColor.white in dark mode but NSColor.black (or a sampled label color) in light mode so the contrast target matches the actual rendered foreground.


private func sidebarSelectedWorkspaceCustomBackgroundNSColor(
hex: String,
colorScheme: ColorScheme
) -> NSColor? {
guard let color = WorkspaceTabColorSettings.displayNSColor(
hex: hex,
colorScheme: colorScheme
) else {
return nil
}
return sidebarSelectedWorkspaceReadableBackgroundNSColor(color)
}

struct SidebarRemoteErrorCopyEntry: Equatable {
let workspaceTitle: String
let target: String
Expand Down Expand Up @@ -112,8 +174,19 @@ enum SidebarRemoteErrorCopySupport {
}
}

func sidebarSelectedWorkspaceBackgroundNSColor(for colorScheme: ColorScheme) -> NSColor {
if let hex = UserDefaults.standard.string(forKey: "sidebarSelectionColorHex"),
func sidebarSelectedWorkspaceBackgroundNSColor(
for colorScheme: ColorScheme,
customHex: String? = nil,
sidebarSelectionColorHex: String? = UserDefaults.standard.string(forKey: "sidebarSelectionColorHex")
) -> NSColor {
if let customHex,
let customColor = sidebarSelectedWorkspaceCustomBackgroundNSColor(
hex: customHex,
colorScheme: colorScheme
) {
return customColor
}
if let hex = sidebarSelectionColorHex,
let parsed = NSColor(hex: hex) {
return parsed
}
Expand Down Expand Up @@ -13323,10 +13396,11 @@ private struct TabItemView: View, Equatable {
}

private var selectionBackgroundColor: NSColor {
if let hex = sidebarSelectionColorHex, let parsed = NSColor(hex: hex) {
return parsed
}
return cmuxAccentNSColor(for: colorScheme)
sidebarSelectedWorkspaceBackgroundNSColor(
for: colorScheme,
customHex: tab.customColor,
sidebarSelectionColorHex: sidebarSelectionColorHex
)
}

private var backgroundColor: Color {
Expand Down
Loading