Skip to content

Commit f2b1994

Browse files
sprettizadoesdev
andauthored
added support for system wide theme preferance (#177)
* added support for system wide theme preferance * fix: theme toggle * fix: hydration issues, icon color * fix: theme handling --------- Co-authored-by: iza <[email protected]>
1 parent 622c5f7 commit f2b1994

File tree

2 files changed

+81
-15
lines changed

2 files changed

+81
-15
lines changed

apps/dashboard/components/layout/theme-toggle.tsx

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { MoonIcon, SunIcon } from '@phosphor-icons/react';
3+
import { MonitorIcon, MoonIcon, SunIcon } from '@phosphor-icons/react';
44
import { useTheme } from 'next-themes';
55
import { Button } from '@/components/ui/button';
66
import { cn } from '@/lib/utils';
@@ -10,11 +10,19 @@ type ThemeTogglerProps = {
1010
};
1111

1212
export function ThemeToggle({ className }: ThemeTogglerProps) {
13-
const { resolvedTheme, setTheme } = useTheme();
13+
const { theme, setTheme } = useTheme();
14+
const currentTheme = theme ?? 'system';
1415

1516
const switchTheme = () => {
16-
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark');
17+
if (currentTheme === 'system') {
18+
setTheme('light');
19+
} else if (currentTheme === 'light') {
20+
setTheme('dark');
21+
} else {
22+
setTheme('system');
23+
}
1724
};
25+
1826
return (
1927
<Button
2028
aria-label="Toggle theme"
@@ -23,17 +31,35 @@ export function ThemeToggle({ className }: ThemeTogglerProps) {
2331
className
2432
)}
2533
onClick={switchTheme}
34+
suppressHydrationWarning
2635
type="button"
2736
variant="ghost"
2837
>
2938
<SunIcon
30-
className="dark:-rotate-90 h-5 w-5 rotate-0 scale-100 not-dark:text-primary transition-all duration-300 dark:scale-0"
39+
className={cn(
40+
'size-5 transition-all duration-300 not-dark:text-primary',
41+
currentTheme === 'light' ? 'scale-100 rotate-0' : 'scale-0 -rotate-90'
42+
)}
3143
size={32}
44+
suppressHydrationWarning
3245
weight="duotone"
3346
/>
3447
<MoonIcon
35-
className="absolute h-5 w-5 rotate-90 scale-0 not-dark:text-primary transition-all duration-300 dark:rotate-0 dark:scale-100"
48+
className={cn(
49+
'absolute size-5 transition-all duration-300 not-dark:text-primary',
50+
currentTheme === 'dark' ? 'scale-100 rotate-0' : 'scale-0 rotate-90'
51+
)}
52+
size={32}
53+
suppressHydrationWarning
54+
weight="duotone"
55+
/>
56+
<MonitorIcon
57+
className={cn(
58+
'absolute size-5 transition-all duration-300 not-dark:text-primary',
59+
currentTheme === 'system' ? 'scale-100 rotate-0' : 'scale-0 rotate-90'
60+
)}
3661
size={32}
62+
suppressHydrationWarning
3763
weight="duotone"
3864
/>
3965
<span className="sr-only">Toggle theme</span>

apps/docs/components/theme-toggle.tsx

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use client';
22

3-
import { MoonIcon, SunIcon } from '@phosphor-icons/react';
3+
import { MonitorIcon, MoonIcon, SunIcon } from '@phosphor-icons/react';
44
import { useTheme } from 'next-themes';
5+
import { useEffect, useState } from 'react';
56
import { Button } from '@/components/ui/button';
67
import { cn } from '@/lib/utils';
78

@@ -10,35 +11,74 @@ type ThemeToggleProps = {
1011
};
1112

1213
export function ThemeToggle({ className }: ThemeToggleProps) {
13-
const { resolvedTheme, setTheme } = useTheme();
14+
const { theme, setTheme } = useTheme();
15+
const [mounted, setMounted] = useState(false);
16+
const currentTheme = theme ?? 'system';
17+
18+
useEffect(() => {
19+
setMounted(true);
20+
}, []);
1421

1522
const switchTheme = () => {
16-
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark');
23+
if (currentTheme === 'system') {
24+
setTheme('light');
25+
} else if (currentTheme === 'light') {
26+
setTheme('dark');
27+
} else {
28+
setTheme('system');
29+
}
1730
};
1831

1932
const toggleTheme = () => {
20-
if (document.startViewTransition) {
21-
document.startViewTransition(switchTheme);
22-
} else {
23-
switchTheme();
24-
}
33+
switchTheme();
2534
};
2635

36+
if (!mounted) {
37+
return (
38+
<Button
39+
className={cn('relative h-8 w-8', className)}
40+
size="sm"
41+
variant="ghost"
42+
>
43+
<MonitorIcon className="h-4 w-4" size={16} weight="duotone" />
44+
<span className="sr-only">Toggle theme</span>
45+
</Button>
46+
);
47+
}
48+
2749
return (
2850
<Button
2951
className={cn('relative h-8 w-8', className)}
3052
onClick={toggleTheme}
3153
size="sm"
54+
suppressHydrationWarning
3255
variant="ghost"
3356
>
3457
<SunIcon
35-
className="dark:-rotate-90 h-4 w-4 rotate-0 scale-100 transition-all dark:scale-0"
58+
className={cn(
59+
'h-4 w-4 transition-all duration-300',
60+
currentTheme === 'light' ? 'scale-100 rotate-0' : 'scale-0 -rotate-90'
61+
)}
3662
size={16}
63+
suppressHydrationWarning
3764
weight="duotone"
3865
/>
3966
<MoonIcon
40-
className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
67+
className={cn(
68+
'absolute h-4 w-4 transition-all duration-300',
69+
currentTheme === 'dark' ? 'scale-100 rotate-0' : 'scale-0 rotate-90'
70+
)}
71+
size={16}
72+
suppressHydrationWarning
73+
weight="duotone"
74+
/>
75+
<MonitorIcon
76+
className={cn(
77+
'absolute h-4 w-4 transition-all duration-300',
78+
currentTheme === 'system' ? 'scale-100 rotate-0' : 'scale-0 rotate-90'
79+
)}
4180
size={16}
81+
suppressHydrationWarning
4282
weight="duotone"
4383
/>
4484
<span className="sr-only">Toggle theme</span>

0 commit comments

Comments
 (0)