-
Notifications
You must be signed in to change notification settings - Fork 1
이유빈 week2 #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
이유빈 week2 #28
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,33 @@ | ||
| import './App.css'; | ||
| import EmptyList from './components/EmptyList'; | ||
| 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 ( | ||
| <div className="todo"> | ||
| <TodoHeader title="오늘의 할 일" /> | ||
| <TodoList todos={todos} /> | ||
| <TodoList todos={todos} onCheck={onCheck} /> | ||
|
|
||
| <TodoHeader title="오늘의 할 일" /> | ||
| <EmptyList /> | ||
|
Comment on lines
26
to
+30
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다음주에는 이 부분을 리스트가 비어있을 경우에만 EmptyList를 보여주는 방식으로 바꾸시면 될 것 같습니다. |
||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import '../css/EmptyList.css'; | ||
|
|
||
| export default function EmptyList() { | ||
| return( | ||
| <div className='empty-list'> | ||
| <span className='empty-icon'>📋</span> | ||
| <p className="empty-list-text">아직 할 일이 없어요</p> | ||
|
|
||
| </div> | ||
| ) | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <div className="card">{text}</div> | ||
| export default function TodoCard({ id, text, isChecked, onCheck }: Props) { | ||
| return ( | ||
| <li className="card"> | ||
| <label className="card-label"> | ||
| <input | ||
| className="card-input" | ||
| type="checkbox" | ||
| checked={isChecked} | ||
| onChange={() => onCheck(id)} | ||
| /> | ||
| <span className="card-checkbox-ui"> | ||
| {isChecked ? ( | ||
| <img src={checkIcon} alt="" className="card-checkbox-icon" /> | ||
| ) : null} | ||
| </span> | ||
| <span className="card-text">{text}</span> | ||
| </label> | ||
| </li> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,29 @@ | ||
| import TodoCard from './TodoCard'; | ||
| import '../css/TodoList.css'; | ||
|
|
||
| export type TodoItem = { | ||
| id: number; | ||
| text: string; | ||
| isChecked: boolean; | ||
| }; | ||
|
|
||
|
Comment on lines
+4
to
+9
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 |
||
| type Props = { | ||
| todos: string[]; | ||
| todos: TodoItem[]; | ||
| onCheck: (id: number) => void; | ||
| }; | ||
|
|
||
| export default function TodoList({ todos }: Props) { | ||
| export default function TodoList({ todos, onCheck }: Props) { | ||
| return ( | ||
| <div className="card-list"> | ||
| <ul className="card-list"> | ||
| {todos.map((todo) => ( | ||
| <TodoCard key={todo} text={todo} /> | ||
| <TodoCard | ||
| key={todo.id} | ||
| id={todo.id} | ||
| text={todo.text} | ||
| isChecked={todo.isChecked} | ||
| onCheck={onCheck} | ||
| /> | ||
| ))} | ||
| </div> | ||
| </ul> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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% */ | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| .card { | ||
| width: 100%; | ||
| width: 640px; | ||
| height: 56px; | ||
| padding: 16px; | ||
| box-sizing: border-box; | ||
| display: flex; | ||
|
|
@@ -16,4 +17,54 @@ | |
| font-style: normal; | ||
| font-weight: 400; | ||
| line-height: 21px; | ||
| } | ||
| } | ||
|
|
||
| .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; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이부분은 제가 figma에 잘못 기입했는데 border-radius: 50%나 9999px정도만 해도 동그라미가 잘 되고 의미 전달도 잘 됩니다. |
||
| border: 2px solid #E5E7EB; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo 데이터가 컴포넌트 안에 직접 들어가 있는데,
App.tsx가 상태 관리와 화면 조합에 더 집중하도록 하려면todo.data.ts같은 파일로 분리해두는 것도 좋은 방향입니다.