feat(mac): show session labels under context bars
This commit is contained in:
@@ -22,7 +22,7 @@ struct MenuContent: View {
|
|||||||
|
|
||||||
private let activeSessionWindowSeconds: TimeInterval = 24 * 60 * 60
|
private let activeSessionWindowSeconds: TimeInterval = 24 * 60 * 60
|
||||||
private let contextCardPadding: CGFloat = 10
|
private let contextCardPadding: CGFloat = 10
|
||||||
private let contextPillHeight: CGFloat = 16
|
private let contextBarHeight: CGFloat = 6
|
||||||
private let contextFallbackWidth: CGFloat = 280
|
private let contextFallbackWidth: CGFloat = 280
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -260,25 +260,19 @@ struct MenuContent: View {
|
|||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var contextCardRow: some View {
|
private var contextCardRow: some View {
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
HStack(alignment: .firstTextBaseline) {
|
Text("Context")
|
||||||
Text("Context")
|
.font(.caption.weight(.semibold))
|
||||||
.font(.caption.weight(.semibold))
|
.foregroundStyle(.secondary)
|
||||||
.foregroundStyle(.secondary)
|
|
||||||
Spacer(minLength: 10)
|
if self.contextSessions.isEmpty {
|
||||||
Text(self.contextSubtitle)
|
Text("No active sessions")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
|
||||||
if self.contextSessions.isEmpty {
|
|
||||||
Text("No sessions yet")
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundStyle(.secondary)
|
|
||||||
} else {
|
|
||||||
ForEach(self.contextSessions) { row in
|
ForEach(self.contextSessions) { row in
|
||||||
self.contextSessionPill(row)
|
self.contextSessionRow(row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,46 +298,33 @@ struct MenuContent: View {
|
|||||||
.disabled(true)
|
.disabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var contextSubtitle: String {
|
|
||||||
let count = self.contextActiveCount
|
|
||||||
if count == 0 { return "Main session" }
|
|
||||||
if count == 1 { return "1 active session" }
|
|
||||||
return "\(count) active sessions"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var contextPillWidth: CGFloat {
|
private var contextPillWidth: CGFloat {
|
||||||
let base = self.contextCardWidth > 0 ? self.contextCardWidth : self.contextFallbackWidth
|
let base = self.contextCardWidth > 0 ? self.contextCardWidth : self.contextFallbackWidth
|
||||||
return max(1, base - (self.contextCardPadding * 2))
|
return max(1, base - (self.contextCardPadding * 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func contextSessionPill(_ row: SessionRow) -> some View {
|
private func contextSessionRow(_ row: SessionRow) -> some View {
|
||||||
let label = row.key
|
|
||||||
let summary = row.tokens.contextSummaryShort
|
|
||||||
|
|
||||||
let width = self.contextPillWidth
|
let width = self.contextPillWidth
|
||||||
ZStack(alignment: .center) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
ContextUsageBar(
|
ContextUsageBar(
|
||||||
usedTokens: row.tokens.total,
|
usedTokens: row.tokens.total,
|
||||||
contextTokens: row.tokens.contextTokens,
|
contextTokens: row.tokens.contextTokens,
|
||||||
width: width,
|
width: width,
|
||||||
height: self.contextPillHeight)
|
height: self.contextBarHeight)
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
Text(label)
|
Text(row.key)
|
||||||
.font(.caption.weight(row.key == "main" ? .semibold : .regular))
|
.font(.caption2.weight(row.key == "main" ? .semibold : .regular))
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.truncationMode(.middle)
|
.truncationMode(.middle)
|
||||||
.layoutPriority(1)
|
.layoutPriority(1)
|
||||||
Spacer(minLength: 8)
|
Spacer(minLength: 8)
|
||||||
Text(summary)
|
Text(row.tokens.contextSummaryShort)
|
||||||
.font(.caption.monospacedDigit())
|
.font(.caption2.monospacedDigit())
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 8)
|
|
||||||
.padding(.vertical, 1)
|
|
||||||
}
|
}
|
||||||
.frame(width: width, height: self.contextPillHeight)
|
.frame(width: width)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var heartbeatStatusRow: some View {
|
private var heartbeatStatusRow: some View {
|
||||||
@@ -516,14 +497,8 @@ struct MenuContent: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let activeCount = active.count
|
let activeCount = active.count
|
||||||
let main = rows.first(where: { $0.key == "main" })
|
|
||||||
var merged = active
|
|
||||||
if let main, !merged.contains(where: { $0.key == "main" }) {
|
|
||||||
merged.insert(main, at: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep stable ordering: main first, then most recent.
|
// Keep stable ordering: main first, then most recent.
|
||||||
let sorted = merged.sorted { lhs, rhs in
|
let sorted = active.sorted { lhs, rhs in
|
||||||
if lhs.key == "main" { return true }
|
if lhs.key == "main" { return true }
|
||||||
if rhs.key == "main" { return false }
|
if rhs.key == "main" { return false }
|
||||||
return (lhs.updatedAt ?? .distantPast) > (rhs.updatedAt ?? .distantPast)
|
return (lhs.updatedAt ?? .distantPast) > (rhs.updatedAt ?? .distantPast)
|
||||||
|
|||||||
Reference in New Issue
Block a user