feat: auto dark mode (#321)

This commit is contained in:
XYenon
2025-10-15 12:43:24 +08:00
committed by GitHub
parent a095a2c01c
commit 6827985289
5 changed files with 46 additions and 7 deletions

View File

@@ -141,7 +141,7 @@ export const DEFAULT_MOUSE_HOVER_SETTING = {
};
export const DEFAULT_SETTING = {
darkMode: false, // 深色模式
darkMode: "auto", // 深色模式
uiLang: "en", // 界面语言
// fetchLimit: DEFAULT_FETCH_LIMIT, // 最大任务数量(移至rule作废)
// fetchInterval: DEFAULT_FETCH_INTERVAL, // 任务间隔时间(移至rule作废)

View File

@@ -12,7 +12,12 @@ export function useDarkMode() {
} = useSetting();
const toggleDarkMode = useCallback(() => {
updateSetting({ darkMode: !darkMode });
const nextMode = {
light: "dark",
dark: "auto",
auto: "light",
};
updateSetting({ darkMode: nextMode[darkMode] || "light" });
}, [darkMode, updateSetting]);
return { darkMode, toggleDarkMode };

View File

@@ -33,6 +33,15 @@ export function SettingProvider({ children }) {
reload,
} = useStorage(STOKEY_SETTING, DEFAULT_SETTING, KV_SETTING_KEY);
useEffect(() => {
if (typeof setting?.darkMode === "boolean") {
update((currentSetting) => ({
...currentSetting,
darkMode: currentSetting.darkMode ? "dark" : "light",
}));
}
}, [setting?.darkMode, update]);
useEffect(() => {
(async () => {
try {

View File

@@ -1,4 +1,4 @@
import { useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import { CssBaseline, GlobalStyles } from "@mui/material";
import { useDarkMode } from "./ColorMode";
@@ -11,6 +11,21 @@ import { THEME_DARK, THEME_LIGHT } from "../config";
*/
export default function Theme({ children, options, styles }) {
const { darkMode } = useDarkMode();
const [systemMode, setSystemMode] = useState(THEME_LIGHT);
useEffect(() => {
if (typeof window.matchMedia !== "function") {
return;
}
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = () => {
setSystemMode(mediaQuery.matches ? THEME_DARK : THEME_LIGHT);
};
handleChange(); // Set initial value
mediaQuery.addEventListener("change", handleChange);
return () => mediaQuery.removeEventListener("change", handleChange);
}, []);
const theme = useMemo(() => {
let htmlFontSize = 16;
try {
@@ -23,16 +38,19 @@ export default function Theme({ children, options, styles }) {
//
}
const isDarkMode =
darkMode === "dark" || (darkMode === "auto" && systemMode === THEME_DARK);
return createTheme({
palette: {
mode: darkMode ? THEME_DARK : THEME_LIGHT,
mode: isDarkMode ? THEME_DARK : THEME_LIGHT,
},
typography: {
htmlFontSize,
},
...options,
});
}, [darkMode, options]);
}, [darkMode, options, systemMode]);
return (
<ThemeProvider theme={theme}>

View File

@@ -2,12 +2,19 @@ import IconButton from "@mui/material/IconButton";
import { useDarkMode } from "../../hooks/ColorMode";
import LightModeIcon from "@mui/icons-material/LightMode";
import DarkModeIcon from "@mui/icons-material/DarkMode";
import BrightnessAutoIcon from "@mui/icons-material/BrightnessAuto";
export default function DarkModeButton() {
const { darkMode, toggleDarkMode } = useDarkMode();
return (
<IconButton onClick={toggleDarkMode} color="inherit">
{darkMode ? <LightModeIcon /> : <DarkModeIcon />}
<IconButton sx={{ ml: 1 }} onClick={toggleDarkMode} color="inherit">
{darkMode === "dark" ? (
<DarkModeIcon />
) : darkMode === "light" ? (
<LightModeIcon />
) : (
<BrightnessAutoIcon />
)}
</IconButton>
);
}