Skip to content
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주차] 심여은 미션 제출합니다. #5

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
89e77a0
✨ Feat : 기본 html 구조 작성
ongheong Aug 27, 2024
db6fbdf
💄 Feat : 웹 폰트 추가
ongheong Aug 27, 2024
70fcdc8
✨ Feat : 사용자 입력을 localStorage에 저장, 업데이트, 화면 출력 기능 추가
ongheong Aug 27, 2024
0ec49be
🐛 Fix : Enter 키 입력 시 화면이 새로고침되는 문제 수정
ongheong Aug 27, 2024
ce263a0
🔨 Refactor : html에서 onclick 이벤트 제거 -> addEventListener로 바꿈
ongheong Aug 27, 2024
8dec920
✨ Feat : todo item의 done, delete 기능 추가
ongheong Aug 27, 2024
ebf9167
🐛 Fix : localStorage의 순서와 화면 출력 순서가 다른 오류 해결
ongheong Aug 27, 2024
a1d5cdd
🏗️ Feat : 배경 이미지 업로드
ongheong Aug 27, 2024
5a3602c
💄 Refactor : 버튼의 innerText 수정
ongheong Aug 27, 2024
ca63868
💄 Refactor : label 태그 추가, h4 태그 innerText 수정
ongheong Aug 27, 2024
82d8789
💄 Feat : 각 태그들의 스타일 1차 작성
ongheong Aug 27, 2024
142f541
💄 Refactor : 스크롤바 추가
ongheong Aug 27, 2024
aab51c6
🐛 Fix : 빈 문자열 입력 -> 유효성 검사 추가
ongheong Aug 27, 2024
32c826e
✨ Feat : 하위 li 태그의 개수를 출력하는 기능 추가
ongheong Aug 27, 2024
f43362a
🐛 Fix : 할 일 완료 시 Done의 개수가 업데이트되지 않는 오류 수정
ongheong Aug 27, 2024
6379d37
💬 Style : 불필요한 주석 삭제 및 수정
ongheong Aug 27, 2024
0d17840
🐛 Fix : li가 없을 경우 section title이 없는 오류 해결
ongheong Aug 28, 2024
0546dc2
💄 Refactor : body, container, ul의 높이 수정
ongheong Aug 28, 2024
c46b278
💄 Refactor : + 버튼 클릭 시 hover 효과 추가
ongheong Aug 28, 2024
1f3acc7
🔧 Style : .prettier 설정 추가
ongheong Aug 29, 2024
61c6b32
Update script.js
ongheong Aug 30, 2024
956b42c
changes committed
ongheong Aug 30, 2024
0bd49ca
♻️ Refactor: 배열내장함수(filter, foreach 등)와 spread 문법 사용, newTodo 객체에 cre…
ongheong Sep 3, 2024
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
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}
Binary file added grid.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,25 @@
<title>Vanilla Todo</title>
<link rel="stylesheet" href="style.css" />
</head>

<body>
<div class="container"></div>
<div class="container">
<header>Todo List</header>
<form id="input-form" onsubmit="return false;">
<label for="todo-input">할 일 : </label>
<input id="todo-input" placeholder="할 일을 입력하세요" />
<button id="input-btn">+</button>
</form>
<section id="todo-list-section">
<h4 class="section-title" id="todo-num">📋 Todo (0)</h4>
<ul id="todo-list">
</ul>
</section>
<section id="done-list-section">
<h4 class="section-title done" id="done-num">👍🏻 Done (0)</h4>
<ul id="done-list">
</ul>
</section>
</div>
</body>
<script src="script.js"></script>
</html>
115 changes: 114 additions & 1 deletion script.js
Original file line number Diff line number Diff line change
@@ -1 +1,114 @@
// 다들 화이팅!! ٩( *˙0˙*)۶
// 다들 화이팅!! ٩( *˙0˙*)۶

const todoInputElement = document.getElementById('todo-input');
const todoInputButton = document.getElementById('input-btn');
const todoListElement = document.getElementById('todo-list');
const doneListElement = document.getElementById('done-list');

// local storage에서 todo list 가져오기
function getTodoList() {
const todoList = localStorage.getItem('todoList');
return todoList ? JSON.parse(todoList) : [];
}

// local storage에 todo list 저장하기
function setTodoList(todoList) {
localStorage.setItem('todoList', JSON.stringify(todoList));
}

window.onload = function () {
// 창을 새로고침해도 todo list가 유지되도록 하기
todoListElement.innerHTML = '';
getTodoList().forEach((todo) => {
createTodoElement(todo);
});
};

// input 버튼 클릭 시
todoInputButton.addEventListener('click', () => {
if (todoInputElement.value === '') {
//입력값이 없을 때
alert('한 글자 이상 입력해주세요!');
return;
}

const newTodo = {
createTime: Date.now(), //todo 객체를 구분하기 위한 고유값으로 생성한 시간 사용
content: todoInputElement.value,
isComplete: false,
};

const newTodoList = [...getTodoList(), newTodo];
setTodoList(newTodoList); //local storage에 저장
createTodoElement(newTodo); //새로운 todo element를 화면에 출력
todoInputElement.value = ''; // input value 초기화
});

// todo element 생성
function createTodoElement(todo) {
const newLi = document.createElement('li');
const newDoneBtn = document.createElement('button');
const newSpan = document.createElement('span');
const newDeleteBtn = document.createElement('button');

newLi.appendChild(newDoneBtn);
newLi.appendChild(newSpan);
newLi.appendChild(newDeleteBtn);

newSpan.textContent = todo.content;

//완료 버튼 클릭 시
newDoneBtn.addEventListener('click', () => {updateIsComplete(todo, newLi)});
//삭제 버튼 클릭 시
newDeleteBtn.addEventListener('click', () => {deleteFromList(todo, newLi)});

//완료 여부에 따라 todoList / doneList에 추가
if (todo.isComplete) {
newDoneBtn.innerText = 'v';
doneListElement.appendChild(newLi);
} else {
newDoneBtn.innerHTML = '';
todoListElement.appendChild(newLi);
}

newDeleteBtn.textContent = 'x';
updateItemCount();
}

//완료 버튼 클릭 시 이벤트
function updateIsComplete(todo, liElement) {
// filter로 기존 todoList에서 해당 todo 삭제 -> todo.isComplete 변경 -> 다시 추가
let newTodoList = getTodoList().filter((item) => {
return item.createTime != todo.createTime;
});
todo.isComplete = !todo.isComplete;
newTodoList = [...newTodoList, todo];

setTodoList(newTodoList);
liElement.remove(); //기존 li 삭제
createTodoElement(todo); //새로운 li 생성
updateItemCount();
}

//삭제 버튼 클릭 시 이벤트
function deleteFromList(todo, liElement) {
const newTodoList = getTodoList().filter((item) => {
return item.createTime != todo.createTime;
});

setTodoList(newTodoList);
liElement.remove();
updateItemCount();
}

// todo, done 개수 업데이트
function updateItemCount() {
const todoNum = document.getElementById('todo-num');
const doneNum = document.getElementById('done-num');
todoNum.textContent = `📋 Todo (${
todoListElement.getElementsByTagName('li').length
})`;
doneNum.textContent = `👍🏻 Done (${
doneListElement.getElementsByTagName('li').length
})`;
}
171 changes: 170 additions & 1 deletion style.css
Original file line number Diff line number Diff line change
@@ -1 +1,170 @@
/* 자유롭게 디자인 해 주세요! */
/* 자유롭게 디자인 해 주세요! */
@font-face {
font-family: 'RixXladywatermelonR';
src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/[email protected]/RixXladywatermelonR.woff2') format('woff2');
font-weight: normal;
font-style: normal;
}

html {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

body {
font-family: RixXladywatermelonR;
max-width: 500px;
padding: 10px;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
scrollbar-width: thin;
}

.container {
position: relative;
display: flex;
width: 450px;
height: 680px;
flex-direction: column;
background-color: #fef79fbd;
overflow: hidden;
}

.container::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("./grid.jpg");
background-size: cover;
background-blend-mode: darken;
opacity: 0.5;
z-index: -1;
}

header {
font-size: 40px;
font-weight: bold;
padding: 20px;
background-color: #2b3681;
color: white;
box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.5);
}

form {
padding: 10px;
display: flex;
justify-content: center;
align-items: baseline;
gap: 10px;
margin-top: 20px;
}

label {
align-items: center;
padding: 2px 7px;
font-size: 20px;
}

input {
border-color: black;
border-width: 0 0 2px;
background-color: transparent;
width: 180px;
margin: 0;
font-family: RixXladywatermelonR;
padding-bottom: 5px;
color:rgb(50, 50, 50);
}

input:focus {
outline: none;
box-shadow: none;
}

button {
font-family: RixXladywatermelonR;
display: flex;
justify-content: center;
align-content: center;
flex-wrap: wrap-reverse;
}
Comment on lines +92 to +98
Copy link
Member

Choose a reason for hiding this comment

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

cursor: pointer 를 추가하면 더 좋을 것 같습니다 😉

Copy link
Member Author

@ongheong ongheong Aug 30, 2024

Choose a reason for hiding this comment

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

오 버튼에 추가해보겠습니다!


#input-btn {
border: transparent;
border-radius: 4px;
background-color: transparent;
padding: 2px 7px;
font-size: 25px;
font-weight: 500;
}

#input-btn:hover {
color: green;
background-color: transparent;
}

section {
margin-top: 20px;
}

h4 {
font-size: 20px;
text-align: left;
padding: 10px 20px;
margin: 0;
}

ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
height: 168px;
overflow-y: scroll;
}

li {
display: flex;
align-items: center;
padding: 8px 30px;
gap: 8px;
}

li > :nth-child(1) {
width: 25px;
height: 25px;
border-radius: 8px;
background-color: transparent;
font-size: 25px;
border-color: #393939;
}

li > :nth-child(3) {

Choose a reason for hiding this comment

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

css 정석대로 야무지게 잘 사용하시네요 멋집니다!

border: transparent;
background-color: transparent;
font-size: 20px;
font-weight: 500;
}

#done-list span {
text-decoration: line-through;
color: #b3b3b3;
}

#done-list li > :nth-child(1) {
border: transparent;
background-color: green;
font-size: 20px;
font-weight: 500;
color: white;
}