feat(desktop): add resolvedTheme to theme provider
- Add resolvedTheme state to expose actual applied theme - Listen for system theme changes when in "system" mode - Fix mode toggle to show correct icon based on selected theme Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
54bc00ce3f
commit
07b8a014aa
2 changed files with 36 additions and 22 deletions
|
|
@ -1,6 +1,5 @@
|
|||
import { HugeiconsIcon } from "@hugeicons/react"
|
||||
import { Sun03Icon, Moon02Icon, ComputerIcon } from "@hugeicons/core-free-icons"
|
||||
import { Button } from "@multica/ui/components/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
|
@ -10,22 +9,15 @@ import {
|
|||
import { useTheme } from "./theme-provider"
|
||||
|
||||
export function ModeToggle() {
|
||||
const { setTheme } = useTheme()
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const icon = theme === "light" ? Sun03Icon : theme === "dark" ? Moon02Icon : ComputerIcon
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<HugeiconsIcon
|
||||
icon={Sun03Icon}
|
||||
className="size-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
|
||||
/>
|
||||
<HugeiconsIcon
|
||||
icon={Moon02Icon}
|
||||
className="absolute size-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
|
||||
/>
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
<DropdownMenuTrigger className="inline-flex items-center justify-center size-8 rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">
|
||||
<HugeiconsIcon icon={icon} className="size-4" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => setTheme("light")}>
|
||||
|
|
|
|||
|
|
@ -10,16 +10,24 @@ type ThemeProviderProps = {
|
|||
|
||||
type ThemeProviderState = {
|
||||
theme: Theme
|
||||
resolvedTheme: "light" | "dark"
|
||||
setTheme: (theme: Theme) => void
|
||||
}
|
||||
|
||||
const initialState: ThemeProviderState = {
|
||||
theme: "system",
|
||||
resolvedTheme: "light",
|
||||
setTheme: () => null,
|
||||
}
|
||||
|
||||
const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
|
||||
|
||||
function getSystemTheme(): "light" | "dark" {
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light"
|
||||
}
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
defaultTheme = "system",
|
||||
|
|
@ -28,25 +36,39 @@ export function ThemeProvider({
|
|||
const [theme, setTheme] = useState<Theme>(
|
||||
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
|
||||
)
|
||||
const [resolvedTheme, setResolvedTheme] = useState<"light" | "dark">(
|
||||
() => (theme === "system" ? getSystemTheme() : theme)
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const root = window.document.documentElement
|
||||
root.classList.remove("light", "dark")
|
||||
|
||||
if (theme === "system") {
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches
|
||||
? "dark"
|
||||
: "light"
|
||||
root.classList.add(systemTheme)
|
||||
return
|
||||
const resolved = theme === "system" ? getSystemTheme() : theme
|
||||
root.classList.add(resolved)
|
||||
setResolvedTheme(resolved)
|
||||
}, [theme])
|
||||
|
||||
// Listen for system theme changes
|
||||
useEffect(() => {
|
||||
if (theme !== "system") return
|
||||
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
const handleChange = () => {
|
||||
const resolved = getSystemTheme()
|
||||
const root = window.document.documentElement
|
||||
root.classList.remove("light", "dark")
|
||||
root.classList.add(resolved)
|
||||
setResolvedTheme(resolved)
|
||||
}
|
||||
|
||||
root.classList.add(theme)
|
||||
mediaQuery.addEventListener("change", handleChange)
|
||||
return () => mediaQuery.removeEventListener("change", handleChange)
|
||||
}, [theme])
|
||||
|
||||
const value = {
|
||||
theme,
|
||||
resolvedTheme,
|
||||
setTheme: (theme: Theme) => {
|
||||
localStorage.setItem(storageKey, theme)
|
||||
setTheme(theme)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue