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