[Toy Projects] 'TODOoO' project (10)
다음은 카테고리 별로 색상을 적용하는 것이다.
우선 카테고리 순서에 맞게 색상을 저장할 color 배열을 App 컴포넌트에서 state로 선언했다.
Category 컴포넌트에서는 카테고리와 할 일들을 해당 색상에 맞춰 화면에 띄어줘야 하기 때문에 color 배열도 props로 전달을 해주었다.
// App.js
...
// color state, 초기값은 임의로 설정
const [color, setColor] = useState(['#ffc4c4', '#ffd9c4']);
...
// Category 컴포넌트 호출할 때 props에 color 추가
useEffect(()=>{
...
_cateform.push(
<Category
key={i}
category={category[i]}
color={color[i]}
todo={_todo}
onCreate={(data) => {
let _id = todo[todo.length - 1].id;
setTodo([...todo, {
id:_id + 1,
category: category[i],
desc: data
}]);
}}
onUpdate={(id, data)=>{
let changeTodo = Array.from(todo);
for(let i = 0; i < todo.length; i++){
if(changeTodo[i].id === id){
changeTodo[i].desc = data;
break;
}
}
setTodo(changeTodo);
}}
onDelete={(id)=>{
let changeTodo = Array.from(todo);
for(let i = 0; i < todo.length; i++){
if(changeTodo[i].id === id){
changeTodo.splice(i,1);
break;
}
}
setTodo(changeTodo);
}}
isOpen={isOpen}
setIsOpen={setIsOpen}
></Category>
);
....
},[category, todo, isOpen, color])
...
// Nav 컴포넌트 호출할 때 props에 color, setColor 추가
<Nav
category={category}
setCategory={setCategory}
todo={todo}
setTodo={setTodo}
color={color}
setColor={setColor}
></Nav>
...
// component/Category.js
...
// props로 전달 받은 변수에 color 추가
const { category, color, todo, onCreate, onUpdate, onDelete, isOpen, setIsOpen } = props;
...
// useEffect 의존성 배열에 color 추가 및 styled component로 지정한 태그에 color props 전달
useEffect(() => {
let _form = [];
for (let i = 0; i < todo.length; i++) {
_form.push(
<div key={i}>
{/* styled component로 지정한 태그에 color props 전달 */}
<TodoList color={color}>
...
</TodoList>
...
</div>
);
...
}, [todo, isUpdate, color]);
...
// style 설정
const TodoList = styled.div`
...
background-color: ${(props) => props.color};
`;
...
색상 변경을 어디서 진행할지에 대한 고민이 있었지만, Setting 컴포넌트에서 카테고리를 설정하면서 같이 변경할 수 있도록 계획했다.
Setting 컴포넌트에서는 color을 변경할 수 있어야 하기 때문에 Nav 컴포넌트를 거쳐 color 뿐만 아니라 상태 변환 함수인 setColor도 props로 전달을 해 주었다.
// component/Nav.js
...
// props로 전달 받은 변수에 color, setColor 추가
const { category, setCategory, todo, setTodo, color, setColor } = props;
...
// Setting 컴포넌트 호출할 때 props에 color, setColor 추가
<Setting
category={category}
setCategory={setCategory}
todo={todo}
setTodo={setTodo}
setIsOpen={setIsOpen}
color={color}
setColor={setColor}></Setting>
...
Setting 컴포넌트에서 어떻게 색상을 변경할 수 있게 할까 생각하다가,
각 카테고리를 클릭하면 생성되는 이름 변경 및 삭제 버튼과 함께 팔레트를 생성하도록 했다.
그렇게 Palette 컴포넌트를 생성하게 됐다.
이때, Palette 컴포넌트에는 현재 색상을 전달해 주고, 선택한 색상을 변경하기 위한 함수를 전달했다.
// component/Setting.js
...
// component/Palette.js import
import Palette from './Palette';
...
// props로 전달 받은 변수에 color, setColor 추가
const { category, setCategory, todo, setTodo, setIsOpen, color, setColor } = props;
...
// useEffect 의존성 배열에 color 추가 및 Palette 컴포넌트 호출
useEffect(() => {
...
_allCategory.push(
...
{formOn === i ?
<CategoryForm>
<FormBtn onClick={() => UpdateCategory(i)}>이름 변경</FormBtn>
<FormBtn onClick={() => DeleteCategory(i)}>삭제</FormBtn>
{/* Palette 컴포넌트 호출 */}
<Palette
nowColor={color[i]}
onChangeColor={(data)=>{
let _color = Array.from(color);
_color[i] = data;
setColor(_color);
}}
></Palette>
</CategoryForm>
: null}
...
);
...
}, [category, todo, formOn, color]);
// 카테고리를 추가할 때 color도 추가하는데, 디폴트 값은 #dedede로 설정
function PlusCategory() {
let str = "추가할 카테고리 명을 입력해주세요!";
let _new = window.prompt(str);
if (_new !== null) { // null이 아니라면
if (category.indexOf(_new) !== -1 || _new === '') {
while(true){
if(category.indexOf(_new) !== -1) _new = window.prompt("중복입니다.\n추가할 카테고리 명을 입력해주세요!");
else if(_new === '') _new = window.prompt("추가할 카테고리 명을 입력해주세요!");
else if(_new !== null) {
setCategory([...category, _new]);
// color 추가
setColor([...color, '#eeeeee'])
setFormOn(-1)
break;
}
else break;
}
} else {
setCategory([...category, _new]);
// color 추가
setColor([...color, '#eeeeee'])
setFormOn(-1)
}
}
}
...
Palette 컴포넌트에서는 보기 색상을 화면에 보여줌으로써 사용자로 하여금 선택할 수 있도록 했다.
보기 색상은 color 배열에 저장했으며( 앞에서 선언한 color와 다름), 각각의 색상마다 Color 컴포넌트를 생성하도록 했다.
총 12개의 보기 색상이 준비되어 있으며, 12개의 Color 컴포넌트가 생성된다.
// component/Palette.js
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import Color from './Color';
function Palette(props){
const { onChangeColor, nowColor } = props;
const [colorForm, setColorForm] = useState([]);
const [color, setColor] = useState([
'#ffc4c4', '#ffd9c4', '#fff8c4', '#e7ffc4', '#ccffc4', '#c4ffed', '#c4f5ff', '#c4dbff', '#c8c4ff', '#e0c4ff', '#fcc4ff', '#dedede'
])
useEffect(()=>{
let _colorForm = [];
for(let i = 0; i < color.length; i++){
if(nowColor === color[i]){
_colorForm.push(
<Color key={i} color={color[i]} check={true} onChangeColor={onChangeColor}></Color>
);
} else{
_colorForm.push(
<Color key={i} color={color[i]} check={false} onChangeColor={onChangeColor}></Color>
);
}
}
setColorForm(_colorForm)
},[nowColor])
return(
<StyledPalette>
{colorForm}
{/* <Color color=''></Color> */}
</StyledPalette>
);
}
const StyledPalette = styled.div`
width: 220px;
margin: 0 auto;
margin-top: 15px;
display: flex;
flex-wrap: wrap;
justify-content: center;
`;
export default Palette;
Color 컴포넌트에서는 Palette에 존재할 하나하나의 색상을 원 모양으로 칠해준다.
각 Color 컴포넌트를 호출할 때, 현재 색상을 가리키는 Color 컴포넌트에는 check라는 props를 전달해 줌으로써 현재 색상에는 검은색 border가 나타나게 했다.
(만약 현재 카테고리 색이 빨강이면 빨강을 나타내는 컴포넌트에 검은색 테두리 표시)
또한, 선택한 색상을 클릭하면 Setting에서 받아온 onChangeColor 함수를 통해 색상을 변경할 수 있도록 했다.
// component/Color.js
import styled from 'styled-components';
function Color(props){
const { color, check, onChangeColor } = props;
return(
<Circle color={color} check={check} onClick={()=>{onChangeColor(color)}}></Circle>
);
}
const Circle = styled.div`
width: 30px;
height: 30px;
border-radius: 50%;
background-color: ${(props) => props.color};
border: 2px solid ${props => props.check ? 'black' : 'white'};
margin: 5px 10px;
&:hover{
cursor: pointer;
}
`;
export default Color;
이렇게 코드를 작성하면 다음과 같은 결과가 생성된다.
다음 게시글에서는 할 일을 했을 때 처리하는 기능에 대해 다루도록 하겠다.
글 내용 중, 잘못됐거나 더 알아야 하는 지식이 있다면 댓글로 남겨주시면 감사하겠습니다!
모두 좋은 하루 보내세요:)