import { h } from "preact"; import { useEffect, useState, useMemo } from "preact/hooks"; export enum ThemeModes { AUTO, LIGHT, DARK, } export interface IThemeProps { mode: ThemeModes; children: any; primary?: string; onPrimary?: string; secondary?: string; onSecondary?: string; error?: string; onError?: string; success?: string; onSuccess?: string; } const modeMediaQuery = window.matchMedia("prefers-color-scheme: dark"); export default function Theme({ mode, children, ...colors }: IThemeProps) { const [isDark, setIsDark] = useState( mode === ThemeModes.AUTO ? modeMediaQuery.matches : mode === ThemeModes.DARK ); useEffect(() => { if (mode === ThemeModes.AUTO) { const listener = (ev: MediaQueryListEvent) => { setIsDark(ev.matches); }; modeMediaQuery.addListener(listener); setIsDark(modeMediaQuery.matches); return modeMediaQuery.removeListener(listener); } }, [mode]); const style = useMemo(() => { let style = ""; const getRGB = (color: string) => { const cv = document.createElement("canvas"); cv.width = 10; cv.height = 10; const ctx = cv.getContext("2d"); ctx.rect(0, 0, 1, 1); ctx.fillStyle = color; ctx.fill(); const [r, g, b] = ctx.getImageData(0, 0, 10, 10).data; return [r, g, b]; }; const add = (name: string, value: string) => (style += `--${name}: ${value};`); if (colors.primary) { add("primary:", colors.primary); add("primary-rgb", getRGB(colors.primary).join(", ")); } if (colors.onPrimary) add("on-primary:", colors.onPrimary); if (colors.secondary) { add("secondary:", colors.secondary); add("secondary-rgb", getRGB(colors.secondary).join(", ")); } if (colors.onSecondary) add("on-secondary:", colors.onSecondary); if (colors.error) { add("error:", colors.error); add("error-rgb", getRGB(colors.error).join(", ")); } if (colors.onError) add("on-error:", colors.onError); if (colors.success) { add("success:", colors.success); add("success-rgb", getRGB(colors.success).join(", ")); } if (colors.onSuccess) add("on-success:", colors.onSuccess); return style; }, [ colors.primary, colors.secondary, colors.error, colors.success, colors.onPrimary, colors.onSecondary, colors.onError, colors.onSuccess, ]); return (