App-wide retheme done at the token layer: Tailwind's zinc scale is remapped to warm ink/paper neutrals and indigo to copper in globals.css, so every page inherits the palette. Fraunces (serif display) added for page titles and hero figures; all figures now render in mono with tabular numerals. Analytics page redesigned around a month spine — twelve clickable columns scaled to each month's spend that act as hero, context, and period navigation. Adds a 'What changed' top-movers panel vs the previous month, replaces the 8-line category trend chart with per-category sparkline small multiples, heat-tints the six-month ledger table, and restyles the Pareto, pace chart, and cashflow strip. Kept: Pareto, cumulative-vs-typical pace, drill-downs, regular/occasional split. Insights and Merchants restyled to the same kit; chart tokens centralised in category-colors.ts (CHART). Cleared the pre-existing lint errors in insights (typed tooltip, removed any-casts).
This commit is contained in:
+15
-15
@@ -129,7 +129,7 @@ function MerchantProfile({
|
||||
}));
|
||||
}, [merchant.monthly_trend]);
|
||||
|
||||
const color = CATEGORY_COLORS[merchant.category] || "#6366f1";
|
||||
const color = CATEGORY_COLORS[merchant.category] || "#bc6f30";
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex justify-end">
|
||||
@@ -190,23 +190,23 @@ function MerchantProfile({
|
||||
<p className="text-sm font-medium text-zinc-300 mb-3">Monthly Spend</p>
|
||||
<ResponsiveContainer width="100%" height={120}>
|
||||
<LineChart data={trendData}>
|
||||
<CartesianGrid stroke="#27272a" strokeDasharray="3 3" />
|
||||
<CartesianGrid stroke="#242019" strokeDasharray="3 3" />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
tick={{ fill: "#71717a", fontSize: 10 }}
|
||||
tick={{ fill: "#94896f", fontSize: 10 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
/>
|
||||
<YAxis
|
||||
tick={{ fill: "#71717a", fontSize: 10 }}
|
||||
tick={{ fill: "#94896f", fontSize: 10 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tickFormatter={(v) => `$${Math.round(v)}`}
|
||||
width={45}
|
||||
/>
|
||||
<Tooltip
|
||||
contentStyle={{ background: "#18181b", border: "1px solid #3f3f46", borderRadius: "8px" }}
|
||||
labelStyle={{ color: "#a1a1aa" }}
|
||||
contentStyle={{ background: "#171410", border: "1px solid #332d23", borderRadius: "8px" }}
|
||||
labelStyle={{ color: "#b3a88e" }}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
@@ -295,7 +295,7 @@ export default function MerchantsPage() {
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-white">Merchants</h1>
|
||||
<h1 className="text-2xl font-display text-zinc-50">Merchants</h1>
|
||||
<p className="text-zinc-400 text-sm mt-0.5">{merchants.length} merchants · last {months} months</p>
|
||||
</div>
|
||||
<select
|
||||
@@ -320,28 +320,28 @@ export default function MerchantsPage() {
|
||||
<QuadrantLabels medianX={medianX} medianY={medianY} />
|
||||
<ResponsiveContainer width="100%" height={360}>
|
||||
<ScatterChart margin={{ top: 10, right: 20, bottom: 20, left: 10 }}>
|
||||
<CartesianGrid stroke="#27272a" strokeDasharray="3 3" />
|
||||
<CartesianGrid stroke="#242019" strokeDasharray="3 3" />
|
||||
<XAxis
|
||||
dataKey="debit_count"
|
||||
name="Transactions"
|
||||
type="number"
|
||||
tick={{ fill: "#71717a", fontSize: 11 }}
|
||||
tick={{ fill: "#94896f", fontSize: 11 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
label={{ value: "Transaction Count", position: "insideBottom", offset: -10, fill: "#52525b", fontSize: 11 }}
|
||||
label={{ value: "Transaction Count", position: "insideBottom", offset: -10, fill: "#6e644f", fontSize: 11 }}
|
||||
/>
|
||||
<YAxis
|
||||
dataKey="net_spend"
|
||||
name="Net Spend"
|
||||
type="number"
|
||||
tick={{ fill: "#71717a", fontSize: 11 }}
|
||||
tick={{ fill: "#94896f", fontSize: 11 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tickFormatter={(v) => `$${Math.round(v / 1000)}k`}
|
||||
width={48}
|
||||
label={{ value: "Total Spend", angle: -90, position: "insideLeft", offset: 10, fill: "#52525b", fontSize: 11 }}
|
||||
label={{ value: "Total Spend", angle: -90, position: "insideLeft", offset: 10, fill: "#6e644f", fontSize: 11 }}
|
||||
/>
|
||||
<Tooltip content={<ScatterTooltip />} cursor={{ strokeDasharray: "3 3", stroke: "#52525b" }} />
|
||||
<Tooltip content={<ScatterTooltip />} cursor={{ strokeDasharray: "3 3", stroke: "#6e644f" }} />
|
||||
<Scatter
|
||||
data={scatterData}
|
||||
onClick={(d) => setSelected(d as unknown as MerchantRow)}
|
||||
@@ -350,7 +350,7 @@ export default function MerchantsPage() {
|
||||
{scatterData.map((entry, idx) => (
|
||||
<Cell
|
||||
key={idx}
|
||||
fill={CATEGORY_COLORS[entry.category] || "#6366f1"}
|
||||
fill={CATEGORY_COLORS[entry.category] || "#bc6f30"}
|
||||
fillOpacity={0.75}
|
||||
stroke={selected?.merchant === entry.merchant ? "#fff" : "transparent"}
|
||||
strokeWidth={2}
|
||||
@@ -400,7 +400,7 @@ export default function MerchantsPage() {
|
||||
</thead>
|
||||
<tbody>
|
||||
{filtered.map((m) => {
|
||||
const color = CATEGORY_COLORS[m.category] || "#6366f1";
|
||||
const color = CATEGORY_COLORS[m.category] || "#bc6f30";
|
||||
return (
|
||||
<tr
|
||||
key={m.merchant}
|
||||
|
||||
Reference in New Issue
Block a user