"use client"; import { useMemo } from "react"; import { Area, AreaChart, YAxis } from "recharts"; import { scaleSymlog } from "d3-scale"; import { ChartContainer, type ChartConfig } from "../ui/chart"; import { ChartMessage } from "./ChartMessage"; import type { HomepageSummary } from "../../lib/homepageSummary"; import { SYMLOG_CONSTANT, compactNumber, symlogTicks, type ChartState, } from "../../lib/homepageChart"; import { buildTimeSeries, type ChartSeries } from "../../lib/homepageChartData"; // One mini-panel per series, each on its OWN y-scale — so the outlier can't // crush the others by construction (the honest per-shape comparison). With three // sites this is a clean 3-up; the panel scale follows the chart's linear/symlog. export function SmallMultiples({ summary, state, }: { summary: HomepageSummary; state: ChartState; }) { const { labels, series } = useMemo( () => buildTimeSeries(summary, state), [summary, state], ); if (series.length === 0) { return No data for this view yet.; } return (
{series.map((s) => ( ))}
); } function Panel({ s, labels, scale, }: { s: ChartSeries; labels: string[]; scale: ChartState["scale"]; }) { const config = useMemo( () => ({ v: { label: s.label, color: s.color } }), [s.label, s.color], ); const rows = useMemo( () => labels.map((x, i) => ({ x, v: s.values[i] ?? null })), [labels, s.values], ); const symlog = useMemo(() => scaleSymlog().constant(SYMLOG_CONSTANT), []); const max = s.values.reduce((m, v) => (v != null && v > m ? v : m), 0); // The panel's headline number is the window total (the per-bucket latest is // often 0 for the current partial bucket). const total = s.values.reduce((sum, v) => sum + (v ?? 0), 0); const isSymlog = scale === "symlog"; const domainMax = Math.max(10, max); return (
{s.label} {compactNumber(Math.round(total))}
); }