Emotion 으로 Dark Mode를 설정을 해보았다. TypeScript 에 아직 익숙치 않아서 Type 지정을 하는 데에 시간이 많이 소요된 것 같다, 문법 공부를 다시 해야할 것 같다.
우선은 이 part에서는 Dark Mode를 구현하는 것에 집중하기로 했다.
import { DarkTheme, LightTheme } from '@emotion/react';
export const lightTheme: LightTheme = {
mode: {
text: '#000',
background: '#fff',
buttonText: '#000',
buttonTextHover: '#fff',
buttonBorder: '#000',
buttonBg: 'rgba(0, 0, 0, 0)',
buttonBgHover: 'rgba(0, 0, 0, 1)',
},
};
export const darkTheme: DarkTheme = {
mode: {
text: '#fff',
background: '#121212',
buttonText: '#fff',
buttonTextHover: '#000',
buttonBorder: '#fff',
buttonBg: 'rgba(255, 255, 255, 0)',
buttonBgHover: 'rgba(255, 255, 255, 1)',
},
};
lightTheme와 darkTheme 으로 나누어서 color 색상을 지정하였다.
import '@emotion/react';
declare module '@emotion/react' {
export interface LightTheme {
mode: {
text: string;
background: string;
buttonText: string;
buttonTextHover: string;
buttonBorder: string;
buttonBg: string;
buttonBgHover: string;
};
}
export interface DarkTheme {
mode: {
text: string;
background: string;
buttonText: string;
buttonTextHover: string;
buttonBorder: string;
buttonBg: string;
buttonBgHover: string;
};
}
}
theme를 사용할 때 반드시 type을 지정해주어야 한다.
import React from 'react';
import { Global, css, LightTheme, DarkTheme } from '@emotion/react';
const style = (theme: any) => css`
* {
margin: 0;
padding: 0;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
body {
color: ${theme.mode.text};
background: ${theme.mode.background};
}
`;
const GlobalStyle = () => {
return <Global styles={style} />;
};
export default GlobalStyle;
이 부분을 구현할 때 아쉬웠던 점은, theme 를 변수로 받아올 때 any 로 지정을 한 점이다.
type ColorMode = LightTheme | DarkTheme; 를 변수로 지정한 다음
any 대신 ColorMode
로 Type을 선언하고 싶었지만 밑의 style
에서 에러 메시지가 작동하여, 이 부분에서 에러메시지를 구글링 하다가 못 찾아서 우선 any 로 Type을 지정해두었다.
추후에 수정 할 예정이다.
type ColorMode = LightTheme | DarkTheme;
const style = (theme: ColorMode) => css`
...
`;
const GlobalStyle = () => {
return <Global styles={style} />;
};
export default GlobalStyle;
다시 살펴보니, Type 선언 시에, interface 를 LightTheme 와 DarkTheme 두 가지로 나누었던 것이 에러의 근본 원인이었다. 동일한 내용의 Interface를 굳이 쪼개어서 선언한 것이었다 .. 🤦♀️
type을 any 대신 Theme로 지정해줄 수 있게 되었다 .. !
const style = (theme: Theme) => css`
...
`;
const GlobalStyle = () => {
return <Global styles={style} />;
};
export default GlobalStyle;
import React, { useState } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from '@emotion/react';
import GlobalStyle from '@src/styles/global';
import Routes from '@src/Routes';
import { darkTheme, lightTheme } from '@src/styles/theme';
const App = () => {
const [isDark, setIsDark] = useState(false);
return (
<BrowserRouter>
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<GlobalStyle />
<Routes isDark={isDark} setIsDark={setIsDark} />
</ThemeProvider>
</BrowserRouter>
);
};
export default App;
/** @jsx jsx */
import { css, jsx } from '@emotion/react';
import React, { Dispatch, SetStateAction } from 'react';
import { Route } from 'react-router-dom';
import Home from './pages/Home';
interface RoutesProps {
isDark: boolean;
setIsDark: Dispatch<SetStateAction<boolean>>;
}
const Routes: React.FC<RoutesProps> = ({ isDark, setIsDark }) => {
return (
<div>
<button
css={css`
color: ${isDark ? 'white' : 'black'};
`}
onClick={() => {
setIsDark(!isDark);
}}
>
{isDark ? 'dark' : 'light'}버튼 입니다.
</button>
<Route exact path="/" component={Home} />
</div>
);
};
export default Routes;