fix: improve theme management and styling for better user experience

This commit is contained in:
hamster1963
2026-06-04 11:11:49 +08:00
parent c8b7dcc8a8
commit 70532eb44d
4 changed files with 77 additions and 102 deletions
+31 -76
View File
@@ -1,95 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<script>
// 在页面渲染前就执行主题初始化
try {
const storageKey = "vite-ui-theme"
let theme = localStorage.getItem(storageKey)
if (theme === "system" || !theme) {
theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
}
document.documentElement.classList.add(theme)
} catch (_e) {
document.documentElement.classList.add("light")
}
</script>
<style>
/* Prevent FOUC in Safari */
html:not(.dark):not(.light) * {
visibility: hidden;
}
:root {
color-scheme: light;
--bg: #ffffff;
}
html.dark {
color-scheme: dark;
--bg: #242424;
}
html.light {
color-scheme: light;
--bg: #ffffff;
}
html {
background-color: var(--bg);
}
body {
background-color: var(--bg);
}
#root {
background-color: var(--bg);
visibility: hidden;
}
#root.loaded {
visibility: visible;
animation: fadein 0.2s;
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
<script>
;(() => {
const storageKey = "vite-ui-theme"
const theme = localStorage.getItem(storageKey) || "system"
const root = document.documentElement
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
function updateThemeColor(isDark) {
const themeColor = isDark ? "#242424" : "#fafafa"
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", themeColor)
const resolveTheme = (theme) =>
theme === "system" ? (mediaQuery.matches ? "dark" : "light") : theme
function updateThemeColor(nextTheme) {
const themeColor = nextTheme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)"
let meta = document.querySelector('meta[name="theme-color"]')
if (!meta) {
meta = document.createElement("meta")
meta.setAttribute("name", "theme-color")
document.head.appendChild(meta)
}
meta.setAttribute("content", themeColor)
}
function setTheme(newTheme) {
function applyResolvedTheme(resolvedTheme) {
root.classList.remove("light", "dark")
root.classList.add(newTheme)
updateThemeColor(newTheme === "dark")
root.classList.add(resolvedTheme)
root.style.colorScheme = resolvedTheme
root.style.backgroundColor =
resolvedTheme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)"
updateThemeColor(resolvedTheme)
}
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
setTheme(systemTheme)
let theme = "system"
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
setTheme(e.matches ? "dark" : "light")
})
} else {
setTheme(theme)
try {
const storedTheme = localStorage.getItem(storageKey)
if (storedTheme === "light" || storedTheme === "dark" || storedTheme === "system") {
theme = storedTheme
}
} catch (_e) {
theme = "system"
}
applyResolvedTheme(resolveTheme(theme))
// Add loaded class after React has mounted
window.addEventListener("load", () => {
const root = document.getElementById("root")
+6 -1
View File
@@ -8,7 +8,12 @@ export function ThemeColorManager() {
useEffect(() => {
const updateThemeColor = () => {
const currentTheme = theme;
const currentTheme =
theme === "system"
? window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
: theme;
const meta = document.querySelector('meta[name="theme-color"]');
if (!meta) {
+34 -21
View File
@@ -30,37 +30,50 @@ export function ThemeProvider({
useEffect(() => {
const root = window.document.documentElement;
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
root.classList.add("disable-transitions");
root.classList.remove("light", "dark");
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
root.classList.add(systemTheme);
const updateThemeColor = (nextTheme: "light" | "dark") => {
const themeColor =
systemTheme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)";
nextTheme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)";
document
.querySelector('meta[name="theme-color"]')
?.setAttribute("content", themeColor);
const timeoutId = window.setTimeout(() => {
root.classList.remove("disable-transitions");
}, 0);
return () => window.clearTimeout(timeoutId);
};
const applyTheme = (nextTheme: "light" | "dark") => {
root.classList.remove("light", "dark");
root.classList.add(nextTheme);
root.style.colorScheme = nextTheme;
root.style.backgroundColor =
nextTheme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)";
updateThemeColor(nextTheme);
};
root.classList.add("disable-transitions");
let cleanupMediaListener: (() => void) | undefined;
if (theme === "system") {
const applySystemTheme = () => {
applyTheme(mediaQuery.matches ? "dark" : "light");
};
applySystemTheme();
mediaQuery.addEventListener("change", applySystemTheme);
cleanupMediaListener = () =>
mediaQuery.removeEventListener("change", applySystemTheme);
} else {
applyTheme(theme);
}
root.classList.add(theme);
const themeColor = theme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)";
document
.querySelector('meta[name="theme-color"]')
?.setAttribute("content", themeColor);
const timeoutId = window.setTimeout(() => {
root.classList.remove("disable-transitions");
}, 0);
return () => window.clearTimeout(timeoutId);
return () => {
window.clearTimeout(timeoutId);
cleanupMediaListener?.();
};
}, [theme]);
const value = {
+6 -4
View File
@@ -100,10 +100,6 @@
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
@@ -192,6 +188,12 @@
}
html {
@apply scroll-smooth;
background-color: hsl(0 0% 98%);
color-scheme: light;
}
html.dark {
background-color: hsl(30 15% 8%);
color-scheme: dark;
}
body {
@apply bg-background text-foreground;