구글 폰트 -> 아이콘에서 원하는 아이콘 svg파일로 다운받아서 assets폴더에 넣음
state 초기값을 변경한다.( 모드: dark)
테마 리듀서에 case추가한다.
action이 업데이트 할 명령어랑 내용임.
payload : 업데이트 할 값
프로바이더에 추가해서 전역으로 사용이 가능하도록 한다.
import { createContext, useReducer } from "react";
export const ThemeContext = createContext();
const themeReducer = (state, action) => {
switch (action.type) {
case "CHANGE_COLOR":
return { ...state, color: action.payload };
case "CHANGE_MODE":
return { ...state, mode: action.payload };
default:
return state;
}
};
//children은 하위 컴포넌트를 의미한다.
//컨텍스트.프로바이더에서 value값을 전역으로 제공한다.
export function ThemeProvider({ children }) {
//리듀서는 state , dispatch로 업데이트
const [state, dispatch] = useReducer(themeReducer, {
color: "#fea1a1",
mode: "dark",
});
//모드 변경 (payload에 업데이트 할 내용을 작성)
const changeMode = (mode) => {
dispatch({ type: "CHANGE_MODE", payload: mode });
};
//컬러 변경
const changeColor = (color) => {
dispatch({ type: "CHANGE_COLOR", payload: color });
};
return (
//state 모든 값과 changeColor 를 추가한다.
<ThemeContext.Provider value={{ ...state, changeColor, changeModeA }}>
{children}
</ThemeContext.Provider>
);
}
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), svgr()],
});
ThemeSelector.jsx
import React, { useContext } from "react";
import "./ThemeSelector.css";
import { ThemeContext } from "../context/ThemeContext";
import modeIcon from "../assets/mode-icon.svg";
//테마색 3가지로 정함
const themeColors = ["#fea1a1", "#FFCD4B", "#89CFF3"];
export default function ThemeSelector() {
const { changeColor, changeMode, mode } = useContext(ThemeContext);
const toggleMode = () => {
changeMode(mode === "dark" ? "light" : "dark");
console.log(mode);
};
return (
<div className="theme-selector">
<div className="mode-toggle">
<img src={modeIcon} onClick={toggleMode} alt="" />
</div>
<div className="theme-buttons">
{themeColors.map((color) => (
<div
key={color}
onClick={() => changeColor(color)}
style={{ background: color }}
/>
))}
</div>
</div>
);
}
아이콘을 클릭 시 모드가 dark이면 light로 , light면 dark로 모드를 변경한다.
CSS추가
.mode-toggle {
margin-right: auto;
}
.mode-toggle img {
width: 24px;
height: 24px;
cursor: pointer;
}
ThemeSelector.jsx
img(아이콘)에 style을 추가한다.
filter로
모드가 dark이면 invert 100%를, light면 invert를 20%를준다.
https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/invert
테스트를 해보면
App.jsx
현재 모드가 css로 적용된다는것
개발자 모드로 확인하면 root아래의 div가 모드에 따라 dark, light로 달라지는것을 확인가능하다
App.css
.App.dark {
background-color: #333;
}
테스트 해보기
light모드
dark모드 - 백그라운드색이 변경되는것이 확인가능하다.
RecipeList.jsx에도 모드를 적용한다.
useContetx로 ThemeContetx 불러옴
RecipeList .css
/* dark mode */
.recipe-list .card.dark {
background: #555;
}
.recipe-list .card.dark p,
.recipe-list .card.dark h3,
.recipe-list .card.dark div {
color: #e4e4e4;
}
라이트모드
다크모드
Recipe.jsx에도 모드를 추가한다.
import { useParams } from "react-router-dom";
import "./Recipe.css";
import { useFetch } from "../../hooks/useFetch";
import { useContext } from "react";
import { ThemeContext } from "../../context/ThemeContext";
export default function Recipe() {
const { mode } = useContext(ThemeContext);
const { id } = useParams();
const url = "http://localhost:3030/recipes/" + id;
const { error, isPending, data: recipe } = useFetch(url);
return (
<div className={`recipe ${mode}`}>
{error && <p className="error">{error}</p>}
{isPending && <p className="loading">로딩중...</p>}
{recipe && (
<>
<h2 className={`page-title ${mode}`}>{recipe.title}</h2>
<p className="time">요리시간 {recipe.cookingTime} 완성</p>
<ul>
{recipe.ingredients.map((ing) => (
<li className={`page-li ${mode}`} key={ing}>
{ing}
</li>
))}
</ul>
<p className="method">{recipe.method}</p>
</>
)}
</div>
);
}
/* dark mode */
.recipe.dark {
background: #555;
color: #e4e4e4;
}
.page-title.dark {
color: #e4e4e4;
}
.page-li.dark {
color: #e4e4e4;
}
'FRONTEND > React' 카테고리의 다른 글
[쿠킹레시피] 파이어 베이스 연결하기 (레시피 상세화면, 레시피 추가 DB연결) (1) | 2023.11.27 |
---|---|
[쿠킹레시피] 파이어 베이스 연결하기 (홈 화면 DB연결) (0) | 2023.11.27 |
[React] 라우터를 이용한 카피 프로젝트 (0) | 2023.11.24 |
[쿠킹레시피] Context 와 Provider 만들어 적용하기, 리듀서 함수 적용 (1) | 2023.11.24 |
[쿠킹레시피] 검색창 컴포넌트 및 검색 결과 출력 (0) | 2023.11.24 |