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 @@
-
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 (
-
+

+
+
+ {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 && (
-
- {TODO_ITEMS.map((item) => (
-
- ))}
-
- )
- }
-
+
+ {todos.map((todo) => (
+
+ ))}
+
+ )}
>
);
-
}
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,
- }
-];