모든 완성도 높은 핀테크 또는 투자 분석 대시보드는 다크 모드(Dark Mode)와 라이트 모드(Light Mode) 전환을 필수로 지원합니다. 장시간 차트 캔들과 세부 시세 표를 쳐다봐야 하는 투자자들은 눈의 피로를 최소화해주는 다크 테마를 절대적으로 신뢰하기 때문입니다.
이번 챕터에서는 Tailwind CSS의 테마 설정 기능과 CSS 변수를 연동하여, 사용자가 밤에는 어두운 테마로 차트를 보고 낮에는 밝은 테마로 돌아갈 수 있는 완벽한 테마 스위처를 사이드바 하단부에 일체형으로 통합하겠습니다.
다크/라이트 테마 전환의 핵심 기법
- 클래스 기반 다크 모드(Class-based Dark Mode): Tailwind CSS는
dark클래스가 최상위 태그(주로html또는body)에 삽입되면 하위의 모든dark:프리픽스가 붙은 유틸리티 클래스(예:dark:bg-gray-900)를 작동시킵니다. - 테마 영속성(Theme Persistence): 새로고침하거나 브라우저를 껐다 켜도 사용자가 이전에 선택한 테마를 기억해야 합니다. 테마 전환 시 사용자의 선택(Light / Dark)을 브라우저의
localStorage에 즉시 저장하고, React 생명주기 마운트 시 이를 감지하여 해당 클래스를 주입합니다. - 깜빡임(Flicker) 현상 해결: Next.js 같은 SSR 환경에서 서버가 만들어 보낸 HTML이 브라우저에 도달하고 자바스크립트가 로딩될 때까지 테마가 동기화되지 않아 화면이 일시적으로 하얗게 켜지는 “눈뽕(Flickering)” 현상이 일어납니다. 이를 방지하기 위해 마운트 시점에 빠르게 상태를 적용하거나,
layout.tsx헤드에 작은 동적 스크립트를 심어 제어합니다.
🤖 실전! 테마 토글 버튼 추가 및 사이드바 결합(2-20)
🧠 이번 실습은 테마 변경 상태를 제어하는 커스텀 훅(useTheme.ts)을 추가하고, 이 훅을 방금 구현한 Sidebar.tsx 컴포넌트 하단에 스위치 버튼 형태로 결합하여 전역 다크모드를 완성하는 과정입니다.
사전작업
Next.js App Router 구조에서 전역 스타일을 결정하는 globals.css 파일에 다크모드 대응을 위한 백그라운드 색상 변수 설정과 컴포넌트의 테마 스타일 매칭을 사전에 설정합니다.
✨ 사용자의 의도(Vibe)
사용자가 언제든지 테마를 라이트/다크 모드로 전환할 수 있도록 사이드바에 테마 선택 모듈을 완성해줘.
- 파일명 1:
frontend/src/hooks/useTheme.ts-> 테마 모드(‘light’ | ‘dark’) 상태를 다루고 로컬 스토리지에 이를 저장하고 불러오는 훅을 제작해줘. - 파일명 2:
frontend/src/components/layout/Sidebar.tsx-> 사이드바의 가장 아래 부분에 Sun(해)과 Moon(달) 아이콘이 조합된 테마 변경 슬라이더 버튼을 추가해줘. - 테마 적용: 다크 테마 적용 시 대시보드와 차트, Ag-Grid 테이블의 내부 텍스트 및 프레임 색상도 어두운 톤으로 부드럽게 반전되게 스타일을 잡아줘.
💻 AI가 생성한 코드 (Syntax) 및 결과
frontend/src/hooks/useTheme.ts
"use client"; import { useEffect, useState } from "react"; export type Theme = "light" | "dark"; export
function useTheme() { const [theme, setTheme] = useState<Theme>("light"); useEffect(() => { // 브라우저 초기 진입 시 로컬스토리지 또는 시스템 기본 테마 감지 const savedTheme = localStorage.getItem("theme") as Theme | null; const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; const initialTheme = savedTheme || systemTheme; setTheme(initialTheme); document.documentElement.classList.toggle("dark", initialTheme === "dark"); }, []); const toggleTheme = () => { const nextTheme = theme === "light" ? "dark" : "light"; setTheme(nextTheme); localStorage.setItem("theme", nextTheme); document.documentElement.classList.toggle("dark", nextTheme === "dark"); };
return { theme, toggleTheme }; }
frontend/src/components/layout/Sidebar.tsx에 하단 테마 스위치 추가 연동
// Sidebar.tsx 하단 추가 코드 부분 import { useTheme } from "@/hooks/useTheme"; import { Sun, Moon } from "lucide-react"; // ... Sidebar 내부 ... const { theme, toggleTheme } = useTheme();
return ( // ...기존 사이드바 메뉴 렌더링 코드... <div className="p-4 border-t border-gray-800 flex items-center justify-between"> {!isCollapsed && ( <span className="text-sm font-medium text-gray-400"> {theme === "light" ? "Light Mode" : "Dark Mode"} </span> )} <button onClick={toggleTheme} className="p-2 rounded-lg bg-gray-800 hover:bg-gray-700 text-yellow-400 dark:text-blue-400 transition-colors" > {theme === "light" ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />} </button> </div> );
- 사이드바 하단 태양 아이콘을 클릭하는 순간, 대시보드 전체 프레임과 Highcharts, AG Grid 테이블 등이 깔끔하게 눈이 편안한 딥 그레이 다크 테마(dark:bg-gray-900)로 완벽하게 전환됩니다.
“`