Pro To-Do-App
This version is essentially a mini productivity tool, fully functional in-browser:
- Tasks with categories and priorities
- Drag-and-drop across categories
- Persistent storage with localStorage
- Filters, search, and sorting by priority
HTML Structure
<div id="todo-app">
<h1>Pro To-Do List</h1>
<input type="text" id="task-input" placeholder="Add a task" />
<select id="category-select">
<option value="General">General</option>
<option value="Work">Work</option>
<option value="Personal">Personal</option>
</select>
<select id="priority-select">
<option value="High">High</option>
<option value="Medium" selected>Medium</option>
<option value="Low">Low</option>
</select>
<button id="add-btn">Add Task</button>
<div id="filters">
<label>Status:
<select id="filter-status">
<option value="all">All</option>
<option value="completed">Completed</option>
<option value="pending">Pending</option>
</select>
</label>
<label>Category:
<select id="filter-category">
<option value="all">All</option>
<option value="General">General</option>
<option value="Work">Work</option>
<option value="Personal">Personal</option>
</select>
</label>
<label>Search:
<input type="text" id="search" placeholder="Search tasks" />
</label>
<label>Sort by Priority:
<button id="sort-priority">Sort</button>
</label>
</div>
<ul id="task-list"></ul>
</div>
CSS (Optional for clarity)
<style>
#task-list li {
padding: 8px;
margin-bottom: 4px;
border: 1px solid #ccc;
cursor: move;
list-style: none;
}
#task-list li.completed {
text-decoration: line-through;
color: gray;
}
.category-label {
font-size: 0.8em;
color: #555;
margin-left: 8px;
}
.priority-label {
font-size: 0.8em;
margin-left: 4px;
font-weight: bold;
}
.High { color: red; }
.Medium { color: orange; }
.Low { color: green; }
</style>
JavaScript: Pro To-Do App
<script>
let tasks = [];
// Load and save
function loadTasks() {
const stored = localStorage.getItem("tasks");
tasks = stored ? JSON.parse(stored) : [];
}
function saveTasks() {
localStorage.setItem("tasks", JSON.stringify(tasks));
}
const input = document.getElementById("task-input");
const categorySelect = document.getElementById("category-select");
const prioritySelect = document.getElementById("priority-select");
const addBtn = document.getElementById("add-btn");
const taskList = document.getElementById("task-list");
const filterStatus = document.getElementById("filter-status");
const filterCategory = document.getElementById("filter-category");
const searchInput = document.getElementById("search");
const sortPriorityBtn = document.getElementById("sort-priority");
// Render tasks
function renderTasks() {
taskList.innerHTML = "";
let filteredTasks = tasks;
// Filter by status
const status = filterStatus.value;
if (status === "completed") filteredTasks = filteredTasks.filter(t => t.completed);
else if (status === "pending") filteredTasks = filteredTasks.filter(t => !t.completed);
// Filter by category
const category = filterCategory.value;
if (category !== "all") filteredTasks = filteredTasks.filter(t => t.category === category);
// Search filter
const search = searchInput.value.toLowerCase();
if (search) filteredTasks = filteredTasks.filter(t => t.text.toLowerCase().includes(search));
filteredTasks.forEach((task, index) => {
const li = document.createElement("li");
li.textContent = task.text;
if (task.completed) li.classList.add("completed");
// Category and priority labels
const catSpan = document.createElement("span");
catSpan.textContent = `[${task.category}]`;
catSpan.className = "category-label";
const priSpan = document.createElement("span");
priSpan.textContent = `[${task.priority}]`;
priSpan.className = `priority-label ${task.priority}`;
li.appendChild(catSpan);
li.appendChild(priSpan);
li.draggable = true;
// Toggle completed
li.addEventListener("click", () => {
task.completed = !task.completed;
saveTasks();
renderTasks();
});
// Delete on double click
li.addEventListener("dblclick", () => {
const originalIndex = tasks.indexOf(task);
tasks.splice(originalIndex, 1);
saveTasks();
renderTasks();
});
// Drag-and-drop
li.addEventListener("dragstart", (e) => {
e.dataTransfer.setData("text/plain", tasks.indexOf(task));
});
li.addEventListener("dragover", (e) => e.preventDefault());
li.addEventListener("drop", (e) => {
e.preventDefault();
const draggedIndex = e.dataTransfer.getData("text");
const temp = tasks[draggedIndex];
tasks.splice(draggedIndex, 1);
const dropIndex = tasks.indexOf(task);
tasks.splice(dropIndex, 0, temp);
saveTasks();
renderTasks();
});
taskList.appendChild(li);
});
}
// Add task
addBtn.addEventListener("click", () => {
const text = input.value.trim();
const category = categorySelect.value;
const priority = prioritySelect.value;
if (!text) return;
tasks.push({ text, completed: false, category, priority });
saveTasks();
input.value = "";
renderTasks();
});
// Filters and search
filterStatus.addEventListener("change", renderTasks);
filterCategory.addEventListener("change", renderTasks);
searchInput.addEventListener("input", renderTasks);
// Sort by priority
sortPriorityBtn.addEventListener("click", () => {
const priorityOrder = { "High": 1, "Medium": 2, "Low": 3 };
tasks.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
saveTasks();
renderTasks();
});
// Enter key to add task
input.addEventListener("keypress", (e) => {
if (e.key === "Enter") addBtn.click();
});
// Initialize
loadTasks();
renderTasks();
</script>
Features of the Pro To-Do App
- Add tasks → text + category + priority
- Mark completed → click task
- Delete task → double-click
- Drag-and-drop reorder → works across categories
- Filter by status → All, Completed, Pending
- Filter by category → General, Work, Personal
- Search tasks → filter dynamically as you type
- Sort by priority → High → Medium → Low
- Persistent storage → tasks stay on page reload
This version is essentially a mini productivity tool, fully functional in-browser, combining everything we discussed in the other todo app posts:
- Array methods:
push,splice,filter,sort - DOM manipulation:
createElement,appendChild,classList - Events: click, double-click, drag-and-drop, input
- Persistent storage: localStorage