Hey there, fellow coders! Vishnu Rajoria here, your friendly neighborhood coding instructor and Full Stack Developer at CSLAB Computer Institute in Sikar. Today, I’m excited to walk you through a fun little project we recently tackled in class: building a simple Task Manager application using HTML, CSS, and JavaScript.
What We’re Building
Before we dive in, let’s quickly overview what our Task Manager can do:
- Add new tasks with custom colors
- Edit existing tasks
- Delete tasks
- Save tasks to local storage (so they persist even when you close the browser)
Sounds cool, right? Let’s break it down!
The Building Blocks
Our Task Manager is built using three core technologies:
- HTML: This forms the structure of our app.
- CSS: This makes our app look pretty (and trust me, it does look pretty!).
- JavaScript: This is where the magic happens – it makes our app interactive.
See the Pen Task Manager App UI by CSLAB Software Development and Computer Training (@CSLAB) on CodePen.
HTML CODE :
<div class="container">
<div class="app-container">
<!-- Header section -->
<div class="header">
<h1>Task Manager</h1>
<img class="icon" id="menu-btn" src="https://www.svgrepo.com/show/345223/three-dots-vertical.svg" alt="Menu">
</div>
<!-- Task list container -->
<div class="task-container">
<!-- Tasks will be dynamically added here -->
</div>
<!-- Footer section with color selector and task input -->
<div class="footer">
<div class="color-selector-menu">
<!-- Color options will be dynamically added here -->
</div>
<div id="color-menu-toggle-btn" class="color red">
<!-- Color selector toggle button -->
</div>
<input id="task-input" type="text" placeholder="Enter a task">
<button id="add-task-btn">Add</button>
</div>
</div>
</div>
CSS CODE :
body {
background: url("https://plus.unsplash.com/premium_photo-1672115681150-cce7a518bba1?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D");
background-size: 150%;
margin: 0px;
}
.container {
background: rgba(255,255,255,0.8);
height: 100vh;
display: grid;
place-content: center;
}
.app-container {
box-shadow: 0px 5px 10px rgba(0,0,0,0.3);
background: #fff;
width: 300px;
height: 400px;
display: grid;
grid-template-rows: auto 1fr auto;
font-family: arial;
font-size: 14px;
}
.header {
box-shadow: 0px 5px 10px rgba(0,0,0,0.1);
padding: 10px;
position: relative;
}
.task-container {
padding: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
.footer {
padding: 10px;
border-top: 1px solid rgba(0,0,0,0.1);
display: grid;
grid-template-columns: auto 1fr auto;
position: relative;
}
h1 {
margin: 0px;
font-size: 22px;
text-align: center;
}
.icon {
width: 14px;
opacity: 0.5;
}
#menu-btn {
position: absolute;
right: 10px;
top: 17px;
}
.color {
border: 5px solid #fff;
width: 20px;
height: 20px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.2);
}
.footer input {
outline: none;
border: none;
padding: 0px 10px;
}
.footer button {
border: none;
background: #fff;
padding: 3px 10px;
border-radius: 5px;
}
.footer button:hover {
background: #eef;
}
.footer button:active {
background: #222;
color: #fff;
}
.task {
display: flex;
gap: 10px;
padding: 5px;
box-shadow: 0px 5px 10px rgba(0,0,0,0.1);
}
.task .delete-btn {
margin-left: auto;
}
.task-color {
width: 5px;
min-height: 10px;
}
.color-selector-menu {
position: absolute;
width: 100px;
bottom: 50px;
left: 5px;
display: flex;
gap: 2px;
padding: 5px;
background: #fff;
box-shadow: 0px 2px 5px rgba(0,0,0,0.3);
border-radius: 5px;
display: none;
flex-wrap: wrap;
}
.color-selector-menu .color {
border-radius: 50%;
transform: scale(0.6);
}
.btn {
display: grid;
place-content: center;
background: #000;
color: #fff;
border-radius: 5px;
border: none;
padding: 3px 10px;
}
.btn:hover {
background: #36f;
}
.btn img {
width: 16px;
filter: invert();
}
JAVASCRIPT CODE :
// DOM element selections
let colorSelectorMenu = document.querySelector(".color-selector-menu");
let colorMenuToggleBtn = document.querySelector("#color-menu-toggle-btn");
let taskInput = document.querySelector("#task-input");
let addTaskBtn = document.querySelector("#add-task-btn");
let taskContainer = document.querySelector(".task-container");
// State variables
let isColorSelectorMenuOpened = false;
let colors = ["red", "green", "purple", "orange", "blue"];
let colorDotsHtml = "";
let selectedColor = colors[0];
let taskCounter = 0;
let savedTasks = [];
let currentlyEditingIndex = -1;
// Load saved tasks from local storage
if (localStorage.getItem("tasks") != null) {
savedTasks = JSON.parse(localStorage.getItem("tasks"));
taskCounter = savedTasks[savedTasks.length - 1].id;
for (let i = 0; i < savedTasks.length; i++) {
addNewTask(savedTasks[i].id, savedTasks[i].color, savedTasks[i].text);
}
}
// Set initial color for the color menu toggle button
colorMenuToggleBtn.style.background = selectedColor;
// Generate color selector menu HTML
for (let i = 0; i < colors.length; i++) {
colorDotsHtml += `<div onclick="changeSelectedColor('${colors[i]}')" data-color="${colors[i]}" style="background:${colors[i]};" class="color ${colors[i]}"></div>`;
}
colorSelectorMenu.innerHTML = colorDotsHtml;
// Toggle color selector menu
colorMenuToggleBtn.addEventListener("click", () => {
isColorSelectorMenuOpened = !isColorSelectorMenuOpened;
colorSelectorMenu.style.display = isColorSelectorMenuOpened ? "flex" : "none";
});
// Change selected color
function changeSelectedColor(color) {
selectedColor = color;
colorMenuToggleBtn.style.background = selectedColor;
colorSelectorMenu.style.display = "none";
isColorSelectorMenuOpened = false;
}
// Add or update task
addTaskBtn.addEventListener("click", () => {
if (addTaskBtn.innerText == "Add") {
taskCounter++;
let taskText = taskInput.value;
taskInput.value = "";
let newTaskObject = {
id: taskCounter,
color: selectedColor,
text: taskText
};
savedTasks.push(newTaskObject);
localStorage.setItem("tasks", JSON.stringify(savedTasks));
addNewTask(newTaskObject.id, newTaskObject.color, newTaskObject.text);
} else if (addTaskBtn.innerText == "Update") {
updateTask();
}
});
// Add new task to the DOM
function addNewTask(taskNumber, color, text) {
let newTask = document.createElement("div");
newTask.setAttribute("class", "task");
newTask.setAttribute("id", "task-" + taskNumber);
let taskColor = document.createElement("div");
taskColor.setAttribute("class", "task-color");
taskColor.setAttribute("style", `background:${color}`);
let taskTextElement = document.createElement("div");
taskTextElement.setAttribute("class", "task-text");
taskTextElement.innerText = text;
let deleteBtn = document.createElement("button");
deleteBtn.innerText = "x";
deleteBtn.setAttribute("class", "btn delete-btn");
deleteBtn.setAttribute("onclick", `deleteTask(${taskNumber})`);
let editBtn = document.createElement("button");
editBtn.innerHTML = "<img src='https://www.svgrepo.com/show/522526/edit.svg'>";
editBtn.setAttribute("class", "btn edit-btn");
editBtn.setAttribute("onclick", `editTask(${taskNumber})`);
newTask.append(taskColor, taskTextElement, deleteBtn, editBtn);
taskContainer.append(newTask);
}
// Delete task
function deleteTask(taskNumber) {
let selectedElement = document.querySelector("#task-" + taskNumber);
selectedElement.remove();
let index = getIndexOfElement(taskNumber);
if (index != -1) {
savedTasks.splice(index, 1);
localStorage.setItem("tasks", JSON.stringify(savedTasks));
}
}
// Get index of task by ID
function getIndexOfElement(id) {
return savedTasks.findIndex(task => task.id == id);
}
// Edit task
function editTask(taskId) {
let selectedIndex = getIndexOfElement(taskId);
let color = savedTasks[selectedIndex].color;
changeSelectedColor(color);
taskInput.value = savedTasks[selectedIndex].text;
addTaskBtn.innerText = "Update";
currentlyEditingIndex = selectedIndex;
}
// Update task
function updateTask() {
savedTasks[currentlyEditingIndex].color = selectedColor;
savedTasks[currentlyEditingIndex].text = taskInput.value;
let selectedTaskColorElement = document.querySelector(`#task-${savedTasks[currentlyEditingIndex].id} .task-color`);
let selectedTaskTextElement = document.querySelector(`#task-${savedTasks[currentlyEditingIndex].id} .task-text`);
selectedTaskColorElement.setAttribute("style", "background:" + selectedColor + ";");
selectedTaskTextElement.innerText = taskInput.value;
// Reset UI after update
taskInput.value = "";
addTaskBtn.innerText = "Add";
currentlyEditingIndex = -1;
localStorage.setItem("tasks", JSON.stringify(savedTasks));
}
Key Features Explained
Let’s look at some of the cool features we’ve implemented:
1. Color Coding Tasks
- We’ve added a color selector that lets users assign different colors to tasks.
- This feature helps in visually organizing and prioritizing tasks.
2. Local Storage
- Ever closed your to-do app and lost all your tasks? Not with our app!
- We use the browser’s local storage to save tasks, so they’re there when you come back.
3. Edit and Delete Functionality
- Made a typo? No worries! You can easily edit any task.
- Finished a task? Simply delete it with a click.
The Code: Simpler Than You Think!
Now, I know some of you might be thinking, “But Vishnu, this sounds complicated!” Trust me, it’s simpler than you imagine. Here are some key points about our code:
- We use event listeners to handle user interactions like adding or editing tasks.
- The color selector is just a bunch of divs with different background colors.
- For saving tasks, we convert our task list to a JSON string and store it in local storage.
- Adding and removing tasks is as simple as creating or removing HTML elements dynamically.
Why This Project is Great for Learning
This Task Manager project is fantastic for several reasons:
- It covers fundamental concepts of web development.
- It’s a real-world application that you can actually use.
- It introduces you to working with browser storage.
- It’s a great starting point for more complex projects.
Wrapping Up
Building this Task Manager is more than just coding – it’s about understanding how different parts of web development come together to create something useful. Whether you’re a beginner or looking to brush up your skills, projects like these are invaluable.
Remember, the key to becoming a great developer is practice and curiosity. So, why not try adding your own twist to this project? Maybe add categories, due dates, or even a pomodoro timer?
Happy coding, everyone! And remember, if you’re ever in Sikar, drop by CSLAB Computer Institute – I’d love to code with you in person!
Vishnu Rajoria
Coding Instructor & Full Stack Developer
CSLAB Computer Institute, Sikar