From afc2c5933031ad8dc22a93cdbee4992bc295e8d4 Mon Sep 17 00:00:00 2001 From: Chad Neal Date: Thu, 19 Mar 2026 23:29:20 -0600 Subject: [PATCH 1/2] Fix preferences sidebar clipping and window sizing on macOS Tahoe The Providers tab sidebar was clipping provider names, icons, and reorder handles on the left edge due to .listStyle(.sidebar) imposing internal leading insets that push content beyond the 240px frame on macOS Tahoe. - Replace List with ScrollView+VStack for full control over sidebar layout - Add direct NSWindow.setFrame resizing since SwiftUI's .windowResizability(.contentSize) doesn't propagate frame changes - Add PreferencesTab.title and CaseIterable to eliminate hardcoded tab title strings in the window finder - Use system selectedContentBackgroundColor for sidebar selection highlight - Add ensure_swift_version() to compile_and_run.sh for Xcode toolchain fallback Co-Authored-By: Claude Opus 4.6 (1M context) --- Scripts/compile_and_run.sh | 22 ++++++++++ .../PreferencesProviderSidebarView.swift | 43 +++++++++++-------- Sources/CodexBar/PreferencesView.swift | 31 ++++++++++++- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/Scripts/compile_and_run.sh b/Scripts/compile_and_run.sh index ce6992d45..2d6758a13 100755 --- a/Scripts/compile_and_run.sh +++ b/Scripts/compile_and_run.sh @@ -20,6 +20,27 @@ SIGNING_MODE="${CODEXBAR_SIGNING:-}" log() { printf '%s\n' "$*"; } fail() { printf 'ERROR: %s\n' "$*" >&2; exit 1; } +# Ensure Swift >= 5.5 (required for --arch flag in swift build) +ensure_swift_version() { + local swift_ver + swift_ver=$(swift --version 2>&1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1) + local major minor + major=$(echo "$swift_ver" | cut -d. -f1) + minor=$(echo "$swift_ver" | cut -d. -f2) + if [[ "${major:-0}" -ge 6 ]] || { [[ "${major:-0}" -eq 5 ]] && [[ "${minor:-0}" -ge 5 ]]; }; then + return 0 + fi + # Try Xcode toolchain + local xcrun_swift + xcrun_swift=$(xcrun --find swift 2>/dev/null || true) + if [[ -n "$xcrun_swift" && -x "$xcrun_swift" ]]; then + log "WARN: PATH swift is v${swift_ver}; switching to Xcode toolchain at $(dirname "$xcrun_swift")" + export PATH="$(dirname "$xcrun_swift"):$PATH" + return 0 + fi + fail "Swift >= 5.5 required (found ${swift_ver:-none}). Install Xcode or update swiftly." +} + has_signing_identity() { local identity="${1:-}" if [[ -z "${identity}" ]]; then @@ -163,6 +184,7 @@ for arg in "$@"; do esac done +ensure_swift_version resolve_signing_mode if [[ "${SIGNING_MODE}" == "adhoc" ]]; then log "==> Signing: adhoc (set APP_IDENTITY or install a dev cert to avoid keychain prompts)" diff --git a/Sources/CodexBar/PreferencesProviderSidebarView.swift b/Sources/CodexBar/PreferencesProviderSidebarView.swift index ee34cb3e7..dfc5ca54a 100644 --- a/Sources/CodexBar/PreferencesProviderSidebarView.swift +++ b/Sources/CodexBar/PreferencesProviderSidebarView.swift @@ -13,26 +13,33 @@ struct ProviderSidebarListView: View { @State private var draggingProvider: UsageProvider? var body: some View { - List(selection: self.$selection) { - ForEach(self.providers, id: \.self) { provider in - ProviderSidebarRowView( - provider: provider, - store: self.store, - isEnabled: self.isEnabled(provider), - subtitle: self.subtitle(provider), - draggingProvider: self.$draggingProvider) - .tag(provider) - .onDrop( - of: [UTType.plainText], - delegate: ProviderSidebarDropDelegate( - item: provider, - providers: self.providers, - dragging: self.$draggingProvider, - moveProviders: self.moveProviders)) + ScrollView { + VStack(spacing: 0) { + ForEach(self.providers, id: \.self) { provider in + ProviderSidebarRowView( + provider: provider, + store: self.store, + isEnabled: self.isEnabled(provider), + subtitle: self.subtitle(provider), + draggingProvider: self.$draggingProvider) + .padding(.horizontal, 8) + .background( + RoundedRectangle(cornerRadius: 6, style: .continuous) + .fill(self.selection == provider ? Color(nsColor: .selectedContentBackgroundColor) : Color.clear) + .padding(.horizontal, 4)) + .contentShape(Rectangle()) + .onTapGesture { self.selection = provider } + .onDrop( + of: [UTType.plainText], + delegate: ProviderSidebarDropDelegate( + item: provider, + providers: self.providers, + dragging: self.$draggingProvider, + moveProviders: self.moveProviders)) + } } + .padding(.vertical, 4) } - .listStyle(.sidebar) - .scrollContentBackground(.hidden) .background( RoundedRectangle(cornerRadius: ProviderSettingsMetrics.sidebarCornerRadius, style: .continuous) .fill(.regularMaterial)) diff --git a/Sources/CodexBar/PreferencesView.swift b/Sources/CodexBar/PreferencesView.swift index a6f893950..d661d7b6b 100644 --- a/Sources/CodexBar/PreferencesView.swift +++ b/Sources/CodexBar/PreferencesView.swift @@ -1,7 +1,7 @@ import AppKit import SwiftUI -enum PreferencesTab: String, Hashable { +enum PreferencesTab: String, CaseIterable, Hashable { case general case providers case display @@ -13,6 +13,17 @@ enum PreferencesTab: String, Hashable { static let providersWidth: CGFloat = 720 static let windowHeight: CGFloat = 580 + var title: String { + switch self { + case .general: "General" + case .providers: "Providers" + case .display: "Display" + case .advanced: "Advanced" + case .about: "About" + case .debug: "Debug" + } + } + var preferredWidth: CGFloat { self == .providers ? PreferencesTab.providersWidth : PreferencesTab.defaultWidth } @@ -84,6 +95,24 @@ struct PreferencesView: View { } else { change() } + Self.resizeSettingsWindow(width: tab.preferredWidth, height: tab.preferredHeight, animate: animate) + } + + private static let settingsWindowIdentifier = "com_apple_SwiftUI_Settings_window" + private static let knownTabTitles = Set(PreferencesTab.allCases.map(\.title)) + + private static func resizeSettingsWindow(width: CGFloat, height: CGFloat, animate: Bool) { + guard let window = NSApp.windows.first(where: { + $0.identifier?.rawValue == settingsWindowIdentifier + || knownTabTitles.contains($0.title) + }) else { return } + let toolbarHeight = window.frame.height - window.contentLayoutRect.height + guard toolbarHeight > 0 else { return } + let newSize = NSSize(width: width, height: height + toolbarHeight) + var frame = window.frame + frame.origin.y += frame.size.height - newSize.height + frame.size = newSize + window.setFrame(frame, display: true, animate: animate) } private func ensureValidTabSelection() { From a906c812e583f6a89e86b6173140c5f64a46340e Mon Sep 17 00:00:00 2001 From: Chad Neal Date: Fri, 20 Mar 2026 05:18:58 -0600 Subject: [PATCH 2/2] Fix lint: wrap long line to stay within 120-char max width Co-Authored-By: Claude Opus 4.6 (1M context) --- Sources/CodexBar/PreferencesProviderSidebarView.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/CodexBar/PreferencesProviderSidebarView.swift b/Sources/CodexBar/PreferencesProviderSidebarView.swift index dfc5ca54a..f42028588 100644 --- a/Sources/CodexBar/PreferencesProviderSidebarView.swift +++ b/Sources/CodexBar/PreferencesProviderSidebarView.swift @@ -25,7 +25,10 @@ struct ProviderSidebarListView: View { .padding(.horizontal, 8) .background( RoundedRectangle(cornerRadius: 6, style: .continuous) - .fill(self.selection == provider ? Color(nsColor: .selectedContentBackgroundColor) : Color.clear) + .fill( + self.selection == provider + ? Color(nsColor: .selectedContentBackgroundColor) + : Color.clear) .padding(.horizontal, 4)) .contentShape(Rectangle()) .onTapGesture { self.selection = provider }