diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..64a14d8
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1616478436556
+
+
+ 1616478436556
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1616743594750
+
+
+
+ 1616743594750
+
+
+ 1616744018643
+
+
+
+ 1616744018643
+
+
+ 1616744362700
+
+
+
+ 1616744362700
+
+
+ 1616751914957
+
+
+
+ 1616751914957
+
+
+ 1616773460749
+
+
+
+ 1616773460749
+
+
+ 1616834916360
+
+
+
+ 1616834916360
+
+
+ 1616834969396
+
+
+
+ 1616834969396
+
+
+ 1616847328440
+
+
+
+ 1616847328440
+
+
+ 1616848370331
+
+
+
+ 1616848370331
+
+
+ 1616848810154
+
+
+
+ 1616848810154
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 36372ce..8a256b2 100644
--- a/README.md
+++ b/README.md
@@ -27,13 +27,12 @@
## 🎯 요구사항
-- [ ] todo list에 todoItem을 키보드로 입력하여 추가하기
-- [ ] todo list의 체크박스를 클릭하여 complete 상태로 변경. (li tag 에 completed class 추가, input 태그에 checked 속성 추가)
-- [ ] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제
-- [ ] todo list를 더블클릭했을 때 input 모드로 변경. (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면 수정되지 않은 채로 다시 view 모드로 복귀
-- [ ] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기
-- [ ] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기
-- [ ] localStorage에 데이터를 저장하여, TodoItem의 CRUD를 반영하기. 따라서 새로고침하여도 저장된 데이터를 확인할 수 있어야 함
+- [x] todo list에 todoItem을 키보드로 입력하여 추가하기
+- [x] todo list의 체크박스를 클릭하여 complete 상태로 변경 (li tag 에 completed class 추가, input 태그에 checked 속성 추가)
+- [x] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제
+- [x] todo list를 더블클릭했을 때 input 모드로 변경 (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면 수정되지 않은 채로 다시 view 모드로 복귀
+- [x] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기
+- [x] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기
diff --git a/index.html b/index.html
index c1d9095..b095706 100644
--- a/index.html
+++ b/index.html
@@ -1,10 +1,11 @@
-
+
@@ -19,16 +20,15 @@
TODOS
diff --git a/src/js/store/todoListStore.js b/src/js/store/todoListStore.js
new file mode 100644
index 0000000..6a93b02
--- /dev/null
+++ b/src/js/store/todoListStore.js
@@ -0,0 +1,47 @@
+export {addTodoItem, updateTodoItem, removeTodoItem, findById, toggleStateTodoItem, deepCopyStore}
+
+const todoListStore = [];
+
+const EMPTY_STRING = "";
+
+function deepCopyStore() {
+ return JSON.parse(JSON.stringify(todoListStore));
+}
+
+function createTodoItem(id, title = EMPTY_STRING, state = "active") {
+ return {id: `i-${id}`, title: title, state: state}
+}
+
+function addTodoItem(id, title = EMPTY_STRING) {
+ todoListStore.push(createTodoItem(id, title));
+}
+
+function updateTodoItem(id, insert = EMPTY_STRING) {
+ findById(id).title = insert;
+}
+
+function findById(id) {
+ if (todoListStore.some(item => item.id === id)) {
+ return todoListStore.find(item => item.id === id);
+ } else {
+ throw `${id}라는 ID를 가진 요소가 없습니다!`;
+ }
+}
+
+function removeTodoItem(id) {
+ const index = todoListStore.findIndex(item => item.id === id);
+ if (index !== -1) {
+ todoListStore.splice(index, 1);
+ } else {
+ throw `${id}라는 ID를 가진 요소가 없습니다!`;
+ }
+}
+
+function toggleStateTodoItem(id) {
+ const element = findById(id);
+ if (element.state === "completed") {
+ element.state = "active";
+ } else {
+ element.state = "completed";
+ }
+}
diff --git a/src/js/store/todoListStoreAccessor.js b/src/js/store/todoListStoreAccessor.js
new file mode 100644
index 0000000..2917245
--- /dev/null
+++ b/src/js/store/todoListStoreAccessor.js
@@ -0,0 +1,57 @@
+import {addTodoItem, removeTodoItem, deepCopyStore, toggleStateTodoItem, updateTodoItem} from './todoListStore.js';
+import itemTemplate from "../template/todoItemTemplate.js";
+import countTemplate from "../template/todoCountTemplate.js";
+
+export {execute, renderTodoList}
+
+const EMPTY_STRING = "";
+
+function execute(command, {id, title}, state) {
+ switch (command) {
+ case "add" :
+ addTodoItem(id, title);
+ break;
+ case "update" :
+ updateTodoItem(id, title);
+ break;
+ case "delete" :
+ removeTodoItem(id);
+ break;
+ case "toggle" :
+ toggleStateTodoItem(id);
+ break;
+ default :
+ throw `가능한 명령 : add, update, delete, toggle / 입력된 명령: ${command}`;
+ }
+ renderTodoList(state);
+}
+
+function renderTodoList(state) {
+ const todoListElement = document.querySelector(".todo-list");
+ todoListElement.innerHTML = EMPTY_STRING;
+ visibleTotoList(state).forEach(
+ item => todoListElement.insertAdjacentHTML("beforeend", itemTemplate(item.id, item.title, item.state))
+ )
+
+ const countContainerElement = document.querySelector(".count-container");
+ if (countContainerElement.querySelector(".todo-count")) {
+ countContainerElement.querySelector(".todo-count").remove();
+ }
+ countContainerElement.insertAdjacentHTML("afterbegin", createCountTemplate(state));
+}
+
+function visibleTotoList(state) {
+ if (state && state !== "all") {
+ return deepCopyStore().filter(item => item.state === state);
+ } else {
+ return deepCopyStore();
+ }
+}
+
+function createCountTemplate(state) {
+ if (state === "completed") {
+ return countTemplate(deepCopyStore().filter(item => item.state === state).length);
+ } else {
+ return countTemplate(deepCopyStore().length);
+ }
+}
\ No newline at end of file
diff --git a/src/js/template/todoCountTemplate.js b/src/js/template/todoCountTemplate.js
new file mode 100644
index 0000000..ec88f6e
--- /dev/null
+++ b/src/js/template/todoCountTemplate.js
@@ -0,0 +1,4 @@
+export default function (count) {
+ return `
총 ${count} 개 `
+}
+
diff --git a/src/js/template/todoItemTemplate.js b/src/js/template/todoItemTemplate.js
new file mode 100644
index 0000000..ef7dd74
--- /dev/null
+++ b/src/js/template/todoItemTemplate.js
@@ -0,0 +1,11 @@
+export default function itemTemplate(id, title, state) {
+ return `
+
+
+ ${title}
+
+
+
+ `
+}
+
diff --git a/src/js/todoList.js b/src/js/todoList.js
new file mode 100644
index 0000000..b9197b6
--- /dev/null
+++ b/src/js/todoList.js
@@ -0,0 +1,80 @@
+import {execute, renderTodoList} from './store/todoListStoreAccessor.js';
+
+const $todoInput = document.querySelector("#new-todo-title");
+const $toggleParentList = document.querySelector(".todo-list");
+const $filterList = document.querySelector(".filters");
+
+const EMPTY_STRING = "";
+
+$todoInput.addEventListener("keyup", onAddTodoItem);
+
+$toggleParentList.addEventListener("keyup", onEditTodoItem)
+$toggleParentList.addEventListener("click", onClickTodoItem);
+$toggleParentList.addEventListener("dblclick", onEditModeTodoItem);
+
+$filterList.addEventListener("click", onClickFilter);
+
+function onAddTodoItem(event) {
+ const todoTitle = event.target.value;
+ if (event.key === "Enter" && todoTitle !== "") {
+ execute("add", {id: Date.now(), title: todoTitle}, getState());
+ event.target.value = EMPTY_STRING;
+ }
+}
+
+function onClickTodoItem(event) {
+ onToggleTodoItem(event);
+ onRemoveTodoItem(event);
+}
+
+function onRemoveTodoItem(event) {
+ if (event.target && event.target.className === "destroy") {
+ execute("delete", {id: getOnEventClosestTodoItemId(event)}, getState());
+ }
+}
+
+function onEditModeTodoItem(event) {
+ event.target.closest(".todo-item").classList.add("editing");
+}
+
+function onEditTodoItem(event) {
+ if (event.target && event.target.className === "edit") {
+ const todoTitle = event.target.value;
+
+ if (event.key === "Enter" && todoTitle !== "") {
+ execute("update", {id: getOnEventClosestTodoItemId(event), title: todoTitle}, getState());
+ } else if (event.key === "Escape") {
+ renderTodoList(getState());
+ }
+ }
+}
+
+function getOnEventClosestTodoItemId(event) {
+ return event.target.closest(".todo-item").id;
+}
+
+function onToggleTodoItem(event) {
+ if (event.target && event.target.className === "toggle") {
+ execute("toggle", {id: getOnEventClosestTodoItemId(event)}, getState());
+ }
+}
+
+function onClickFilter(event) {
+ if (event.target.classList.contains("filter-item")) {
+ const $filterItems = event.target.closest(".filters").querySelectorAll("li>a");
+ $filterItems.forEach(item => item.classList.remove("selected"));
+ event.target.classList.add("selected");
+ renderTodoList(getState());
+ }
+}
+
+function getState() {
+ let state = "";
+ $filterList.querySelector(".selected").classList
+ .forEach(className => {
+ if (className !== "filter-item" && className !== "selected") {
+ state = className;
+ }
+ });
+ return state;
+}
\ No newline at end of file