diff --git a/api/user_setting.go b/api/user_setting.go index 99a4102c0..cdff09394 100644 --- a/api/user_setting.go +++ b/api/user_setting.go @@ -35,7 +35,7 @@ func (key UserSettingKey) String() string { var ( UserSettingLocaleValue = []string{"en", "zh", "vi", "fr", "sv"} - UserSettingAppearanceValue = []string{"light", "dark"} + UserSettingAppearanceValue = []string{"system", "light", "dark"} UserSettingMemoVisibilityValue = []Visibility{Private, Protected, Public} UserSettingMemoDisplayTsOptionKeyValue = []string{"created_ts", "updated_ts"} ) diff --git a/web/src/App.tsx b/web/src/App.tsx index ec36bf0a2..3c0f05503 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,17 +1,18 @@ +import { useColorScheme } from "@mui/joy"; import { useEffect, Suspense } from "react"; import { useTranslation } from "react-i18next"; import { RouterProvider } from "react-router-dom"; -import { locationService } from "./services"; +import { globalService, locationService } from "./services"; import { useAppSelector } from "./store"; import Loading from "./pages/Loading"; import router from "./router"; import * as storage from "./helpers/storage"; -import { useColorScheme } from "@mui/joy"; +import { getSystemColorScheme } from "./helpers/utils"; function App() { const { i18n } = useTranslation(); const { appearance, locale, systemStatus } = useAppSelector((state) => state.global); - const { setMode } = useColorScheme(); + const { mode, setMode } = useColorScheme(); useEffect(() => { locationService.updateStateWithLocation(); @@ -20,6 +21,15 @@ function App() { }; }, []); + useEffect(() => { + window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => { + if (globalService.getState().appearance === "system") { + const mode = e.matches ? "dark" : "light"; + setMode(mode); + } + }); + }, []); + // Inject additional style and script codes. useEffect(() => { if (systemStatus.additionalStyle) { @@ -43,18 +53,27 @@ function App() { }, [locale]); useEffect(() => { - const root = document.documentElement; - if (appearance === "light") { - root.classList.remove("dark"); - } else if (appearance === "dark") { - root.classList.add("dark"); - } - setMode(appearance); storage.set({ appearance: appearance, }); + + let currentAppearance = appearance; + if (appearance === "system") { + currentAppearance = getSystemColorScheme(); + } + + setMode(currentAppearance); }, [appearance]); + useEffect(() => { + const root = document.documentElement; + if (mode === "light") { + root.classList.remove("dark"); + } else { + root.classList.add("dark"); + } + }, [mode]); + return ( }> diff --git a/web/src/components/AppearanceSelect.tsx b/web/src/components/AppearanceSelect.tsx index 371e18e5a..2ddf3f04d 100644 --- a/web/src/components/AppearanceSelect.tsx +++ b/web/src/components/AppearanceSelect.tsx @@ -4,7 +4,7 @@ import { globalService, userService } from "../services"; import { useAppSelector } from "../store"; import Icon from "./Icon"; -const appearanceList = ["light", "dark"]; +const appearanceList = ["system", "light", "dark"]; const AppearanceSelect = () => { const user = useAppSelector((state) => state.user.user); @@ -17,6 +17,8 @@ const AppearanceSelect = () => { return ; } else if (apperance === "dark") { return ; + } else { + return ; } }; diff --git a/web/src/locales/en.json b/web/src/locales/en.json index 3169195eb..0619ae10e 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -168,9 +168,9 @@ "additional-script-placeholder": "Additional JavaScript codes" }, "apperance-option": { + "system": "Follow system", "light": "Always light", - "dark": "Always dark", - "system": "Follow system" + "dark": "Always dark" } }, "amount-text": { diff --git a/web/src/locales/sv.json b/web/src/locales/sv.json index 3bbc94f9d..0d2988d14 100644 --- a/web/src/locales/sv.json +++ b/web/src/locales/sv.json @@ -168,9 +168,9 @@ "additional-script-placeholder": "Ytterligare JavaScript kod" }, "apperance-option": { + "system": "Follow system", "light": "Alltid ljus", - "dark": "Alltid mörk", - "system": "Följ systeminställningarna" + "dark": "Alltid mörk" } }, "amount-text": { @@ -210,4 +210,4 @@ "not-allow-space": "Tillåt inte mellanslag", "not-allow-chinese": "Tillåt inte kinesiska" } -} \ No newline at end of file +} diff --git a/web/src/locales/zh.json b/web/src/locales/zh.json index 01752cf17..71762c195 100644 --- a/web/src/locales/zh.json +++ b/web/src/locales/zh.json @@ -168,9 +168,9 @@ "additional-script-placeholder": "自定义 JavaScript 代码" }, "apperance-option": { + "system": "跟随系统", "light": "总是浅色", - "dark": "总是深色", - "system": "跟随系统" + "dark": "总是深色" } }, "amount-text": { diff --git a/web/src/services/globalService.ts b/web/src/services/globalService.ts index 10f442b2b..92889a30b 100644 --- a/web/src/services/globalService.ts +++ b/web/src/services/globalService.ts @@ -11,7 +11,7 @@ const globalService = { initialState: async () => { const defaultGlobalState = { locale: "en" as Locale, - appearance: "light" as Appearance, + appearance: "system" as Appearance, systemStatus: { allowSignUp: false, additionalStyle: "", diff --git a/web/src/store/modules/global.ts b/web/src/store/modules/global.ts index 7c5ecd954..492b9613a 100644 --- a/web/src/store/modules/global.ts +++ b/web/src/store/modules/global.ts @@ -10,7 +10,7 @@ const globalSlice = createSlice({ name: "global", initialState: { locale: "en", - appearance: "light", + appearance: "system", systemStatus: { host: undefined, profile: { diff --git a/web/src/types/modules/setting.d.ts b/web/src/types/modules/setting.d.ts index 04689418e..a423f4c15 100644 --- a/web/src/types/modules/setting.d.ts +++ b/web/src/types/modules/setting.d.ts @@ -1,4 +1,4 @@ -type Appearance = "light" | "dark"; +type Appearance = "system" | "light" | "dark"; interface Setting { locale: Locale;