From c0f7a07a7b87f9ec6539eb05e2186471720549ab Mon Sep 17 00:00:00 2001 From: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Date: Mon, 16 Feb 2026 03:20:51 -0800 Subject: [PATCH] Fix sidebar tabs getting extra left padding when update pill is visible Move GeometryReader from wrapping the entire VStack to wrapping only the ScrollView so proxy.size.height reflects available height (minus pill), preventing unnecessary scrollability that triggered macOS horizontal insets. Also clamp update pill text width with maxWidth instead of fixed width so it truncates gracefully at narrow sidebar widths and grows when wider, add horizontal padding, left-align truncated text, and add debug menu item for testing with long nightly version strings. --- Sources/AppDelegate.swift | 9 +++++++++ Sources/ContentView.swift | 26 +++++++++++++------------- Sources/Update/UpdatePill.swift | 2 +- Sources/Update/UpdateViewModel.swift | 6 ++++++ Sources/cmuxApp.swift | 3 +++ 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Sources/AppDelegate.swift b/Sources/AppDelegate.swift index b712734b..c2951cde 100644 --- a/Sources/AppDelegate.swift +++ b/Sources/AppDelegate.swift @@ -799,18 +799,27 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent #if DEBUG @objc func showUpdatePill(_ sender: Any?) { + updateViewModel.debugOverrideText = nil + updateViewModel.overrideState = .installing(.init(isAutoUpdate: true, retryTerminatingApplication: {}, dismiss: {})) + } + + @objc func showUpdatePillLongNightly(_ sender: Any?) { + updateViewModel.debugOverrideText = "Update Available: 1.32.0-nightly+20260216.abc1234" updateViewModel.overrideState = .notFound(.init(acknowledgement: {})) } @objc func showUpdatePillLoading(_ sender: Any?) { + updateViewModel.debugOverrideText = nil updateViewModel.overrideState = .checking(.init(cancel: {})) } @objc func hideUpdatePill(_ sender: Any?) { + updateViewModel.debugOverrideText = nil updateViewModel.overrideState = .idle } @objc func clearUpdatePillOverride(_ sender: Any?) { + updateViewModel.debugOverrideText = nil updateViewModel.overrideState = nil } #endif diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 18b7b15d..58444ba0 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -526,8 +526,8 @@ struct VerticalTabsSidebar: View { private let tabRowSpacing: CGFloat = 2 var body: some View { - GeometryReader { proxy in - VStack(spacing: 0) { + VStack(spacing: 0) { + GeometryReader { proxy in ScrollView { VStack(spacing: 0) { // Space for traffic lights @@ -577,18 +577,18 @@ struct VerticalTabsSidebar: View { } .background(Color.clear) .modifier(ClearScrollBackground()) -#if DEBUG - SidebarDevFooter(updateViewModel: updateViewModel) - .frame(maxWidth: .infinity, alignment: .leading) -#else - UpdatePill(model: updateViewModel) - .padding(.leading, 10) - .padding(.bottom, 10) - .frame(maxWidth: .infinity, alignment: .leading) -#endif } - .accessibilityIdentifier("Sidebar") +#if DEBUG + SidebarDevFooter(updateViewModel: updateViewModel) + .frame(maxWidth: .infinity, alignment: .leading) +#else + UpdatePill(model: updateViewModel) + .padding(.horizontal, 10) + .padding(.bottom, 10) + .frame(maxWidth: .infinity, alignment: .leading) +#endif } + .accessibilityIdentifier("Sidebar") .ignoresSafeArea() .background(SidebarBackdrop().ignoresSafeArea()) .onAppear { @@ -740,7 +740,7 @@ private struct SidebarDevFooter: View { .font(.system(size: 11, weight: .semibold)) .foregroundColor(.red) } - .padding(.leading, 10) + .padding(.horizontal, 10) .padding(.bottom, 10) } } diff --git a/Sources/Update/UpdatePill.swift b/Sources/Update/UpdatePill.swift index 0ff1f606..a976fee5 100644 --- a/Sources/Update/UpdatePill.swift +++ b/Sources/Update/UpdatePill.swift @@ -42,7 +42,7 @@ struct UpdatePill: View { .font(Font(textFont)) .lineLimit(1) .truncationMode(.tail) - .frame(width: textWidth) + .frame(maxWidth: textWidth, alignment: .leading) } .padding(.horizontal, 8) .padding(.vertical, 4) diff --git a/Sources/Update/UpdateViewModel.swift b/Sources/Update/UpdateViewModel.swift index 4644e745..8aa275af 100644 --- a/Sources/Update/UpdateViewModel.swift +++ b/Sources/Update/UpdateViewModel.swift @@ -6,12 +6,18 @@ import Sparkle class UpdateViewModel: ObservableObject { @Published var state: UpdateState = .idle @Published var overrideState: UpdateState? + #if DEBUG + @Published var debugOverrideText: String? + #endif var effectiveState: UpdateState { overrideState ?? state } var text: String { + #if DEBUG + if let debugOverrideText { return debugOverrideText } + #endif switch effectiveState { case .idle: return "" diff --git a/Sources/cmuxApp.swift b/Sources/cmuxApp.swift index 8c775dce..0eba58c4 100644 --- a/Sources/cmuxApp.swift +++ b/Sources/cmuxApp.swift @@ -202,6 +202,9 @@ struct cmuxApp: App { Button("Show Update Pill") { appDelegate.showUpdatePill(nil) } + Button("Show Long Nightly Pill") { + appDelegate.showUpdatePillLongNightly(nil) + } Button("Show Loading State") { appDelegate.showUpdatePillLoading(nil) }