Sync PWA status bar theme-color with resolved app theme (#24203)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s

* sync PWA status bar theme-color with resolved app theme

* update tags on login page too

* track system theme preference

* revert
This commit is contained in:
Josh Hawkins
2026-09-05 15:57:39 -06:00
committed by GitHub
parent 6ceb370abb
commit 4ac92dac72
3 changed files with 45 additions and 8 deletions
+43 -8
View File
@@ -1,6 +1,7 @@
import { createContext, useContext, useEffect, useMemo, useState } from "react";
type Theme = "dark" | "light" | "system";
type ActiveTheme = Exclude<Theme, "system">;
type ColorScheme =
| "theme-blue"
| "theme-green"
@@ -51,6 +52,32 @@ const initialState: ThemeProviderState = {
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
function updateThemeMetaTags(theme: ActiveTheme): void {
const isDark = theme === "dark";
const metaDefinitions = [
{ name: "theme-color", content: isDark ? "#000000" : "#ffffff" },
{
name: "apple-mobile-web-app-status-bar-style",
content: isDark ? "black" : "default",
},
];
for (const { name, content } of metaDefinitions) {
const tags = document.head.querySelectorAll<HTMLMetaElement>(
`meta[name="${name}"]`,
);
const matchingTags =
tags.length > 0
? Array.from(tags)
: [document.head.appendChild(document.createElement("meta"))];
for (const tag of matchingTags) {
tag.name = name;
tag.content = content;
}
}
}
export function ThemeProvider({
children,
defaultTheme = "system",
@@ -82,15 +109,21 @@ export function ThemeProvider({
}
});
const systemTheme = useMemo<Theme | undefined>(() => {
if (theme != "system") {
return undefined;
}
const [systemPrefersDark, setSystemPrefersDark] = useState(
() => window.matchMedia("(prefers-color-scheme: dark)").matches,
);
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}, [theme]);
useEffect(() => {
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = () => setSystemPrefersDark(mediaQuery.matches);
mediaQuery.addEventListener("change", handleChange);
return () => mediaQuery.removeEventListener("change", handleChange);
}, []);
const systemTheme = useMemo<ActiveTheme | undefined>(() => {
if (theme !== "system") return undefined;
return systemPrefersDark ? "dark" : "light";
}, [theme, systemPrefersDark]);
useEffect(() => {
//localStorage.removeItem(storageKey);
@@ -101,6 +134,8 @@ export function ThemeProvider({
root.classList.add(theme, colorScheme);
updateThemeMetaTags(systemTheme ?? (theme === "system" ? "light" : theme));
if (systemTheme) {
root.classList.add(systemTheme);
return;