/** * The window's four headline numbers (ui-visual-redesign.md): centred 2.5rem * numerals over lowercase captions, each with the way into the rows behind it. * Colour is semantic and nothing else — the blocked count is red, the share is * muted, the rest is ink — so a tile never implies a state it is not reporting. * * On a phone the four tiles merge into one card: the three counts side by side * and the share on a line under them, so the set fits above the fold. * * The Activity links carry the bounds the **overview response** returned, not * bounds computed here — a client-computed window would send the reader to a * slightly different span than the one they were just reading — and the client * scope the page is under, so the rows they open are the rows the tile counted. */ import * as stylex from "@stylexjs/stylex"; import { Link } from "@tanstack/react-router"; import { formatCount, formatPercent } from "@/lib/format"; import type { OverviewTotals } from "@/lib/types"; import { styles as shared } from "@/ui/styles"; import { colors, metrics } from "@/ui/tokens.stylex"; const NARROW = "@media (max-width: 800px)"; const styles = stylex.create({ grid: { display: "grid", gap: { default: "1rem", [NARROW]: 0 }, gridTemplateColumns: { default: "repeat(4, minmax(0, 1fr))", [NARROW]: "repeat(3, minmax(0, 1fr))" }, margin: 0, padding: 0, listStyleType: "none", borderRadius: { default: null, [NARROW]: metrics.radius }, borderWidth: { default: 0, [NARROW]: 1 }, borderStyle: "solid", borderColor: colors.border, backgroundColor: { default: null, [NARROW]: colors.surfaceRaised }, paddingInline: { default: 0, [NARROW]: "0.5rem" }, paddingBlock: { default: 0, [NARROW]: "1rem" }, }, tile: { display: "flex", flexDirection: "column", alignItems: "center", gap: "0.375rem", minWidth: 0, borderRadius: metrics.radius, borderWidth: { default: 1, [NARROW]: 0 }, borderStyle: "solid", borderColor: colors.border, backgroundColor: colors.surfaceRaised, paddingInline: { default: "1rem", [NARROW]: "0.25rem" }, paddingBlock: { default: "1.5rem", [NARROW]: 0 }, textAlign: "center", }, /** The share drops under the three counts on a phone, divided from them by a hairline. */ shareTile: { gridColumn: { default: null, [NARROW]: "1 / -1" }, marginTop: { default: 0, [NARROW]: "1rem" }, paddingTop: { default: null, [NARROW]: "1rem" }, borderTopWidth: { default: null, [NARROW]: 1 }, borderTopStyle: "solid", borderTopColor: colors.border, }, value: { margin: 0, fontSize: { default: "2.5rem", [NARROW]: "1.75rem" }, lineHeight: 1, fontWeight: 400, letterSpacing: "-0.02em", color: colors.text, }, valueBlocked: { color: colors.chartRed }, valueMuted: { color: colors.textMuted }, caption: { margin: 0, fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.textMuted, }, link: { marginTop: "0.25rem", fontSize: "0.75rem", lineHeight: "1rem", color: colors.primaryOnSurface, textDecorationLine: "none", }, }); function Tile({ value, caption, tone, style, children, }: { value: string; caption: string; tone?: "blocked" | "muted"; style?: stylex.StyleXStyles; children?: React.ReactNode; }) { return (
  • {value}

    {caption}

    {children}
  • ); } /** The window's totals with the bounds they were measured over and the scope they were read under. */ export interface StatTilesData extends OverviewTotals { since: number; until: number; client: string | undefined; } export default function StatTiles({ stats }: { stats: StatTilesData }) { const window = { mode: "history" as const, since: stats.since, until: stats.until, domain: undefined, client: stats.client, }; return ( ); }