Files
Compass/web/hooks/use-theme-colors.ts
MartinBraquet 95d217fb61 Add StatDonut, WorldHeatmap, and support for full country lists on stats page
- Introduced `StatDonut` and `WorldHeatmap` components for improved data visualization.
- Enhanced API to provide full country lists instead of a top-N subset for accurate map shading.
- Removed hardcoded country truncation logic in favor of dynamic slicing in the frontend.
- Updated age grouping logic to consolidate older age ranges and simplify backend queries.
- Refactored stats page layout to reduce redundancy and improve clarity of data presentation.
2026-07-24 02:57:51 +02:00

41 lines
1.6 KiB
TypeScript

import {useEffect, useState} from 'react'
/**
* Resolves Tailwind colour CSS variables (e.g. `--color-primary-500`) to concrete `rgb(r g b)` strings,
* and re-resolves when the theme flips — the app stamps `data-theme` / a class on `<html>`.
*
* Why it exists: recharts writes fills as SVG *presentation attributes*, which do not evaluate `var()`.
* So a chart can't just reference `rgb(var(--color-primary-500))` the way normal CSS can; it needs the
* value read out of the cascade. Raw SVG we render ourselves can use `var()` inline and doesn't need this.
*
* Runs entirely in an effect (no `getComputedStyle` on the server); components that use it for chart
* fills should be client-only anyway. Before the first effect it returns `null`s, so guard on that.
*/
export function useThemeColors(varNames: string[]): (string | null)[] {
const key = varNames.join(',')
const [colors, setColors] = useState<(string | null)[]>(() => varNames.map(() => null))
useEffect(() => {
const names = key.split(',')
const resolve = () => {
const styles = getComputedStyle(document.documentElement)
setColors(
names.map((n) => {
const v = styles.getPropertyValue(n).trim()
return v ? `rgb(${v})` : null
}),
)
}
resolve()
// The theme toggle mutates <html> rather than firing an event, so watch the attributes it touches.
const observer = new MutationObserver(resolve)
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class', 'data-theme'],
})
return () => observer.disconnect()
}, [key])
return colors
}