diff --git a/src/app/p/[secret]/page.tsx b/src/app/p/[secret]/page.tsx index 0471a87..09fdb2b 100644 --- a/src/app/p/[secret]/page.tsx +++ b/src/app/p/[secret]/page.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useTRPC } from "@/trpc/client"; -import { Flag, Clock, TriangleAlert } from "lucide-react"; +import { Flag, Clock, TriangleAlert, TrendingUp, ShieldAlert, Info } from "lucide-react"; import { TimeSeriesChart } from "@/components/admin/TimeSeriesChart"; import { GranularityToggle, type Granularity } from "@/components/admin/GranularityToggle"; import { Button } from "@/components/ui/button"; @@ -56,10 +56,10 @@ export default function AdminDashboard() { {canToggleMaintenance && (
@@ -92,27 +92,60 @@ export default function AdminDashboard() { <> {/* Needs attention — the only stats that earn individual weight and real color; color means "act on this", not "posts are orange". */} -
- - +
+

Needs attention

+
+ + +
- {/* Everything else — a flat overview, not a wall of identical cards */} -
-

Overview

-
- - - - - - - - - - -
-
+ {/* Everything else, grouped by what kind of number it is — activity + (growth/usage), violations (moderation risk), info (context only). + Category color is a legend, not a wash: only violation values + that are actually > 0 pick up the color, same "act on this" + logic as AttentionStat above. */} + + + Overview + + +
+ + + +
+
+
)} @@ -227,8 +260,8 @@ function AttentionStat({ const needsAttention = value > 0; return (
@@ -242,12 +275,51 @@ function AttentionStat({ ); } -/** Everything else — a plain label/value pair, no per-item card chrome. */ -function OverviewStat({ label, value }: { label: string; value: number }) { +const STAT_GROUP_COLORS = { + emerald: { text: "text-emerald-400", bg: "bg-emerald-500/5", ring: "ring-emerald-500/15" }, + rose: { text: "text-rose-400", bg: "bg-rose-500/5", ring: "ring-rose-500/15" }, + sky: { text: "text-sky-400", bg: "bg-sky-500/5", ring: "ring-sky-500/15" }, +} as const; + +/** + * One labeled, color-identified slice of the Overview card — Activity, + * Violations, or Info. The color lives on the group's icon/label (a legend) + * and, when `emphasizeNonZero` is set, on individual values that are actually + * non-zero — never as a flat wash across numbers that don't mean anything yet. + */ +function StatGroup({ + icon: Icon, + label, + color, + items, + emphasizeNonZero = false, +}: { + icon: React.ElementType; + label: string; + color: keyof typeof STAT_GROUP_COLORS; + items: { label: string; value: number }[]; + emphasizeNonZero?: boolean; +}) { + const c = STAT_GROUP_COLORS[color]; return ( -
-
{label}
-
{value.toLocaleString()}
+
+
+ + {label} +
+
+ {items.map((item) => { + const flagged = emphasizeNonZero && item.value > 0; + return ( +
+
{item.label}
+
+ {item.value.toLocaleString()} +
+
+ ); + })} +
); }