62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import { useAuth } from "@/contexts/auth-context";
|
|
import { useMantineColorScheme } from "@mantine/core";
|
|
import { useEffect, useRef } from "react";
|
|
import { getTheme } from "@/themes/registry";
|
|
import { resolveChromeColors } from "@/themes/chrome";
|
|
import { setBaseThemeColor } from "./theme-colors";
|
|
|
|
const ColorSchemeProvider = ({ children }: { children: React.ReactNode }) => {
|
|
const {
|
|
metadata: { colorScheme, theme },
|
|
} = useAuth();
|
|
const { colorScheme: currentScheme, setColorScheme } =
|
|
useMantineColorScheme();
|
|
|
|
// Mantine recreates setColorScheme every render; calling it redundantly
|
|
// triggers its global transition-suppression flash, so ref it and only
|
|
// call on an actual value change.
|
|
const setColorSchemeRef = useRef(setColorScheme);
|
|
setColorSchemeRef.current = setColorScheme;
|
|
|
|
const manifest = getTheme(theme);
|
|
const forcedScheme =
|
|
manifest.colorSchemes === "both" ? undefined : manifest.colorSchemes;
|
|
|
|
useEffect(() => {
|
|
const chrome = resolveChromeColors(manifest);
|
|
|
|
if (forcedScheme) {
|
|
setBaseThemeColor(chrome[forcedScheme].base);
|
|
return;
|
|
}
|
|
|
|
if (!colorScheme) return;
|
|
|
|
if (colorScheme !== currentScheme) {
|
|
setColorSchemeRef.current(colorScheme);
|
|
}
|
|
|
|
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
const applyThemeColor = () => {
|
|
const resolved =
|
|
colorScheme === "auto"
|
|
? media.matches
|
|
? "dark"
|
|
: "light"
|
|
: colorScheme;
|
|
setBaseThemeColor(chrome[resolved].base);
|
|
};
|
|
|
|
applyThemeColor();
|
|
|
|
if (colorScheme === "auto") {
|
|
media.addEventListener("change", applyThemeColor);
|
|
return () => media.removeEventListener("change", applyThemeColor);
|
|
}
|
|
}, [colorScheme, currentScheme, manifest, forcedScheme]);
|
|
|
|
return children;
|
|
};
|
|
|
|
export default ColorSchemeProvider;
|