refactor(ui): use CSS variables for chart colors instead of hardcoded values
Update DailyVisitsChart and HourlyActivityChart to consume injected theme CSS variables (--primary, --muted-foreground, --border) instead of hardcoded color values. Adds getAccentColor() helper to safely read --primary from root element with fallback support.
- commit
- ef844de6ca7567f04093e66c4418f0969a3ff3d2
- author
- brice · · 2025-12-18 17:04 UTC
- parent
- ccc1c3e
- signature
- unsigned
2 files · +18 -8
M webui/src/pages/homepage/analytics/DailyVisitsChart.svelte +9 -4
| @@ -12,6 +12,11 @@ | |||
| 12 | 12 | let container: HTMLDivElement; | |
| 13 | 13 | let chart: Chart | null = null; | |
| 14 | 14 | ||
| 15 | + | // Get accent color from CSS variable | |
| 16 | + | function getAccentColor(): string { | |
| 17 | + | return getComputedStyle(document.documentElement).getPropertyValue('--primary').trim() || '#4ade80'; | |
| 18 | + | } | |
| 19 | + | ||
| 15 | 20 | // Convert data to Frappe Charts format | |
| 16 | 21 | const chartData = $derived.by(() => { | |
| 17 | 22 | if (!dailyVisits || dailyVisits.length === 0) { | |
| @@ -40,7 +45,7 @@ | |||
| 40 | 45 | data: chartData, | |
| 41 | 46 | type: 'line', | |
| 42 | 47 | height: 160, | |
| 43 | - | colors: ['#4ade80'], | |
| 48 | + | colors: [getAccentColor()], | |
| 44 | 49 | axisOptions: { xAxisMode: 'tick', xIsSeries: true }, | |
| 45 | 50 | lineOptions: { regionFill: 1, hideDots: 0, dotSize: 4 }, | |
| 46 | 51 | tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` } | |
| @@ -90,7 +95,7 @@ | |||
| 90 | 95 | } | |
| 91 | 96 | ||
| 92 | 97 | .chart-label { | |
| 93 | - | color: #4ade80; | |
| 98 | + | color: var(--primary, #4ade80); | |
| 94 | 99 | font-weight: 600; | |
| 95 | 100 | } | |
| 96 | 101 | ||
| @@ -108,12 +113,12 @@ | |||
| 108 | 113 | ||
| 109 | 114 | .chart-container :global(.frappe-chart .axis text), | |
| 110 | 115 | .chart-container :global(.frappe-chart .chart-label) { | |
| 111 | - | fill: #737373; | |
| 116 | + | fill: var(--muted-foreground, #737373); | |
| 112 | 117 | font-size: 10px; | |
| 113 | 118 | } | |
| 114 | 119 | ||
| 115 | 120 | .chart-container :global(.frappe-chart .axis line), | |
| 116 | 121 | .chart-container :global(.frappe-chart .chart-strokes) { | |
| 117 | - | stroke: #333; | |
| 122 | + | stroke: var(--border, #333); | |
| 118 | 123 | } | |
| 119 | 124 | </style> | |
| @@ -12,6 +12,11 @@ | |||||
| 12 | let container: HTMLDivElement; | 12 | let container: HTMLDivElement; | ||
| 13 | let chart: Chart | null = null; | 13 | let chart: Chart | null = null; | ||
| 14 | 14 | ||||
| 15 | + | // Get accent color from CSS variable | |||
| 16 | + | function getAccentColor(): string { | |||
| 17 | + | return getComputedStyle(document.documentElement).getPropertyValue('--primary').trim() || '#4ade80'; | |||
| 18 | + | } | |||
| 19 | + | ||||
| 15 | // Convert data to Frappe Charts format | 20 | // Convert data to Frappe Charts format | ||
| 16 | const chartData = $derived.by(() => { | 21 | const chartData = $derived.by(() => { | ||
| 17 | if (!dailyVisits || dailyVisits.length === 0) { | 22 | if (!dailyVisits || dailyVisits.length === 0) { | ||
| @@ -40,7 +45,7 @@ | |||||
| 40 | data: chartData, | 45 | data: chartData, | ||
| 41 | type: 'line', | 46 | type: 'line', | ||
| 42 | height: 160, | 47 | height: 160, | ||
| 43 | - | colors: ['#4ade80'], | 48 | + | colors: [getAccentColor()], |
| 44 | axisOptions: { xAxisMode: 'tick', xIsSeries: true }, | 49 | axisOptions: { xAxisMode: 'tick', xIsSeries: true }, | ||
| 45 | lineOptions: { regionFill: 1, hideDots: 0, dotSize: 4 }, | 50 | lineOptions: { regionFill: 1, hideDots: 0, dotSize: 4 }, | ||
| 46 | tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` } | 51 | tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` } | ||
| @@ -90,7 +95,7 @@ | |||||
| 90 | } | 95 | } | ||
| 91 | 96 | ||||
| 92 | .chart-label { | 97 | .chart-label { | ||
| 93 | - | color: #4ade80; | 98 | + | color: var(--primary, #4ade80); |
| 94 | font-weight: 600; | 99 | font-weight: 600; | ||
| 95 | } | 100 | } | ||
| 96 | 101 | ||||
| @@ -108,12 +113,12 @@ | |||||
| 108 | 113 | ||||
| 109 | .chart-container :global(.frappe-chart .axis text), | 114 | .chart-container :global(.frappe-chart .axis text), | ||
| 110 | .chart-container :global(.frappe-chart .chart-label) { | 115 | .chart-container :global(.frappe-chart .chart-label) { | ||
| 111 | - | fill: #737373; | 116 | + | fill: var(--muted-foreground, #737373); |
| 112 | font-size: 10px; | 117 | font-size: 10px; | ||
| 113 | } | 118 | } | ||
| 114 | 119 | ||||
| 115 | .chart-container :global(.frappe-chart .axis line), | 120 | .chart-container :global(.frappe-chart .axis line), | ||
| 116 | .chart-container :global(.frappe-chart .chart-strokes) { | 121 | .chart-container :global(.frappe-chart .chart-strokes) { | ||
| 117 | - | stroke: #333; | 122 | + | stroke: var(--border, #333); |
| 118 | } | 123 | } | ||
| 119 | </style> | 124 | </style> | ||
M webui/src/pages/homepage/analytics/HourlyActivityChart.svelte +9 -4
| @@ -12,6 +12,11 @@ | |||
| 12 | 12 | let container: HTMLDivElement; | |
| 13 | 13 | let chart: Chart | null = null; | |
| 14 | 14 | ||
| 15 | + | // Get accent color from CSS variable | |
| 16 | + | function getAccentColor(): string { | |
| 17 | + | return getComputedStyle(document.documentElement).getPropertyValue('--primary').trim() || '#4ade80'; | |
| 18 | + | } | |
| 19 | + | ||
| 15 | 20 | // Convert data to Frappe Charts format (ensure all 24 hours) | |
| 16 | 21 | const chartData = $derived.by(() => { | |
| 17 | 22 | const visitsByHour = new Map<number, number>(); | |
| @@ -47,7 +52,7 @@ | |||
| 47 | 52 | data: chartData, | |
| 48 | 53 | type: 'bar', | |
| 49 | 54 | height: 120, | |
| 50 | - | colors: ['#4ade80'], | |
| 55 | + | colors: [getAccentColor()], | |
| 51 | 56 | axisOptions: { xAxisMode: 'tick' }, | |
| 52 | 57 | barOptions: { spaceRatio: 0.3 }, | |
| 53 | 58 | tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` } | |
| @@ -95,7 +100,7 @@ | |||
| 95 | 100 | } | |
| 96 | 101 | ||
| 97 | 102 | .chart-label { | |
| 98 | - | color: #4ade80; | |
| 103 | + | color: var(--primary, #4ade80); | |
| 99 | 104 | font-weight: 600; | |
| 100 | 105 | } | |
| 101 | 106 | ||
| @@ -113,12 +118,12 @@ | |||
| 113 | 118 | ||
| 114 | 119 | .chart-container :global(.frappe-chart .axis text), | |
| 115 | 120 | .chart-container :global(.frappe-chart .chart-label) { | |
| 116 | - | fill: #737373; | |
| 121 | + | fill: var(--muted-foreground, #737373); | |
| 117 | 122 | font-size: 10px; | |
| 118 | 123 | } | |
| 119 | 124 | ||
| 120 | 125 | .chart-container :global(.frappe-chart .axis line), | |
| 121 | 126 | .chart-container :global(.frappe-chart .chart-strokes) { | |
| 122 | - | stroke: #333; | |
| 127 | + | stroke: var(--border, #333); | |
| 123 | 128 | } | |
| 124 | 129 | </style> | |
| @@ -12,6 +12,11 @@ | |||||
| 12 | let container: HTMLDivElement; | 12 | let container: HTMLDivElement; | ||
| 13 | let chart: Chart | null = null; | 13 | let chart: Chart | null = null; | ||
| 14 | 14 | ||||
| 15 | + | // Get accent color from CSS variable | |||
| 16 | + | function getAccentColor(): string { | |||
| 17 | + | return getComputedStyle(document.documentElement).getPropertyValue('--primary').trim() || '#4ade80'; | |||
| 18 | + | } | |||
| 19 | + | ||||
| 15 | // Convert data to Frappe Charts format (ensure all 24 hours) | 20 | // Convert data to Frappe Charts format (ensure all 24 hours) | ||
| 16 | const chartData = $derived.by(() => { | 21 | const chartData = $derived.by(() => { | ||
| 17 | const visitsByHour = new Map<number, number>(); | 22 | const visitsByHour = new Map<number, number>(); | ||
| @@ -47,7 +52,7 @@ | |||||
| 47 | data: chartData, | 52 | data: chartData, | ||
| 48 | type: 'bar', | 53 | type: 'bar', | ||
| 49 | height: 120, | 54 | height: 120, | ||
| 50 | - | colors: ['#4ade80'], | 55 | + | colors: [getAccentColor()], |
| 51 | axisOptions: { xAxisMode: 'tick' }, | 56 | axisOptions: { xAxisMode: 'tick' }, | ||
| 52 | barOptions: { spaceRatio: 0.3 }, | 57 | barOptions: { spaceRatio: 0.3 }, | ||
| 53 | tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` } | 58 | tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` } | ||
| @@ -95,7 +100,7 @@ | |||||
| 95 | } | 100 | } | ||
| 96 | 101 | ||||
| 97 | .chart-label { | 102 | .chart-label { | ||
| 98 | - | color: #4ade80; | 103 | + | color: var(--primary, #4ade80); |
| 99 | font-weight: 600; | 104 | font-weight: 600; | ||
| 100 | } | 105 | } | ||
| 101 | 106 | ||||
| @@ -113,12 +118,12 @@ | |||||
| 113 | 118 | ||||
| 114 | .chart-container :global(.frappe-chart .axis text), | 119 | .chart-container :global(.frappe-chart .axis text), | ||
| 115 | .chart-container :global(.frappe-chart .chart-label) { | 120 | .chart-container :global(.frappe-chart .chart-label) { | ||
| 116 | - | fill: #737373; | 121 | + | fill: var(--muted-foreground, #737373); |
| 117 | font-size: 10px; | 122 | font-size: 10px; | ||
| 118 | } | 123 | } | ||
| 119 | 124 | ||||
| 120 | .chart-container :global(.frappe-chart .axis line), | 125 | .chart-container :global(.frappe-chart .axis line), | ||
| 121 | .chart-container :global(.frappe-chart .chart-strokes) { | 126 | .chart-container :global(.frappe-chart .chart-strokes) { | ||
| 122 | - | stroke: #333; | 127 | + | stroke: var(--border, #333); |
| 123 | } | 128 | } | ||
| 124 | </style> | 129 | </style> | ||