From 085b182e3fd06ec186461755247b69768feae655 Mon Sep 17 00:00:00 2001 From: yubin Date: Thu, 26 Mar 2026 13:42:14 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feature:=20=EC=B2=B4=ED=81=AC=EB=B0=95?= =?UTF-8?q?=EC=8A=A4=20=ED=95=A0=20=EC=9D=BC=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 23 +++++++++++----- src/assets/checkIcon.svg | 10 +++++++ src/components/TodoCard.tsx | 25 ++++++++++++++++-- src/components/TodoList.tsx | 19 +++++++++++--- src/css/TodoCard.css | 52 ++++++++++++++++++++++++++++++++++++- 5 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 src/assets/checkIcon.svg diff --git a/src/App.tsx b/src/App.tsx index e3fe9c9..a1d4f80 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,20 +1,29 @@ import './App.css'; import TodoHeader from './components/TodoHeader'; import TodoList from './components/TodoList'; +import { useState } from 'react'; function App() { - const todos = [ - '리액트 공식문서 읽기', - '알고리즘 문제 풀기', - '운동 30분 하기', - '프로젝트 회의 준비', - ]; + const [todos, setTodos] = useState([ + {id:1, text:'리액트 공식문서 읽기', isChecked:false}, + {id:2, text:'알고리즘 문제 풀기', isChecked:false}, + {id:3, text:'운동 30분 하기', isChecked:false}, + {id:4, text:'프로젝트 회의 준비', isChecked:false}, + ]); + + const onCheck = (id: number) => { + setTodos((prev) => + prev.map((todo) => + todo.id === id ? { ...todo, isChecked: !todo.isChecked } : todo + ) + ); + }; return (
- +
); } diff --git a/src/assets/checkIcon.svg b/src/assets/checkIcon.svg new file mode 100644 index 0000000..0227bad --- /dev/null +++ b/src/assets/checkIcon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/components/TodoCard.tsx b/src/components/TodoCard.tsx index be05361..1f6b633 100644 --- a/src/components/TodoCard.tsx +++ b/src/components/TodoCard.tsx @@ -1,9 +1,30 @@ import '../css/TodoCard.css'; +import checkIcon from '../assets/checkIcon.svg'; type Props = { + id: number; text: string; + isChecked: boolean; + onCheck: (id: number) => void; }; -export default function TodoCard({text}: Props){ - return
{text}
+export default function TodoCard({ id, text, isChecked, onCheck }: Props) { + return ( +
+ +
+ ); } \ No newline at end of file diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx index 654feab..f31f84a 100644 --- a/src/components/TodoList.tsx +++ b/src/components/TodoList.tsx @@ -1,15 +1,28 @@ import TodoCard from './TodoCard'; import '../css/TodoList.css'; +export type TodoItem = { + id: number; + text: string; + isChecked: boolean; +}; + type Props = { - todos: string[]; + todos: TodoItem[]; + onCheck: (id: number) => void; }; -export default function TodoList({ todos }: Props) { +export default function TodoList({ todos, onCheck }: Props) { return (
{todos.map((todo) => ( - + ))}
); diff --git a/src/css/TodoCard.css b/src/css/TodoCard.css index 63750ee..990eb29 100644 --- a/src/css/TodoCard.css +++ b/src/css/TodoCard.css @@ -16,4 +16,54 @@ font-style: normal; font-weight: 400; line-height: 21px; -} \ No newline at end of file +} + +.card:has(.card-input:checked) { + text-decoration: line-through; + opacity: 0.5; + +} + +.card-label:has(.card-input:checked) .card-checkbox-ui { + display: flex; + width: 24px; + height: 24px; + justify-content: center; + align-items: center; + + border-radius: 13421800px; + border: 2px solid #3B82F6; + background: #3B82F6; +} + +.card-label:has(.card-input:checked) .card-checkbox-icon { + width: 14px; + height: 10px; + flex-shrink: 0; + display: block; + +} + + + +.card-label { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + flex: 1; + min-width: 0; +} + +.card-input { + display: none; +} + +.card-checkbox-ui { + width: 24px; + height: 24px; + + border-radius: 13421800px; + border: 2px solid #E5E7EB; +} + From d6b4d1ca28b40f74917db5572b47e42c7e2005da Mon Sep 17 00:00:00 2001 From: yubin Date: Thu, 26 Mar 2026 13:43:18 +0900 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/favicon.svg | 1 - public/icons.svg | 24 ------------------------ 2 files changed, 25 deletions(-) delete mode 100644 public/favicon.svg delete mode 100644 public/icons.svg diff --git a/public/favicon.svg b/public/favicon.svg deleted file mode 100644 index 6893eb1..0000000 --- a/public/favicon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons.svg b/public/icons.svg deleted file mode 100644 index e952219..0000000 --- a/public/icons.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - From 5c7491ddf2c5fdc5b6ba462aee73e17eae69108a Mon Sep 17 00:00:00 2001 From: yubin Date: Thu, 26 Mar 2026 15:06:20 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feature:=20=EB=B9=88=20=EB=B0=B0=EC=97=B4?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 4 ++++ src/components/EmptyList.tsx | 12 ++++++++++++ src/css/EmptyList.css | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/components/EmptyList.tsx create mode 100644 src/css/EmptyList.css diff --git a/src/App.tsx b/src/App.tsx index a1d4f80..192e81d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,5 @@ import './App.css'; +import EmptyList from './components/EmptyList'; import TodoHeader from './components/TodoHeader'; import TodoList from './components/TodoList'; import { useState } from 'react'; @@ -24,6 +25,9 @@ function App() {
+ + +
); } diff --git a/src/components/EmptyList.tsx b/src/components/EmptyList.tsx new file mode 100644 index 0000000..d669597 --- /dev/null +++ b/src/components/EmptyList.tsx @@ -0,0 +1,12 @@ +import '../css/EmptyList.css'; + +export default function EmptyList() { + return( +
+ 📋 +

아직 할 일이 없어요

+ +
+ ) + +} \ No newline at end of file diff --git a/src/css/EmptyList.css b/src/css/EmptyList.css new file mode 100644 index 0000000..95c8ec4 --- /dev/null +++ b/src/css/EmptyList.css @@ -0,0 +1,32 @@ +.empty-list{ + display: flex; + width: 640px; + height: 233px; + flex-direction: column; + gap: 12px; + justify-content: center; + align-items: center; + border-radius: 12px; + background: #FFF; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10); + +} + +.empty-icon{ + text-align: center; + font-family: Pretendard; + font-size: 48px; + font-style: normal; + font-weight: 400; + line-height: 72px; /* 150% */ +} + +.empty-list-text{ + color: #6B7280; + text-align: center; + font-family: Pretendard; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 21px; /* 150% */ + } \ No newline at end of file From 28eed94f59a9b4f4041973535d40952c287b4fb5 Mon Sep 17 00:00:00 2001 From: yubin Date: Thu, 26 Mar 2026 15:10:25 +0900 Subject: [PATCH 4/5] =?UTF-8?q?style:=20TodoCard=20=ED=81=AC=EA=B8=B0=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/TodoCard.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/css/TodoCard.css b/src/css/TodoCard.css index 990eb29..213ffc3 100644 --- a/src/css/TodoCard.css +++ b/src/css/TodoCard.css @@ -1,5 +1,6 @@ .card { - width: 100%; + width: 640px; + height: 56px; padding: 16px; box-sizing: border-box; display: flex; From 462199321f7614e4df9658a21d97cab242940c9b Mon Sep 17 00:00:00 2001 From: yubin Date: Thu, 26 Mar 2026 15:19:25 +0900 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20=EC=8B=9C=EB=A9=98=ED=8B=B1=20?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoCard.tsx | 4 ++-- src/components/TodoList.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/TodoCard.tsx b/src/components/TodoCard.tsx index 1f6b633..0a312cc 100644 --- a/src/components/TodoCard.tsx +++ b/src/components/TodoCard.tsx @@ -10,7 +10,7 @@ type Props = { export default function TodoCard({ id, text, isChecked, onCheck }: Props) { return ( -
+
  • -
  • + ); } \ No newline at end of file diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx index f31f84a..2748a16 100644 --- a/src/components/TodoList.tsx +++ b/src/components/TodoList.tsx @@ -14,7 +14,7 @@ type Props = { export default function TodoList({ todos, onCheck }: Props) { return ( -
    +
      {todos.map((todo) => ( ))} -
    + ); } \ No newline at end of file