JS Library/React

todolist 만들기

원2 2022. 8. 3. 14:05
728x90
반응형

기능 구현하기 전

 

UI 를 만들자

프로젝트 생성

$ npx create-react-app 프로젝트명

icons, styled-componest  라이브러리 설치

$ yarn add react-icons styled-components

 

만들 컴포넌트 목록

TodoTemplate - 레아이웃

TodoHead - 날짜 , 남은 해야할일

TodoList - 할 일의 정보

TodoItem - 할 일의 정보 렌더링

TodoCreate - 할 일 등록

 

1. 배경 색 설정

글로벌 스타일 설정, createGlobalStyle 사용

App.js

import './App.css';
import {createGlobalStyle} from "styled-components";

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
  return (
      <>
        <GlobalStyle />
        <div>반갑소</div>
      </>
  );
}

export default App;

나는 안 반갑소

 

Todo Template

- 중앙에 정렬된 흰색 박스 생성

- src > components 디렉토리 생성 후 파일 생성 . 이후 모든 파일 components 에 생성

import React from "react";
import styled from "styled-components";

const TodoTemplateBlock = styled.div`
    width: 512px;
    height: 768px;
    
    position: relative;
    background: white;
    border-radius: 16px;
    box-shadow: 0 0 8px 0 rgba(0,0,0,0.04);
    
    margin: 0 auto;
    
    margin-top: 96px;
    margin-bottom: 32px;
    display: flex;
    flex-direction: column;
`;

function TodoTemplate({children}) {
    return <TodoTemplateBlock>{children}</TodoTemplateBlock>;
}

export default TodoTemplate;

App.js

import './App.css';
import {createGlobalStyle} from "styled-components";
import TodoTemplate from "./components/TodoTemplate";

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
  return (
      <>
        <GlobalStyle />
        <TodoTemplate>반갑소</TodoTemplate>
      </>
  );
}

export default App;

안 반갑소..

 

TodoHead

import React from "react";
import styled from "styled-components";

const TodoHeadBlock = styled.div`
    padding-top: 48px;
    padding-left: 32px;
    padding-right: 24px;
    padding-left: 32px;
    border-bottom: 1px solid #e9ecef;
    h1 {
        margin: 0;
        font-size: 36px;
        color: #343a40;
    } 
    .day {
        margin-top: 4px;
        color: #868e96;
        font-size: 21px;
    }
    .tasks-left {
        color: #20c997;
        font-size: 18px;
        margin-top: 40px;
        font-weight: bold;
    }
`;

function TodoHead() {
    return (
        <TodoHeadBlock>
            <h1>2022년 08월 03일</h1>
            <div className="day">수요일</div>
            <div className="tasks-left">할일이 3개 남았소</div>
        </TodoHeadBlock>
    );
}

export default TodoHead;

App.js 렌더링

import './App.css';
import {createGlobalStyle} from "styled-components";
import TodoTemplate from "./components/TodoTemplate";
import TodoHead from "./components/TodoHead";

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
    return (
        <>
            <GlobalStyle/>
            <TodoTemplate>
                <TodoHead/>
            </TodoTemplate>
        </>
    );
}

export default App;

음 좀 반가울지도

 

TodoList

import React from "react";
import styled from "styled-components";

const TodoListBlock = styled.div`
    // flex: 1; 자신의 영역을 꽉채우도록 설정
    flex: 1; 
    padding: 20px, 32px;
    padding-bottom: 48px;
    overflow-y: auto;
    // flex: 1 이 잘먹혔는지 확인하기 위해서 background 임시 설정 
    background: gray;
`;

function TodoList() {
    return <TodoListBlock>TodoList</TodoListBlock>;
}

export default TodoList;

app

import './App.css';
import {createGlobalStyle} from "styled-components";
import TodoTemplate from "./components/TodoTemplate";
import TodoHead from "./components/TodoHead";
import TodoList from "./components/TodoList";

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
    return (
        <>
            <GlobalStyle/>
            <TodoTemplate>
                <TodoHead/>
                <TodoList />
            </TodoTemplate>
        </>
    );
}

export default App;

felx 잘 먹히죠?

background 는 이제 지우고

 

TodoItem

import React from "react";
import styled, {css} from "styled-components";
import {MdDelete, MdDone} from "react-icons/md";

// 휴지통 아이콘
const Remove = styled.div`
    display: flex;
    align-items: center;
    justify-content: center;
    color: #dee2e6;
    font-size: 24px;
    cursor: pointer;
    &:hover {
        color: #ff6b6b;
    }
    display: none;
`;

const TodoItemBlock = styled.div`
    display: flex;
    align-items: center;
    padding-top: 12px;
    padding-bottom: 12px;
    &:hover {
        ${Remove} {
            display: initial;
        }
    }
`;

const CheckCircle = styled.div`
    width: 32px;
    height: 32px;
    border-radius: 16px;
    border: 1px solid #ced4da;
    font-size: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 20px;
    cursor: pointer;
    ${props =>
        props.done &&
        css`
            border: 1px solid #38d9a9;
            color: #38d9a9;
        `}
`;

const Text = styled.div`
    flex: 1;
    font-size: 21px;
    color: #495057;
    ${props =>
        props.done &&
        css`
            color: #ced4da;
        `}
`;

function TodoItem({id, done, text}) {
    return(
        <TodoItemBlock>
            <CheckCircle done={done}>{done && <MdDone />}</CheckCircle>
            <Text done={done}>{text}</Text>
            <Remove>
                <MdDelete />
            </Remove>
        </TodoItemBlock>
    );
}

export default TodoItem;

만든 TodoItem 을 TodoList에 렌더링

import React from "react";
import styled from "styled-components";
import TodoItem from "./TodoItem";

const TodoListBlock = styled.div`
    // flex: 1; 자신의 영역을 꽉채우도록 설정
    flex: 1; 
    padding-top: 20px;
    padding-left: 32px;
    padding-bottom: 48px;
    padding-right: 32px;
    overflow-y: auto;
`;

function TodoList() {
    return (
        <TodoListBlock>
            <TodoItem text="프로젝트 생성하기" done={true}/>
            <TodoItem text="컴포넌트 스타일링 하기" done={true}/>
            <TodoItem text="Context 만들기" done={false}/>
            <TodoItem text="기능 구현하기" done={false}/>
        </TodoListBlock>
    );
}

export default TodoList;

마우스 호버시 휴지통이 나오고 휴지통에 호버시 빨간 색으로 변함

 

TodoCreate

import React, {useState} from "react";
import styled, {css} from "styled-components";
import {MdAdd} from "react-icons/md";

const CircleButton = styled.div`
    background: #38d9a9;
    &:hover {
        background: #63e6be;
    }
    
    &:active {
        background: #20c997;
    }
    
    z-index: 5;
    cursor: pointer;
    width: 80px;
    height: 80px;
    display: block;
    align-items: center;
    justify-content: center;
    font-size: 60px;
    position: absolute;
    left: 50%;
    bottom: 0px;
    transform: translate(-50%, 50%);
    color: white;
    border-radius: 50%;
    border: none;
    outline: none;
    display: flex;
    align-items: center;
    justify-content: center;
    
    transition: 0.125s all ease-in;
    ${props => 
        props.open &&
        css`
            background: #ff6b6b;
            &:hover {
                background: #ff8787;
            }
            &:active {
                background: #fa5252;
            }
            transform: translate(-50%, 50%) rotate(45deg);
        `}
`;

const InsertFormPositioner = styled.div`
    width: 100%;
    bottom: 0;
    left: 0;
    position: absolute;
`;

const InsertForm = styled.div`
    background: #f8f9fa;
    padding-top: 32px;
    padding-right: 32px;
    padding-bottom: 72px;
    padding-left: 32px;
    
    border-bottom-right-radius: 16px;
    border-bottom-left-radius: 16px;
    border-top: 1px solid #e9ecef;
`;

const Input = styled.input`
    padding: 12px;
    border-radius: 4px;
    border: 1px solid #dee2e6;
    width: 100%;
    outline: none;
    font-size: 18px;
    box-sizing: border-box;
`;

function TodoCreate() {
    const [open, setOpen] = useState(false);

    const onToggle = () => setOpen(!open);

    return (
        <>
            {open && (
                <InsertFormPositioner>
                    <InsertForm>
                        <Input autoFocus placeholder="할 일을 입력 후, Enter 를 누르시게" />
                    </InsertForm>
                </InsertFormPositioner>
            )}
            <CircleButton onClick={onToggle} open={open}>
                <MdAdd />
            </CircleButton>
        </>
    );
}

export default TodoCreate;

app 에서 렌더링

import './App.css';
import {createGlobalStyle} from "styled-components";
import TodoTemplate from "./components/TodoTemplate";
import TodoHead from "./components/TodoHead";
import TodoList from "./components/TodoList";
import TodoCreate from "./components/TodoCreate";

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
    return (
        <>
            <GlobalStyle/>
            <TodoTemplate>
                <TodoHead/>
                <TodoList />
                <TodoCreate />
            </TodoTemplate>
        </>
    );
}

export default App;

이거 화질 왜이럼; 아무튼 버튼은 동작함 ㅋ
이렇게 잘 되있음

728x90
반응형

'JS Library > React' 카테고리의 다른 글

React Router  (0) 2022.08.04
TodoList 기능 구현  (0) 2022.08.03
Context API 활용 상태 관리  (0) 2022.08.03
styled-components  (0) 2022.08.02
react-icons link  (0) 2022.08.01
CSS Module  (0) 2022.08.01