Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 43 additions & 11 deletions mac/Sources/CodeBurnMenubar/Views/HeatmapSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ private struct InsightPillSwitcher: View {
private struct TrendInsight: View {
let days: [DailyHistoryEntry]
let period: Period
@AppStorage("codeburn.trendShowsTokens") private var showTokens = false

private var trendDayCount: Int {
switch period {
Expand All @@ -156,10 +157,9 @@ private struct TrendInsight: View {
let dayCount = trendDayCount
let bars = buildTrendBars(from: days, dayCount: dayCount)
let stats = computeTrendStats(bars: bars, allDays: days, dayCount: dayCount)
// Tokens are real for the .all-providers view; per-provider history doesn't carry
// token breakdown yet, so fall back to $ when no tokens are present.
// Per-provider history doesn't carry a token breakdown yet, so tokens mode falls back to $.
let totalTokens = bars.reduce(0.0) { $0 + $1.tokens }
let useTokens = totalTokens > 0
let useTokens = showTokens && totalTokens > 0
let metric: (TrendBar) -> Double = useTokens ? { $0.tokens } : { $0.cost }
let maxValue = max(bars.map(metric).max() ?? 1, 0.01)
let avgValue = bars.isEmpty ? 0 : bars.map(metric).reduce(0, +) / Double(bars.count)
Expand All @@ -178,15 +178,20 @@ private struct TrendInsight: View {
.foregroundStyle(.primary)
}
Spacer()
if let delta = stats.deltaPercent {
HStack(spacing: 3) {
Image(systemName: delta >= 0 ? "arrow.up.right" : "arrow.down.right")
.font(.system(size: 9, weight: .bold))
Text(L("%1$@%% vs prior %2$lldd", (delta >= 0 ? "+" : "") + String(format: "%.0f", delta), dayCount))
.font(.system(size: 10.5))
.monospacedDigit()
VStack(alignment: .trailing, spacing: 4) {
if totalTokens > 0 {
TrendMetricToggle(showTokens: $showTokens)
}
if let delta = stats.deltaPercent {
HStack(spacing: 3) {
Image(systemName: delta >= 0 ? "arrow.up.right" : "arrow.down.right")
.font(.system(size: 9, weight: .bold))
Text(L("%1$@%% vs prior %2$lldd", (delta >= 0 ? "+" : "") + String(format: "%.0f", delta), dayCount))
.font(.system(size: 10.5))
.monospacedDigit()
}
.foregroundStyle(Theme.brandAccent)
}
.foregroundStyle(Theme.brandAccent)
}
}

Expand Down Expand Up @@ -234,6 +239,33 @@ private struct TrendInsight: View {
}
}

private struct TrendMetricToggle: View {
@Binding var showTokens: Bool

var body: some View {
HStack(spacing: 2) {
pill(L("Cost"), selected: !showTokens) { showTokens = false }
pill(L("Tokens"), selected: showTokens) { showTokens = true }
}
}

private func pill(_ label: String, selected: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text(label)
.font(.system(size: 10, weight: .medium))
.fixedSize()
.foregroundStyle(selected ? AnyShapeStyle(.white) : AnyShapeStyle(.secondary))
.padding(.horizontal, 7)
.padding(.vertical, 2)
.background(
RoundedRectangle(cornerRadius: 5)
.fill(selected ? AnyShapeStyle(Theme.brandAccent) : AnyShapeStyle(Color.secondary.opacity(0.10)))
)
}
.buttonStyle(.plain)
}
}

private struct TrendChart: View {
let bars: [TrendBar]
let maxValue: Double
Expand Down
Loading