Styled-components로 다크모드 구현하기

밍글·2023년 3월 29일
0

⌨️서론

현재 API가 완료되지 않았기 때문에 Quill의 ImageHandler는 코드를 짜놔도 당장 테스트할 수 없다😫 그래서 project에 어떤 걸 구현할까 생각하다가 CSS library를 사용하면 무조건 구현해보는 DarkMode를 구현해보기로 했다.💪


1. 테마 상태관리 만들기

먼저 테마와 관련된 상태를 Recoil을 이용해서 atom으로 만들었다. 이는 나중에 DarkMode를 구현할 때 필수적이기 때문에 만들어두어야 한다.

import { atom } from "recoil";

//테마
export const isDarkAtom = atom({
  key: "isDark",
  default: true,
});

2. 테마 CSS 처리 및 버튼만들기

이 다음은 테마가 바뀌었을 때 어떻게 CSS를 처리할지를 만들어둬야 한다. Dark일때랑 Light, 그리고 기본값일때를 나눠서 CSS를 만들어준다. style을 따로 만들기 복잡해서 interface로 해당 style의 타입을 만든 뒤에 theme을 만들었다. 이는 나중에 App.tsx에서 처리하는 방법이 나오므로 미리 만들어두면 좋다. 아래 코드는 참고용일뿐 각자 알맞게 처리를 해주면 된다.

import {DefaultTheme} from "styled-components";
//테마 interface
declare module 'styled-components' {
  export interface DefaultTheme {
    textColor: string,
    bgColor: string,
    accentColor: string,
  }
}
//테마관련 디자인 수정가능
export const Theme:DefaultTheme = {
  bgColor: "#57606f",
  textColor: "#70a1ff",
  accentColor: "#ff4757"
}

export const LightTheme:DefaultTheme = {
  bgColor: "whitesmoke",
  textColor: "black",
  accentColor: "#ff4757"
}

export const DarkTheme:DefaultTheme = {
  bgColor: "#57606f",
  textColor: "white",
  accentColor: "#ff4757"
}

그런 다음 테마를 바꿔주는 버튼을 만들어준다. 이 때 먼저 만들어두었던 테마 상태관리를 사용하게 된다. 이 때 버튼모양이나 이미지 같은건 styled-components로 만들거나 css형식으로 만들면 된다.

import { useRecoilValue, useSetRecoilState } from "recoil";
import styled from "styled-components";
import { isDarkAtom } from "../atom";
//테마 변경 버튼
function ThemeChangeBtn(){
  const setIsDark = useSetRecoilState(isDarkAtom);
  const isDark = useRecoilValue(isDarkAtom);
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    setIsDark((prev) => !prev);
  }
  const icon = isDark ? "../sun.png": "../moon.png";
  return (<>
    <Button onClick = {handleClick}> 
      <BtnImg src = {icon} alt="theme change button"/>
    </Button>
  </>)
}
export default ThemeChangeBtn;

const BtnImg = styled.img`
  width: 30px;
  height: 30px;

`;

const Button = styled.button`
  border: none;
  background-color: transparent; 
`;

이렇게 만든 버튼은 다른 페이지에 import하여 적용하면 된다.

      <ThemeChangeBtn />

3. 전체에 적용하기

‼️전체에 적용할 때 ThemeProvider를 import하여 감싸주어야 한다. 그리고 theme에 따라 어떻게 처리할 것인지 나타내주면 된다. 이 때도 테마와 관련된 status를 import해주어야 한다. 또한 GlobalStyle도 사용해주어야 한다.(body,div,p에다가 해당 theme bgColor와 textColor를 지정해주었다)‼️

const GlobalStyle = createGlobalStyle`
//생략
body, p, div {
  font-weight: 300;
  background-color:${(props) => props.theme.bgColor};
  color:${(props) => props.theme.textColor};
  //생략
}
`
function App() {
  const isDark = useRecoilValue(isDarkAtom);
  return (
    <div>
      <div>
        <ThemeProvider theme={isDark ? DarkTheme : LightTheme}>
         <GlobalStyle />
          <HashRouter>
            <Routes>
				//Route종류들
            </Routes>
          </HashRouter>
        </ThemeProvider>
      </div>
    </div>
  );
}

4. 완성모습


계속 미뤄지고 있는 imageHandler때문에 당장 다음 포스팅은 아니더라도 나중에 Quill옆에 있는 react-calendar에 대해서도 다뤄보도록 하겠다🙇‍♂️

📚참고문헌

https://whales.tistory.com/96
https://memostack.tistory.com/334

profile
예비 초보 개발자의 프로젝트와 공부 기록일지

0개의 댓글