Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 77 additions & 3 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ body {
margin-bottom: 33px;
}

.text {
.name {
color: #1F2937;
font-weight: 700;
line-height: 36px; /* 150% */
Expand Down Expand Up @@ -76,6 +76,52 @@ body {
line-height: 21px;
}
Comment on lines 36 to 77
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 클래스 명이 바뀌었는데 아직까지 text 클래스만 사용중인걸로 보여요. 스타일이 실제로 잘 적용되는지 확인해보면 좋을 것 같아요.


.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;
Expand All @@ -85,20 +131,47 @@ body {
.item {
display: flex;
align-items: center;
align-self: stretch;
flex-shrink: 0;

padding: 16px;
background-color: #FFF;
font-size: 14px;
color: #1F2937;
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;
Expand All @@ -120,6 +193,7 @@ body {
.UncheckedBox {
width: 24px;
height: 24px;
border-radius: 13421800px;
border-radius: 50%;
border: 2px solid #E5E7EB;
}

29 changes: 25 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -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]);
}
}

Comment on lines +17 to +25
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addTodo, deleteTodo도 동작은 잘 전달되지만, 이벤트를 처리하는 함수라는 점이 더 잘 드러나도록 handleAddTodo, handleDeleteTodo처럼 이름을 지어보는 것도 좋아요. 그리고 자식 컴포넌트에 props로 넘길 때는 onDelete처럼 역할이 보이는 이름을 쓰면, 이건 콜백 props구나가 더 바로 읽힙니다.

setTodos(result);
}
Comment on lines +17 to +27
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서는 직접 for문으로 새 배열을 만드는 것보다 todos.filter((todo) => todo.id !== id)처럼 쓰면, '이 id만 제외한다'는 의도가 더 바로 보여서 읽기 쉬워져요


return (
<>
<div className="container">
<TodoHeader />
<TodoList />
<TodoInput todos={todos} setTodos={setTodos} />
<TodoList todos={todos} onDelete={deleteTodo}/>

</div>
</>
Expand Down
Binary file removed src/assets/hero.png
Binary file not shown.
23 changes: 23 additions & 0 deletions src/assets/icons/checkedIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/assets/react.svg

This file was deleted.

1 change: 0 additions & 1 deletion src/assets/vite.svg

This file was deleted.

57 changes: 27 additions & 30 deletions src/components/TodoCard.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
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 (
<li className={`item checked`}>
<div className="CheckedBox">
<svg
className="CheckedIcon"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="10"
viewBox="0 0 14 10"
fill="none"
>
<g clip-path="url(#clip0_16_101)">
<path
d="M1 5L5 9L13 1"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_16_101">
<rect width="14" height="10" fill="white" />
</clipPath>
</defs>
</svg>
<img src={checkedIcon} alt="checked" />
</div>
<div className="text">
<del>{text}</del>
</div>
{name}
<button className="delBtn">🗑</button>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

완료된 항목 쪽 삭제 버튼에는 onClick이 연결되어 있지 않아서, 지금은 완료된 todo를 삭제할 수 없어요. 완료 여부와 관계없이 같은 삭제 핸들러가 연결되도록 맞춰 주세요

</li>
);
}

return (
<li className="item">
<div className="UncheckedBox"></div>
{name}
<div className="text">{text}</div>
<button className="delBtn" onClick={handleClick}>
🗑
</button>
</li>
);
}
Comment on lines +20 to 43
Copy link
Copy Markdown
Collaborator

@bk-git-hub bk-git-hub Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (completed) {
return (
<li className={`item checked`}>
<div className="CheckedBox">
<svg
className="CheckedIcon"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="10"
viewBox="0 0 14 10"
fill="none"
>
<g clip-path="url(#clip0_16_101)">
<path
d="M1 5L5 9L13 1"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_16_101">
<rect width="14" height="10" fill="white" />
</clipPath>
</defs>
</svg>
<img src={checkedIcon} alt="checked" />
</div>
<div className="text">
<del>{text}</del>
</div>
{name}
<button className="delBtn">🗑</button>
</li>
);
}
return (
<li className="item">
<div className="UncheckedBox"></div>
{name}
<div className="text">{text}</div>
<button className="delBtn" onClick={handleClick}>
🗑
</button>
</li>
);
}
return (
<li className={`item ${completed ? "checked" : ""}`}>
<div className={completed ? "CheckedBox" : "UncheckedBox"}>
{completed && <img src={checkedIcon} alt="" />}
</div>
<div className="text">{completed ? <del>{text}</del> : text}</div>
<button className="delBtn" onClick={handleClick}>
🗑
</button>
</li>
);
}

20 changes: 10 additions & 10 deletions src/components/TodoHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export function TodoHeader() {
return (
<>
<div className="title">
<div className="icon">✅</div>
<div className="text">오늘의 할 일</div>
</div>
</>
);
}
export default function TodoHeader() {
return (
<>
<h1 className="title">
<div className="icon">✅</div>
<div className="text">오늘의 할 일</div>
</h1>
</>
);
}
Loading