From 5e51107711e4e0486eb1a67be8884d7c9eebbdac Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 13 Dec 2025 00:23:00 +0000 Subject: [PATCH] fix(mac): size context bar to menu --- .../Sources/Clawdis/ContextUsageBar.swift | 34 ++++++++++++++----- .../Sources/Clawdis/MenuContentView.swift | 9 ++++- .../Sources/Clawdis/SessionsSettings.swift | 2 +- apps/macos/Sources/Clawdis/ViewMetrics.swift | 20 +++++++++++ 4 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 apps/macos/Sources/Clawdis/ViewMetrics.swift diff --git a/apps/macos/Sources/Clawdis/ContextUsageBar.swift b/apps/macos/Sources/Clawdis/ContextUsageBar.swift index 6c1a2d497..0e8beb6c6 100644 --- a/apps/macos/Sources/Clawdis/ContextUsageBar.swift +++ b/apps/macos/Sources/Clawdis/ContextUsageBar.swift @@ -4,7 +4,7 @@ import SwiftUI struct ContextUsageBar: View { let usedTokens: Int let contextTokens: Int - var width: CGFloat = 220 + var width: CGFloat? var height: CGFloat = 6 private var clampedFractionUsed: Double { @@ -28,14 +28,30 @@ struct ContextUsageBar: View { var body: some View { // SwiftUI menus (MenuBarExtraStyle.menu) drop certain view types (including ProgressView/Canvas). // Render the bar as an image to reliably display inside the menu. - Image(nsImage: Self.renderBar( - width: self.width, - height: self.height, - fractionUsed: self.clampedFractionUsed, - percentUsed: self.percentUsed)) - .resizable() - .interpolation(.none) - .frame(width: self.width, height: self.height) + Group { + if let width = self.width, width > 0 { + Image(nsImage: Self.renderBar( + width: width, + height: self.height, + fractionUsed: self.clampedFractionUsed, + percentUsed: self.percentUsed)) + .resizable() + .interpolation(.none) + .frame(width: width, height: self.height) + } else { + GeometryReader { proxy in + Image(nsImage: Self.renderBar( + width: proxy.size.width, + height: self.height, + fractionUsed: self.clampedFractionUsed, + percentUsed: self.percentUsed)) + .resizable() + .interpolation(.none) + .frame(width: proxy.size.width, height: self.height) + } + .frame(height: self.height) + } + } .accessibilityLabel("Context usage") .accessibilityValue(self.accessibilityValue) } diff --git a/apps/macos/Sources/Clawdis/MenuContentView.swift b/apps/macos/Sources/Clawdis/MenuContentView.swift index 5ae855e45..ed84385a1 100644 --- a/apps/macos/Sources/Clawdis/MenuContentView.swift +++ b/apps/macos/Sources/Clawdis/MenuContentView.swift @@ -17,6 +17,7 @@ struct MenuContent: View { @State private var loadingMics = false @State private var sessionMenu: [SessionRow] = [] @State private var mainSessionRow: SessionRow? + @State private var mainSessionContextWidth: CGFloat = 0 var body: some View { VStack(alignment: .leading, spacing: 8) { @@ -266,9 +267,15 @@ struct MenuContent: View { ContextUsageBar( usedTokens: row.tokens.total, contextTokens: row.tokens.contextTokens, - width: 220) + width: self.mainSessionContextWidth > 0 ? self.mainSessionContextWidth : nil) } .padding(.vertical, 2) + .onWidthChange { width in + let next = max(120, width) + if abs(next - self.mainSessionContextWidth) > 1 { + self.mainSessionContextWidth = next + } + } } else { HStack(spacing: 8) { Text("Context (main)") diff --git a/apps/macos/Sources/Clawdis/SessionsSettings.swift b/apps/macos/Sources/Clawdis/SessionsSettings.swift index 78cb47671..0512a033a 100644 --- a/apps/macos/Sources/Clawdis/SessionsSettings.swift +++ b/apps/macos/Sources/Clawdis/SessionsSettings.swift @@ -154,7 +154,7 @@ struct SessionsSettings: View { ContextUsageBar( usedTokens: row.tokens.total, contextTokens: row.tokens.contextTokens, - width: 260) + width: nil) } HStack(spacing: 10) { diff --git a/apps/macos/Sources/Clawdis/ViewMetrics.swift b/apps/macos/Sources/Clawdis/ViewMetrics.swift new file mode 100644 index 000000000..e33945512 --- /dev/null +++ b/apps/macos/Sources/Clawdis/ViewMetrics.swift @@ -0,0 +1,20 @@ +import SwiftUI + +private struct ViewWidthPreferenceKey: PreferenceKey { + static let defaultValue: CGFloat = 0 + + static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { + value = max(value, nextValue()) + } +} + +extension View { + func onWidthChange(_ onChange: @escaping (CGFloat) -> Void) -> some View { + self.background( + GeometryReader { proxy in + Color.clear.preference(key: ViewWidthPreferenceKey.self, value: proxy.size.width) + }) + .onPreferenceChange(ViewWidthPreferenceKey.self, perform: onChange) + } +} +