diff --git a/packages/ui/components/ui/chart.tsx b/packages/ui/components/ui/chart.tsx
index 72f6fb116..8d09b7322 100644
--- a/packages/ui/components/ui/chart.tsx
+++ b/packages/ui/components/ui/chart.tsx
@@ -127,6 +127,7 @@ function ChartTooltipContent({
labelFormatter,
labelClassName,
formatter,
+ footer,
color,
nameKey,
labelKey,
@@ -137,6 +138,16 @@ function ChartTooltipContent({
indicator?: "line" | "dot" | "dashed"
nameKey?: string
labelKey?: string
+ footer?:
+ | React.ReactNode
+ | ((
+ payload: NonNullable<
+ RechartsPrimitive.DefaultTooltipContentProps<
+ TooltipValueType,
+ TooltipNameType
+ >["payload"]
+ >,
+ ) => React.ReactNode)
} & Omit<
RechartsPrimitive.DefaultTooltipContentProps<
TooltipValueType,
@@ -266,6 +277,11 @@ function ChartTooltipContent({
)
})}
+ {footer != null && (
+
+ {typeof footer === "function" ? footer(payload) : footer}
+
+ )}
)
}
diff --git a/packages/views/locales/en/runtimes.json b/packages/views/locales/en/runtimes.json
index 8dfcc7623..32ed75fc1 100644
--- a/packages/views/locales/en/runtimes.json
+++ b/packages/views/locales/en/runtimes.json
@@ -154,7 +154,8 @@
},
"charts": {
"heatmap_less": "Less",
- "heatmap_more": "More"
+ "heatmap_more": "More",
+ "tooltip_total": "Total"
},
"list": {
"col_runtime": "Runtime",
diff --git a/packages/views/locales/zh-Hans/runtimes.json b/packages/views/locales/zh-Hans/runtimes.json
index 9ecdc0f17..c1aba9772 100644
--- a/packages/views/locales/zh-Hans/runtimes.json
+++ b/packages/views/locales/zh-Hans/runtimes.json
@@ -149,7 +149,8 @@
},
"charts": {
"heatmap_less": "少",
- "heatmap_more": "多"
+ "heatmap_more": "多",
+ "tooltip_total": "总计"
},
"list": {
"col_runtime": "运行时",
diff --git a/packages/views/runtimes/components/charts/daily-cost-chart.tsx b/packages/views/runtimes/components/charts/daily-cost-chart.tsx
index 625716618..5f9ee2032 100644
--- a/packages/views/runtimes/components/charts/daily-cost-chart.tsx
+++ b/packages/views/runtimes/components/charts/daily-cost-chart.tsx
@@ -12,6 +12,7 @@ import {
type ChartConfig,
} from "@multica/ui/components/ui/chart";
import type { DailyCostStackData } from "../../utils";
+import { useT } from "../../../i18n";
// Three-segment stack (input / output / cache write) — keeps the user's
// attention on what's actually driving spend. Cache reads are excluded
@@ -29,6 +30,7 @@ export const costStackConfig = {
} satisfies ChartConfig;
export function DailyCostChart({ data }: { data: DailyCostStackData[] }) {
+ const { t } = useT("runtimes");
// No internal empty-state — the parent decides what to show in place of
// the chart (often a diagnostic explaining *why* there's no cost). Letting
// recharts render an empty axis would be both ugly and uninformative.
@@ -58,6 +60,22 @@ export function DailyCostChart({ data }: { data: DailyCostStackData[] }) {
? `$${value.toFixed(2)} ${name}`
: `${value} ${name}`
}
+ footer={(payload) => {
+ const total = payload.reduce(
+ (sum, item) =>
+ sum +
+ (typeof item.value === "number" ? item.value : 0),
+ 0,
+ );
+ return (
+
+ {t(($) => $.charts.tooltip_total)}
+
+ ${total.toFixed(2)}
+
+
+ );
+ }}
/>
}
/>
diff --git a/packages/views/runtimes/components/charts/daily-tokens-chart.tsx b/packages/views/runtimes/components/charts/daily-tokens-chart.tsx
index 27da0408e..48110e6f1 100644
--- a/packages/views/runtimes/components/charts/daily-tokens-chart.tsx
+++ b/packages/views/runtimes/components/charts/daily-tokens-chart.tsx
@@ -12,6 +12,7 @@ import {
type ChartConfig,
} from "@multica/ui/components/ui/chart";
import { formatTokens, type DailyTokenData } from "../../utils";
+import { useT } from "../../../i18n";
// Four-segment stack — input / output / cache read / cache write. Unlike the
// cost chart, cache reads ARE visible here: a typical day on Claude shows
@@ -32,6 +33,7 @@ export const tokenStackConfig = {
} satisfies ChartConfig;
export function DailyTokensChart({ data }: { data: DailyTokenData[] }) {
+ const { t } = useT("runtimes");
// No internal empty-state — same convention as DailyCostChart: the parent
// decides what to render when there's nothing to show.
return (
@@ -60,6 +62,22 @@ export function DailyTokensChart({ data }: { data: DailyTokenData[] }) {
? `${formatTokens(value)} ${name}`
: `${value} ${name}`
}
+ footer={(payload) => {
+ const total = payload.reduce(
+ (sum, item) =>
+ sum +
+ (typeof item.value === "number" ? item.value : 0),
+ 0,
+ );
+ return (
+
+ {t(($) => $.charts.tooltip_total)}
+
+ {total.toLocaleString()}
+
+
+ );
+ }}
/>
}
/>