From 1854026a769d609777f2200a2281d8960ea1fc49 Mon Sep 17 00:00:00 2001 From: megaproxy Date: Thu, 23 Apr 2026 23:14:36 +0000 Subject: [PATCH] Fix theme text visibility, tooltip colours, and chart hover states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract shared TOOLTIP_STYLE and ACTIVE_DOT to utils/chartTheme.ts so all four chart files use one source of truth - itemStyle now uses card-foreground (not muted-foreground) — guarantees tooltip text is readable on all themes including Terminal, Vault, Synthwave - cursor now uses primary at 12% opacity — always visible and thematic, replaces near-invisible muted-foreground at 8% opacity - activeDot is now explicit on every Line/Area — prevents Recharts default white dot breaking dark themes - Terminal: muted-foreground bumped 38%→55% lightness, border lightened, warning brightened, text-shadow scoped to headings/labels/table cells (was applying to every p and span, causing tooltip glow bleed) - Synthwave: muted-foreground bumped 56%→68% lightness for legibility - Vault: muted-foreground bumped 52%→60% lightness Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/index.css | 20 +++++----- frontend/src/pages/dashboard/Dashboard.tsx | 17 +------- .../src/pages/investments/PortfolioCharts.tsx | 15 +------ .../src/pages/predictions/PredictionsPage.tsx | 17 ++++---- frontend/src/pages/reports/ReportsPage.tsx | 25 +++--------- frontend/src/utils/chartTheme.ts | 40 +++++++++++++++++++ 6 files changed, 69 insertions(+), 65 deletions(-) create mode 100644 frontend/src/utils/chartTheme.ts diff --git a/frontend/src/index.css b/frontend/src/index.css index cb4d240..a3cbb0a 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -143,7 +143,7 @@ --secondary: 30 18% 14%; --secondary-foreground: 38 20% 88%; --muted: 30 18% 14%; - --muted-foreground: 38 12% 52%; + --muted-foreground: 38 18% 60%; --accent: 38 92% 50%; --accent-foreground: 30 18% 6%; --destructive: 0 72% 55%; @@ -170,17 +170,17 @@ --secondary: 120 60% 9%; --secondary-foreground: 120 100% 72%; --muted: 120 60% 9%; - --muted-foreground: 120 50% 38%; + --muted-foreground: 120 60% 55%; --accent: 120 100% 50%; --accent-foreground: 120 60% 3%; --destructive: 0 84% 55%; --destructive-foreground: 0 0% 100%; - --border: 120 60% 14%; + --border: 120 60% 16%; --input: 120 60% 9%; --ring: 120 100% 50%; --radius: 0.2rem; --success: 120 100% 50%; - --warning: 60 100% 55%; + --warning: 60 100% 60%; } .theme-terminal body, @@ -213,11 +213,13 @@ z-index: 9999; } -/* Phosphor glow on text */ +/* Phosphor glow — targeted to headings and explicit foreground text only */ .theme-terminal .text-foreground, -.theme-terminal p, -.theme-terminal span:not(.text-muted-foreground):not(.text-destructive) { - text-shadow: 0 0 8px hsl(120 100% 50% / 0.4); +.theme-terminal h1, .theme-terminal h2, .theme-terminal h3, +.theme-terminal h4, .theme-terminal h5, .theme-terminal h6, +.theme-terminal th, .theme-terminal td, +.theme-terminal label { + text-shadow: 0 0 8px hsl(120 100% 50% / 0.35); } /* Glow on cards */ @@ -239,7 +241,7 @@ --secondary: 268 90% 14%; --secondary-foreground: 280 30% 92%; --muted: 268 90% 14%; - --muted-foreground: 270 20% 56%; + --muted-foreground: 270 25% 68%; --accent: 190 100% 55%; --accent-foreground: 268 90% 6%; --destructive: 0 84% 60%; diff --git a/frontend/src/pages/dashboard/Dashboard.tsx b/frontend/src/pages/dashboard/Dashboard.tsx index 2846bf5..5e6015a 100644 --- a/frontend/src/pages/dashboard/Dashboard.tsx +++ b/frontend/src/pages/dashboard/Dashboard.tsx @@ -15,23 +15,10 @@ import { XAxis, YAxis, Tooltip, ResponsiveContainer, } from "recharts"; import { Link } from "react-router-dom"; +import { TOOLTIP_STYLE, ACTIVE_DOT } from "@/utils/chartTheme"; const COLORS = ["#6366f1","#22c55e","#f97316","#ec4899","#14b8a6","#f59e0b","#8b5cf6","#ef4444"]; -const TOOLTIP_STYLE = { - contentStyle: { - background: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", - borderRadius: "8px", - fontSize: "12px", - color: "hsl(var(--foreground))", - boxShadow: "0 4px 12px rgba(0,0,0,0.15)", - }, - labelStyle: { color: "hsl(var(--foreground))", fontWeight: 500, marginBottom: "4px" }, - itemStyle: { color: "hsl(var(--muted-foreground))" }, - cursor: { fill: "hsl(var(--muted-foreground))", fillOpacity: 0.08 }, -}; - const TYPE_COLORS: Record = { income: "text-success", expense: "text-destructive", @@ -132,7 +119,7 @@ export default function Dashboard() { `£${(v/1000).toFixed(0)}k`} width={45} /> formatCurrency(v, nwReport.base_currency)} /> - + ) : ( diff --git a/frontend/src/pages/investments/PortfolioCharts.tsx b/frontend/src/pages/investments/PortfolioCharts.tsx index 9f5ee35..26b5fd5 100644 --- a/frontend/src/pages/investments/PortfolioCharts.tsx +++ b/frontend/src/pages/investments/PortfolioCharts.tsx @@ -4,26 +4,13 @@ import { } from "recharts"; import { formatCurrency } from "@/utils/currency"; import type { PortfolioSummary, HoldingResponse } from "@/api/investments"; +import { TOOLTIP_STYLE } from "@/utils/chartTheme"; const COLORS = [ "#6366f1","#22c55e","#f97316","#ec4899","#14b8a6", "#f59e0b","#8b5cf6","#06b6d4","#84cc16","#ef4444", ]; -const TOOLTIP_STYLE = { - contentStyle: { - background: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", - borderRadius: "8px", - fontSize: "12px", - color: "hsl(var(--foreground))", - boxShadow: "0 4px 12px rgba(0,0,0,0.15)", - }, - labelStyle: { color: "hsl(var(--foreground))", fontWeight: 500, marginBottom: "4px" }, - itemStyle: { color: "hsl(var(--muted-foreground))" }, - cursor: { fill: "hsl(var(--muted-foreground))", fillOpacity: 0.08 }, -}; - const TYPE_COLORS: Record = { stock: "#6366f1", etf: "#22c55e", diff --git a/frontend/src/pages/predictions/PredictionsPage.tsx b/frontend/src/pages/predictions/PredictionsPage.tsx index 9317ffa..bc659ab 100644 --- a/frontend/src/pages/predictions/PredictionsPage.tsx +++ b/frontend/src/pages/predictions/PredictionsPage.tsx @@ -13,6 +13,7 @@ import { } from "recharts"; import Plot from "react-plotly.js"; import { cssVar } from "@/utils/cssVar"; +import { TOOLTIP_STYLE, ACTIVE_DOT } from "@/utils/chartTheme"; const TABS = [ { id: "spending", label: "Spending", icon: BarChart3 }, @@ -108,7 +109,7 @@ function SpendingTab() { `£${v}`} width={55} /> - formatCurrency(v, "GBP")} /> + formatCurrency(v, "GBP")} /> @@ -241,13 +242,13 @@ function NetWorthTab() { `£${(v / 1000).toFixed(0)}k`} width={55} /> - formatCurrency(v, "GBP")} /> + formatCurrency(v, "GBP")} /> {lastHistory && } - - - - + + + + @@ -468,9 +469,9 @@ function CashFlowTab() { v.slice(5)} /> `£${(v / 1000).toFixed(1)}k`} width={55} /> - formatCurrency(v, "GBP")} /> + formatCurrency(v, "GBP")} /> - + diff --git a/frontend/src/pages/reports/ReportsPage.tsx b/frontend/src/pages/reports/ReportsPage.tsx index e6bd75e..722b796 100644 --- a/frontend/src/pages/reports/ReportsPage.tsx +++ b/frontend/src/pages/reports/ReportsPage.tsx @@ -21,6 +21,7 @@ import { Tooltip, ResponsiveContainer, Legend } from "recharts"; import { TrendingUp, TrendingDown, Minus, Landmark, CreditCard, PiggyBank } from "lucide-react"; +import { TOOLTIP_STYLE, ACTIVE_DOT } from "@/utils/chartTheme"; const TABS = [ "Balance Sheet", "Net Worth", "Income vs Expense", @@ -37,20 +38,6 @@ const COLORS = [ const ASSET_COLORS = ["#22c55e", "#14b8a6", "#6366f1", "#8b5cf6", "#06b6d4", "#84cc16"]; const LIABILITY_COLORS = ["#ef4444", "#f97316", "#ec4899"]; -const TOOLTIP_STYLE = { - contentStyle: { - background: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", - borderRadius: "8px", - fontSize: "12px", - color: "hsl(var(--foreground))", - boxShadow: "0 4px 12px rgba(0,0,0,0.15)", - }, - labelStyle: { color: "hsl(var(--foreground))", fontWeight: 500, marginBottom: "4px" }, - itemStyle: { color: "hsl(var(--muted-foreground))" }, - cursor: { fill: "hsl(var(--muted-foreground))", fillOpacity: 0.08 }, -}; - function StatCard({ label, value, change, currency }: { label: string; value: number; change?: number; currency: string; }) { @@ -271,9 +258,9 @@ function NetWorthTab() { `£${(v/1000).toFixed(0)}k`} /> formatCurrency(v, data.base_currency)} /> - - - + + + @@ -362,7 +349,7 @@ function CashFlowTab() { - + @@ -426,7 +413,7 @@ function SavingsRateTab() { - + diff --git a/frontend/src/utils/chartTheme.ts b/frontend/src/utils/chartTheme.ts new file mode 100644 index 0000000..d6b0599 --- /dev/null +++ b/frontend/src/utils/chartTheme.ts @@ -0,0 +1,40 @@ +/** + * Shared Recharts tooltip and chart style constants. + * + * All colour values use CSS custom properties so they adapt to every theme. + * itemStyle uses card-foreground (not muted-foreground) to guarantee + * readability inside the tooltip card on all themes including Terminal, + * Synthwave and Vault which have dim muted-foreground values. + * + * cursor uses --primary at low opacity — always visible and thematic. + */ +export const TOOLTIP_STYLE = { + contentStyle: { + background: "hsl(var(--card))", + border: "1px solid hsl(var(--border))", + borderRadius: "8px", + fontSize: "12px", + color: "hsl(var(--card-foreground))", + boxShadow: "0 4px 20px rgba(0,0,0,0.35)", + padding: "8px 12px", + }, + labelStyle: { + color: "hsl(var(--card-foreground))", + fontWeight: 600, + marginBottom: "4px", + fontSize: "12px", + }, + itemStyle: { + color: "hsl(var(--card-foreground))", + opacity: 0.8, + }, + cursor: { fill: "hsl(var(--primary))", fillOpacity: 0.12 }, +}; + +/** Standard activeDot for Line/Area charts — theme-adaptive. */ +export const ACTIVE_DOT = { + r: 4, + stroke: "hsl(var(--card))", + strokeWidth: 2, + fill: "hsl(var(--primary))", +};