diff --git a/package.json b/package.json index f6879be7..3722dc3c 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "eslint-config-next": "13.2.4", "eventsource-parser": "^1.0.0", "next": "13.2.4", + "next-themes": "^0.2.1", "openai": "^3.2.1", "parse-numeric-range": "^1.3.0", "react": "18.2.0", diff --git a/src/components/chat/sidebar/buttons/ThemeButton.tsx b/src/components/chat/sidebar/buttons/ThemeButton.tsx index be5b5329..9e988b6d 100644 --- a/src/components/chat/sidebar/buttons/ThemeButton.tsx +++ b/src/components/chat/sidebar/buttons/ThemeButton.tsx @@ -1,30 +1,30 @@ import React from "react"; import { MdColorLens } from "react-icons/md"; import ButtonContainer from "./ButtonContainer"; +import { useTheme } from "next-themes"; type Props = {}; export default function ThemeButton({}: Props) { - const [dark, setDark] = React.useState(false); + const { theme, setTheme } = useTheme(); + const [mounted, setMounted] = React.useState(false); - React.useEffect(() => { - if (localStorage.theme === "dark") { - setDark(true); - } else { - setDark(false); - } - }, []); + React.useEffect(() => setMounted(true), []); const handleThemeChange = () => { - document.documentElement.classList.toggle("dark"); - localStorage.theme = localStorage.theme === "dark" ? "light" : "dark"; - setDark(!dark); + if (theme === "dark") { + setTheme("light"); + } else { + setTheme("dark"); + } }; + if (!mounted) return null; + return ( - {dark ? "Light" : "Dark"} mode + {`${theme === "dark" ? "Light" : "Dark"} mode`} ); } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 987a0eb9..31741559 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -3,30 +3,19 @@ import OpenAIProvider from "@/context/OpenAIProvider"; import "@/styles/globals.css"; import type { AppProps } from "next/app"; import { Analytics } from "@vercel/analytics/react"; +import { ThemeProvider } from "next-themes"; export default function App({ Component, pageProps }: AppProps) { - if (typeof window !== "undefined") { - const isDarkSet = localStorage.theme === "dark"; - const isThemeStored = "theme" in localStorage; - const isDarkPrefered = window.matchMedia( - "(prefers-color-scheme: dark)" - ).matches; - - if (isDarkSet || (!isThemeStored && isDarkPrefered)) { - document.documentElement.classList.add("dark"); - } else { - document.documentElement.classList.remove("dark"); - } - } - return ( <> - - - - - - + + + + + + + + ); } diff --git a/src/styles/globals.css b/src/styles/globals.css index ac3ad5dc..663601ee 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -10,7 +10,7 @@ --bg-tertiary: 209, 213, 219; } - .dark { + .dark, [data-theme="dark"] { --text-primary: 255, 255, 255; --bg-primary: 17, 24, 39; --bg-secondary: 31, 41, 55; diff --git a/yarn.lock b/yarn.lock index e0f96d6d..e43ed3cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2292,6 +2292,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +next-themes@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45" + integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A== + next@13.2.4: version "13.2.4" resolved "https://registry.yarnpkg.com/next/-/next-13.2.4.tgz#2363330392b0f7da02ab41301f60857ffa7f67d6"