-
Notifications
You must be signed in to change notification settings - Fork 10
[1주차] 정윤지 과제 제출합니다. #6
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
base: main
Are you sure you want to change the base?
Changes from all commits
78bfb7e
b8298bd
5186cf1
cfee746
58f26c8
88ee5c7
2659692
4acf022
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="ko"> | ||
| <head> | ||
| <title>TO DO LIST</title> | ||
| <meta charset="utf-8" /> | ||
| <link rel="stylesheet" href="style.css" /> | ||
| </head> | ||
| <body> | ||
| <div class="container"> | ||
| <header> | ||
| <h1>투두 리스트</h1> | ||
| </header> | ||
|
|
||
| <main> | ||
| <section class="date"> | ||
| <button id="prev">◀</button> | ||
| <p id="date"></p> | ||
| <button id="next">▶</button> | ||
| </section> | ||
|
|
||
| <section class="count"> | ||
| <p id="counter"></p> | ||
| </section> | ||
|
|
||
| <section class="todo-block"> | ||
| <ul id="todo-list" class="todo-list"></ul> | ||
| </section> | ||
| </main> | ||
|
|
||
| <footer class="todo-input"> | ||
| <button id="add-btn"> | ||
|
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. todo list 추가 버튼이 왼쪽에 있고 + 모양이면, 처음 사용하는 입장에서 파일 추가 버튼이라고 생각할 수 도 있을 거 같습니다! |
||
| <img src="asset/addButton.png" /> | ||
| </button> | ||
| <input | ||
| id="todo-input" | ||
| type="text" | ||
| placeholder="할 일을 입력해주세요. . !" | ||
| /> | ||
| </footer> | ||
| </div> | ||
| </body> | ||
| <script src="script.js"></script> | ||
| </html> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| let currentDate = new Date(); //오늘 날짜 및 시간 | ||
| let todosForEachDay = {}; //날짜별 투두를 저장할 배열 | ||
|
|
||
| const addButton = document.getElementById("add-btn"); | ||
| const todoInput = document.getElementById("todo-input"); | ||
| const todoList = document.getElementById("todo-list"); | ||
| const prevButton = document.getElementById("prev"); | ||
| const nextButton = document.getElementById("next"); | ||
|
|
||
| // 날짜를 키로 사용하기 위해서 포맷팅 필요 | ||
| function formatDate(date) { | ||
| const year = date.getFullYear(); | ||
| const month = String(date.getMonth() + 1).padStart(2, "0"); | ||
| const day = String(date.getDate()).padStart(2, "0"); | ||
| return `${year}-${month}-${day}`; | ||
| } | ||
|
|
||
| //날짜 보여주기 | ||
| function showDate() { | ||
| const dateElement = document.getElementById("date"); | ||
|
|
||
| // 형식 변환 | ||
| const options = { | ||
| year: "numeric", | ||
| month: "long", | ||
| day: "numeric", | ||
| weekday: "long", | ||
| }; | ||
|
|
||
| dateElement.textContent = currentDate.toLocaleDateString("ko-KR", options); | ||
| } | ||
|
|
||
| // 투두 개수 보여주기 - 날짜 key에 해당하는 todo의 개수 중 completed 아닌 것만 골라서 개수 | ||
| function Counter() { | ||
|
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. 일관성 있게 lowerCamelCase로 함수명을 counter로 하시거나, updateCounter가 더 적절할 거 같습니다! |
||
| const key = formatDate(currentDate); | ||
| const todos = todosForEachDay[key] || []; | ||
| const todoCount = todos.filter((todo) => !todo.completed).length; | ||
| const countTodos = document.getElementById("counter"); // 여기서 가져오기 | ||
|
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.
|
||
| if (countTodos) { | ||
| countTodos.textContent = `오늘의 남은 할 일은 ${todoCount}개 입니다 !`; | ||
| } | ||
| } | ||
|
|
||
| //투두 요소 | ||
| function showTodos() { | ||
| todoList.innerHTML = ""; | ||
| const key = formatDate(currentDate); //키: 날짜 | ||
| const todos = todosForEachDay[key] || []; //투두요소: 각 키에 할당되는 요소들 | ||
|
|
||
| todos.forEach((todo) => { | ||
| todoList.appendChild(createTodoElement(todo, key)); //투두 만들어지면 append | ||
| }); | ||
| Counter(); | ||
| } | ||
|
|
||
| // 투두 요소 만들기 (내용 및 완료, 삭제) | ||
| function createTodoElement(todo, key) { | ||
| const li = document.createElement("li"); | ||
|
|
||
| //내용 | ||
| const todoText = document.createElement("span"); | ||
| todoText.className = "todo-text"; | ||
| todoText.textContent = todo.text; | ||
|
|
||
| //완료 버튼 | ||
| const completeButton = document.createElement("button"); | ||
| completeButton.textContent = " "; | ||
| completeButton.className = "complete-btn"; | ||
| completeButton.addEventListener("click", () => { | ||
| li.classList.toggle("completed"); | ||
| todo.completed = !todo.completed; | ||
| saveTodos(); | ||
| Counter(); | ||
| }); | ||
|
|
||
| //삭제 버튼 | ||
| const deleteButton = document.createElement("button"); | ||
| deleteButton.className = "delete-btn"; | ||
| const deleteIcon = document.createElement("img"); | ||
| deleteIcon.src = "asset/trash.png"; | ||
| deleteIcon.width = 18; | ||
| deleteIcon.height = 18; | ||
| deleteButton.appendChild(deleteIcon); | ||
| deleteButton.addEventListener("click", () => { | ||
| todosForEachDay[key] = todosForEachDay[key].filter((t) => t.id !== todo.id); | ||
| saveTodos(); | ||
| showTodos(); | ||
| }); | ||
|
|
||
| //li에 투두요소 추가 | ||
| li.append(completeButton, todoText, deleteButton); | ||
| //완료 상태 보여주기 | ||
| if (todo.completed) { | ||
| li.classList.add("completed"); | ||
| } | ||
| return li; | ||
| } | ||
|
|
||
| //투두 추가 | ||
| function addTodo() { | ||
| const text = todoInput.value.trim(); //입력받은 텍스트 공백 제거 후 text에 저장 | ||
| if (text === "") return; | ||
|
|
||
| // 오늘 날짜에 해당하는 키에 투두 추가 | ||
| const key = formatDate(currentDate); | ||
| if (!todosForEachDay[key]) todosForEachDay[key] = []; | ||
|
|
||
| // 삭제를 위한 id, 완료 여부 저장을 위한 completed 추가 | ||
| const todo = { id: Date.now(), text, completed: false }; | ||
| todosForEachDay[key].push(todo); | ||
|
|
||
| saveTodos(); | ||
| showTodos(); | ||
| todoInput.value = ""; | ||
| Counter(); | ||
| } | ||
|
Comment on lines
+100
to
+116
Member
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. https://developer.mozilla.org/ko/docs/Web/API/KeyboardEvent/key |
||
|
|
||
| // 날짜 이동 버튼 및 투두와 날짜 재랜더링 | ||
| prevButton.addEventListener("click", () => { | ||
| currentDate.setDate(currentDate.getDate() - 1); | ||
| showDate(); | ||
| showTodos(); | ||
| }); | ||
| nextButton.addEventListener("click", () => { | ||
| currentDate.setDate(currentDate.getDate() + 1); | ||
| showDate(); | ||
| showTodos(); | ||
| }); | ||
|
|
||
| //로컬스토리지 저장 및 불러오기 | ||
|
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. 코드가 기능별로 정리되어있고 주석까지 잘 달려있어서 한눈에 보기 좋은 것 같아요! |
||
| function saveTodos() { | ||
| // 배열 문자열 변환 후 저장 | ||
| localStorage.setItem("todosForEachDay", JSON.stringify(todosForEachDay)); | ||
| } | ||
|
|
||
| function loadTodos() { | ||
| const data = localStorage.getItem("todosForEachDay"); | ||
| if (data) { | ||
| // JSON 데이터 parsing -> 원래 배열로 | ||
| todosForEachDay = JSON.parse(data); | ||
| } | ||
| } | ||
|
|
||
| //실행 시 | ||
| addButton.addEventListener("click", addTodo); | ||
| loadTodos(); | ||
| showDate(); | ||
| showTodos(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| @font-face { | ||
| font-family: "Pretendard Variable"; | ||
| src: url("asset/fonts/PretendardVariable.woff2") format("woff2"); | ||
| font-weight: 100 900; | ||
| font-style: normal; | ||
| } | ||
|
|
||
| body { | ||
| justify-content: center; | ||
| font-family: "Pretendard Variable", sans-serif; | ||
| font-weight: 400; | ||
| background-color: #ffd7e9; | ||
| color: #202020; | ||
| } | ||
|
|
||
| .container { | ||
| display: flex; | ||
| justify-content: center; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| padding: 10px; | ||
| font-size: large; | ||
| transition: margin-left 0.3s; | ||
| } | ||
|
|
||
| .date { | ||
| justify-content: center; | ||
| } | ||
|
|
||
| .count { | ||
| text-align: center; | ||
| font-weight: 300; | ||
| font-size: medium; | ||
| } | ||
|
|
||
| .todo-block { | ||
| flex: 1; | ||
| width: 100%; | ||
| max-height: calc(100vh - 250px); | ||
| overflow-y: auto; | ||
| margin-bottom: 60px; | ||
| } | ||
|
|
||
| .date { | ||
| display: flex; | ||
| } | ||
|
|
||
| .date button { | ||
| background-color: transparent; | ||
| border: 0; | ||
| outline: none; | ||
| } | ||
|
|
||
| .todo-list { | ||
| list-style: none; | ||
| padding: 0; | ||
| } | ||
|
|
||
| .todo-list li { | ||
|
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. 만들어진 todo list에 hover할때마다 삭제 아이콘이 옆에 생기면서, 리스트가 아래로 내려갔다 올라갔다 하는거 같습니다! 여기에 min-height: 30px; 정도 추가하시거나, img 사이즈를 15x15 정도로 줄이시는게 좋을 거 같습니다! |
||
| display: flex; | ||
| align-items: center; | ||
| gap: 10px; | ||
| margin-bottom: 5px; | ||
| } | ||
|
|
||
| .todo-list li .complete-btn { | ||
| order: -1; | ||
| border: none; | ||
| width: 20px; | ||
| height: 20px; | ||
| background-color: #f0f0f0; | ||
| border-radius: 50%; | ||
| cursor: pointer; | ||
| transition: background-color 0.3s; | ||
| position: relative; | ||
| } | ||
|
Comment on lines
+66
to
+76
Member
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. 텍스트가 길어지면 다음과 같이 complete-btn도 길어지는데, |
||
|
|
||
| .todo-list li.completed .complete-btn { | ||
| background-color: #eb89b5; | ||
| } | ||
|
|
||
| .todo-list li.completed .todo-text { | ||
| text-decoration: line-through; | ||
| opacity: 0.6; | ||
| } | ||
|
|
||
| .todo-list li.completed .complete-btn::after { | ||
| content: "✔"; | ||
| color: #fffef1; | ||
| font-size: 14px; | ||
| position: absolute; | ||
| top: 50%; | ||
| left: 50%; | ||
| transform: translate(-50%, -50%); | ||
| } | ||
|
|
||
| .todo-list li .delete-btn { | ||
| display: none; | ||
| margin-left: auto; | ||
| border: none; | ||
| background: transparent; | ||
| cursor: pointer; | ||
| font-size: 16px; | ||
| } | ||
|
|
||
| .todo-list li:hover .delete-btn { | ||
| display: inline-block; | ||
| } | ||
|
|
||
| .todo-input { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 10px; | ||
| background-color: #fffef1; | ||
| position: fixed; | ||
| bottom: 10px; | ||
| padding-top: 4px; | ||
| height: 40px; | ||
| width: calc(90vw - 100px); | ||
|
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.
|
||
| border-radius: 30px; | ||
| } | ||
|
Comment on lines
+110
to
+121
Member
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. |
||
|
|
||
| #todo-input { | ||
| background-color: transparent; | ||
| height: 32px; | ||
| font-size: 15px; | ||
| border: 0; | ||
| outline: none; | ||
| } | ||
|
Comment on lines
+123
to
+129
Member
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. |
||
|
|
||
| #add-btn { | ||
| background-color: transparent; | ||
| border: 0; | ||
| outline: none; | ||
| } | ||
|
|
||
| #add-btn img { | ||
| width: 34px; | ||
| height: 34px; | ||
| object-fit: contain; | ||
| } | ||
|
|
||
| #add-btn:hover { | ||
| transform: scale(1.05); | ||
| } | ||
|
|
||
| #add-btn:active { | ||
| transform: scale(0.9); | ||
| } | ||



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.
png보다는 svg를 사용하면, 벡터로 아이콘이 바뀌면서 색상을 수정할 수도 있고, 크기도 변화를 줄 수도 있습니다. 그외도 화질저하가 없다거나 다양한 장점이 있어서 아이콘 같은 asset파일에는 svg파일로 사용합니다!
-> 피그마에서 asset export해올 때 svg로 변경해서 다운 받으면 좋아요!