Simple TODO app in javascript
Project Layout
tp-git-lint/
app.js
button.js
index.html
img/
img files for button displays
app.js
"use strict";
/**
* This script manages a task list with favorites functionality.
*/
// Selecting DOM elements
const taskInput = document.querySelector('input.task');
const lists = document.querySelector('.lists');
const favsSection = document.querySelector('.favs');
const favTitle = document.querySelector('.favs h3');
const favs = document.querySelector('.favs ul');
const favsItems = favs.children;
const tasksSection = document.querySelector('.tasks');
const tasksTitle = document.querySelector('.tasks h3');
const tasks = document.querySelector('.tasks ul');
const taskItems = tasks.children;
// Hide favorites section if no favorites
if ( favsItems.length === 0 ) {
favsSection.style.display = 'none';
}
// Hide tasks section if no tasks
if ( taskItems.length === 0 ) {
tasksSection.style.display = "none";
}
// Event listener for adding tasks
taskInput.addEventListener('keyup', (e) => {
if (e.keyCode === 13) {
let li = document.createElement('li');
if (taskInput.value === "") {
alert("Please add a task");
} else {
li.textContent = taskInput.value;
attachButton(li);
tasks.appendChild(li);
tasksTitle.style.display = '';
taskInput.value = '';
tasksTitle.textContent = "Inbox";
tasksSection.style.display = "";
}
}
});
// Event listener for click events on task/favorites list
lists.addEventListener('click', (event) => {
const tag = event.target.tagName;
const basevalue = event.target.className.baseVal;
const clickArea1 = event.target.parentNode.parentNode.parentNode.parentNode.className;
const clickArea2 = event.target.parentNode.parentNode.parentNode.parentNode.parentNode.className;
const clickArea3 = event.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.className;
// Checking if buttons inside tasks section is clicked
if ( clickArea1 === 'tasks' || clickArea2 === 'tasks' || clickArea3 === 'tasks' ) {
if (tag === 'svg') {
if (basevalue === 'delete' || basevalue === 'can' || basevalue === 'cap' || basevalue === 'bin') {
let li = event.target.parentNode.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
} else if ( basevalue === 'fav') {
let li = event.target.parentNode.parentNode;
let ul = li.parentNode;
favsSection.style.display = '';
favs.appendChild(li);
favTitle.textContent = "Favorites";
}
if ( taskItems.length === 0 ) {
tasksSection.style.display = "none";
}
} else if (tag === 'path') {
if (basevalue === 'delete' || basevalue === 'can' || basevalue === 'cap' || basevalue === 'bin') {
let li = event.target.parentNode.parentNode.parentNode.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
} else if ( basevalue === 'favPath') {
let li = event.target.parentNode.parentNode.parentNode;
let ul = li.parentNode;
favsSection.style.display = '';
favs.appendChild(li);
favTitle.textContent = "Favorites";
}
if ( taskItems.length === 0 ) {
tasksSection.style.display = "none";
}
}
// Checking if buttons inside favs section is clicked
} else if ( clickArea1 === 'favs' || clickArea2 === 'favs' || clickArea3 === 'favs' ) {
if (tag === 'svg') {
if (basevalue === 'delete' || basevalue === 'can' || basevalue === 'cap' || basevalue === 'bin') {
let li = event.target.parentNode.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
} else if ( basevalue === 'fav') {
let li = event.target.parentNode.parentNode;
let ul = li.parentNode;
tasksSection.style.display = '';
tasks.appendChild(li);
tasksTitle.textContent = "Inbox";
}
if ( favsItems.length === 0 ) {
favsSection.style.display = 'none';
}
} else if (tag === 'path') {
if (basevalue === 'delete' || basevalue === 'can' || basevalue === 'cap' || basevalue === 'bin') {
let li = event.target.parentNode.parentNode.parentNode.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
} else if ( basevalue === 'favPath') {
let li = event.target.parentNode.parentNode.parentNode;
let ul = li.parentNode;
tasksSection.style.display = '';
tasks.appendChild(li);
tasksTitle.textContent = "Inbox";
}
if ( favsItems.length === 0 ) {
favsSection.style.display = 'none';
}
}
}
});
/**
* Attaches buttons to a given list item (li) for interaction.
* @param {HTMLElement} li - The list item to which buttons will be attached.
*/
function attachButton(li) {
// Creating a container for buttons
let btns = document.createElement('div');
btns.className = 'btns';
li.appendChild(btns);
// SVG namespace
const xmlns = "http://www.w3.org/2000/svg";
// Dimensions for favorite button
let boxWidth = 36;
let boxHeight = 36;
// Creating favorite button
const favoriteButton = document.createElementNS(xmlns, "svg");
favoriteButton.setAttributeNS(null, "viewBox", "0 0" + " " + boxWidth + " "+ boxHeight);
favoriteButton.setAttributeNS(null, "width", boxWidth);
favoriteButton.setAttributeNS(null, "height", boxHeight);
favoriteButton.setAttributeNS(null, 'class', "fav");
favoriteButton.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid');
// Creating path for favorite button
let favPath = document.createElementNS (xmlns, "path");
favPath.setAttributeNS (null, 'd', "M23 11L18 0l-5 11c-.4.5-1 1-1.6 1L0 13.8l8.3 8.4c.4.5.6 1.2.5 2L6.8 36 17 30.4l1-.3c.4 0 .7.4 1 .6L29 36l-1.8-12c0-.6 0-1.3.5-1.8l8.3-8.4L24.6 12c-.7 0-1.2-.5-1.5-1z");
favPath.setAttributeNS(null, 'class', "favPath");
// Appending path to favorite button
favoriteButton.appendChild(favPath);
btns.appendChild(favoriteButton);
// Dimensions for delete button
boxWidth = 36;
boxHeight = 24;
// Creating delete button
const deleteButton = document.createElementNS(xmlns, "svg");
deleteButton.setAttributeNS(null, "viewBox", "0 0" + " " + boxWidth + " "+ boxHeight);
deleteButton.setAttributeNS(null, "width", boxWidth);
deleteButton.setAttributeNS(null, "height", boxHeight);
deleteButton.setAttributeNS(null, 'class', "delete");
deleteButton.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid');
// Creating group for delete button
let bin = document.createElementNS(xmlns, "g");
bin.setAttributeNS(null, "class", "bin");
// Creating paths for delete button
let cap = document.createElementNS (xmlns, "path");
cap.setAttributeNS(null, "class", "cap");
cap.setAttributeNS (null, 'd', "M23.7252648,1.75191502 L16.5206374,1.75191502 L16.5206374,0.358408695 C16.5206374,0.160513813 16.3638258,0 16.1703135,0 L8.60470208,0 C8.41127124,0 8.25445962,0.160513813 8.25445962,0.358408695 L8.25445962,1.75183177 L1.04975087,1.75183177 C0.46994661,1.75183177 0,2.23270718 0,2.8258923 L0,6.19992928 L24.7750156,6.19992928 L24.7750156,2.82597555 C24.7750156,2.23279043 24.305069,1.75191502 23.7252648,1.75191502 Z");
let can = document.createElementNS (xmlns, "path");
can.setAttributeNS(null, "class", "can");
can.setAttributeNS (null, 'd', "M3.11525858,32.2713554 C3.15277293,33.1879825 3.89003982,33.911377 4.78664099,33.911377 L20.4035975,33.911377 C21.3001987,33.911377 22.0374655,33.1879825 22.0749799,32.2713554 L23.1902385,8.18462596 L2,8.18462596 L3.11525858,32.2713554 Z M16.1278564,14.1673454 C16.1278564,13.7835442 16.43204,13.4722573 16.8073463,13.4722573 L17.8941233,13.4722573 C18.2691854,13.4722573 18.5736132,13.783461 18.5736132,14.1673454 L18.5736132,27.9286575 C18.5736132,28.3125419 18.2694296,28.6237456 17.8941233,28.6237456 L16.8073463,28.6237456 C16.4322028,28.6237456 16.1278564,28.3127084 16.1278564,27.9286575 L16.1278564,14.1673454 Z M11.3723222,14.1673454 C11.3723222,13.7835442 11.6765059,13.4722573 12.0517308,13.4722573 L13.1385077,13.4722573 C13.5135699,13.4722573 13.8179162,13.783461 13.8179162,14.1673454 L13.8179162,27.9286575 C13.8179162,28.3125419 13.513814,28.6237456 13.1385077,28.6237456 L12.0517308,28.6237456 C11.6765872,28.6237456 11.3723222,28.3127084 11.3723222,27.9286575 L11.3723222,14.1673454 L11.3723222,14.1673454 Z M6.61662529,14.1673454 C6.61662529,13.7835442 6.92080891,13.4722573 7.29603382,13.4722573 L8.38289216,13.4722573 C8.75803569,13.4722573 9.06230069,13.783461 9
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ToDo - App by Dhanish Gajjar</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<link href="img/apple-touch-icon.png" rel="apple-touch-icon" />
<link href="img/apple-touch-icon-152x152.png" rel="apple-touch-icon" sizes="152x152" />
<link href="img/apple-touch-icon-167x167.png" rel="apple-touch-icon" sizes="167x167" />
<link href="img/apple-touch-icon-180x180.png" rel="apple-touch-icon" sizes="180x180" />
<link href="img/icon-hires.png" rel="icon" sizes="192x192" />
<link href="img/icon-normal.png" rel="icon" sizes="128x128" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700" rel="stylesheet">
<link href="style.css" rel="stylesheet">
</head>
<body>
<div class="wrapper">
<div class="app">
<!-- Input field for adding tasks -->
<input type="text" id="task" placeholder="Add Your Task Here" class="task">
<!-- Container for lists -->
<div class="lists">
<!-- Favorites section -->
<section class="favs">
<h3></h3>
<ul></ul>
</section>
<!-- Tasks section -->
<section class="tasks">
<h3></h3>
<ul></ul>
</section>
<!-- Done section -->
<section class="done">
<h3></h3>
<ul></ul>
</section>
</div>
</div>
<!-- Footer section -->
<footer>
<p>©2017 Dhanish Gajjar. All Rights Reserved</p>
<p>Made using HTML, CSS and JavaScript</p>
</footer>
</div>
<!-- Script for attaching buttons to tasks -->
<script src="buttons.js"></script>
<!-- Main application script -->
<script src="app.js"></script>
</body>
</html>
style.css
/**
* Global styles
*/
* {
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
background: rgb(187, 222, 240);
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
h3 {
font-size: 1em;
font-weight: 700;
color: rgba(0, 0, 0, 0.3);
}
/**
* Wrapper styles
*/
.wrapper {
width: 90%;
margin: 0 auto;
}
/**
* App styles
*/
.app {
margin-top: 2em;
width: 100%;
}
.app input {
padding-left: .65em;
font-size: 1em;
font-weight: 400;
color: rgba(0, 0, 0, 0.4);
width: 100%;
line-height: 3em;
border-radius: 0;
background: none;
border: none;
border-bottom: 2px solid rgba(0, 0, 0, 0.1);
}
.app input::placeholder {
font-weight: 400;
color: inherit;
}
.app input:focus {
outline: none;
}
/**
* Lists styles
*/
.favs,
.tasks,
.favs ul li,
.tasks ul li,
.btns,
footer {
display: flex;
}
.favs {
margin-bottom: 1em;
}
.favs,
.tasks {
margin-top: 1em;
flex-direction: column;
text-align: center;
}
.btns {
flex-direction: row;
margin-right: -18px;
}
ul li {
color: #666;
font-size: 1em;
font-weight: 400;
background: white;
padding: .75em 1.2em;
border-radius: .3em;
margin: .5em 0;
flex-direction: row;
justify-content: space-between;
align-items: center;
line-height: 1.5;
}
.favs ul li svg,
.tasks ul li svg {
height: 36px;
margin-left: 1.2em;
}
.favs .fav {
fill: #FFD842;
}
.bin {
fill: tomato;
transform: scale(0.75);
}
.cap {
transition: transform 0.2s;
}
.fav {
fill: lightgray;
transition: transform 0.2s, fill 0.5s;
transform: scale(0.75);
}
/**
* Footer styles
*/
footer {
flex-direction: column;
align-items: center;
margin: 3em 0;
}
footer p {
margin: 0;
padding: 0;
height: 1.5em;
font-size: .75em;
color: rgba(0, 0, 0, 0.4);
}
/**
* Media queries
*/
@media (min-width: 768px) {
.app input {
font-size: 1.2em;
}
.delete {
height: 1.2em;
}
.favs,
.tasks {
text-align: left;
}
.favs li,
.tasks li {
font-size: 1.25em;
}
li svg:hover {
cursor: pointer;
}
.fav,
.bin {
transform: scale(0.85);
}
.fav:hover {
transform: scale(0.9);
}
.bin:hover .cap {
transform: rotate(-9deg);
}
}