0. TL;DR
- 웹 이력서에 다크모드를 적용할 필요성을 느낌
- 일관적인 경험을 위해 system값을 기본값으로 사용하고, 이후에는 dark / light모드를 토글로 변환하도록 결정
- 'system 값 사용'과 'load 시 flickering 이슈' 해결에 장점이 있는 next-themes 라이브러리를 사용해서 구현
1. Why?
이력서의 경우 많은 사람들에게 피드백을 받아보는 것이 좋다고 생각한다. 그래서 어느정도 완성된 이력서 사이트를 친구에게 보여줬더니 개발자를 위한 다크모드는 없냐고 불평을 했다.
난 사실 화이트모드를 더 좋아하지만, 상당수의 개발자들이 다크모드를 선호하는 것은 사실이다. 내 이력서 보는 사람들도 어두운 화면을 보다가 갑자기 밝은 화면을 보면 불쾌할 수도 있고, 눈 아프다고 그냥 끄고 나가버릴 수도 있으니 다크모드를 구현해보자.
2. How?
아래 두 부분에서 어떻게 구현할지 고민했다.
- System 설정 사용
- System 설정을 고려한다면, 버튼은 어떻게?
- 구현 방법
1. System 설정 사용
구현하는 이유 자체가 사용자의 일관적인 경험을 위해서이니, system 설정에 따라서 다크모드를 해주는 것이 이상적
1-1. System 설정을 고려한다면, 버튼은 어떻게?
- 내 타겟은 면접관, 이 사람들 볼 거 많은데 최대한 덜 귀찮게 하는게 중요
- 만약 모바일로 들어온다면, 더욱 직관적인게 중요
- system 설정 넣었다고 굳이 1단계의 depth를 추가하는 것 보다는 그냥 직관적으로 동작하게끔 하고싶음
2. 어떻게 구현할까?
- 'system 값 사용'과 'load 시 flickering 이슈' 해결에 장점이 있는 next-themes 라이브러리를 사용해서 구현
3. 코드
1️⃣ ThemeProvider를 구현
next-themes를 사용해 ThemeProvider를 구현
- 'use client'를 통해 client component로 사용하고자 분리
// components/provider/ThemeProvider.tsx
import { ThemeProvider as NextThemesProvider } from 'next-themes';
import { type ThemeProviderProps } from 'next-themes/dist/types';
export default function ThemeProvider({ children }: ThemeProviderProps) {
return (
<NextThemesProvider attribute="class" defaultTheme="system">
// 일관적인 UX를 위해 defaultTheme를 system으로 설정
{children}
</NextThemesProvider>
);
}
- provider를 Home 컴포넌트에 적용
// ./src/app/mocks/browser.ts
import ThemeProvider from './components/provider/ThemeProvider';
export default function Home() {
return (
<ThemeProvider enableSystem>
// system의 값을 가져오도록 enableSystem을 true로 설정
// ...
</ThemeProvider>
- ThemeButton 컴포넌트 구현
// component/app/ThemeButton.tsx
export default function ThemeButton() {
const [mounted, setMounted] = useState(false);
const { systemTheme, theme, setTheme } = useTheme();
const currentTheme = theme === 'system' ? systemTheme : theme;
// theme값이 'system'이라면 systemTheme값을 가져와서 사용하도록 설정
const themeChange = (nowTheme: string | undefined) => {
if (nowTheme === 'dark') {
return 'light';
}
return 'dark';
};
const themeButtonHandler = () => {
setTheme(themeChange(currentTheme));
};
useEffect(() => {
setMounted(true);
}, []);
// 클라이언트 사이드에서만 접근 가능하도록
if (!mounted) return null;
// ...
위와 같이 구현한 결과, dark/light 모드 변환이 정상적으로 동작하는 것을 확인
https://resume-legitgoons.vercel.app
4. 래퍼런스
https://www.d5br5.dev/blog/nextjs_blog/theme
'Project > 기타' 카테고리의 다른 글
Next.js에서 MongoDB Data 가져오기 / 웹 이력서 (0) | 2024.03.03 |
---|---|
Next.js 14 SEO(검색엔진 최적화) 도전기 / 웹 이력서 (2) | 2024.03.01 |
LCP 개선하기 / 아워홈 사전과제 (0) | 2024.01.15 |
비슷한 컴포넌트 재사용하기 / 아워홈 사전과제 (0) | 2024.01.14 |
Context Api + Reducer로 전역상태 관리하기 / 아워홈 사전과제 (1) | 2024.01.12 |