fix: web app dark mode (#131)

* fix: web app dark mode

Signed-off-by: Innei <i@innei.in>

* update electron logic

Signed-off-by: Innei <i@innei.in>

---------

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-07-12 00:19:23 +08:00 committed by GitHub
parent b2d6797d42
commit 19796d9220
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 15 deletions

View File

@ -177,7 +177,14 @@ export const router = {
setAppearance: t.procedure
.input<"light" | "dark" | "system">()
.action(async ({ input }) => {
nativeTheme.themeSource = input
// NOTE: Temporarily changing to system to get the color mode that system is in at the moment may cause a bit of a problem.
// On macos, there is a bug, traffic lights flicker
nativeTheme.themeSource = "system"
const systemColorMode = nativeTheme.shouldUseDarkColors ?
"dark" :
"light"
nativeTheme.themeSource = systemColorMode === input ? "system" : input
}),
setMacOSBadge: t.procedure.input<number>().action(async ({ input }) => {
if (app.dock) {

View File

@ -1,24 +1,68 @@
import { jotaiStore } from "@renderer/lib/jotai"
import { getStorageNS } from "@renderer/lib/ns"
import { atom, useAtomValue } from "jotai"
import { useLayoutEffect } from "react"
import { atomWithStorage } from "jotai/utils"
import { useCallback, useLayoutEffect } from "react"
import { useMediaQuery } from "usehooks-ts"
const darkAtom = atom(false)
export function useDark() {
return useAtomValue(darkAtom)
const useDarkQuery = () => useMediaQuery("(prefers-color-scheme: dark)")
type ColorMode = "light" | "dark" | "system"
const darkAtom = !window.electron ?
atomWithStorage(
getStorageNS("color-mode"),
"system" as ColorMode,
undefined,
{
getOnInit: true,
},
) :
atom("system" as ColorMode)
function useDarkElectron() {
return useAtomValue(darkAtom) === "dark"
}
function useDarkWebApp() {
const systemIsDark = useDarkQuery()
const mode = useAtomValue(darkAtom)
return mode === "dark" || (mode === "system" && systemIsDark)
}
export const useDark = window.electron ? useDarkElectron : useDarkWebApp
export const useSyncDark = () => {
const isDark = useMediaQuery("(prefers-color-scheme: dark)")
const useSyncDarkElectron = () => {
const appIsDark = useDarkQuery()
useLayoutEffect(() => {
jotaiStore.set(darkAtom, isDark)
document.documentElement.dataset.theme = appIsDark ? "dark" : "light"
disableTransition(["[role=switch]>*"])
document.documentElement.dataset.theme = isDark ? "dark" : "light"
disableTransition([
"[role=switch]>*",
])
}, [isDark])
jotaiStore.set(darkAtom, appIsDark ? "dark" : "light")
}, [appIsDark])
}
const useSyncDarkWebApp = () => {
const colorMode = useAtomValue(darkAtom)
const systemIsDark = useDarkQuery()
useLayoutEffect(() => {
const realColorMode: Exclude<ColorMode, "system"> =
colorMode === "system" ? (systemIsDark ? "dark" : "light") : colorMode
document.documentElement.dataset.theme = realColorMode
disableTransition(["[role=switch]>*"])
}, [colorMode, systemIsDark])
}
export const useSyncDark = window.electron ?
useSyncDarkElectron :
useSyncDarkWebApp
export const useSetDarkInWebApp = () => {
const systemColorMode = useDarkQuery() ? "dark" : "light"
return useCallback(
(colorMode: Exclude<ColorMode, "system">) =>
jotaiStore.set(
darkAtom,
colorMode === systemColorMode ? "system" : colorMode,
),
[systemColorMode],
)
}
function disableTransition(disableTransitionExclude: string[] = []) {

View File

@ -11,7 +11,7 @@ import {
SelectTrigger,
SelectValue,
} from "@renderer/components/ui/select"
import { useDark } from "@renderer/hooks/common"
import { useDark, useSetDarkInWebApp } from "@renderer/hooks/common"
import { tipcClient } from "@renderer/lib/client"
import { getOS } from "@renderer/lib/utils"
import { useQuery } from "@tanstack/react-query"
@ -26,6 +26,8 @@ const SettingBuilder = createSettingBuilder(useUISettingValue)
export const SettingAppearance = () => {
const isDark = useDark()
const setDarkInWebApp = useSetDarkInWebApp()
return (
<>
<SettingsTitle />
@ -41,7 +43,11 @@ export const SettingAppearance = () => {
label="Dark Mode"
checked={isDark}
onCheckedChange={(e) => {
tipcClient?.setAppearance(e ? "dark" : "light")
if (window.electron) {
tipcClient?.setAppearance(e ? "dark" : "light")
} else {
setDarkInWebApp(e ? "dark" : "light")
}
}}
/>,
{