hsl to rgba not as effect but immediately, so all components have the correct theme applied at once

This commit is contained in:
Vinzenz Schroeter 2024-05-07 12:28:04 +02:00
parent 40bb1ec28a
commit 4960df370c

View file

@ -1,5 +1,5 @@
import {useStoredObjectState} from './useStoredState.ts';
import {createContext, ReactNode, useContext, useEffect, useRef, useState} from 'react';
import {createContext, ReactNode, useContext, useMemo, useRef, useState} from 'react';
type HSL = {
h: number;
@ -14,6 +14,15 @@ export type HslTheme = {
tertiary: HSL;
}
type Rgba = Uint8ClampedArray;
export type RgbaTheme = {
primary: Rgba;
secondary: Rgba;
background: Rgba;
tertiary: Rgba;
}
// @ts-ignore
const rootStyle = document.querySelector(':root')?.style;
@ -76,22 +85,6 @@ export function getRandomTheme(): HslTheme {
return {background, primary, secondary, tertiary};
}
function applyTheme(theme: HslTheme) {
console.log('apply theme', theme);
rootStyle.setProperty('--color-primary', hslToString(theme.primary));
rootStyle.setProperty('--color-secondary', hslToString(theme.secondary));
rootStyle.setProperty('--color-background', hslToString(theme.background));
}
type Rgba = Uint8ClampedArray;
export type RgbaTheme = {
primary: Rgba;
secondary: Rgba;
background: Rgba;
tertiary: Rgba;
}
const dummyRgbaTheme: RgbaTheme = {
primary: new Uint8ClampedArray([0, 0, 0, 0]),
secondary: new Uint8ClampedArray([0, 0, 0, 0]),
@ -105,7 +98,6 @@ function hslToRgba(context: CanvasRenderingContext2D, color: HSL) {
return context.getImageData(0, 0, 1, 1).data;
}
const HslThemeContext = createContext<null | {
hslTheme: HslTheme,
setHslTheme: (mutator: (oldState: HslTheme) => HslTheme) => void
@ -128,34 +120,41 @@ export function useHslTheme() {
export function ThemeProvider({children}: {
children?: ReactNode;
}) {
const [rgbaTheme, setRgbaTheme] = useState<RgbaTheme | null>(null);
function applyTheme(theme: HslTheme) {
console.log('apply theme', theme);
rootStyle.setProperty('--color-primary', hslToString(theme.primary));
rootStyle.setProperty('--color-secondary', hslToString(theme.secondary));
rootStyle.setProperty('--color-background', hslToString(theme.background));
}
const [hslTheme, setHslTheme] = useStoredObjectState<HslTheme>('theme', getRandomTheme, {
load: applyTheme,
save: applyTheme
});
const [rgbaTheme, setRgbaTheme] = useState<RgbaTheme | null>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (canvas === null)
throw new Error('canvas null');
useMemo(() => {
if (!canvas)
return;
const drawContext = canvas.getContext('2d', {
alpha: true,
alpha: false,
colorSpace: 'srgb',
willReadFrequently: true
});
if (!drawContext)
throw new Error('could not get draw context');
setRgbaTheme({
background: hslToRgba(drawContext, hslTheme.background),
primary: hslToRgba(drawContext, hslTheme.primary),
secondary: hslToRgba(drawContext, hslTheme.secondary),
tertiary: hslToRgba(drawContext, hslTheme.tertiary),
});
}, [hslTheme, canvasRef.current]);
}, [hslTheme, canvas]);
return <HslThemeContext.Provider value={{hslTheme, setHslTheme}}>
<RgbaThemeContext.Provider value={rgbaTheme || dummyRgbaTheme}>