diff --git a/src/App.tsx b/src/App.tsx index 7363f71..79d3932 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,7 +10,6 @@ import ErrorBoundary from "./components/ErrorBoundary"; import Footer from "./components/Footer"; import Header, { RefreshToast } from "./components/Header"; import { useBackground } from "./hooks/use-background"; -import { useTheme } from "./hooks/use-theme"; import { InjectContext } from "./lib/inject"; import { fetchSetting } from "./lib/nezha-api"; import { cn } from "./lib/utils"; @@ -32,54 +31,41 @@ const MainApp: React.FC = () => { refetchOnWindowFocus: true, }); const { i18n } = useTranslation(); - const { setTheme } = useTheme(); const [isCustomCodeInjected, setIsCustomCodeInjected] = useState(false); const { backgroundImage: customBackgroundImage } = useBackground(); useEffect(() => { - if (settingData?.data?.config?.custom_code) { - InjectContext(settingData?.data?.config?.custom_code); - setIsCustomCodeInjected(true); - } + const updateConfig = () => { + const config = settingData?.data?.config; + if (config) { + if (config.custom_code) { + InjectContext(config.custom_code); + setIsCustomCodeInjected(true); + } - // 同步自定义配置到全局变量 - const config = settingData?.data?.config; - if (config) { - if (config.custom_logo) window.CustomLogo = config.custom_logo; - if (config.custom_description) - window.CustomDesc = config.custom_description; - if (config.custom_links) window.CustomLinks = config.custom_links; + // 同步自定义配置到全局变量 + if (config.custom_logo) window.CustomLogo = config.custom_logo; + if (config.custom_description) + window.CustomDesc = config.custom_description; + if (config.custom_links) window.CustomLinks = config.custom_links; - const hour = DateTime.now().hour; - const isNight = hour >= 18 || hour < 6; + const hour = DateTime.now().hour; + const isNight = hour >= 18 || hour < 6; - if (isNight && config.background_image_night) { - window.CustomBackgroundImage = config.background_image_night; - } else if (!isNight && config.background_image_day) { - window.CustomBackgroundImage = config.background_image_day; + if (isNight && config.background_image_night) { + window.CustomBackgroundImage = config.background_image_night; + } else if (!isNight && config.background_image_day) { + window.CustomBackgroundImage = config.background_image_day; + } + window.CustomMobileBackgroundImage = window.CustomBackgroundImage; } - window.CustomMobileBackgroundImage = window.CustomBackgroundImage; + }; - // 设置强制主题 - window.ForceTheme = isNight ? "dark" : "light"; - } + updateConfig(); + const interval = setInterval(updateConfig, 60000); // Check every minute + return () => clearInterval(interval); }, [settingData]); - // 检测是否强制指定了主题颜色 - const forceTheme = - (window.ForceTheme as string) !== "" ? window.ForceTheme : undefined; - - useEffect(() => { - const savedTheme = localStorage.getItem("vite-ui-theme"); - // Only auto-apply ForceTheme if the user hasn't manually picked one (or picked 'system') - if ( - (!savedTheme || savedTheme === "system") && - (forceTheme === "dark" || forceTheme === "light") - ) { - setTheme(forceTheme); - } - }, [forceTheme, setTheme]); - if (error) { return ; } diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx index f9606fd..4fbc19c 100644 --- a/src/components/ThemeProvider.tsx +++ b/src/components/ThemeProvider.tsx @@ -1,4 +1,5 @@ import { createContext, type ReactNode, useEffect, useState } from "react"; +import { DateTime } from "luxon"; export type Theme = "dark" | "light" | "system"; @@ -28,40 +29,40 @@ export function ThemeProvider({ () => (localStorage.getItem(storageKey) as Theme) || "system", ); + const [hour, setHour] = useState(() => DateTime.now().hour); + + useEffect(() => { + const timer = setInterval(() => { + setHour(DateTime.now().hour); + }, 60000); + return () => clearInterval(timer); + }, []); + useEffect(() => { const root = window.document.documentElement; root.classList.add("disable-transitions"); root.classList.remove("light", "dark"); + let effectiveTheme = theme; if (theme === "system") { - const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") - .matches - ? "dark" - : "light"; - - root.classList.add(systemTheme); - const themeColor = - systemTheme === "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); + // Time-based theme: 18:00 - 06:00 is dark + const isNight = hour >= 18 || hour < 6; + effectiveTheme = isNight ? "dark" : "light"; } - root.classList.add(theme); - const themeColor = theme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)"; + root.classList.add(effectiveTheme); + const themeColor = + effectiveTheme === "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); - }, [theme]); + }, [theme, hour]); const value = { theme,