mirror of
https://gitea.smigz.com/smiggiddy/odin-codeprojects.git
synced 2024-12-26 14:20:43 -05:00
feat: add todo UI componenets
This commit is contained in:
parent
65064cabe2
commit
3305e39bf2
4 changed files with 312 additions and 66 deletions
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
|
||||
};
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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; */
|
||||
/* } */
|
||||
|
|
Loading…
Reference in a new issue