History

fix: align menu selection colors

Peter Steinberger committed 10 months ago

Commit dedcd251 parent e9491c15 files · +69 −24Browse files

Unified · Split

5 files
  1. CHANGELOG.md +1 −1
  2. Sources/CodexBar/MenuCardView.swift +22 −17
  3. Sources/CodexBar/MenuHighlightStyle.swift +37 −0
  4. Sources/CodexBar/StatusItemController+Menu.swift +6 −4
  5. Sources/CodexBar/UsageProgressBar.swift +3 −2
CHANGELOG.md+1−1
@@ -1,7 +1,7 @@
11 # Changelog
22
33 ## 0.12.1 — Unreleased
4−- (nothing yet)
4+- Menu: custom menu items now use full selection highlight with inverted white text and bars.
55
66 ## 0.12.0 — 2025-12-23
77 - Widgets: add WidgetKit extension backed by a shared app‑group usage snapshot.
Sources/CodexBar/MenuCardView.swift+22−17
@@ -64,6 +64,7 @@ struct UsageMenuCardView: View { · 63 unmodified lines
6464 }
6565
6666 let model: Model
67+ @Environment(\.menuItemHighlighted) private var isHighlighted
6768
6869 init(model: Model) {
6970 self.model = model
@@ -80,7 +81,7 @@ struct UsageMenuCardView: View { · 10 unmodified lines
8081 if self.model.metrics.isEmpty {
8182 if let placeholder = self.model.placeholder {
8283 Text(placeholder)
83− .foregroundStyle(.secondary)
84+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
8485 .font(.subheadline)
8586 }
8687 } else {
@@ -107,13 +108,13 @@ struct UsageMenuCardView: View { · 20 unmodified lines
107108 if let reset = metric.resetText {
108109 Text(reset)
109110 .font(.footnote)
110− .foregroundStyle(.secondary)
111+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
111112 }
112113 }
113114 if let detail = metric.detailText {
114115 Text(detail)
115116 .font(.footnote)
116− .foregroundStyle(.secondary)
117+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
117118 .lineLimit(1)
118119 }
119120 }
@@ -145,14 +146,14 @@ struct UsageMenuCardView: View { · 25 unmodified lines
145146 if let hint = tokenUsage.hintLine, !hint.isEmpty {
146147 Text(hint)
147148 .font(.footnote)
148− .foregroundStyle(.secondary)
149+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
149150 .lineLimit(2)
150151 .fixedSize(horizontal: false, vertical: true)
151152 }
152153 if let error = tokenUsage.errorLine, !error.isEmpty {
153154 Text(error)
154155 .font(.footnote)
155− .foregroundStyle(Color(nsColor: .systemRed))
156+ .foregroundStyle(MenuHighlightStyle.error(self.isHighlighted))
156157 .lineLimit(2)
157158 .fixedSize(horizontal: false, vertical: true)
158159 }
@@ -175,6 +176,7 @@ struct UsageMenuCardView: View { · 16 unmodified lines
175176
176177 private struct UsageMenuCardHeaderView: View {
177178 let model: UsageMenuCardView.Model
179+ @Environment(\.menuItemHighlighted) private var isHighlighted
178180
179181 var body: some View {
180182 VStack(alignment: .leading, spacing: 3) {
@@ -185,7 +187,7 @@ private struct UsageMenuCardHeaderView: View { · 4 unmodified lines
185187 Spacer()
186188 Text(self.model.email)
187189 .font(.subheadline)
188− .foregroundStyle(.secondary)
190+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
189191 }
190192 HStack(alignment: .firstTextBaseline) {
191193 Text(self.model.subtitleText)
@@ -198,7 +200,7 @@ private struct UsageMenuCardHeaderView: View { · 6 unmodified lines
198200 if let plan = self.model.planText {
199201 Text(plan)
200202 .font(.footnote)
201− .foregroundStyle(.secondary)
203+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
202204 .lineLimit(1)
203205 }
204206 }
@@ -207,9 +209,9 @@ private struct UsageMenuCardHeaderView: View { · 2 unmodified lines
207209
208210 private var subtitleColor: Color {
209211 switch self.model.subtitleStyle {
210− case .info: .secondary
211− case .loading: .secondary
212− case .error: Color(nsColor: .systemRed)
212+ case .info: MenuHighlightStyle.secondary(self.isHighlighted)
213+ case .loading: MenuHighlightStyle.secondary(self.isHighlighted)
214+ case .error: MenuHighlightStyle.error(self.isHighlighted)
213215 }
214216 }
215217 }
@@ -236,13 +238,14 @@ struct UsageMenuCardUsageSectionView: View { · 20 unmodified lines
236238 let model: UsageMenuCardView.Model
237239 let showBottomDivider: Bool
238240 let bottomPadding: CGFloat
241+ @Environment(\.menuItemHighlighted) private var isHighlighted
239242
240243 var body: some View {
241244 VStack(alignment: .leading, spacing: 12) {
242245 if self.model.metrics.isEmpty {
243246 if let placeholder = self.model.placeholder {
244247 Text(placeholder)
245− .foregroundStyle(.secondary)
248+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
246249 .font(.subheadline)
247250 }
248251 } else {
@@ -262,13 +265,13 @@ struct UsageMenuCardUsageSectionView: View { · 13 unmodified lines
262265 if let reset = metric.resetText {
263266 Text(reset)
264267 .font(.footnote)
265− .foregroundStyle(.secondary)
268+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
266269 }
267270 }
268271 if let detail = metric.detailText {
269272 Text(detail)
270273 .font(.footnote)
271− .foregroundStyle(.secondary)
274+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
272275 .lineLimit(1)
273276 }
274277 }
@@ -330,6 +333,7 @@ private struct CreditsBarContent: View { · 55 unmodified lines
330333 let creditsRemaining: Double?
331334 let hintText: String?
332335 let progressColor: Color
336+ @Environment(\.menuItemHighlighted) private var isHighlighted
333337
334338 private var percentLeft: Double? {
335339 guard let creditsRemaining else { return nil }
@@ -358,7 +362,7 @@ private struct CreditsBarContent: View { · 22 unmodified lines
358362 Spacer()
359363 Text(self.scaleText)
360364 .font(.caption)
361− .foregroundStyle(.secondary)
365+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
362366 }
363367 } else {
364368 Text(self.creditsText)
@@ -367,7 +371,7 @@ private struct CreditsBarContent: View { · 2 unmodified lines
367371 if let hintText, !hintText.isEmpty {
368372 Text(hintText)
369373 .font(.footnote)
370− .foregroundStyle(.secondary)
374+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
371375 .lineLimit(2)
372376 .fixedSize(horizontal: false, vertical: true)
373377 }
@@ -379,6 +383,7 @@ struct UsageMenuCardCostSectionView: View { · 5 unmodified lines
379383 let model: UsageMenuCardView.Model
380384 let topPadding: CGFloat
381385 let bottomPadding: CGFloat
386+ @Environment(\.menuItemHighlighted) private var isHighlighted
382387
383388 var body: some View {
384389 if let tokenUsage = self.model.tokenUsage {
@@ -393,14 +398,14 @@ struct UsageMenuCardCostSectionView: View { · 8 unmodified lines
393398 if let hint = tokenUsage.hintLine, !hint.isEmpty {
394399 Text(hint)
395400 .font(.footnote)
396− .foregroundStyle(.secondary)
401+ .foregroundStyle(MenuHighlightStyle.secondary(self.isHighlighted))
397402 .lineLimit(2)
398403 .fixedSize(horizontal: false, vertical: true)
399404 }
400405 if let error = tokenUsage.errorLine, !error.isEmpty {
401406 Text(error)
402407 .font(.footnote)
403− .foregroundStyle(Color(nsColor: .systemRed))
408+ .foregroundStyle(MenuHighlightStyle.error(self.isHighlighted))
404409 .lineLimit(2)
405410 .fixedSize(horizontal: false, vertical: true)
406411 }
Sources/CodexBar/MenuHighlightStyle.swift+37−0
@@ -0,0 +1,37 @@
1+import SwiftUI
2+
3+private struct MenuItemHighlightedKey: EnvironmentKey {
4+ static let defaultValue = false
5+}
6+
7+extension EnvironmentValues {
8+ var menuItemHighlighted: Bool {
9+ get { self[MenuItemHighlightedKey.self] }
10+ set { self[MenuItemHighlightedKey.self] = newValue }
11+ }
12+}
13+
14+enum MenuHighlightStyle {
15+ static let selectionBackground = Color(nsColor: .controlAccentColor)
16+ static let selectionText = Color.white
17+
18+ static func primary(_ highlighted: Bool) -> Color {
19+ highlighted ? Self.selectionText : .primary
20+ }
21+
22+ static func secondary(_ highlighted: Bool) -> Color {
23+ highlighted ? Self.selectionText : .secondary
24+ }
25+
26+ static func error(_ highlighted: Bool) -> Color {
27+ highlighted ? Self.selectionText : Color(nsColor: .systemRed)
28+ }
29+
30+ static func progressTrack(_ highlighted: Bool) -> Color {
31+ highlighted ? Self.selectionText.opacity(0.35) : Color.secondary.opacity(0.25)
32+ }
33+
34+ static func progressTint(_ highlighted: Bool, fallback: Color) -> Color {
35+ highlighted ? Self.selectionText : fallback
36+ }
37+}
Sources/CodexBar/StatusItemController+Menu.swift+6−4
@@ -469,6 +469,8 @@ extension StatusItemController { · 468 unmodified lines
469469
470470 var body: some View {
471471 self.content
472+ .environment(\.menuItemHighlighted, self.highlightState.isHighlighted)
473+ .foregroundStyle(MenuHighlightStyle.primary(self.highlightState.isHighlighted))
472474 .background(alignment: .topLeading) {
473475 if self.highlightState.isHighlighted {
474476 self.highlightBackground
@@ -478,7 +480,7 @@ extension StatusItemController { · 3 unmodified lines
478480 if self.showsSubmenuIndicator {
479481 Image(systemName: "chevron.right")
480482 .font(.caption2.weight(.semibold))
481− .foregroundStyle(.secondary)
483+ .foregroundStyle(MenuHighlightStyle.secondary(self.highlightState.isHighlighted))
482484 .padding(.top, 8)
483485 .padding(.trailing, 10)
484486 }
@@ -492,7 +494,7 @@ extension StatusItemController { · 7 unmodified lines
492494 let bottomInset: CGFloat = 1
493495 let height = max(0, proxy.size.height - self.highlightExclusionHeight - topInset - bottomInset)
494496 RoundedRectangle(cornerRadius: 6, style: .continuous)
495− .fill(Color(nsColor: .controlAccentColor).opacity(0.18))
497+ .fill(MenuHighlightStyle.selectionBackground)
496498 .frame(height: height, alignment: .top)
497499 .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
498500 .padding(.horizontal, 6)
@@ -676,9 +678,9 @@ private final class ProviderSwitcherView: NSView { · 177 unmodified lines
676678 private let segments: [Segment]
677679 private let onSelect: (UsageProvider) -> Void
678680 private var buttons: [NSButton] = []
679− private let selectedBackground = NSColor.labelColor.withAlphaComponent(0.12).cgColor
681+ private let selectedBackground = NSColor.controlAccentColor.cgColor
680682 private let unselectedBackground = NSColor.clear.cgColor
681− private let selectedTextColor = NSColor.labelColor
683+ private let selectedTextColor = NSColor.white
682684 private let unselectedTextColor = NSColor.secondaryLabelColor
683685
684686 init(
Sources/CodexBar/UsageProgressBar.swift+3−2
@@ -5,6 +5,7 @@ struct UsageProgressBar: View { · 4 unmodified lines
55 let percent: Double
66 let tint: Color
77 let accessibilityLabel: String
8+ @Environment(\.menuItemHighlighted) private var isHighlighted
89
910 private var clamped: Double {
1011 min(100, max(0, self.percent))
@@ -15,9 +16,9 @@ struct UsageProgressBar: View { · 4 unmodified lines
1516 let fillWidth = proxy.size.width * self.clamped / 100
1617 ZStack(alignment: .leading) {
1718 Capsule()
18− .fill(Color.secondary.opacity(0.25))
19+ .fill(MenuHighlightStyle.progressTrack(self.isHighlighted))
1920 Capsule()
20− .fill(self.tint)
21+ .fill(MenuHighlightStyle.progressTint(self.isHighlighted, fallback: self.tint))
2122 .frame(width: fillWidth)
2223 }
2324 }