From bbdeb116737fd74400123ffd47b8241330f0ffe1 Mon Sep 17 00:00:00 2001 From: sxxbxxny Date: Thu, 2 Apr 2026 19:01:53 +0900 Subject: [PATCH 1/2] =?UTF-8?q?week3=20=ED=97=88=EC=88=98=EB=B9=88=20?= =?UTF-8?q?=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.css | 65 ++++++++++++++++++++++++++++++++++++- src/App.tsx | 65 ++++++++++++++++++++++++++++++------- src/components/TodoCard.tsx | 14 ++++++-- src/components/TodoList.tsx | 52 +++++++++++++++++++++++++---- 4 files changed, 173 insertions(+), 23 deletions(-) diff --git a/src/App.css b/src/App.css index 45c6062..4ffd20d 100644 --- a/src/App.css +++ b/src/App.css @@ -64,12 +64,60 @@ body { align-self: stretch; } +.todo-input-card { + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; + width: 100%; +} + +.todo-input { + display: flex; + height: 46.6px; + padding: 12px 16px; + align-items: center; + flex: 1 0 0; + border-radius: 8px; + border: 0.8px solid #E5E7EB; +} + +.todo-input:focus { + outline: none; + border-radius: 8px; + border: 2px solid #3B82F6; + background: rgba(255, 255, 255, 0.00); + box-shadow: 0 0 0 4px #3B82F6; +} + +.add-button { + display: flex; + width: 72.2px; + height: 46.6px; + padding: 12.8px 23.2px 12.8px 24px; + justify-content: center; + align-items: center; + flex-shrink: 0; + border: none; + border-radius: 8px; + background: #3B82F6; + white-space: nowrap; + color: #FFF; + text-align: center; + font-family: Pretendard; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 21px; /* 150% */ +} + .todo-card { display: flex; padding: 16px; align-items: center; gap: 10px; align-self: stretch; + justify-content: space-between; border-radius: 12px; background: #FFF; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10); @@ -115,6 +163,20 @@ body { text-decoration-line: line-through; } +.delete-button { + color: #0A0A0A; + text-align: center; + font-family: Pretendard; + font-size: 20px; + font-style: normal; + font-weight: 500; + line-height: 30px; /* 150% */ + border: none; + background: none; + margin-left: auto; + gap: 12px; +} + .todo-empty { display: flex; width: 640px; @@ -146,4 +208,5 @@ body { font-style: normal; font-weight: 400; line-height: 72px; /* 150% */ -} \ No newline at end of file +} + diff --git a/src/App.tsx b/src/App.tsx index b37b93b..e2fcfd8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,67 @@ +import { useState } from "react"; import TodoHeader from "./components/TodoHeader"; import TodoList from "./components/TodoList"; import "./App.css"; -const headerIcon = "✅"; -const headerTitle = "오늘의 할 일"; +interface Todo { + id: number; + text: string; + done: boolean; +} -const todos = [ - {id: 1, text:"리액트 공식문서 읽기", done: true}, - {id: 2, text:"알고리즘 문제 풀기", done: true}, - {id: 3, text:"운동 30분 하기", done: false}, - {id: 4, text:"프로젝트 회의 준비", done: false}, -]; +export default function App() { + const [todos, setTodos] = useState([ + { id: 1, text: "리액트 공식문서 읽기", done: true }, + { id: 2, text: "알고리즘 문제 풀기", done: true }, + { id: 3, text: "운동 30분 하기", done: false }, + { id: 4, text: "프로젝트 회의 준비", done: false }, + { id: 5, text: "장보기", done: false }, + ]); + const [inputValue, setInputValue] = useState(""); -const weekLabel = todos.length === 0 ? "Week 2 — 빈 상태" : "Week 2 — 체크박스 토글"; + const [isFocused, setIsFocused] = useState(false); + + const weekLabel = isFocused + ? "week3 - 입력 중(focus)" + : "week3 - 기본 상태"; + + + const handleAdd = () => { + if (inputValue.trim() === "") return; + setTodos((prev) => [ + ...prev, + { id: Date.now(), text: inputValue.trim(), done: false }, + ]); + setInputValue(""); + }; + + const handleDelete = (id: number) => { + setTodos((prev) => prev.filter((todo) => todo.id !== id)); + }; + + const handleToggle = (id: number) => { + setTodos((prev) => + prev.map((todo) => + todo.id === id ? { ...todo, done: !todo.done } : todo + ) + ); + }; -export default function App() { return (

{weekLabel}

- - + + setIsFocused(true)} + onBlur={() => setIsFocused(false)} + />
); diff --git a/src/components/TodoCard.tsx b/src/components/TodoCard.tsx index 57465b2..8b3b774 100644 --- a/src/components/TodoCard.tsx +++ b/src/components/TodoCard.tsx @@ -3,12 +3,17 @@ import checkIcon from "../assets/check.svg"; type TodoCardProps = { text: string; done: boolean; + onDelete: () => void; + onToggle: () => void; }; -export default function TodoCard({ text, done }: TodoCardProps) { +export default function TodoCard({ text, done, onDelete, onToggle }: TodoCardProps) { return (
-
+
{done && ( 완료 )} @@ -16,6 +21,9 @@ export default function TodoCard({ text, done }: TodoCardProps) { {text} +
); -} \ No newline at end of file +} diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx index 79446d6..05e5bc5 100644 --- a/src/components/TodoList.tsx +++ b/src/components/TodoList.tsx @@ -8,9 +8,25 @@ type Todo = { type TodoListProps = { items: Todo[]; + inputValue: string; + onInputChange: (value: string) => void; + onAdd: () => void; + onDelete: (id: number) => void; + onToggle: (id: number) => void; + onFocus: () => void; + onBlur: () => void; }; -export default function TodoList({ items }: TodoListProps) { +export default function TodoList({ + items, + inputValue, + onInputChange, + onAdd, + onDelete, + onToggle, + onFocus, + onBlur, +}: TodoListProps) { if (items.length === 0) { return (
@@ -20,11 +36,33 @@ export default function TodoList({ items }: TodoListProps) { ); } - return ( -
- {items.map((item) => ( - - ))} +return ( +
+
+ onInputChange(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && onAdd()} + onFocus={onFocus} + onBlur={onBlur} + /> +
- ); + + {items.map((item) => ( + onDelete(item.id)} + onToggle={() => onToggle(item.id)} + /> + ))} +
+); } \ No newline at end of file From 0fd53a42093d9ad6d5235b4b805431154f896542 Mon Sep 17 00:00:00 2001 From: sxxbxxny Date: Thu, 2 Apr 2026 19:36:49 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=ED=97=88=EC=88=98=EB=B9=88=20week3=20?= =?UTF-8?q?=EA=B3=BC=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoList.tsx | 68 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx index 05e5bc5..662325f 100644 --- a/src/components/TodoList.tsx +++ b/src/components/TodoList.tsx @@ -27,42 +27,40 @@ export default function TodoList({ onFocus, onBlur, }: TodoListProps) { - if (items.length === 0) { - return ( -
- {"📋"} -

{"아직 할 일이 없어요"}

+ return ( +
+
+ onInputChange(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && onAdd()} + onFocus={onFocus} + onBlur={onBlur} + /> +
- ); - } -return ( -
-
- onInputChange(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && onAdd()} - onFocus={onFocus} - onBlur={onBlur} - /> - + {items.length === 0 ? ( +
+ {"📋"} +

{"아직 할 일이 없어요"}

+
+ ) : ( + items.map((item) => ( + onDelete(item.id)} + onToggle={() => onToggle(item.id)} + /> + )) + )}
- - {items.map((item) => ( - onDelete(item.id)} - onToggle={() => onToggle(item.id)} - /> - ))} -
-); + ); } \ No newline at end of file