diff --git a/src/App.css b/src/App.css index f771bae..1a76e9b 100644 --- a/src/App.css +++ b/src/App.css @@ -33,7 +33,7 @@ body { margin-bottom: 33px; } -.text { +.name { color: #1F2937; font-weight: 700; line-height: 36px; /* 150% */ @@ -76,6 +76,52 @@ body { line-height: 21px; } +.toDoInputContainer { + display: flex; + align-items: center; + width: 640px; + height: 46.6px; + padding-right: 0; + gap: 12px; + padding-bottom: 24px; + +} + +.toDoInput { + padding: 12px 16px; + align-items: center; + flex: 1 0 0; + border-radius: 8px; + border: 0.8px solid #E5E7EB; + background: transparent; + box-sizing: border-box; +} + +.toDoInput:focus { + border: 2px solid #3B82F6; + box-shadow: 0 0 0 4px #3B82F6; + background: rgba(255, 255, 255, 0.00); + outline: none; +} + +.toDoInputBtn { + display: flex; + width: 72.2px; + padding: 12.8px 23.2px 12.8px 24px; + justify-content: center; + align-items: center; + flex-shrink: 0; + border-radius: 8px; + background: #3B82F6; + border: none; + + color: white; + text-align: center; + font-size: 14px; + font-weight: 500; + line-height: 21px; +} + .toDoList { display: flex; flex-direction: column; @@ -85,6 +131,9 @@ body { .item { display: flex; align-items: center; + align-self: stretch; + flex-shrink: 0; + padding: 16px; background-color: #FFF; font-size: 14px; @@ -92,13 +141,37 @@ body { border-radius: 12px; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10); gap: 12px; + } .item.checked { opacity: 0.5; - text-decoration-line: line-through; } +.delBtn { + display: flex; + width: 40px; + height: 40px; + justify-content: center; + align-items: center; + border-radius: 8px; + margin-left: auto; + + color: #0A0A0A; + text-align: center; + font-family: Pretendard; + font-size: 20px; + font-style: normal; + font-weight: 500; + line-height: 30px; /* 150% */ + + border: none; + background: transparent; + + cursor: pointer; +} + + .CheckedBox { display: flex; justify-content: center; @@ -120,6 +193,7 @@ body { .UncheckedBox { width: 24px; height: 24px; - border-radius: 13421800px; + border-radius: 50%; border: 2px solid #E5E7EB; } + diff --git a/src/App.tsx b/src/App.tsx index eeb1d99..c8ebc9a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,16 +1,37 @@ -// import { useState } from 'react' - +import { useState } from "react"; import "./App.css"; -import { TodoHeader } from "./components/TodoHeader"; +import TodoHeader from "./components/TodoHeader"; +import TodoInput from "./components/TodoInput"; import TodoList from "./components/TodoList"; function App() { + const [todos, setTodos] = useState([ + { id: 0, text: "리액트 공식문서 읽기", completed: true}, + { id: 1, text: "알고리즘 문제 풀기", completed: true}, + { id: 2, text: "운동 30분 하기", completed: false}, + { id: 3, text: "프로젝트 회의 준비", completed: false}, + { id: 4, text: "장보기 하기", completed: false} + ]); + + function deleteTodo(id: number) { + const result = []; + + for (let i = 0; i < todos.length; i++) { + if (todos[i].id !== id) { + result.push(todos[i]); + } + } + + setTodos(result); + } + return ( <>
- + +
diff --git a/src/assets/hero.png b/src/assets/hero.png deleted file mode 100644 index cc51a3d..0000000 Binary files a/src/assets/hero.png and /dev/null differ diff --git a/src/assets/icons/checkedIcon.svg b/src/assets/icons/checkedIcon.svg new file mode 100644 index 0000000..9907fd8 --- /dev/null +++ b/src/assets/icons/checkedIcon.svg @@ -0,0 +1,23 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/vite.svg b/src/assets/vite.svg deleted file mode 100644 index 5101b67..0000000 --- a/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ -Vite diff --git a/src/components/TodoCard.tsx b/src/components/TodoCard.tsx index 8969d90..1314c8b 100644 --- a/src/components/TodoCard.tsx +++ b/src/components/TodoCard.tsx @@ -1,38 +1,32 @@ -interface CardProps { - name: string; - isChecked: boolean; +import checkedIcon from "../assets/icons/checkedIcon.svg"; + +interface TodoCardProps { + id: number; + text: string; + completed: boolean; + onDelete: (id: number) => void; } -export function Card({ name, isChecked }: CardProps) { - if (isChecked) { +export default function TodoCard({ + id, + text, + completed, + onDelete, +}: TodoCardProps) { + function handleClick() { + onDelete(id); + } + + if (completed) { return (
  • - - - - - - - - - - + checked +
    +
    + {text}
    - {name} +
  • ); } @@ -40,7 +34,10 @@ export function Card({ name, isChecked }: CardProps) { return (
  • - {name} +
    {text}
    +
  • ); } diff --git a/src/components/TodoHeader.tsx b/src/components/TodoHeader.tsx index 0e8f023..dedb53f 100644 --- a/src/components/TodoHeader.tsx +++ b/src/components/TodoHeader.tsx @@ -1,10 +1,10 @@ -export function TodoHeader() { - return ( - <> -
    -
    -
    오늘의 할 일
    -
    - - ); -} \ No newline at end of file +export default function TodoHeader() { + return ( + <> +

    +
    +
    오늘의 할 일
    +

    + + ); +} diff --git a/src/components/TodoInput.tsx b/src/components/TodoInput.tsx new file mode 100644 index 0000000..4ad3966 --- /dev/null +++ b/src/components/TodoInput.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; + +interface Todo { + id: number; + text: string; + completed: boolean; +} + +interface TodoInputProps { + todos: Todo[]; + setTodos: React.Dispatch>; +} + +export default function TodoInput({ todos, setTodos } : TodoInputProps) { + const [text, setText] = useState(""); + + function handleFocus() { + if (text === "") { + setText("새로운 할 일"); + } + } + + function handleChange(event: React.ChangeEvent) { + setText(event.target.value); + } + + function handleClick() { + if (text.length === 0) { + return; + } + + const newIndex = todos.length > 0 ? todos[todos.length - 1].id + 1 : 0; + + const newTodo = { + id: newIndex, + text: text, + completed: false, + }; + + setTodos([...todos, newTodo]); + + setText(""); + } + + return ( +
    + + +
    + ); +} diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx index a3b08e9..af479b2 100644 --- a/src/components/TodoList.tsx +++ b/src/components/TodoList.tsx @@ -1,8 +1,17 @@ -import { TODO_ITEMS } from "./todoItems"; -import { Card } from "./TodoCard"; +import TodoCard from "./TodoCard"; -export default function TodoList() { - const isEmpty = TODO_ITEMS.length === 0; +interface Todo { + id: number; + text: string; + completed: boolean; +} +interface TodoListProps { + todos: Todo[]; + onDelete: (id: number) => void; +} + +export default function TodoList({ todos, onDelete }: TodoListProps) { + const isEmpty = todos.length === 0; return ( <> @@ -16,15 +25,18 @@ export default function TodoList() { )} {!isEmpty && ( - - ) - } - + + )} ); - } diff --git a/src/components/todoItems.ts b/src/components/todoItems.ts deleted file mode 100644 index bb01a7b..0000000 --- a/src/components/todoItems.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const TODO_ITEMS = [ - { - id: 0, - name: "리액트 공식문서 읽기", - isChecked: true, - }, - { - id: 1, - name: "알고리즘 문제 풀기", - isChecked: true, - }, - { - id: 2, - name: "운동 30분 하기", - isChecked: false, - }, - { - id: 3, - name: "프로젝트 회의 준비", - isChecked: false, - } -];