-
Notifications
You must be signed in to change notification settings - Fork 10
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
[1주차] 정인영 미션 제출합니다. #7
base: master
Are you sure you want to change the base?
Changes from all commits
f05eb61
5efbd00
1d0ba18
0b39593
c0d4f7e
3539291
1a61f09
a3d640c
7f612ca
86d204d
f703614
5c79b4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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. semantic tag를 사용하여 페이지를 구성해서 훨씬 가독성이 좋은거 같습니다! 저도 다음에는 사용해보겠습니다 ㅎㅎ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,12 +3,49 @@ | |
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Vanilla Todo</title> | ||
<title>Universe-Todo</title> | ||
<link rel="stylesheet" href="reset.css" /> | ||
<link rel="stylesheet" href="style.css" /> | ||
<script defer src="./script.js"></script> | ||
</head> | ||
|
||
<body> | ||
<div class="container"></div> | ||
<header> | ||
<div class="input-section"> | ||
<div class="icon"> | ||
<img src="./images/galaxy-icon.svg" alt="아이콘" /> | ||
</div> | ||
<form class="todo"> | ||
<input | ||
type="text" | ||
placeholder="당신의 할 일을 별을 먹어치우는 블랙홀처럼 모두 해치우세요." | ||
/> | ||
</form> | ||
<button>Enter</button> | ||
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. 이 버튼을 form 안에 옮기면 click과 submit이 모두 submit으로 인식될거에요~ |
||
</div> | ||
<div class="quote-section">Carl Seagan - " 사멸은 법칙이다. "</div> | ||
</header> | ||
<main> | ||
<div class="todos-solves"> | ||
<div class="todo-section"> | ||
<h1>✔ 지금 당장 해결하세요.</h1> | ||
<p class="caption"> | ||
총 <span class="todo-number"></span>개의 할 일이 있어요. | ||
</p> | ||
<ul class="todo-list"> | ||
<!-- <li>백준 실버5 2394, 2395번 풀기</li> | ||
<li>개인 velog에 Recoil의 사용법에 대해서 포스팅 해보기</li> --> | ||
</ul> | ||
</div> | ||
<div class="solved-section"> | ||
<h1>✔ 최근 해결한 내역</h1> | ||
<p class="caption">당신이 해결한 일들은 이곳에 모두 저장됩니다.</p> | ||
<ul class="solved-list"></ul> | ||
</div> | ||
</div> | ||
<div class="blackhole-section"> | ||
<img src="./images/blackhole.gif" alt="블랙홀 이미지" /> | ||
</div> | ||
</main> | ||
<footer>Copyrightⓒ2023 ChungInYoung All rights reserved.</footer> | ||
</body> | ||
<script src="script.js"></script> | ||
</html> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
html, body, div, span, applet, object, iframe, | ||
h1, h2, h3, h4, h5, h6, p, blockquote, pre, | ||
a, abbr, acronym, address, big, cite, code, | ||
del, dfn, em, img, ins, kbd, q, s, samp, | ||
small, strike, strong, sub, sup, tt, var, | ||
b, u, i, center, | ||
dl, dt, dd, ol, ul, li, | ||
fieldset, form, label, legend, | ||
table, caption, tbody, tfoot, thead, tr, th, td, | ||
article, aside, canvas, details, embed, | ||
figure, figcaption, footer, header, hgroup, | ||
menu, nav, output, ruby, section, summary, | ||
time, mark, audio, video { | ||
margin: 0; | ||
padding: 0; | ||
border: 0; | ||
font-size: 100%; | ||
font: inherit; | ||
vertical-align: baseline; | ||
} | ||
/* HTML5 display-role reset for older browsers */ | ||
article, aside, details, figcaption, figure, | ||
footer, header, hgroup, menu, nav, section { | ||
display: block; | ||
} | ||
body { | ||
line-height: 1; | ||
} | ||
ol, ul { | ||
list-style: none; | ||
} | ||
blockquote, q { | ||
quotes: none; | ||
} | ||
blockquote:before, blockquote:after, | ||
q:before, q:after { | ||
content: ''; | ||
content: none; | ||
} | ||
table { | ||
border-collapse: collapse; | ||
border-spacing: 0; | ||
} | ||
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. reset.css를 사용하여 디폴트 스타일을 초기화한다는 개념을 처음 알았네요!! 한 수 배워갑니다👍 |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,155 @@ | ||||||||||
let currentTasks = []; | ||||||||||
let completedTasks = []; | ||||||||||
const maxCompletedTasksToShow = 5; | ||||||||||
|
||||||||||
const taskForm = document.querySelector(".todo"); | ||||||||||
const taskList = document.querySelector(".todo-list"); | ||||||||||
const completedList = document.querySelector(".solved-list"); | ||||||||||
const submitButton = document.querySelector("button"); | ||||||||||
|
||||||||||
const resetInputText = () => { | ||||||||||
const taskInput = document.querySelector(".todo > input"); | ||||||||||
taskInput.value = ""; | ||||||||||
}; | ||||||||||
|
||||||||||
const addTaskToList = (text) => { | ||||||||||
if (!currentTasks.includes(text)) { | ||||||||||
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. 이미 같은 일을 할 일에 적어두었을 때는 추가되지 않도록 해두었군요!!! 디테일이 너무 좋아요~~👍 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. includes 메서드 사용해서 task의 중복이 없도록 예외처리한게 인상 깊습니다! |
||||||||||
const listItem = document.createElement("li"); | ||||||||||
listItem.innerHTML = text; | ||||||||||
currentTasks.push(text); | ||||||||||
taskList.appendChild(listItem); | ||||||||||
} | ||||||||||
}; | ||||||||||
|
||||||||||
const addCompletedTaskToList = (text) => { | ||||||||||
if (!completedTasks.includes(text)) { | ||||||||||
const listItem = document.createElement("li"); | ||||||||||
const textElement = document.createElement("p"); | ||||||||||
textElement.innerHTML = text; | ||||||||||
const deleteImg = document.createElement("img"); | ||||||||||
deleteImg.src = "./images/delete.png"; | ||||||||||
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. 앞으로 디자이너와 소통하면서 logic과 view를 최대한 분리시킨 상태로 코딩을 진행하는 것이 좀 더 편하실 거라고 생각해요! 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. 말씀해주신 것처럼 앞으로의 디자이너와의 협업 과정에서 logic과 view를 분리하는 것은 중요한 과정인 것 같습니다 ㅎㅎ 피드백 감사합니다! |
||||||||||
const restoreImg = document.createElement("img"); | ||||||||||
restoreImg.src = "./images/restore.png"; | ||||||||||
listItem.appendChild(deleteImg); | ||||||||||
listItem.appendChild(restoreImg); | ||||||||||
listItem.appendChild(textElement); | ||||||||||
Comment on lines
+33
to
+35
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. 저도 똑같이 피드백 받은 부분인데 append() 메서드를 사용해서 child를 한번에 append하는 방식을 사용해도 좋을 것 같아요~!
Suggested change
|
||||||||||
completedTasks.push(text); | ||||||||||
completedList.appendChild(listItem); | ||||||||||
const filteredTasks = currentTasks.filter((task) => task !== text); | ||||||||||
currentTasks = filteredTasks; | ||||||||||
localStorage.setItem("currentTasks", JSON.stringify(currentTasks)); | ||||||||||
localStorage.setItem("completedTasks", JSON.stringify(completedTasks)); | ||||||||||
if (completedList.children.length > maxCompletedTasksToShow) { | ||||||||||
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. 완료된 task의 수에 제한을 두는건 과도하게 데이터가 쌓이지 않도록 방지하는 차원에서 좋은 것 같습니다! 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. 확실히 함수가 실행됐을 때 미리 체크하는게 성능적으로 봤을 때 훨씬 효율적일 것 같습니다!! |
||||||||||
completedList.lastChild.remove(); | ||||||||||
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. 만약, 개수 검증을 하는걸 뒷쪽에 두는 것이 좀 더 의미있으려면, firstChild를 지워서 가장 일찍 list에 들어온 항목이 지워지고 새로운 항목이 추가되도록 하면 재밌을 것 같아요~~ 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. 사실 개수 검증 코드를 작성하려다가,, 뭔가 계속 꼬여서 그만두었는데 마음을 가다듬고 로직을 찬찬히 생각해보면서 좋았을거같네요.. 감사합니다!! |
||||||||||
} | ||||||||||
} | ||||||||||
}; | ||||||||||
|
||||||||||
const loadTasks = (item) => { | ||||||||||
const storedTasks = localStorage.getItem(item); | ||||||||||
const parsedTasks = JSON.parse(storedTasks); | ||||||||||
parsedTasks.forEach((task) => { | ||||||||||
addTaskToList(task); | ||||||||||
}); | ||||||||||
}; | ||||||||||
|
||||||||||
const loadCompletedTasks = (item) => { | ||||||||||
const storedCompletedTasks = localStorage.getItem(item); | ||||||||||
const parsedCompletedTasks = JSON.parse(storedCompletedTasks); | ||||||||||
parsedCompletedTasks.forEach((completedTask) => { | ||||||||||
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. js의 iteration 방법을 잘 이용하신 것 같습니다~~ |
||||||||||
addCompletedTaskToList(completedTask); | ||||||||||
}); | ||||||||||
}; | ||||||||||
Comment on lines
+48
to
+62
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. 코드 전체적으로 Task와 CompletedTask에 대한 함수로 기능이 확실하게 구분돼있어서 굉장히 좋습니다! |
||||||||||
|
||||||||||
const updateTaskCount = () => { | ||||||||||
const taskCount = document.querySelector(".todo-number"); | ||||||||||
taskCount.innerHTML = currentTasks.length; | ||||||||||
}; | ||||||||||
|
||||||||||
const submitHandler = (event) => { | ||||||||||
event.preventDefault(); | ||||||||||
const taskText = event.target.children[0].value; | ||||||||||
if (taskText.length < 3) { | ||||||||||
alert("3글자 이상 입력하세요."); | ||||||||||
return; | ||||||||||
} else if (taskText.length > 25) { | ||||||||||
alert("25글자 이하로 요약해서 입력해주세요."); | ||||||||||
return; | ||||||||||
} | ||||||||||
addTaskToList(taskText); | ||||||||||
localStorage.setItem("currentTasks", JSON.stringify(currentTasks)); | ||||||||||
updateTaskCount(); | ||||||||||
resetInputText(); | ||||||||||
}; | ||||||||||
|
||||||||||
const clickHandler = (event) => { | ||||||||||
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. 지금은 submit handler와 clickHandler를 따로 명시해서 작성해주셨는데, 같은 기능을 하는 코드를 따로 작성하는 것보다 하나로 작성하는게 효율적일 것 같아요! 아마, 지금 html 작성된 것을 보면 태그 바깥에 button이 위치해서, click과 enter가 서로 다르게 작동하는 것 같습니다button을 form 태그 안에 위치시키면 submit event에 클릭과 엔터가 모두 반응할거에요~~ 그러면 클릭 이벤트 헨들러는 따로 작성하지 않아도 될 것 같습니다ㅎㅎ(그리고 button에 type='submit'을 지정하는게 좀 더 명시적으로 역할을 보여줄 수 있을 것 같아요!) 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. 맞습니다... 확실히 html 구조를 어떻게 설계하냐에 따라 코드 로직 구조의 효율성이 많이 다른 것 같아요, 그리고 button에 type을 명시하는 것 ㅎㅎㅎ 감사합니다! |
||||||||||
event.preventDefault(); | ||||||||||
const taskText = event.target.previousElementSibling.children[0].value; | ||||||||||
if (taskText.length < 3) { | ||||||||||
alert("3글자 이상 입력하세요."); | ||||||||||
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. 글자 수를 이용해서 3글자 이상일 때, alert 창이 나오도록 해주셨는데, |
||||||||||
return; | ||||||||||
} else if (taskText.length > 25) { | ||||||||||
alert("25글자 이하로 요약해서 입력해주세요."); | ||||||||||
return; | ||||||||||
} | ||||||||||
addTaskToList(taskText); | ||||||||||
localStorage.setItem("currentTasks", JSON.stringify(currentTasks)); | ||||||||||
updateTaskCount(); | ||||||||||
resetInputText(); | ||||||||||
}; | ||||||||||
|
||||||||||
const taskClickHandler = (event) => { | ||||||||||
const filteredTasks = currentTasks.filter( | ||||||||||
(task) => task !== event.target.innerHTML | ||||||||||
); | ||||||||||
addCompletedTaskToList(event.target.innerHTML); | ||||||||||
currentTasks.length = 0; | ||||||||||
currentTasks.push(...filteredTasks); | ||||||||||
localStorage.setItem("currentTasks", JSON.stringify(currentTasks)); | ||||||||||
completedTasks.push(event.target.innerHTML); | ||||||||||
localStorage.setItem("completedTasks", JSON.stringify(completedTasks)); | ||||||||||
event.target.remove(); | ||||||||||
updateTaskCount(); | ||||||||||
}; | ||||||||||
|
||||||||||
const completedTaskClickHandler = (event) => { | ||||||||||
if ( | ||||||||||
event.target.tagName === "IMG" && | ||||||||||
event.target.src.includes("delete.png") | ||||||||||
) { | ||||||||||
const deletedTask = | ||||||||||
event.target.nextElementSibling.nextElementSibling.innerHTML; | ||||||||||
const filteredCompletedTasks = completedTasks.filter( | ||||||||||
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. filter method를 통해서 delete와 completed 구분하신 것 잘하신 것 같습니다~~ |
||||||||||
(task) => task !== deletedTask | ||||||||||
); | ||||||||||
completedTasks = filteredCompletedTasks; | ||||||||||
console.log(completedTasks); | ||||||||||
localStorage.setItem("completedTasks", JSON.stringify(completedTasks)); | ||||||||||
event.target.parentElement.remove(); | ||||||||||
} else if ( | ||||||||||
event.target.tagName == "IMG" && | ||||||||||
event.target.src.includes("restore.png") | ||||||||||
) { | ||||||||||
const restoredTask = event.target.nextElementSibling.innerHTML; | ||||||||||
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. event 객체를 통해서 dom element를 조작하는거 좋은 것 같습니다ㅎㅎ 저는 nextElementSibling 이 있는지 몰랐는데 앞으로 써먹어봐야겠네요! |
||||||||||
const filteredCompletedTasks = completedTasks.filter( | ||||||||||
(task) => task !== restoredTask | ||||||||||
); | ||||||||||
completedTasks = filteredCompletedTasks; | ||||||||||
localStorage.setItem("completedTasks", JSON.stringify(completedTasks)); | ||||||||||
addTaskToList(restoredTask); | ||||||||||
localStorage.setItem("currentTasks", JSON.stringify(currentTasks)); | ||||||||||
event.target.parentElement.remove(); | ||||||||||
updateTaskCount(); | ||||||||||
} | ||||||||||
}; | ||||||||||
|
||||||||||
taskForm.addEventListener("submit", submitHandler); | ||||||||||
submitButton.addEventListener("click", clickHandler); | ||||||||||
taskList.addEventListener("click", taskClickHandler); | ||||||||||
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. |
||||||||||
completedList.addEventListener("click", completedTaskClickHandler); | ||||||||||
|
||||||||||
(() => { | ||||||||||
loadTasks("currentTasks"); | ||||||||||
loadCompletedTasks("completedTasks"); | ||||||||||
updateTaskCount(); | ||||||||||
})(); |
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.
엄청 강렬한 이미지네요ㅋㅋㅋ 시선을 확 끕니다
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.
감사합니다 😊 giphy에서 긁어왔어요!