-
Notifications
You must be signed in to change notification settings - Fork 0
Fix dark mode toggle and respect browser preference #18
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,16 +5,9 @@ | |
| --foreground: #171717; | ||
| } | ||
|
|
||
| @theme inline { | ||
| --color-background: var(--background); | ||
| --color-foreground: var(--foreground); | ||
| } | ||
|
|
||
| @media (prefers-color-scheme: dark) { | ||
| :root { | ||
| --background: #0a0a0a; | ||
| --foreground: #ededed; | ||
| } | ||
| .dark { | ||
| --background: #0a0a0a; | ||
| --foreground: #ededed; | ||
| } | ||
|
Comment on lines
+8
to
11
|
||
|
|
||
| body { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,7 +13,30 @@ export default function RootLayout({ | |||||||||||||||||||||||||||||
| children: React.ReactNode; | ||||||||||||||||||||||||||||||
| }>) { | ||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||
| <html lang="en"> | ||||||||||||||||||||||||||||||
| <html lang="en" suppressHydrationWarning> | ||||||||||||||||||||||||||||||
| <head> | ||||||||||||||||||||||||||||||
| <script | ||||||||||||||||||||||||||||||
| dangerouslySetInnerHTML={{ | ||||||||||||||||||||||||||||||
| __html: ` | ||||||||||||||||||||||||||||||
| (function() { | ||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const savedTheme = localStorage.getItem('theme'); | ||||||||||||||||||||||||||||||
| if (savedTheme === 'dark' || savedTheme === 'light') { | ||||||||||||||||||||||||||||||
| if (savedTheme === 'dark') { | ||||||||||||||||||||||||||||||
| document.documentElement.classList.add('dark'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; | ||||||||||||||||||||||||||||||
| if (isDark) { | ||||||||||||||||||||||||||||||
| document.documentElement.classList.add('dark'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+25
to
+33
|
||||||||||||||||||||||||||||||
| if (savedTheme === 'dark') { | |
| document.documentElement.classList.add('dark'); | |
| } | |
| return; | |
| } | |
| const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; | |
| if (isDark) { | |
| document.documentElement.classList.add('dark'); | |
| } | |
| document.documentElement.classList.toggle('dark', savedTheme === 'dark'); | |
| return; | |
| } | |
| const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; | |
| document.documentElement.classList.toggle('dark', isDark); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,29 +11,38 @@ interface ThemeContextType { | |
|
|
||
| const ThemeContext = createContext<ThemeContextType | undefined>(undefined); | ||
|
|
||
| export function ThemeProvider({ children }: { children: React.ReactNode }) { | ||
| const [theme, setTheme] = useState<Theme>(() => { | ||
| if (typeof window === "undefined") { | ||
| return "light"; | ||
| } | ||
| function getInitialTheme(): Theme { | ||
| if (typeof window === "undefined") { | ||
| return "light"; | ||
| } | ||
|
|
||
| const savedTheme = window.localStorage.getItem("theme"); | ||
| if (savedTheme === "light" || savedTheme === "dark") { | ||
| return savedTheme; | ||
| } | ||
|
|
||
| const savedTheme = window.localStorage.getItem("theme"); | ||
| if (savedTheme === "light" || savedTheme === "dark") { | ||
| return savedTheme; | ||
| } | ||
| const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches; | ||
| return isDark ? "dark" : "light"; | ||
|
Comment on lines
+19
to
+25
|
||
| } | ||
|
|
||
| export function ThemeProvider({ children }: { children: React.ReactNode }) { | ||
| const [theme, setTheme] = useState<Theme>("light"); | ||
| const [mounted, setMounted] = useState(false); | ||
|
|
||
| const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches; | ||
| return isDark ? "dark" : "light"; | ||
| }); | ||
| useEffect(() => { | ||
| setMounted(true); | ||
| const initialTheme = getInitialTheme(); | ||
| setTheme(initialTheme); | ||
| document.documentElement.classList.toggle("dark", initialTheme === "dark"); | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| if (typeof window === "undefined") return; | ||
| if (!mounted) return; | ||
| document.documentElement.classList.toggle("dark", theme === "dark"); | ||
| }, [theme]); | ||
| }, [theme, mounted]); | ||
|
|
||
| const toggleTheme = () => { | ||
| if (typeof window === "undefined") return; | ||
|
|
||
| if (!mounted) return; | ||
| const newTheme = theme === "light" ? "dark" : "light"; | ||
| setTheme(newTheme); | ||
| window.localStorage.setItem("theme", newTheme); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The theme variables are currently scoped to the generic
.darkclass selector. This will apply to any element with classdark, not just the root element. To make the intent explicit and avoid accidental scoping changes later, consider usinghtml.dark/:root.darkinstead.