Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: set app dark mode instead of renderer #130

Merged
merged 2 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@
"idb-keyval": "6.2.1",
"immer": "10.1.1",
"jotai": "2.8.4",
"jotai-dark": "0.4.0",
"jotai-effect": "1.0.0",
"lethargy": "1.0.9",
"lodash-es": "4.17.21",
"lowdb": "7.0.1",
Expand Down
35 changes: 0 additions & 35 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion src/main/tipc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { createRequire } from "node:module"

import { getRendererHandlers, tipc } from "@egoist/tipc/main"
import { callGlobalContextMethod } from "@shared/bridge"
import type { BrowserWindow, MessageBoxOptions } from "electron"
import { app, dialog, Menu, ShareMenu } from "electron"
import { app, dialog, Menu, nativeTheme, ShareMenu } from "electron"

import { downloadFile } from "./lib/download"
import type { RendererHandlers } from "./renderer-handlers"
Expand All @@ -10,6 +12,7 @@ import { createSettingWindow, createWindow, getMainWindow } from "./window"

const t = tipc.create()

const require = createRequire(import.meta.url)
export const router = {
inspectElement: t.procedure
.input<{ x: number, y: number }>()
Expand Down Expand Up @@ -171,6 +174,11 @@ export const router = {
})
}),
),
setAppearance: t.procedure
.input<"light" | "dark" | "system">()
.action(async ({ input }) => {
nativeTheme.themeSource = input
}),
setMacOSBadge: t.procedure.input<number>().action(async ({ input }) => {
if (app.dock) {
if (input === 0) {
Expand Down
2 changes: 0 additions & 2 deletions src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import { Outlet } from "react-router-dom"
import { useAppIsReady } from "./atoms/app"
import { useUISettingKey } from "./atoms/settings/ui"
import { Logo } from "./components/icons/logo"
import { useDark } from "./hooks/common/useDark"
import { tipcClient } from "./lib/client"
import { appLog } from "./lib/log"
import { getOS } from "./lib/utils"
import { RootProviders } from "./providers/root-providers"
import { handlers } from "./tipc"

function App() {
useDark()
useEffect(() => {
const cleanup = handlers?.invalidateQuery.listen((queryKey) => {
queryClient.invalidateQueries({
Expand Down
7 changes: 1 addition & 6 deletions src/renderer/src/components/ui/background/vibrancy.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useUISettingKey } from "@renderer/atoms/settings/ui"
import { useDark } from "@renderer/hooks/common"
import { cn } from "@renderer/lib/utils"
import { useMediaQuery } from "usehooks-ts"

export const Vibrancy: Component<
React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
Expand All @@ -11,15 +9,12 @@ export const Vibrancy: Component<
window.electron &&
window.electron.process.platform === "darwin" &&
!opaqueSidebar
const systemDark = useMediaQuery("(prefers-color-scheme: dark)")
const { isDark } = useDark()

return (
<div
className={cn(
canVibrancy ? "bg-native/50 dark:bg-native/10" : "bg-native",
// NOTE: if the system is light and the app is dark, we need to apply a background to the vibrancy, otherwise it will be transparent
systemDark !== isDark && "!bg-native/75",

className,
)}
{...rest}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useDark } from "@renderer/hooks/common"

export const useShikiDefaultTheme = () => {
const { isDark } = useDark()
const isDark = useDark()

return isDark ? "github-dark" : "github-light"
}
38 changes: 18 additions & 20 deletions src/renderer/src/components/ui/sonner.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import { useDark } from "@renderer/hooks/common"
import { Toaster as Sonner } from "sonner"

type ToasterProps = React.ComponentProps<typeof Sonner>

const Toaster = ({ ...props }: ToasterProps) => {
const { theme } = useDark()

return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
toastOptions={{
classNames: {
toast: "group toast group-[.toaster]:bg-theme-background group-[.toaster]:text-theme-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...props}
/>
)
}
const Toaster = ({ ...props }: ToasterProps) => (
<Sonner
theme="system"
className="toaster group"
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-theme-background group-[.toaster]:text-theme-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton:
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...props}
/>
)

export { Toaster }
59 changes: 46 additions & 13 deletions src/renderer/src/hooks/common/useDark.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
import { useAtom } from "jotai"
import { atomDark } from "jotai-dark"

const isDarkAtom = atomDark({
storageKey: "theme",
disableTransition: true,
mode: "data-theme",
})
import { jotaiStore } from "@renderer/lib/jotai"
import { atom, useAtomValue } from "jotai"
import { useLayoutEffect } from "react"
import { useMediaQuery } from "usehooks-ts"

const darkAtom = atom(false)
export function useDark() {
const [isDark, setIsDark] = useAtom(isDarkAtom)
return {
isDark,
toggleDark: setIsDark as () => void,
theme: (isDark ? "dark" : "light") as "dark" | "light",
return useAtomValue(darkAtom)
}

export const useSyncDark = () => {
const isDark = useMediaQuery("(prefers-color-scheme: dark)")

useLayoutEffect(() => {
jotaiStore.set(darkAtom, isDark)

document.documentElement.dataset.theme = isDark ? "dark" : "light"
disableTransition([
"[role=switch]>*",
])
}, [isDark])
}

function disableTransition(disableTransitionExclude: string[] = []) {
const css = document.createElement("style")
css.append(
document.createTextNode(
`
*${disableTransitionExclude.map((s) => `:not(${s})`).join("")} {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
`,
),
)
document.head.append(css)

return () => {
// Force restyle
(() => window.getComputedStyle(document.body))()

// Wait for next tick before removing
setTimeout(() => {
css.remove()
}, 1)
}
}
10 changes: 4 additions & 6 deletions src/renderer/src/modules/settings/tabs/apperance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { useDark } from "@renderer/hooks/common"
import { tipcClient } from "@renderer/lib/client"
import { getOS } from "@renderer/lib/utils"
import { useQuery } from "@tanstack/react-query"
import { useCallback } from "react"
import { bundledThemes } from "shiki/themes"

import { SettingSwitch } from "../control"
Expand All @@ -25,10 +24,7 @@ import { SettingsTitle } from "../title"
const SettingBuilder = createSettingBuilder(useUISettingValue)

export const SettingAppearance = () => {
const { isDark, toggleDark } = useDark()
const saveDarkSetting = useCallback(() => {
toggleDark()
}, [])
const isDark = useDark()

return (
<>
Expand All @@ -44,7 +40,9 @@ export const SettingAppearance = () => {
key="darkMode"
label="Dark Mode"
checked={isDark}
onCheckedChange={saveDarkSetting}
onCheckedChange={(e) => {
tipcClient?.setAppearance(e ? "dark" : "light")
}}
/>,
{
label: "Opaque Sidebars",
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/providers/root-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { FC, PropsWithChildren } from "react"

import { StableRouterProvider } from "./biz-router-provider"
import { ContextMenuProvider } from "./context-menu-provider"
import { SettingSync } from "./ui-setting-Initialize"
import { SettingSync } from "./ui-setting-sync"
import { UserProvider } from "./user-provider"

const loadFeatures = () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { useUISettingValue } from "@renderer/atoms/settings/ui"
import { useSyncDark } from "@renderer/hooks/common"
import { tipcClient } from "@renderer/lib/client"
import { feedUnreadActions } from "@renderer/store/unread"
import { useEffect, useInsertionEffect } from "react"

const useUISettingSync = () => {
const setting = useUISettingValue()

useSyncDark()
useInsertionEffect(() => {
const root = document.documentElement
root.style.fontSize = `${setting.uiTextSize}px`
}, [setting.uiTextSize])

useEffect(() => {
if (setting.showDockBadge) {
return feedUnreadActions.subscribeUnreadCount((count) => tipcClient?.setMacOSBadge(count), true)
return feedUnreadActions.subscribeUnreadCount(
(count) => tipcClient?.setMacOSBadge(count),
true,
)
} else {
tipcClient?.setMacOSBadge(0)
}
Expand Down
Loading