feat: add todo UI componenets

This commit is contained in:
Mike 2024-01-04 00:42:30 -05:00
parent 65064cabe2
commit 3305e39bf2
4 changed files with 312 additions and 66 deletions

View file

@ -1,3 +1,5 @@
import { getActiveProject } from "..";
function navbar(projects) { function navbar(projects) {
let nav = document.createElement('nav'); let nav = document.createElement('nav');
nav.classList.add('nav'); nav.classList.add('nav');
@ -17,7 +19,8 @@ function navbar(projects) {
} }
function projectButtons(projects) { function projectButtons(projects) {
let projectsDiv = document.createElement('div'); const projectsDiv = document.createElement('div');
const activeProject = getActiveProject();
projectsDiv.classList.add(['projects']); projectsDiv.classList.add(['projects']);
projects.forEach(e => { projects.forEach(e => {
@ -44,8 +47,9 @@ function projectButtons(projects) {
// delete button // delete button
btn.classList.add('btn', 'project-btn'); btn.classList.add('btn', 'project-btn');
if (e.name === activeProject) {
btn.addEventListener('click', activeProjectBtn); btn.classList += ' active';
};
btn.appendChild(iTag); btn.appendChild(iTag);
btn.appendChild(btnSpan); 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 }; export { navbar };

View file

@ -1,46 +1,151 @@
import { setActiveProject, updateDisplay } from ".."; import { getActiveProject, setActiveProject, updateDisplay } from "..";
import { save } from "./storage"; import { save } from "./storage";
function todoTableComponent(todos) { function todoTableComponent(todos) {
const div = document.createElement('div'); const div = document.createElement('div');
div.classList.add('todos'); 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) { if (todos.length > 0) {
const table = document.createElement('table'); const table = document.createElement('table');
table.classList.add(['table']); table.classList.add(['table']);
todos.forEach(element => { todos.forEach(element => {
const tr = document.createElement('tr'); const tr = createTableRow(element);
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);
table.appendChild(tr); table.appendChild(tr);
}); });
div.appendChild(table); div.appendChild(table);
} else { } else {
div.textContent = 'All tasks completed';
const p = document.createElement('p')
p.textContent = 'All tasks completed';
div.appendChild(p);
} }
div.appendChild(addTodoButton);
return div; 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() { function projectComponent() {
const div = document.createElement('div'); const div = document.createElement('div');
const input = document.createElement('input'); const input = document.createElement('input');
@ -50,9 +155,9 @@ function projectComponent() {
div.classList.add('project-add'); div.classList.add('project-add');
input.classList.add('project-input-name'); input.classList.add('project-input-name');
cancelButton.classList.add('cancel-project-btn'); cancelButton.classList.add('cancel-btn');
submitButton.classList.add('submit-project-btn'); submitButton.classList.add('submit-btn');
buttonDiv.classList.add('project-buttons'); buttonDiv.classList.add('popup-buttons');
input.placeholder = 'Project name...'; input.placeholder = 'Project name...';
submitButton.textContent = 'Submit'; submitButton.textContent = 'Submit';
@ -66,27 +171,34 @@ function projectComponent() {
return div; return div;
} }
function addProject(proj) { function addProject(todoHandler) {
const button = document.querySelector('.add-project-btn'); 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 div = document.querySelector('.project-add');
const submitButton = div.querySelector('.submit-btn')
const cancelButton = div.querySelector('.cancel-btn');
const input = document.querySelector('.project-input-name'); const input = document.querySelector('.project-input-name');
button.addEventListener('click', () => div.classList.add('project-add-active')); button.addEventListener('click', () => {
cancelButton.addEventListener('click', () => div.classList.remove('project-add-active')); 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', () => { submitButton.addEventListener('click', () => {
let name = input.value; let name = input.value;
// Add project via the global todos component // Add project via the global todos component
proj.addProject(name); todoHandler.addProject(name);
div.classList.remove('project-add-active'); div.classList.remove('project-add-active');
setActiveProject(name);
updateDisplay(); updateDisplay();
save(proj.getEverything()); save(todoHandler.getEverything());
}); });
} }
function deleteProject(proj) { function deleteProject(todoHandler) {
const deleteButtons = document.querySelectorAll('.project-delete-btn'); const deleteButtons = document.querySelectorAll('.project-delete-btn');
deleteButtons.forEach(e => { deleteButtons.forEach(e => {
@ -94,9 +206,9 @@ function deleteProject(proj) {
// prevent this click from bubbling into button clicks // prevent this click from bubbling into button clicks
element.stopPropagation(); element.stopPropagation();
let projectName = element.target.parentNode.parentNode.dataset.projectName; let projectName = element.target.parentNode.parentNode.dataset.projectName;
proj.delProject(projectName); todoHandler.delProject(projectName);
setActiveProject('default'); setActiveProject('default');
save(proj.getEverything()); save(todoHandler.getEverything());
// Always load default project after deleting // Always load default project after deleting
updateDisplay(); 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
};

View file

@ -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 { navbar } from "./components/navbar";
import { todoHandler as todoManager } from "./components/todo"; import { todoHandler as todoManager } from "./components/todo";
import { save, load } from "./components/storage"; import { save, load } from "./components/storage";
import './style.css'; import './style.css';
import { add } from "date-fns";
const data = load(); const data = load();
let todos = data ? new todoManager(JSON.parse(data)) : new todoManager(); let todos = data ? new todoManager(JSON.parse(data)) : new todoManager();
let activeProject; let activeProject = 'default';
function setActiveProject(value) { function setActiveProject(value) {
activeProject = value; activeProject = value;
} }
function getActiveProject() {
return activeProject;
}
function fontAwesome() { function fontAwesome() {
let script = document.createElement('script'); let script = document.createElement('script');
script.src = 'https://kit.fontawesome.com/24f16b96cf.js'; script.src = 'https://kit.fontawesome.com/24f16b96cf.js';
@ -34,19 +48,23 @@ function updateDisplay() {
// ensure grabbing latest projects // ensure grabbing latest projects
let projects = todos.getProjects(); let projects = todos.getProjects();
let currentActiveProject = activeProject || 'default'; let currentActiveProject = activeProject;
let todosToRender = todos.getTodosFromProject(currentActiveProject); let todosToRender = todos.getTodosFromProject(currentActiveProject);
const _navbar = navbar(projects); const _navbar = navbar(projects);
const _addProject = projectComponent(); const _addProject = projectComponent();
const _todoComponent = addTodoComponent();
const _todos = todoTableComponent(todosToRender); const _todos = todoTableComponent(todosToRender);
_navbar.appendChild(_addProject); _navbar.appendChild(_addProject);
_todos.appendChild(_todoComponent);
div.appendChild(_navbar); div.appendChild(_navbar);
div.appendChild(_todos); div.appendChild(_todos);
document.body.appendChild(div); document.body.appendChild(div);
getTodoFromActiveProject(); getTodoFromActiveProject();
addTodo(todos);
deleteTodo(todos);
addProject(todos); addProject(todos);
deleteProject(todos); deleteProject(todos);
} }
@ -55,4 +73,4 @@ fontAwesome();
website(); website();
save(todos.getEverything()); save(todos.getEverything());
export { setActiveProject, updateDisplay }; export { getActiveProject, setActiveProject, updateDisplay };

View file

@ -1,5 +1,4 @@
:root { :root {
--color: 1234;
--font-size: 18px; --font-size: 18px;
} }
@ -8,11 +7,17 @@ html {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: var(--font-size); font-size: var(--font-size);
line-height: 1.5; line-height: 1.7;
} }
table { table {
width: 100%; width: 100%;
margin-bottom: 30px;
padding: 0 5px;
}
tr {
height: 2em;
} }
button { button {
@ -25,6 +30,16 @@ button {
font-size: 1rem; 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 { .container {
display: flex; display: flex;
} }
@ -77,12 +92,12 @@ button {
} }
.project-buttons { .popup-buttons {
display: flex; display: flex;
gap: 10px; gap: 10px;
} }
.project-buttons button { .popup-buttons button {
width: 100%; width: 100%;
margin: 10px 0; margin: 10px 0;
} }
@ -95,4 +110,64 @@ button {
.todos { .todos {
flex: 1; 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; */
/* } */