블로그 만들기(NEXT.JS) 다크모드 적용까지만

신상우·2023년 6월 30일

터미널에
npx create-next-app@latest

√ What is your project named? ... new
√ Would you like to use TypeScript with this project? ... No / Yes
√ Would you like to use ESLint with this project? ... No / Yes
√ Would you like to use Tailwind CSS with this project? ... No / Yes
√ Would you like to use src/ directory with this project? ... No / Yes
√ Use App Router (recommended)? ... No / Yes
√ Would you like to customize the default import alias? ... No / Yes

이렇게 생성했다 NO/YES는 취향대로


npm i next-themes
npm i @heroicons/react
npm i react-icons

npm i next-themes @heroicons/react react-icons 이렇게 한번에 됨

/app/components/DarkModeBtn.tsx 에

"use client"
import { useState, useEffect } from "react"
import { useTheme } from "next-themes"
import { MoonIcon, SunIcon } from "@heroicons/react/24/solid"

const DarkModeBtn = () => {
	const [mounted, setMounted] = useState(false)
	const { systemTheme, theme, setTheme } = useTheme()
	const [play, { stop }] = useSound("./sound/bubble-sound.mp3")

	useEffect(() => {
		setMounted(true)
	}, [])

	if (!mounted) {
		return null
	}

	const currentTheme = theme === "system" ? systemTheme : theme

	return (
		<div>
			{currentTheme === "dark" ? (
				<SunIcon
					className="h-6 w-6 cursor-pointer text-yellow-400"
					onClick={() => {
						setTheme("light")
					}}
				/>
			) : (
				<MoonIcon
					className="h-6 w-6 cursor-pointer text-slate-700"
					onClick={() => {
						setTheme("dark")
					}}
				/>
			)}
		</div>
	)
}

export default DarkModeBtn

/app/components/Header.tsx 에

import DarkModeBtn from "./DarkModeBtn";

const Header = () => {
  let user_name = "Shin";
  return (
    <header className="py-5 px-5 flex items-center justify-between">
      <div>
        <h4 className="font-popins font-normal text-xl">{user_name}</h4>
      </div>
      <div className="flex">
        <DarkModeBtn />
        <h4 className="ml-4">Login</h4>
      </div>
    </header>
  );
};
export default Header;

app/Providers.tsx 에

"use client"
import { ThemeProvider } from "next-themes"

const Providers = ({ children }: { children: React.ReactNode }) => {
	return (
		<ThemeProvider enableSystem={true} attribute="class">
			{children}
		</ThemeProvider>
	)
}

export default Providers

app/layout.tsx에

import "./globals.css";
import Header from "./components/Header";
import Providers from "./Providers";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html className="h-full scroll-smooth">
      <head />
      <body>
        <Providers>
            <Header />
            <main>{children}</main>
        </Providers>
      </body>
    </html>
  );
}

/app/DarkMode.tsx 에

"use client";

import { BsFillSunFill, BsFillMoonFill } from "react-icons/bs";
import { useState, useEffect } from "react";
import { useTheme } from "next-themes";

interface IDarkMode {}

function DarkMode({}: IDarkMode) {
  const [mounted, setMounted] = useState(false);
  const { systemTheme, theme, setTheme } = useTheme();

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) {
    return null;
  }

  const onClick = (mode: string) => () => {
    setTheme(mode);
  };

  const currentTheme = theme === "system" ? systemTheme : theme;

  return (
    <div className="bg-darkModeBg cursor-pointer rounded-[50%] p-1">
    {currentTheme === "dark" ? (
    <BsFillMoonFill onClick={onClick("light")} />
) : (
  <BsFillSunFill onClick={onClick("dark")} />
)}
  </div>
);
}

export default DarkMode;
profile
기록 남기기

0개의 댓글