From 51ef4632e6d8a0fd91be922e557d879329eabbe9 Mon Sep 17 00:00:00 2001 From: Felipe Cardoso Date: Fri, 7 Nov 2025 12:41:53 +0100 Subject: [PATCH] Refactor charts to use centralized color palette configuration - Introduced `chart-colors.ts` utility to manage reusable color configurations across all chart components (`UserGrowthChart`, `OrganizationDistributionChart`, `SessionActivityChart`, `UserStatusChart`). - Updated chart components to replace inline color definitions with `CHART_PALETTES` for improved consistency and maintainability. - Enhanced tooltip, legend, and axis styles to align with updated project theming. --- .../charts/OrganizationDistributionChart.tsx | 16 ++-- .../charts/SessionActivityChart.tsx | 24 +++--- .../src/components/charts/UserGrowthChart.tsx | 16 ++-- .../src/components/charts/UserStatusChart.tsx | 11 ++- frontend/src/lib/chart-colors.ts | 78 +++++++++++++++++++ 5 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 frontend/src/lib/chart-colors.ts diff --git a/frontend/src/components/charts/OrganizationDistributionChart.tsx b/frontend/src/components/charts/OrganizationDistributionChart.tsx index 7115e4f..9a64b29 100644 --- a/frontend/src/components/charts/OrganizationDistributionChart.tsx +++ b/frontend/src/components/charts/OrganizationDistributionChart.tsx @@ -7,6 +7,7 @@ import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { ChartCard } from './ChartCard'; +import { CHART_PALETTES } from '@/lib/chart-colors'; export interface OrganizationDistributionData { name: string; @@ -51,18 +52,21 @@ export function OrganizationDistributionChart({ @@ -74,13 +78,13 @@ export function OrganizationDistributionChart({ diff --git a/frontend/src/components/charts/SessionActivityChart.tsx b/frontend/src/components/charts/SessionActivityChart.tsx index 2125fcf..7bcb91c 100644 --- a/frontend/src/components/charts/SessionActivityChart.tsx +++ b/frontend/src/components/charts/SessionActivityChart.tsx @@ -8,6 +8,7 @@ import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { ChartCard } from './ChartCard'; import { format, subDays } from 'date-fns'; +import { CHART_PALETTES } from '@/lib/chart-colors'; export interface SessionActivityData { date: string; @@ -52,29 +53,32 @@ export function SessionActivityChart({ data, loading, error }: SessionActivityCh - - + + - - + + @@ -87,7 +91,7 @@ export function SessionActivityChart({ data, loading, error }: SessionActivityCh type="monotone" dataKey="activeSessions" name="Active Sessions" - stroke="hsl(var(--primary))" + stroke={CHART_PALETTES.area[0]} strokeWidth={2} fillOpacity={1} fill="url(#colorActive)" @@ -96,7 +100,7 @@ export function SessionActivityChart({ data, loading, error }: SessionActivityCh type="monotone" dataKey="newSessions" name="New Sessions" - stroke="hsl(var(--chart-2))" + stroke={CHART_PALETTES.area[1]} strokeWidth={2} fillOpacity={1} fill="url(#colorNew)" diff --git a/frontend/src/components/charts/UserGrowthChart.tsx b/frontend/src/components/charts/UserGrowthChart.tsx index 1138e41..202f001 100644 --- a/frontend/src/components/charts/UserGrowthChart.tsx +++ b/frontend/src/components/charts/UserGrowthChart.tsx @@ -8,6 +8,7 @@ import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { ChartCard } from './ChartCard'; import { format, subDays } from 'date-fns'; +import { CHART_PALETTES } from '@/lib/chart-colors'; export interface UserGrowthData { date: string; @@ -54,18 +55,21 @@ export function UserGrowthChart({ data, loading, error }: UserGrowthChartProps) @@ -78,7 +82,7 @@ export function UserGrowthChart({ data, loading, error }: UserGrowthChartProps) type="monotone" dataKey="totalUsers" name="Total Users" - stroke="hsl(var(--primary))" + stroke={CHART_PALETTES.line[0]} strokeWidth={2} dot={false} activeDot={{ r: 6 }} @@ -87,7 +91,7 @@ export function UserGrowthChart({ data, loading, error }: UserGrowthChartProps) type="monotone" dataKey="activeUsers" name="Active Users" - stroke="hsl(var(--chart-2))" + stroke={CHART_PALETTES.line[1]} strokeWidth={2} dot={false} activeDot={{ r: 6 }} diff --git a/frontend/src/components/charts/UserStatusChart.tsx b/frontend/src/components/charts/UserStatusChart.tsx index 44ef020..6bf6de0 100644 --- a/frontend/src/components/charts/UserStatusChart.tsx +++ b/frontend/src/components/charts/UserStatusChart.tsx @@ -7,6 +7,7 @@ import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from 'recharts'; import { ChartCard } from './ChartCard'; +import { CHART_PALETTES } from '@/lib/chart-colors'; export interface UserStatusData { name: string; @@ -23,10 +24,10 @@ interface UserStatusChartProps { // Generate mock data for development/demo function generateMockData(): UserStatusData[] { return [ - { name: 'Active', value: 142, color: 'hsl(var(--chart-1))' }, - { name: 'Inactive', value: 28, color: 'hsl(var(--chart-2))' }, - { name: 'Pending', value: 15, color: 'hsl(var(--chart-3))' }, - { name: 'Suspended', value: 5, color: 'hsl(var(--chart-4))' }, + { name: 'Active', value: 142, color: CHART_PALETTES.pie[0] }, + { name: 'Inactive', value: 28, color: CHART_PALETTES.pie[1] }, + { name: 'Pending', value: 15, color: CHART_PALETTES.pie[2] }, + { name: 'Suspended', value: 5, color: CHART_PALETTES.pie[3] }, ]; } @@ -67,6 +68,7 @@ export function UserStatusChart({ data, loading, error }: UserStatusChartProps) backgroundColor: 'hsl(var(--popover))', border: '1px solid hsl(var(--border))', borderRadius: '6px', + color: 'hsl(var(--popover-foreground))', }} labelStyle={{ color: 'hsl(var(--popover-foreground))' }} /> @@ -75,6 +77,7 @@ export function UserStatusChart({ data, loading, error }: UserStatusChartProps) height={36} wrapperStyle={{ paddingTop: '20px', + color: 'hsl(var(--foreground))', }} /> diff --git a/frontend/src/lib/chart-colors.ts b/frontend/src/lib/chart-colors.ts new file mode 100644 index 0000000..4ab35d2 --- /dev/null +++ b/frontend/src/lib/chart-colors.ts @@ -0,0 +1,78 @@ +/** + * Chart Color Configuration + * Provides vibrant, accessible colors for data visualization + * Converts design system colors to recharts-compatible formats + */ + +export const CHART_COLORS = { + // Primary blue palette - vibrant and professional + primary: '#3b82f6', // Blue 500 + primaryLight: '#60a5fa', // Blue 400 + primaryDark: '#2563eb', // Blue 600 + + // Secondary accent colors - complementary palette + accent1: '#8b5cf6', // Violet 500 + accent2: '#ec4899', // Pink 500 + accent3: '#f59e0b', // Amber 500 + accent4: '#10b981', // Emerald 500 + accent5: '#06b6d4', // Cyan 500 + + // Status colors + success: '#10b981', // Emerald 500 + warning: '#f59e0b', // Amber 500 + error: '#ef4444', // Red 500 + info: '#3b82f6', // Blue 500 + + // Neutral colors for supporting elements + muted: '#94a3b8', // Slate 400 + mutedDark: '#64748b', // Slate 500 +}; + +// Chart-specific color palettes for different chart types +export const CHART_PALETTES = { + // Line chart palette - 2 contrasting colors + line: [CHART_COLORS.primary, CHART_COLORS.accent1], + + // Bar chart palette - 2 complementary colors + bar: [CHART_COLORS.primary, CHART_COLORS.accent2], + + // Area chart palette - 2 harmonious colors with gradients + area: [CHART_COLORS.primary, CHART_COLORS.accent5], + + // Pie chart palette - 4-5 distinct colors + pie: [ + CHART_COLORS.primary, + CHART_COLORS.accent1, + CHART_COLORS.accent3, + CHART_COLORS.accent4, + ], + + // Multi-series palette - for charts with many data series + multi: [ + CHART_COLORS.primary, + CHART_COLORS.accent1, + CHART_COLORS.accent2, + CHART_COLORS.accent3, + CHART_COLORS.accent4, + CHART_COLORS.accent5, + ], +}; + +// Gradient definitions for area charts +export const CHART_GRADIENTS = { + primary: { + start: CHART_COLORS.primary, + end: `${CHART_COLORS.primary}20`, // 20% opacity + }, + accent: { + start: CHART_COLORS.accent1, + end: `${CHART_COLORS.accent1}20`, // 20% opacity + }, +}; + +// Helper function to get color with opacity +export function withOpacity(color: string, opacity: number): string { + // Convert opacity (0-1) to hex (00-FF) + const hex = Math.round(opacity * 255).toString(16).padStart(2, '0'); + return `${color}${hex}`; +}