From 973977ec73bfc08697521522de52b493cbb501b8 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 14:24:24 +0900 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20html=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 앱 구동에 필요한 기본적인 html 코드를 작성했다. --- index.html | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 420961c..6e27363 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,16 @@ -
+

나의 할 일

+
+
+ + + + +
+ +
- \ No newline at end of file + From 1d64edf4016be5a968417269adea3248e465c4cb Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 15:11:40 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20localStorage=EC=97=90=EC=84=9C=20?= =?UTF-8?q?todolist=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit todo list를 localStorage에서 가져오고 view에 display하는 기능을 구현했다. --- script.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/script.js b/script.js index e69de29..488d0ad 100644 --- a/script.js +++ b/script.js @@ -0,0 +1,30 @@ +// localStorage에서 todo elements 가져오기, 시간을 Date형식으로 변환하기 위해 map 함수를 사용 +const TODOS = JSON.parse(window.localStorage.getItem('todos')).map((todo) => ({ + ...todo, + date: new Date(todo.date), +})); + +for (const todo of TODOS) { + const ul = document.querySelector('.todoList'); + const newLi = document.createElement('li'); + const contentDiv = document.createElement('div'); + const dateDiv = document.createElement('div'); + const doneBtn = document.createElement('button'); + const deleteBtn = document.createElement('button'); + + contentDiv.innerHTML = todo.content; + dateDiv.innerHTML = todo.date.toISOString(); + doneBtn.innerHTML = 'done'; + doneBtn.classList; + deleteBtn.innerHTML = 'delete'; + + newLi.appendChild(contentDiv); + newLi.appendChild(dateDiv); + newLi.appendChild(doneBtn); + newLi.appendChild(deleteBtn); + + if (todo.priority === 3) newLi.classList.add = 'high'; + else if (todo.priority === 2) newLi.classList.add = 'mid'; + else newLi.classList.add = 'low'; + ul.appendChild(newLi); +} From dd15cd2c0269a8f5650de8bbcc42cb6f93447a77 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 16:05:15 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20done,=20delete=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit done, delete 버튼에 onclick handler를 정의하여 클릭 이벤트에 반응할 수 있도록 했다. --- script.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/script.js b/script.js index 488d0ad..6d1cd8b 100644 --- a/script.js +++ b/script.js @@ -1,11 +1,18 @@ // localStorage에서 todo elements 가져오기, 시간을 Date형식으로 변환하기 위해 map 함수를 사용 -const TODOS = JSON.parse(window.localStorage.getItem('todos')).map((todo) => ({ - ...todo, - date: new Date(todo.date), -})); +const unparsedTODOS = localStorage.getItem('todos'); +const TODOS = unparsedTODOS + ? JSON.parse(unparsedTODOS).map((todo, idx) => ({ + ...todo, + idx, + date: new Date(todo.date), + })) + : []; + +let nextIdx = TODOS.length; + +const ul = document.querySelector('.todoList'); for (const todo of TODOS) { - const ul = document.querySelector('.todoList'); const newLi = document.createElement('li'); const contentDiv = document.createElement('div'); const dateDiv = document.createElement('div'); @@ -13,18 +20,55 @@ for (const todo of TODOS) { const deleteBtn = document.createElement('button'); contentDiv.innerHTML = todo.content; + contentDiv.className = 'content'; dateDiv.innerHTML = todo.date.toISOString(); + dateDiv.className = 'date'; doneBtn.innerHTML = 'done'; - doneBtn.classList; + doneBtn.className = 'doneBtn'; deleteBtn.innerHTML = 'delete'; + deleteBtn.className = 'deleteBtn'; newLi.appendChild(contentDiv); newLi.appendChild(dateDiv); newLi.appendChild(doneBtn); newLi.appendChild(deleteBtn); - if (todo.priority === 3) newLi.classList.add = 'high'; - else if (todo.priority === 2) newLi.classList.add = 'mid'; - else newLi.classList.add = 'low'; + newLi.id = todo.idx; + if (todo.priority === 3) newLi.classList.add('high'); + else if (todo.priority === 2) newLi.classList.add('mid'); + else newLi.classList.add('low'); + + if (todo.isDone) newLi.classList.add('done'); ul.appendChild(newLi); } + +const doneBtns = document.querySelectorAll('.doneBtn'); +doneBtns.forEach((btn) => { + btn.addEventListener('click', (e) => { + const idx = e.currentTarget.parentNode.id; + const clickedLi = document.getElementById(idx); + if (clickedLi.classList.contains('done')) + clickedLi.classList.remove('done'); + else clickedLi.classList.add('done'); + + for (const todo of TODOS) { + if (todo.idx == idx) todo.isDone = !todo.isDone; + } + }); +}); + +const deleteBtns = document.querySelectorAll('.deleteBtn'); +deleteBtns.forEach((btn) => { + btn.addEventListener('click', (e) => { + const idx = e.currentTarget.parentNode.id; + const clickedLi = document.getElementById(idx); + ul.removeChild(clickedLi); + + let i; + for (i = 0; i < TODOS.length; i++) { + if (TODOS[i].idx == idx) break; + } + TODOS.splice(i, 1); + localStorage.setItem('todos', JSON.stringify(TODOS)); + }); +}); From 8af74712a487d0cbfce45143a812ef6b7061d516 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 17:42:28 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20add=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add 버튼을 누르면 리스트에 추가되고, 메모리에서 관리되는 todo List가 priority와 date에 따라 정렬될 수 있도록 로직을 구성했다. --- index.html | 12 ++++++ script.js | 123 +++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 108 insertions(+), 27 deletions(-) diff --git a/index.html b/index.html index 6e27363..608e042 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,18 @@

나의 할 일

+
+ 높음 + 보통 + 낮음 +
+ diff --git a/script.js b/script.js index 6d1cd8b..b9920df 100644 --- a/script.js +++ b/script.js @@ -1,65 +1,75 @@ -// localStorage에서 todo elements 가져오기, 시간을 Date형식으로 변환하기 위해 map 함수를 사용 +// localStorage에서 todo elements 가져오기 const unparsedTODOS = localStorage.getItem('todos'); const TODOS = unparsedTODOS ? JSON.parse(unparsedTODOS).map((todo, idx) => ({ ...todo, idx, - date: new Date(todo.date), + fromDate: new Date(todo.fromDate), + toDate: new Date(todo.toDate), })) : []; -let nextIdx = TODOS.length; +let nextIdx = TODOS.length; // idx값을 중복되지 않게 설정하도록 초기값 지정 +const ul = document.querySelector('.todoList'); // child node를 추가/제거 하기 위해 변수에 저장 -const ul = document.querySelector('.todoList'); +// view update +const updateView = () => { + while (ul.hasChildNodes()) { + ul.removeChild(ul.firstChild); + } + for (const todo of TODOS) { + addNewTodoLi(todo); + } +}; -for (const todo of TODOS) { +const addNewTodoLi = (todo) => { const newLi = document.createElement('li'); const contentDiv = document.createElement('div'); - const dateDiv = document.createElement('div'); + const fromDateDiv = document.createElement('div'); + const toDateDiv = document.createElement('div'); const doneBtn = document.createElement('button'); const deleteBtn = document.createElement('button'); contentDiv.innerHTML = todo.content; contentDiv.className = 'content'; - dateDiv.innerHTML = todo.date.toISOString(); - dateDiv.className = 'date'; + fromDateDiv.innerHTML = todo.fromDate; + fromDateDiv.className = 'fromDate'; + toDateDiv.innerHTML = todo.toDate; + toDateDiv.className = 'toDate'; doneBtn.innerHTML = 'done'; doneBtn.className = 'doneBtn'; deleteBtn.innerHTML = 'delete'; deleteBtn.className = 'deleteBtn'; newLi.appendChild(contentDiv); - newLi.appendChild(dateDiv); + newLi.appendChild(fromDateDiv); + newLi.appendChild(toDateDiv); newLi.appendChild(doneBtn); newLi.appendChild(deleteBtn); - newLi.id = todo.idx; - if (todo.priority === 3) newLi.classList.add('high'); - else if (todo.priority === 2) newLi.classList.add('mid'); - else newLi.classList.add('low'); - - if (todo.isDone) newLi.classList.add('done'); - ul.appendChild(newLi); -} - -const doneBtns = document.querySelectorAll('.doneBtn'); -doneBtns.forEach((btn) => { - btn.addEventListener('click', (e) => { + doneBtn.addEventListener('click', (e) => { const idx = e.currentTarget.parentNode.id; const clickedLi = document.getElementById(idx); if (clickedLi.classList.contains('done')) clickedLi.classList.remove('done'); else clickedLi.classList.add('done'); - for (const todo of TODOS) { - if (todo.idx == idx) todo.isDone = !todo.isDone; + let i; + for (i = 0; i < TODOS.length; i++) { + if (TODOS[i].idx == idx) { + TODOS[i].isDone = !TODOS[i].isDone; + break; + } } + const todo = TODOS[i]; + TODOS.splice(i, 1); + + pushTodo(todo); + updateView(); + localStorage.setItem('todos', JSON.stringify(TODOS)); }); -}); -const deleteBtns = document.querySelectorAll('.deleteBtn'); -deleteBtns.forEach((btn) => { - btn.addEventListener('click', (e) => { + deleteBtn.addEventListener('click', (e) => { const idx = e.currentTarget.parentNode.id; const clickedLi = document.getElementById(idx); ul.removeChild(clickedLi); @@ -69,6 +79,65 @@ deleteBtns.forEach((btn) => { if (TODOS[i].idx == idx) break; } TODOS.splice(i, 1); + localStorage.setItem('todos', JSON.stringify(TODOS)); }); + + newLi.id = todo.idx; + if (todo.priority === 3) newLi.classList.add('high'); + else if (todo.priority === 2) newLi.classList.add('mid'); + else newLi.classList.add('low'); + + if (todo.isDone) newLi.classList.add('done'); + ul.appendChild(newLi); +}; + +for (const todo of TODOS) { + addNewTodoLi(todo); +} + +const addBtn = document.querySelector('.addBtn'); +addBtn.addEventListener('click', () => { + const newTodo = {}; + const content = document.querySelector('.content'); + const priorities = document.querySelectorAll("input[name='priority']"); + const fromDate = document.querySelector('.from'); + const toDate = document.querySelector('.to'); + + newTodo.idx = nextIdx++; + newTodo.content = content.value; + priorities.forEach((priority) => { + if (priority.checked) { + newTodo.priority = Number(priority.value); + return; + } + }); + newTodo.fromDate = new Date(fromDate.value); + newTodo.toDate = new Date(toDate.value); + newTodo.isDone = false; + + pushTodo(newTodo); + localStorage.setItem('todos', JSON.stringify(TODOS)); + updateView(); + + content.value = null; + priorities[0].checked = true; + fromDate.value = null; + toDate.value = null; }); + +const pushTodo = (todo) => { + if (todo.isDone) { + TODOS.splice(TODOS.length, 0, todo); + return; + } + let i = 0; + for (; i < TODOS.length; i++) { + if (TODOS[i].isDone) break; + if (TODOS[i].priority < todo.priority) break; + else if (TODOS[i].priority === todo.priority) { + if (TODOS[i].fromDate >= todo.fromDate) break; + } + } + TODOS.splice(i, 0, todo); +}; From b2925148a3ccd0516d90e4629b45d3f15dac7fac Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 17:59:58 +0900 Subject: [PATCH 05/13] =?UTF-8?q?refactor:=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=84=A0=EC=96=B8=20=EC=88=9C=EC=84=9C=20=EC=A0=95=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 137 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 62 deletions(-) diff --git a/script.js b/script.js index b9920df..4a63904 100644 --- a/script.js +++ b/script.js @@ -1,3 +1,4 @@ +// ############################## init ############################## // localStorage에서 todo elements 가져오기 const unparsedTODOS = localStorage.getItem('todos'); const TODOS = unparsedTODOS @@ -12,17 +13,27 @@ const TODOS = unparsedTODOS let nextIdx = TODOS.length; // idx값을 중복되지 않게 설정하도록 초기값 지정 const ul = document.querySelector('.todoList'); // child node를 추가/제거 하기 위해 변수에 저장 +// in memory에 저장된 todo list를 view에 display +for (const todo of TODOS) { + addNewTodoLi(todo); +} + +const addBtn = document.querySelector('.addBtn'); +addBtn.addEventListener('click', handleClickAddBtn); + +// ############################## core functions ############################## // view update -const updateView = () => { +function updateView() { while (ul.hasChildNodes()) { ul.removeChild(ul.firstChild); } for (const todo of TODOS) { addNewTodoLi(todo); } -}; +} -const addNewTodoLi = (todo) => { +// ul에 list들을 삽입 +function addNewTodoLi(todo) { const newLi = document.createElement('li'); const contentDiv = document.createElement('div'); const fromDateDiv = document.createElement('div'); @@ -41,48 +52,15 @@ const addNewTodoLi = (todo) => { deleteBtn.innerHTML = 'delete'; deleteBtn.className = 'deleteBtn'; + doneBtn.addEventListener('click', handleClickDoneBtn); + deleteBtn.addEventListener('click', handleClickDeleteBtn); + newLi.appendChild(contentDiv); newLi.appendChild(fromDateDiv); newLi.appendChild(toDateDiv); newLi.appendChild(doneBtn); newLi.appendChild(deleteBtn); - doneBtn.addEventListener('click', (e) => { - const idx = e.currentTarget.parentNode.id; - const clickedLi = document.getElementById(idx); - if (clickedLi.classList.contains('done')) - clickedLi.classList.remove('done'); - else clickedLi.classList.add('done'); - - let i; - for (i = 0; i < TODOS.length; i++) { - if (TODOS[i].idx == idx) { - TODOS[i].isDone = !TODOS[i].isDone; - break; - } - } - const todo = TODOS[i]; - TODOS.splice(i, 1); - - pushTodo(todo); - updateView(); - localStorage.setItem('todos', JSON.stringify(TODOS)); - }); - - deleteBtn.addEventListener('click', (e) => { - const idx = e.currentTarget.parentNode.id; - const clickedLi = document.getElementById(idx); - ul.removeChild(clickedLi); - - let i; - for (i = 0; i < TODOS.length; i++) { - if (TODOS[i].idx == idx) break; - } - TODOS.splice(i, 1); - - localStorage.setItem('todos', JSON.stringify(TODOS)); - }); - newLi.id = todo.idx; if (todo.priority === 3) newLi.classList.add('high'); else if (todo.priority === 2) newLi.classList.add('mid'); @@ -90,14 +68,65 @@ const addNewTodoLi = (todo) => { if (todo.isDone) newLi.classList.add('done'); ul.appendChild(newLi); -}; +} -for (const todo of TODOS) { - addNewTodoLi(todo); +// 기준에 따라 정렬되어 memory에 저장되도록 push +function pushTodo(todo) { + if (todo.isDone) { + TODOS.splice(TODOS.length, 0, todo); + return; + } + let i = 0; + for (; i < TODOS.length; i++) { + if (TODOS[i].isDone) break; + if (TODOS[i].priority < todo.priority) break; + else if (TODOS[i].priority === todo.priority) { + if (TODOS[i].fromDate >= todo.fromDate) break; + } + } + TODOS.splice(i, 0, todo); } -const addBtn = document.querySelector('.addBtn'); -addBtn.addEventListener('click', () => { +// ############################## click handlers ############################## +// done button click event handler +function handleClickDoneBtn(e) { + const idx = e.currentTarget.parentNode.id; + const clickedLi = document.getElementById(idx); + if (clickedLi.classList.contains('done')) clickedLi.classList.remove('done'); + else clickedLi.classList.add('done'); + + let i; + for (i = 0; i < TODOS.length; i++) { + if (TODOS[i].idx == idx) { + TODOS[i].isDone = !TODOS[i].isDone; + break; + } + } + const todo = TODOS[i]; + TODOS.splice(i, 1); + + pushTodo(todo); + updateView(); + localStorage.setItem('todos', JSON.stringify(TODOS)); +} + +// delete button click event handler +function handleClickDeleteBtn(e) { + const idx = e.currentTarget.parentNode.id; + const clickedLi = document.getElementById(idx); + ul.removeChild(clickedLi); + + let i; + for (i = 0; i < TODOS.length; i++) { + if (TODOS[i].idx == idx) break; + } + TODOS.splice(i, 1); + + localStorage.setItem('todos', JSON.stringify(TODOS)); +} + +// add button click event handler +function handleClickAddBtn() { const newTodo = {}; const content = document.querySelector('.content'); const priorities = document.querySelectorAll("input[name='priority']"); @@ -117,27 +146,11 @@ addBtn.addEventListener('click', () => { newTodo.isDone = false; pushTodo(newTodo); - localStorage.setItem('todos', JSON.stringify(TODOS)); updateView(); + localStorage.setItem('todos', JSON.stringify(TODOS)); content.value = null; priorities[0].checked = true; fromDate.value = null; toDate.value = null; -}); - -const pushTodo = (todo) => { - if (todo.isDone) { - TODOS.splice(TODOS.length, 0, todo); - return; - } - let i = 0; - for (; i < TODOS.length; i++) { - if (TODOS[i].isDone) break; - if (TODOS[i].priority < todo.priority) break; - else if (TODOS[i].priority === todo.priority) { - if (TODOS[i].fromDate >= todo.fromDate) break; - } - } - TODOS.splice(i, 0, todo); -}; +} From 3661d25c352ce875062ea0585844d0a09e462611 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 19:10:04 +0900 Subject: [PATCH 06/13] =?UTF-8?q?style:=20todo=20list=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B6=80=EB=B6=84=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 55 +++++++++++++++++++++++++++++++++----- script.js | 5 +++- style.css | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 608e042..906f67d 100644 --- a/index.html +++ b/index.html @@ -11,23 +11,64 @@

나의 할 일

- -
+ + +
높음 - 보통 - 낮음 + id="high" + /> + + + + + + + + + +
- - +
+ + +
+
    diff --git a/script.js b/script.js index 4a63904..ec00723 100644 --- a/script.js +++ b/script.js @@ -62,6 +62,7 @@ function addNewTodoLi(todo) { newLi.appendChild(deleteBtn); newLi.id = todo.idx; + newLi.classList.add('todoLi'); if (todo.priority === 3) newLi.classList.add('high'); else if (todo.priority === 2) newLi.classList.add('mid'); else newLi.classList.add('low'); @@ -128,11 +129,13 @@ function handleClickDeleteBtn(e) { // add button click event handler function handleClickAddBtn() { const newTodo = {}; - const content = document.querySelector('.content'); + const content = document.querySelector('.contentInput'); const priorities = document.querySelectorAll("input[name='priority']"); const fromDate = document.querySelector('.from'); const toDate = document.querySelector('.to'); + // console.log(fromDate.value); + if (!content.value || !fromDate.value || !toDate.value) return; newTodo.idx = nextIdx++; newTodo.content = content.value; priorities.forEach((priority) => { diff --git a/style.css b/style.css index e69de29..247bbfb 100644 --- a/style.css +++ b/style.css @@ -0,0 +1,77 @@ +button { + all: unset; +} + +body { + display: flex; + flex-direction: column; + align-items: center; + padding: 10px; + width: 100%; + margin: 0; + box-sizing: border-box; +} + +.body { + width: 100%; + height: 50px; +} +.inputOuter { + display: flex; + width: 100%; + height: 100%; + border: 1px solid rgb(227, 227, 227); + border-radius: 8px; + color: rgb(112, 112, 112); + padding: 10px; + box-sizing: border-box; +} + +.contentInput { + border: none; + background-color: transparent; + flex-grow: 2; +} + +.radioOuter { + display: flex; + align-items: center; + border-left: 1px solid rgb(227, 227, 227); + padding: 0 10px; +} +.priority { + margin: 0 5px; +} +label { + font-size: 10px; +} + +.dateOuter { + display: flex; + border-left: 1px solid rgb(227, 227, 227); + padding: 0 10px; +} +.dateInput { + width: 50px; + overflow: hidden; + border: none; + position: relative; + background-color: transparent; + color: rgb(112, 112, 112); + border-radius: 8px; + text-align: center; +} + +.dateInput::before { + content: attr(data-placeholder); + width: 100%; +} + +.dateInput:focus::before, +.dateInput:valid::before { + display: none; +} + +.addBtn { + padding: 0 10px; +} From a41189caf9cf8755cdd84b42e9a3a6740649ed5d Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 20:22:40 +0900 Subject: [PATCH 07/13] =?UTF-8?q?style:=20=EC=A0=84=EC=B2=B4=20=EB=94=94?= =?UTF-8?q?=EC=9E=90=EC=9D=B8=20=EC=A0=81=EC=9A=A9=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 96 ++++++++++++++++++++++--------------------- script.js | 19 ++++++--- style.css | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 175 insertions(+), 58 deletions(-) diff --git a/index.html b/index.html index 906f67d..8b83769 100644 --- a/index.html +++ b/index.html @@ -10,61 +10,63 @@

    나의 할 일

    -
    - - -
    +
    +
    - +
    + - + - + - + - -
    + -
    - - + +
    + +
    + + +
    diff --git a/script.js b/script.js index ec00723..7ce4eb3 100644 --- a/script.js +++ b/script.js @@ -37,19 +37,21 @@ function addNewTodoLi(todo) { const newLi = document.createElement('li'); const contentDiv = document.createElement('div'); const fromDateDiv = document.createElement('div'); + const betweenDiv = document.createElement('div'); const toDateDiv = document.createElement('div'); const doneBtn = document.createElement('button'); const deleteBtn = document.createElement('button'); - + new Date().geth; contentDiv.innerHTML = todo.content; contentDiv.className = 'content'; - fromDateDiv.innerHTML = todo.fromDate; + fromDateDiv.innerHTML = convertDate(todo.fromDate); fromDateDiv.className = 'fromDate'; - toDateDiv.innerHTML = todo.toDate; + betweenDiv.innerHTML = '-'; + toDateDiv.innerHTML = convertDate(todo.toDate); toDateDiv.className = 'toDate'; - doneBtn.innerHTML = 'done'; + doneBtn.innerHTML = todo.isDone ? '↪' : '✓'; doneBtn.className = 'doneBtn'; - deleteBtn.innerHTML = 'delete'; + deleteBtn.innerHTML = '-'; deleteBtn.className = 'deleteBtn'; doneBtn.addEventListener('click', handleClickDoneBtn); @@ -57,6 +59,7 @@ function addNewTodoLi(todo) { newLi.appendChild(contentDiv); newLi.appendChild(fromDateDiv); + newLi.appendChild(betweenDiv); newLi.appendChild(toDateDiv); newLi.appendChild(doneBtn); newLi.appendChild(deleteBtn); @@ -88,9 +91,15 @@ function pushTodo(todo) { TODOS.splice(i, 0, todo); } +function convertDate(date) { + return `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}`; +} + // ############################## click handlers ############################## // done button click event handler function handleClickDoneBtn(e) { + // console.log(e.currentTarget.innerHTML); + // e.target.innerHTML = '↩'; const idx = e.currentTarget.parentNode.id; const clickedLi = document.getElementById(idx); if (clickedLi.classList.contains('done')) clickedLi.classList.remove('done'); diff --git a/style.css b/style.css index 247bbfb..9478bf8 100644 --- a/style.css +++ b/style.css @@ -1,8 +1,40 @@ +@font-face { + font-family: 'GangwonState'; + src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2307-2@1.0/GangwonState.woff2') + format('woff2'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'SUITE-SemiBold'; + src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2304-2@1.0/SUITE-SemiBold.woff2') + format('woff2'); + font-weight: 600; + font-style: normal; +} + +@font-face { + font-family: 'SUITE-Regular'; + src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2304-2@1.0/SUITE-Regular.woff2') + format('woff2'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'SUITE-Medium'; + src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2304-2@1.0/SUITE-Medium.woff2') + format('woff2'); + font-weight: 500; + font-style: normal; +} button { all: unset; } body { + font-family: 'SUITE-Regular'; display: flex; flex-direction: column; align-items: center; @@ -12,18 +44,27 @@ body { box-sizing: border-box; } +.title { + font-family: 'GangwonState'; +} .body { width: 100%; - height: 50px; + /* height: 50px; */ +} +.inputAndAdd { + height: 40px; + display: flex; + align-items: center; } .inputOuter { + overflow: auto; display: flex; width: 100%; height: 100%; - border: 1px solid rgb(227, 227, 227); + border: 1px solid black; border-radius: 8px; color: rgb(112, 112, 112); - padding: 10px; + padding: 5px 10px; box-sizing: border-box; } @@ -36,7 +77,7 @@ body { .radioOuter { display: flex; align-items: center; - border-left: 1px solid rgb(227, 227, 227); + border-left: 1px solid black; padding: 0 10px; } .priority { @@ -48,7 +89,7 @@ label { .dateOuter { display: flex; - border-left: 1px solid rgb(227, 227, 227); + border-left: 1px solid black; padding: 0 10px; } .dateInput { @@ -73,5 +114,70 @@ label { } .addBtn { - padding: 0 10px; + /* padding: 0 10px; */ + margin-left: 10px; + min-width: 20px; + height: 20px; + border: 1px solid black; + border-radius: 50%; + text-align: center; +} + +.todoList { + margin: 10px 0 0 0; + padding: 10px; + /* border-radius: 8px; */ + /* border: 1px solid rgb(227, 227, 227); */ + list-style: none; +} + +.todoLi { + display: flex; + align-items: center; + padding-bottom: 10px; + margin-bottom: 10px; + border-bottom: 1px solid rgb(227, 227, 227); + color: rgb(112, 112, 112); +} + +.content { + flex-grow: 2; +} + +.fromDate, +.toDate { + margin: 0 5px; +} +.doneBtn { + margin: 0 5px 0 10px; + width: 20px; + height: 20px; + color: green; +} + +.deleteBtn { + padding: 0 10px 0 5px; + color: rgb(202, 45, 24); +} + +.high { + color: black; + /* font-weight: 600; */ + font-family: 'SUITE-SemiBold'; +} + +.mid { + color: rgb(120, 120, 120); + font-family: 'SUITE-Medium'; +} + +.low { + color: rgb(200, 200, 200); + font-weight: 400; +} + +.done { + color: rgb(236, 236, 236) !important; + font-weight: 400 !important; + /* background-color: whitesmoke; */ } From 7f149f56b1fffff530d5422e9b6b5e000f7f52ae Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 20:36:04 +0900 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20=EB=82=A0=EC=A7=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=9D=98=20=EC=B6=94=EA=B0=80=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 오늘 날짜보다 시작일이 빠르지 않고, 시작일보다 종료일이 빠르지 않도록 제한하는 기능을 추가했다. --- script.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/script.js b/script.js index 7ce4eb3..50841ad 100644 --- a/script.js +++ b/script.js @@ -18,9 +18,20 @@ for (const todo of TODOS) { addNewTodoLi(todo); } +// 추가 버튼 click event handler 등록 const addBtn = document.querySelector('.addBtn'); addBtn.addEventListener('click', handleClickAddBtn); +// 오늘 이전의 date은 선택하지 못하도록 제한 +const utc = Date.now(); +const timeOff = new Date().getTimezoneOffset() * 60000; +const today = new Date(utc - timeOff).toISOString().split('T')[0]; +document.querySelector('.dateInput').setAttribute('min', today); + +// 시작일 설정에 change event handler 등록 +const fromDate = document.querySelector('.from'); +fromDate.addEventListener('change', handleChangeFromDate); + // ############################## core functions ############################## // view update function updateView() { @@ -91,6 +102,7 @@ function pushTodo(todo) { TODOS.splice(i, 0, todo); } +// Date를 적절하게 display 하도록 convert function convertDate(date) { return `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}`; } @@ -98,8 +110,6 @@ function convertDate(date) { // ############################## click handlers ############################## // done button click event handler function handleClickDoneBtn(e) { - // console.log(e.currentTarget.innerHTML); - // e.target.innerHTML = '↩'; const idx = e.currentTarget.parentNode.id; const clickedLi = document.getElementById(idx); if (clickedLi.classList.contains('done')) clickedLi.classList.remove('done'); @@ -143,7 +153,6 @@ function handleClickAddBtn() { const fromDate = document.querySelector('.from'); const toDate = document.querySelector('.to'); - // console.log(fromDate.value); if (!content.value || !fromDate.value || !toDate.value) return; newTodo.idx = nextIdx++; newTodo.content = content.value; @@ -166,3 +175,13 @@ function handleClickAddBtn() { fromDate.value = null; toDate.value = null; } + +// 종료일이 시작일보다 빠를 수 없도록한 change event handler +function handleChangeFromDate(e) { + if (e.currentTarget.value) { + let utc = new Date(e.currentTarget.value).getTime(); + let timeOff = new Date().getTimezoneOffset() * 60000; + let today = new Date(utc - timeOff).toISOString().split('T')[0]; + document.querySelector('.to').setAttribute('min', today); + } +} From 04c806f578783a95e459df50122f7f7c5f283eff Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 20:46:31 +0900 Subject: [PATCH 09/13] =?UTF-8?q?refactor:=20=EB=82=A0=EC=A7=9C=EB=A5=BC?= =?UTF-8?q?=20=EC=A7=80=EC=A0=95=ED=95=98=EC=A7=80=20=EC=95=8A=EC=95=84?= =?UTF-8?q?=EB=8F=84=20=EB=93=B1=EB=A1=9D=ED=95=A0=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/script.js b/script.js index 50841ad..616097b 100644 --- a/script.js +++ b/script.js @@ -26,7 +26,11 @@ addBtn.addEventListener('click', handleClickAddBtn); const utc = Date.now(); const timeOff = new Date().getTimezoneOffset() * 60000; const today = new Date(utc - timeOff).toISOString().split('T')[0]; -document.querySelector('.dateInput').setAttribute('min', today); +const dateInputs = document + .querySelectorAll('.dateInput') + .forEach((dateInput) => { + dateInput.setAttribute('min', today); + }); // 시작일 설정에 change event handler 등록 const fromDate = document.querySelector('.from'); @@ -153,7 +157,7 @@ function handleClickAddBtn() { const fromDate = document.querySelector('.from'); const toDate = document.querySelector('.to'); - if (!content.value || !fromDate.value || !toDate.value) return; + if (!content.value) return; newTodo.idx = nextIdx++; newTodo.content = content.value; priorities.forEach((priority) => { @@ -162,8 +166,8 @@ function handleClickAddBtn() { return; } }); - newTodo.fromDate = new Date(fromDate.value); - newTodo.toDate = new Date(toDate.value); + newTodo.fromDate = fromDate.value ? new Date(fromDate.value) : new Date(); + newTodo.toDate = toDate.value ? new Date(toDate.value) : new Date(); newTodo.isDone = false; pushTodo(newTodo); @@ -183,5 +187,6 @@ function handleChangeFromDate(e) { let timeOff = new Date().getTimezoneOffset() * 60000; let today = new Date(utc - timeOff).toISOString().split('T')[0]; document.querySelector('.to').setAttribute('min', today); + document.querySelector('.to').setAttribute('value', e.currentTarget.value); } } From be1b69bd901be6991e2d9e6b0c1d63bef231734c Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 20:50:00 +0900 Subject: [PATCH 10/13] =?UTF-8?q?style:=20width=EA=B0=80=20=EC=A2=81?= =?UTF-8?q?=EC=95=84=EC=A7=80=EB=A9=B4=20=EA=B0=84=EC=86=8C=ED=99=94?= =?UTF-8?q?=ED=95=98=EC=97=AC=20display=20=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 1 + style.css | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/script.js b/script.js index 616097b..cf0ac14 100644 --- a/script.js +++ b/script.js @@ -62,6 +62,7 @@ function addNewTodoLi(todo) { fromDateDiv.innerHTML = convertDate(todo.fromDate); fromDateDiv.className = 'fromDate'; betweenDiv.innerHTML = '-'; + betweenDiv.className = 'betweenDate'; toDateDiv.innerHTML = convertDate(todo.toDate); toDateDiv.className = 'toDate'; doneBtn.innerHTML = todo.isDone ? '↪' : '✓'; diff --git a/style.css b/style.css index 9478bf8..8b5317c 100644 --- a/style.css +++ b/style.css @@ -29,6 +29,7 @@ font-weight: 500; font-style: normal; } + button { all: unset; } @@ -181,3 +182,13 @@ label { font-weight: 400 !important; /* background-color: whitesmoke; */ } + +@media (max-width: 500px) { + .radioOuter, + .dateOuter, + .fromDate, + .toDate, + .betweenDate { + display: none; + } +} From ff43d6e149fd348f155bd30f9c84984b32b04ea2 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 21:29:07 +0900 Subject: [PATCH 11/13] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F?= =?UTF-8?q?=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=9D=BC=EB=B6=80=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 108 +++++++++++++++++++++++++++-------------------------- style.css | 23 ++++++------ 2 files changed, 67 insertions(+), 64 deletions(-) diff --git a/index.html b/index.html index 8b83769..2d8b0cf 100644 --- a/index.html +++ b/index.html @@ -8,70 +8,72 @@ -

    나의 할 일

    -
    -
    -
    - - -
    +
    +

    나의 할 일

    +
    +
    +
    - +
    + - + - + - + - -
    + -
    - - + +
    + +
    + + +
    +
    - -
    -
      +
        +
        diff --git a/style.css b/style.css index 8b5317c..deb4eac 100644 --- a/style.css +++ b/style.css @@ -36,21 +36,26 @@ button { body { font-family: 'SUITE-Regular'; + padding: 10px; + margin: 0; +} + +.wrapper { + padding: 10px; display: flex; flex-direction: column; align-items: center; - padding: 10px; width: 100%; margin: 0; box-sizing: border-box; + border: 3px solid black; + border-radius: 10px; } - .title { font-family: 'GangwonState'; } .body { width: 100%; - /* height: 50px; */ } .inputAndAdd { height: 40px; @@ -62,7 +67,7 @@ body { display: flex; width: 100%; height: 100%; - border: 1px solid black; + border: 2px solid black; border-radius: 8px; color: rgb(112, 112, 112); padding: 5px 10px; @@ -115,20 +120,18 @@ label { } .addBtn { - /* padding: 0 10px; */ margin-left: 10px; min-width: 20px; height: 20px; - border: 1px solid black; + border: 2px solid black; border-radius: 50%; + font-family: 'SUITE-SemiBold'; text-align: center; } .todoList { margin: 10px 0 0 0; padding: 10px; - /* border-radius: 8px; */ - /* border: 1px solid rgb(227, 227, 227); */ list-style: none; } @@ -137,7 +140,7 @@ label { align-items: center; padding-bottom: 10px; margin-bottom: 10px; - border-bottom: 1px solid rgb(227, 227, 227); + border-bottom: 1px solid rgb(216, 216, 216); color: rgb(112, 112, 112); } @@ -163,7 +166,6 @@ label { .high { color: black; - /* font-weight: 600; */ font-family: 'SUITE-SemiBold'; } @@ -180,7 +182,6 @@ label { .done { color: rgb(236, 236, 236) !important; font-weight: 400 !important; - /* background-color: whitesmoke; */ } @media (max-width: 500px) { From d0b7045d9b01de34318bf13a9a871489c62b0017 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 22:22:38 +0900 Subject: [PATCH 12/13] =?UTF-8?q?docs:=20readme=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 +++++++------------------------------------------------ style.css | 1 + 2 files changed, 9 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 74c6f58..e4d7505 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,11 @@ -# 1주차 미션: Vanilla-Todo +# 배포 -# 서론 +[오대균의 Todo List](https://daegyuns-todo-list.vercel.app/) -안녕하세요 🙌🏻 18기 프론트엔드 운영진 **배성준**입니다. +# Key Feature -이번 미션은 개발 환경 구축과 스터디 진행 방식에 익숙해지실 수 있도록 간단한 **to-do list** 만들기를 진행합니다. 무작정 첫 스터디부터 React를 다루는 것보다는 왜 React가 필요한지, React가 없으면 무엇이 불편한지 느껴 보고 본격적인 스터디에 들어가는 것이 React를 이해하는 데 더 많은 도움이 될 것이라 생각합니다. - -비교적 가벼운 미션인 만큼 코드를 짜는 데 있어 여러분의 **창의성**을 충분히 발휘해 보시기 바랍니다. 작동하기만 하면 되는 것보다 같은 코드를 짜는 여러가지 방식과 패턴에 대해 고민해 보시고, 본인이 생각한 가장 창의적인 방법으로 코드를 작성해 주세요. 여러분이 미션을 수행하는 과정에서 겪는 고민과 생각의 깊이만큼 스터디에서 더 많은 것을 얻어가실 수 있을 것입니다. - -막히는 부분이 있더라도 우선은 스스로 공부하고 찾아보는 방법을 권고드리지만, 운영진의 도움이 필요하시다면 얼마든지 슬랙 Q&A 채널이나 프론트엔드 카톡방에 질문을 남겨 주세요! - -# 미션 - -## 미션 목표 - -- VSCode, Prettier를 이용하여 개발 환경을 관리합니다. -- HTML/CSS의 기초를 이해합니다. -- JavaScript를 이용한 DOM 조작을 이해합니다. -- Vanilla Js를 이용한 어플리케이션 상태 관리 방법을 이해합니다. - -## 기한 - -- 2023년 9월 15일 금요일 - -## Key Questions - -- DOM은 무엇인가요? -- HTML (tag) Element를 JavaScript로 생성하는 방법은 어떤 것이 있고, 어떤 방법이 가장 적합할까요? -- Semantic tag에는 어떤 것이 있으며, 이를 사용하는 이유는 무엇일까요? -- Flexbox Layout은 무엇이며, 어떻게 사용하나요? -- JavaScript가 다른 언어들에 비해 주목할 만한 점에는 어떤 것들이 있나요? -- 코드에서 주석을 다는 바람직한 방법은 무엇일까요? - -## 필수 요건 - -- [결과 화면](https://vanilla-todo-17th-qras.vercel.app/)의 기능을 그대로 구현합니다. -- 결과 링크의 화면 디자인 그대로 구현해도 좋고, 자신만의 디자인을 적용해도 좋습니다. -- CSS의 Flexbox를 이용하여 레이아웃을 구성합니다. -- JQuery, React, Bootstrap 등 외부 라이브러리를 사용하지 않습니다. -- 함수와 변수의 이름은 lowerCamelCase로 짓습니다. -- 코딩의 단위를 기능별로 나누어 Commit 메세지를 작성합니다. - -## 선택 요건 - -- 외부 폰트([눈누 상업용 무료폰트](https://noonnu.cc/))로 입맛에 맞게 꾸밉니다. -- 브라우저의 `localStorage` 혹은 `sessionStorage`를 이용하여 다음 번 접속 시에 기존의 투두 데이터를 불러옵니다. -- 이 외에도 추가하고 싶은 기능이 있다면 마음껏 추가하셔도 됩니다. - -# 링크 및 참고자료 - -- [HTML/CSS 기초](https://heropy.blog/2019/04/24/html-css-starter/) -- [HTML 태그](https://heropy.blog/2019/05/26/html-elements/) -- [FlexBox 가이드](https://heropy.blog/2018/11/24/css-flexible-box/) -- [JS를 통한 DOM 조작](https://velog.io/@bining/javascript-DOM-%EC%A1%B0%EC%9E%91%ED%95%98%EA%B8%B0#append) -- [localStorage, sessionStorage](https://www.daleseo.com/js-web-storage/) -- [git 사용법](https://wayhome25.github.io/git/2017/07/08/git-first-pull-request-story/) -- [좋은 코드리뷰 방법](https://tech.kakao.com/2022/03/17/2022-newkrew-onboarding-codereview/) +- todo 추가, 제거, 완료 +- 중요도 및 기한 설정 +- 중요도 및 기한(시작일)을 기반으로 정렬된 list +- 중요도에 따라 다른 글자색(중요도가 높을 수록 더 진하게) +- 완료된 todo는 list의 가장 아래에 배치, 글자색 매우 연하게 diff --git a/style.css b/style.css index deb4eac..b331c55 100644 --- a/style.css +++ b/style.css @@ -32,6 +32,7 @@ button { all: unset; + cursor: pointer; } body { From 76e5d664404cc05e63c9a9915d982e511981e172 Mon Sep 17 00:00:00 2001 From: DaegyunOh Date: Mon, 11 Sep 2023 22:45:57 +0900 Subject: [PATCH 13/13] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/script.js b/script.js index cf0ac14..d9dea93 100644 --- a/script.js +++ b/script.js @@ -40,15 +40,18 @@ fromDate.addEventListener('change', handleChangeFromDate); // view update function updateView() { while (ul.hasChildNodes()) { + // 기존에 추가됐든 li 삭제 ul.removeChild(ul.firstChild); } for (const todo of TODOS) { + // 업데이트된 todo list 추가 addNewTodoLi(todo); } } // ul에 list들을 삽입 function addNewTodoLi(todo) { + // li에 필요한 element들 선언 const newLi = document.createElement('li'); const contentDiv = document.createElement('div'); const fromDateDiv = document.createElement('div'); @@ -56,7 +59,8 @@ function addNewTodoLi(todo) { const toDateDiv = document.createElement('div'); const doneBtn = document.createElement('button'); const deleteBtn = document.createElement('button'); - new Date().geth; + + // elements의 내용 추가 contentDiv.innerHTML = todo.content; contentDiv.className = 'content'; fromDateDiv.innerHTML = convertDate(todo.fromDate); @@ -70,9 +74,11 @@ function addNewTodoLi(todo) { deleteBtn.innerHTML = '-'; deleteBtn.className = 'deleteBtn'; + // event listener 추가 doneBtn.addEventListener('click', handleClickDoneBtn); deleteBtn.addEventListener('click', handleClickDeleteBtn); + // li에 child node들 추가 newLi.appendChild(contentDiv); newLi.appendChild(fromDateDiv); newLi.appendChild(betweenDiv); @@ -80,8 +86,9 @@ function addNewTodoLi(todo) { newLi.appendChild(doneBtn); newLi.appendChild(deleteBtn); - newLi.id = todo.idx; - newLi.classList.add('todoLi'); + newLi.id = todo.idx; // 정렬을 위한 id 추가 + // 각종 className 추가 + newLi.classList.add('todoLi'); if (todo.priority === 3) newLi.classList.add('high'); else if (todo.priority === 2) newLi.classList.add('mid'); else newLi.classList.add('low'); @@ -90,18 +97,18 @@ function addNewTodoLi(todo) { ul.appendChild(newLi); } -// 기준에 따라 정렬되어 memory에 저장되도록 push +// 기준에 따라 정렬되어 memory에 저장되도록 push, push할 때만 정렬하면 따로 정렬과정 거치지 않아도 됨 function pushTodo(todo) { - if (todo.isDone) { + if (todo.isDone) { // 완료한 todo는 맨 뒤에 위치 TODOS.splice(TODOS.length, 0, todo); return; } let i = 0; for (; i < TODOS.length; i++) { - if (TODOS[i].isDone) break; - if (TODOS[i].priority < todo.priority) break; - else if (TODOS[i].priority === todo.priority) { - if (TODOS[i].fromDate >= todo.fromDate) break; + if (TODOS[i].isDone) break; // 완료한 todo보다 무조건 앞에 위치 + if (TODOS[i].priority < todo.priority) break; // priority가 더 높으면 그 앞에 위치 + else if (TODOS[i].priority === todo.priority) { // priority가 같다면 + if (TODOS[i].fromDate >= todo.fromDate) break; // 시작일이 빠른 todo가 더 낲에 위치 } } TODOS.splice(i, 0, todo); @@ -117,9 +124,11 @@ function convertDate(date) { function handleClickDoneBtn(e) { const idx = e.currentTarget.parentNode.id; const clickedLi = document.getElementById(idx); + // class 추가/제거 if (clickedLi.classList.contains('done')) clickedLi.classList.remove('done'); else clickedLi.classList.add('done'); + // TODOS에 저장된 todo 객체 수정 let i; for (i = 0; i < TODOS.length; i++) { if (TODOS[i].idx == idx) { @@ -128,10 +137,10 @@ function handleClickDoneBtn(e) { } } const todo = TODOS[i]; - TODOS.splice(i, 1); - pushTodo(todo); - updateView(); + TODOS.splice(i, 1); // 해당 todo를 삭제한 후 + pushTodo(todo); // 새롭게 추가(정렬을 위해) + updateView(); // 화면 업데이트 localStorage.setItem('todos', JSON.stringify(TODOS)); } @@ -139,13 +148,13 @@ function handleClickDoneBtn(e) { function handleClickDeleteBtn(e) { const idx = e.currentTarget.parentNode.id; const clickedLi = document.getElementById(idx); - ul.removeChild(clickedLi); + ul.removeChild(clickedLi); // 클릭한 todo 삭제 let i; for (i = 0; i < TODOS.length; i++) { if (TODOS[i].idx == idx) break; } - TODOS.splice(i, 1); + TODOS.splice(i, 1); // TODOS 에서도 삭제 localStorage.setItem('todos', JSON.stringify(TODOS)); } @@ -153,20 +162,23 @@ function handleClickDeleteBtn(e) { // add button click event handler function handleClickAddBtn() { const newTodo = {}; + // 각종 input element들 참조 const content = document.querySelector('.contentInput'); const priorities = document.querySelectorAll("input[name='priority']"); const fromDate = document.querySelector('.from'); const toDate = document.querySelector('.to'); + // input들의 value값을 newTodo에 저장 if (!content.value) return; newTodo.idx = nextIdx++; newTodo.content = content.value; priorities.forEach((priority) => { if (priority.checked) { - newTodo.priority = Number(priority.value); + newTodo.priority = Number(priority.value); // radio box에서 체크된 priority를 선택 return; } }); + // 에러가 발생하지 않도록 삼항연산자로 분기 newTodo.fromDate = fromDate.value ? new Date(fromDate.value) : new Date(); newTodo.toDate = toDate.value ? new Date(toDate.value) : new Date(); newTodo.isDone = false; @@ -175,6 +187,7 @@ function handleClickAddBtn() { updateView(); localStorage.setItem('todos', JSON.stringify(TODOS)); + // input value들을 초기화 content.value = null; priorities[0].checked = true; fromDate.value = null;