diff --git a/todo/src/components/navbar.js b/todo/src/components/navbar.js index 31928bc..8e27237 100644 --- a/todo/src/components/navbar.js +++ b/todo/src/components/navbar.js @@ -1,3 +1,5 @@ +import { getActiveProject } from ".."; + function navbar(projects) { let nav = document.createElement('nav'); nav.classList.add('nav'); @@ -17,7 +19,8 @@ function navbar(projects) { } function projectButtons(projects) { - let projectsDiv = document.createElement('div'); + const projectsDiv = document.createElement('div'); + const activeProject = getActiveProject(); projectsDiv.classList.add(['projects']); projects.forEach(e => { @@ -44,8 +47,9 @@ function projectButtons(projects) { // delete button btn.classList.add('btn', 'project-btn'); - - btn.addEventListener('click', activeProjectBtn); + if (e.name === activeProject) { + btn.classList += ' active'; + }; btn.appendChild(iTag); btn.appendChild(btnSpan); @@ -68,22 +72,4 @@ function addProject() { } -function activeProjectBtn() { - const projectContainer = document.querySelector('.projects'); - const btns = projectContainer.querySelectorAll('.project-btn'); - - - for (let i=0; i < btns.length; i++) { - - let current = document.getElementsByClassName('active'); - - if (current.length > 0) { - current[0].className = current[0].className.replace(' active', ''); - } - - this.className += ' active'; - }; -} - - export { navbar }; diff --git a/todo/src/components/todoComponent.js b/todo/src/components/todoComponent.js index 6f51e54..5650698 100644 --- a/todo/src/components/todoComponent.js +++ b/todo/src/components/todoComponent.js @@ -1,46 +1,151 @@ -import { setActiveProject, updateDisplay } from ".."; +import { getActiveProject, setActiveProject, updateDisplay } from ".."; import { save } from "./storage"; function todoTableComponent(todos) { const div = document.createElement('div'); div.classList.add('todos'); + const heading = document.createElement('h1'); + heading.classList.add('todo-heading'); + heading.textContent = getActiveProject(); + + const addTodoButton = document.createElement('button'); + const iTag = document.createElement('i'); + const span = document.createElement('span'); + + iTag.classList.add('fas', 'fa-plus', 'itag'); + span.textContent = 'Add Todo'; + addTodoButton.append(iTag, span); + addTodoButton.classList.add('add-todo-btn'); + + div.appendChild(heading); + if (todos.length > 0) { + const table = document.createElement('table'); table.classList.add(['table']); todos.forEach(element => { - const tr = document.createElement('tr'); - const tdTitle = document.createElement('td'); - const tdDesc = document.createElement('td'); - const tdDueDate = document.createElement('td'); - const tdPomodoro = document.createElement('td'); - const tdCompleted = document.createElement('td'); - - tr.classList.add('todo-row'); - tr.dataset.todoId = element.title; - tdTitle.textContent = element.title; - tdDesc.textContent = element.description; - tdDueDate.textContent = element.dueDate; - tdPomodoro.textContent = element.pomodoros; - tdCompleted.textContent = element.completed; - - tr.appendChild(tdTitle); - tr.appendChild(tdDesc); - tr.appendChild(tdDueDate); - tr.appendChild(tdPomodoro); - tr.appendChild(tdCompleted); - + const tr = createTableRow(element); table.appendChild(tr); }); div.appendChild(table); + } else { - div.textContent = 'All tasks completed'; + + const p = document.createElement('p') + p.textContent = 'All tasks completed'; + + div.appendChild(p); } + + div.appendChild(addTodoButton); + return div; } +function createTableCell(content) { + let cell = document.createElement('td'); + + if (typeof content !== 'object') { + cell.textContent = content; + } else { + cell.appendChild(content); + } + + return cell; +} + +function createTableCheckBox(content) { + let checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.classList.add('todo-checkbox'); + checkbox.checked = content; + return checkbox; +} + +function createTableTodoDeleteBtn() { + const button = document.createElement('button'); + button.classList.add('todo-delete-btn'); + + let closeITag = document.createElement('i') + closeITag.classList.add('fa', 'fa-trash'); + + button.appendChild(closeITag) + + return button; + +} + +function createTableRow(_todo) { + const tr = document.createElement('tr'); + tr.classList.add('todo-row'); + tr.dataset.todoId = _todo.title; + + let checkbox = createTableCheckBox(_todo.completed); + const cells = [ + createTableCell(checkbox), + createTableCell(_todo.title), + createTableCell(_todo.description), + createTableCell(_todo.dueDate), + createTableCell(createTableTodoDeleteBtn()) + // createTableCell(_todo.pomodoros) + ] + + cells.forEach(cell => tr.appendChild(cell)); + + return tr; +} + +function addTodo(todoHandler) { + const activeProject = getActiveProject(); + const button = document.querySelector('.add-todo-btn'); + const div = document.querySelector('.todo-add'); + const submitButton = div.querySelector('.submit-btn') + const cancelButton = div.querySelector('.cancel-btn'); + const input = document.querySelector('.todo-add-inputs'); + + button.addEventListener('click', () => { + div.classList.add('todo-add-active') + button.style.display = 'none'; + }); + cancelButton.addEventListener('click', () => { + div.classList.remove('todo-add-active') + button.style.display = 'inline-block'; + }); + submitButton.addEventListener('click', () => { + let newTodo = handleTodoInput(input.childNodes); + let title = newTodo[0]; + let description = newTodo[1]; + let date = Date(newTodo[2]); + todoHandler.addTodo(activeProject, title, description, date, 0); + div.classList.remove('todo-add-active'); + updateDisplay(); + save(todoHandler.getEverything()); + }); +} + +function handleTodoInput(input) { + return [...input].map(element => element.value); +} + +function deleteTodo(todoHandler) { + const deleteButtons = document.querySelectorAll('.todo-delete-btn'); + + deleteButtons.forEach(e => { + e.addEventListener('click', element => { + let activeProject = getActiveProject(); + let todoTitle = element.target.parentNode.parentNode.parentNode.dataset.todoId; + + todoHandler.deleteTodo(activeProject, todoTitle); + save(todoHandler.getEverything()); + updateDisplay(); + }); + }); + +} + function projectComponent() { const div = document.createElement('div'); const input = document.createElement('input'); @@ -50,9 +155,9 @@ function projectComponent() { div.classList.add('project-add'); input.classList.add('project-input-name'); - cancelButton.classList.add('cancel-project-btn'); - submitButton.classList.add('submit-project-btn'); - buttonDiv.classList.add('project-buttons'); + cancelButton.classList.add('cancel-btn'); + submitButton.classList.add('submit-btn'); + buttonDiv.classList.add('popup-buttons'); input.placeholder = 'Project name...'; submitButton.textContent = 'Submit'; @@ -66,27 +171,34 @@ function projectComponent() { return div; } -function addProject(proj) { +function addProject(todoHandler) { const button = document.querySelector('.add-project-btn'); - const submitButton = document.querySelector('.submit-project-btn') - const cancelButton = document.querySelector('.cancel-project-btn'); const div = document.querySelector('.project-add'); + const submitButton = div.querySelector('.submit-btn') + const cancelButton = div.querySelector('.cancel-btn'); const input = document.querySelector('.project-input-name'); - button.addEventListener('click', () => div.classList.add('project-add-active')); - cancelButton.addEventListener('click', () => div.classList.remove('project-add-active')); + button.addEventListener('click', () => { + div.classList.add('project-add-active') + button.style.display = 'none'; + }); + cancelButton.addEventListener('click', () => { + div.classList.remove('project-add-active') + button.style.display = 'block'; + }); submitButton.addEventListener('click', () => { let name = input.value; // Add project via the global todos component - proj.addProject(name); + todoHandler.addProject(name); div.classList.remove('project-add-active'); + setActiveProject(name); updateDisplay(); - save(proj.getEverything()); + save(todoHandler.getEverything()); }); } -function deleteProject(proj) { +function deleteProject(todoHandler) { const deleteButtons = document.querySelectorAll('.project-delete-btn'); deleteButtons.forEach(e => { @@ -94,9 +206,9 @@ function deleteProject(proj) { // prevent this click from bubbling into button clicks element.stopPropagation(); let projectName = element.target.parentNode.parentNode.dataset.projectName; - proj.delProject(projectName); + todoHandler.delProject(projectName); setActiveProject('default'); - save(proj.getEverything()); + save(todoHandler.getEverything()); // Always load default project after deleting updateDisplay(); }); @@ -124,5 +236,60 @@ function getTodoFromActiveProject() { } } +function addTodoComponent() { + const div = document.createElement('div'); + div.classList.add('todo-add'); -export { getTodoFromActiveProject, projectComponent, todoTableComponent, addProject, deleteProject }; + const inputDiv = document.createElement('div'); + inputDiv.classList.add('todo-add-inputs'); + + const titleInput = document.createElement('input'); + titleInput.classList.add('todo-input-name'); + titleInput.placeholder = 'Todo title..'; + titleInput.required = true; + + const descriptionInput = document.createElement('input'); + descriptionInput.classList.add('todo-input-desc'); + descriptionInput.placeholder = 'Todo description..'; + + const dueDateInput = document.createElement('input'); + dueDateInput.classList.add('todo-input-duedate'); + dueDateInput.type = 'date'; + + const pomodoroInput = document.createElement('input'); + pomodoroInput.classList.add('todo-input-pomodoro'); + pomodoroInput.type = ''; + + const cancelButton = document.createElement('button'); + cancelButton.classList.add('cancel-btn'); + cancelButton.textContent = 'Cancel'; + + const submitButton = document.createElement('button'); + submitButton.classList.add('submit-btn'); + submitButton.textContent = 'Submit'; + + const buttonDiv = document.createElement('div'); + buttonDiv.classList.add('popup-buttons'); + + inputDiv.append(titleInput, descriptionInput, dueDateInput); + buttonDiv.append(submitButton, cancelButton) + div.append( + inputDiv, + buttonDiv + ); + + return div; +} + + +export { + addTodoComponent, + getTodoFromActiveProject, + projectComponent, + todoTableComponent, + addProject, + deleteProject, + addTodo, + deleteTodo + +}; diff --git a/todo/src/index.js b/todo/src/index.js index 7113cdb..b57b6a0 100644 --- a/todo/src/index.js +++ b/todo/src/index.js @@ -1,18 +1,32 @@ -import { addProject, deleteProject, projectComponent, todoTableComponent, getTodoFromActiveProject } from "./components/todoComponent"; +import { + addTodo, + deleteTodo, + addProject, + deleteProject, + projectComponent, + todoTableComponent, + getTodoFromActiveProject, + addTodoComponent, + } from "./components/todoComponent"; import { navbar } from "./components/navbar"; import { todoHandler as todoManager } from "./components/todo"; import { save, load } from "./components/storage"; import './style.css'; +import { add } from "date-fns"; const data = load(); let todos = data ? new todoManager(JSON.parse(data)) : new todoManager(); -let activeProject; +let activeProject = 'default'; function setActiveProject(value) { activeProject = value; } +function getActiveProject() { + return activeProject; +} + function fontAwesome() { let script = document.createElement('script'); script.src = 'https://kit.fontawesome.com/24f16b96cf.js'; @@ -34,19 +48,23 @@ function updateDisplay() { // ensure grabbing latest projects let projects = todos.getProjects(); - let currentActiveProject = activeProject || 'default'; + let currentActiveProject = activeProject; let todosToRender = todos.getTodosFromProject(currentActiveProject); const _navbar = navbar(projects); const _addProject = projectComponent(); + const _todoComponent = addTodoComponent(); const _todos = todoTableComponent(todosToRender); _navbar.appendChild(_addProject); + _todos.appendChild(_todoComponent); div.appendChild(_navbar); div.appendChild(_todos); document.body.appendChild(div); getTodoFromActiveProject(); + addTodo(todos); + deleteTodo(todos); addProject(todos); deleteProject(todos); } @@ -55,4 +73,4 @@ fontAwesome(); website(); save(todos.getEverything()); -export { setActiveProject, updateDisplay }; +export { getActiveProject, setActiveProject, updateDisplay }; diff --git a/todo/src/style.css b/todo/src/style.css index c59a801..17f7575 100644 --- a/todo/src/style.css +++ b/todo/src/style.css @@ -1,5 +1,4 @@ :root { - --color: 1234; --font-size: 18px; } @@ -8,11 +7,17 @@ html { margin: 0; padding: 0; font-size: var(--font-size); - line-height: 1.5; + line-height: 1.7; } table { width: 100%; + margin-bottom: 30px; + padding: 0 5px; +} + +tr { + height: 2em; } button { @@ -25,6 +30,16 @@ button { font-size: 1rem; } +input[type="checkbox"] { + /* appearance: none; */ + /* For iOS < 15 to remove gradient background */ + /* background-color: #fff; */ + /* Not removed via appearance */ + /* margin: 0; */ + width: 1.2rem; + height: 1.2rem; +} + .container { display: flex; } @@ -77,12 +92,12 @@ button { } -.project-buttons { +.popup-buttons { display: flex; gap: 10px; } -.project-buttons button { +.popup-buttons button { width: 100%; margin: 10px 0; } @@ -95,4 +110,64 @@ button { .todos { flex: 1; + padding: 0 20px; + margin: 0 20px; + display: flex; + flex-direction: column; + } + +.todos p { + text-align: center; +} + +.todo-add { + display: none; + width: 100%; +} + +.todo-add-active { + display: flex; + flex-direction: column; + padding: 15px 10px; + width: 100%; +} + +.todo-add input { + padding: 10px; +} + +.todo-add-inputs { + display: flex; + gap: 10px; +} + +.todo-add-inputs input { + flex: 1 1 auto; +} + +.todo-delete-btn { + visibility: hidden; + background: none; + width: auto; + padding: 0; + margin: 0; +} + +.todo-row:hover .todo-delete-btn { + visibility: visible; +} + +.add-todo-btn { + width: initial; +} + +/* .todo-buttons { */ +/* display: flex; */ +/* gap: 10px; */ +/* } */ +/**/ +/* .todo-buttons button { */ +/* width: 100%; */ +/* margin: 10px 0; */ +/* } */