diff --git a/app/components/Providers.tsx b/app/components/Providers.tsx new file mode 100644 index 0000000..8edcd45 --- /dev/null +++ b/app/components/Providers.tsx @@ -0,0 +1,12 @@ +'use client'; + +import { ThemeProvider } from 'next-themes'; +import { PropsWithChildren } from 'react'; + +export const Providers = ({ children }: PropsWithChildren) => { + return ( + + {children} + + ); +}; diff --git a/app/components/ToggleDarkMode.tsx b/app/components/ToggleDarkMode.tsx index 08bc1db..a151695 100644 --- a/app/components/ToggleDarkMode.tsx +++ b/app/components/ToggleDarkMode.tsx @@ -1,32 +1,18 @@ 'use client'; import { MoonIcon, SunIcon } from '@radix-ui/react-icons'; -import { useState, Dispatch, SetStateAction, useLayoutEffect } from 'react'; - -const Theme = { - Light: 'light', - Dark: 'dark', - System: 'system', -} as const; - -type ThemeKeys = (typeof Theme)[keyof typeof Theme]; +import { useTheme } from 'next-themes'; /** system일 경우 추가 */ export const ToggleDarkMode = () => { - const [theme, setTheme] = useState('system'); - - useDarkModeInitiailizer(setTheme); + const { resolvedTheme: theme, setTheme } = useTheme(); const toggleTheme = () => { if (theme === 'dark') { - document.documentElement.classList.remove('dark'); - localStorage.setItem('theme', 'light'); setTheme('light'); return; } - document.documentElement.classList.add('dark'); - localStorage.setItem('theme', 'dark'); setTheme('dark'); }; @@ -43,21 +29,3 @@ export const ToggleDarkMode = () => { ); }; - -const useDarkModeInitiailizer = ( - setTheme: Dispatch>, -) => { - // SSR 문제로 다른 곳으로 옮기기 - useLayoutEffect?.(() => { - if (!('theme' in localStorage)) { - localStorage.setItem('theme', 'system'); - return; - } - - if (localStorage.theme === 'dark') { - document.documentElement.classList.add('dark'); - setTheme('dark'); - return; - } - }, [setTheme]); -}; diff --git a/app/layout.tsx b/app/layout.tsx index 2ba9579..c104ae7 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,6 +2,7 @@ import './styles/globals.css'; import type { Metadata } from 'next'; import { Header } from './components/Header'; import { pretendard } from './libs/font'; +import { Providers } from './components/Providers'; export const metadata: Metadata = { title: 'Create Next App', description: 'Generated by create next app', @@ -13,14 +14,16 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - + -
-
-
- {children} + +
+
+
+ {children} +
-
+ ); diff --git a/package-lock.json b/package-lock.json index d0a65b1..5f047cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "date-fns": "^2.30.0", "next": "13.5.4", "next-contentlayer": "^0.3.4", + "next-themes": "^0.3.0", "react": "^18", "react-dom": "^18" }, @@ -7259,6 +7260,15 @@ "react-dom": "*" } }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -14802,6 +14812,12 @@ "@contentlayer/utils": "0.3.4" } }, + "next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "requires": {} + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", diff --git a/package.json b/package.json index 38896b7..1d3b0d9 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "date-fns": "^2.30.0", "next": "13.5.4", "next-contentlayer": "^0.3.4", + "next-themes": "^0.3.0", "react": "^18", "react-dom": "^18" },