Limits move into the Claude/ChatGPT pills (header ran under the camera); balanced home margins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
maksarsanjeev
2026-10-06 22:27:26 +03:00
parent a4d5032959
commit ae394370bf
4 changed files with 59 additions and 24 deletions
+54 -15
View File
@@ -28,6 +28,26 @@ enum DesktopApps {
struct AppGridView: View {
@ObservedObject var state: AppState
/// "9% · сброс через 1 д 18 ч" — the Claude window closest to its limit.
private var claudeLimit: PillLimit? {
guard state.planRelayInstalled, let usage = state.claudePlanUsage,
let pct = ClaudePlanGauge.dominantPct(usage) else { return nil }
var text = "\(Int(pct.rounded()))%"
if let w = ClaudePlanGauge.dominantWindow(usage), w.resetsAt > Date() {
text += " · сброс через \(PlanTime.untilReset(w.resetsAt))"
}
return PillLimit(text: text, color: ClaudePlanGauge.color(for: pct))
}
/// "23% · сброс сб 15:22" — ChatGPT weekly limit from the Codex logs.
private var chatGPTLimit: PillLimit? {
guard let w = state.codexWeekly else { return nil }
let pct = ClaudePlanGauge.effectivePct(w)
var text = "\(Int(pct.rounded()))%"
if w.resetsAt > Date() { text += " · сброс \(PlanTime.resetMoment(w.resetsAt))" }
return PillLimit(text: text, color: ClaudePlanGauge.color(for: pct))
}
var body: some View {
ZStack {
VStack(spacing: 8) {
@@ -36,12 +56,12 @@ struct AppGridView: View {
EmptyPill()
}
HStack(spacing: 8) {
AppPill(app: DesktopApps.claude)
AppPill(app: DesktopApps.chatGPT)
AppPill(app: DesktopApps.claude, limit: claudeLimit)
AppPill(app: DesktopApps.chatGPT, limit: chatGPTLimit)
}
}
.padding(.leading, 108)
.padding(.trailing, 14)
.padding(.leading, 104)
.padding(.trailing, 20)
.padding(.vertical, 6)
#if !APPSTORE
@@ -62,8 +82,14 @@ struct AppGridView: View {
// MARK: - App pill
struct PillLimit {
let text: String
let color: String
}
struct AppPill: View {
let app: DesktopAppSlot
var limit: PillLimit? = nil
@State private var appURL: URL?
@State private var isRunning = false
@State private var isHovered = false
@@ -78,23 +104,36 @@ struct AppPill: View {
HStack(spacing: 10) {
icon
.frame(width: 26, height: 26)
VStack(alignment: .leading, spacing: 1) {
Text(app.name)
.font(.system(size: 13, weight: .semibold))
.foregroundColor(Color(hex: "#F5F6F8"))
VStack(alignment: .leading, spacing: 2) {
HStack(spacing: 6) {
Text(app.name)
.font(.system(size: 13, weight: .semibold))
.foregroundColor(Color(hex: "#F5F6F8"))
Spacer(minLength: 4)
Image(systemName: "arrow.up.right")
.font(.system(size: 9, weight: .semibold))
.foregroundColor(isHovered ? Color(hex: app.color) : Color(hex: "#5F646D"))
}
HStack(spacing: 5) {
Circle()
.fill(isRunning ? Color(hex: "#34D399") : Color(hex: "#5F646D"))
.frame(width: 5, height: 5)
Text(status)
.font(.system(size: 10.5))
.foregroundColor(Color(hex: "#8E939C"))
// With a limit shown, the green dot alone says "running".
if limit == nil || appURL == nil {
Text(status)
.font(.system(size: 10.5))
.foregroundColor(Color(hex: "#8E939C"))
.lineLimit(1)
}
if let limit, appURL != nil {
Text(limit.text)
.font(.system(size: 10.5, weight: .semibold))
.foregroundColor(Color(hex: limit.color))
.lineLimit(1)
.minimumScaleFactor(0.8)
}
}
}
Spacer(minLength: 4)
Image(systemName: "arrow.up.right")
.font(.system(size: 9, weight: .semibold))
.foregroundColor(isHovered ? Color(hex: app.color) : Color(hex: "#5F646D"))
}
.padding(.horizontal, 12)
.frame(maxWidth: .infinity, maxHeight: .infinity)