From 5869efb9cb8855a0fc24d4be892eae69c515cd06 Mon Sep 17 00:00:00 2001 From: Malusi Skunyana Date: Wed, 13 Aug 2025 11:06:50 +0200 Subject: [PATCH 1/3] updated structure, added date picker, added todo list --- Sprint-3/todo-list/index.html | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Sprint-3/todo-list/index.html b/Sprint-3/todo-list/index.html index ee3ef64fd..f070333e0 100644 --- a/Sprint-3/todo-list/index.html +++ b/Sprint-3/todo-list/index.html @@ -1,18 +1,22 @@ - - - Title here - + + + Todo List + +
- + +
- +
+ + + From 1d93b455b8ff7b174b2c155f4351ed98e3ded27e Mon Sep 17 00:00:00 2001 From: Malusi Skunyana Date: Wed, 13 Aug 2025 11:08:37 +0200 Subject: [PATCH 2/3] Implement todo-list functionality with add, delete, toggle complete, remove completed, and deadline countdown --- Sprint-3/todo-list/script.js | 114 +++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/Sprint-3/todo-list/script.js b/Sprint-3/todo-list/script.js index 61982a54f..ec44df7e3 100644 --- a/Sprint-3/todo-list/script.js +++ b/Sprint-3/todo-list/script.js @@ -1,25 +1,117 @@ +function calculateDaysLeft(dateString) { + const today = new Date(); + const deadline = new Date(dateString); + today.setHours(0, 0, 0, 0); + deadline.setHours(0, 0, 0, 0); + + const diffTime = deadline - today; + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); + + if (diffDays > 1) return { text: `${diffDays} days left`, status: "normal" }; + if (diffDays === 1) return { text: "1 day left", status: "normal" }; + if (diffDays === 0) return { text: "Due today", status: "due-today" }; + return { text: "Overdue", status: "overdue" }; +} + +function createTodoElement(todoText, completed = false, deadline = "") { + const li = document.createElement("li"); + li.innerText = todoText; + if (completed) { + li.style.textDecoration = "line-through"; + } + + // Show deadline countdown if provided + if (deadline) { + const countdownInfo = calculateDaysLeft(deadline); + const countdown = document.createElement("small"); + countdown.style.display = "block"; + countdown.style.fontSize = "0.8em"; + + if (countdownInfo.status === "overdue") { + countdown.style.color = "red"; + } else if (countdownInfo.status === "due-today") { + countdown.style.color = "orange"; + } else { + countdown.style.color = "#555"; + } + + countdown.innerText = countdownInfo.text; + li.appendChild(countdown); + } + + const span = document.createElement("span"); + span.className = "badge bg-primary rounded-pill"; + + const tickIcon = document.createElement("i"); + tickIcon.className = "fa fa-check"; + tickIcon.setAttribute("aria-hidden", "true"); + tickIcon.addEventListener("click", () => { + if (li.style.textDecoration === "line-through") { + li.style.textDecoration = ""; + } else { + li.style.textDecoration = "line-through"; + } + }); + + const binIcon = document.createElement("i"); + binIcon.className = "fa fa-trash"; + binIcon.setAttribute("aria-hidden", "true"); + binIcon.addEventListener("click", () => { + li.remove(); + }); + + span.appendChild(tickIcon); + span.appendChild(binIcon); + li.appendChild(span); + + return li; +} + function populateTodoList(todos) { - let list = document.getElementById("todo-list"); - // Write your code to create todo list elements with completed and delete buttons here, all todos should display inside the "todo-list" element. + const list = document.getElementById("todo-list"); + list.innerHTML = ""; + todos.forEach(todo => { + const li = createTodoElement(todo.task, todo.completed, todo.deadline || ""); + list.appendChild(li); + }); } -// These are the same todos that currently display in the HTML -// You will want to remove the ones in the current HTML after you have created them using JavaScript let todos = [ - { task: "Wash the dishes", completed: false }, - { task: "Do the shopping", completed: false }, + { task: "Wash the dishes", completed: false, deadline: "" }, + { task: "Do the shopping", completed: false, deadline: "" }, ]; populateTodoList(todos); -// This function will take the value of the input field and add it as a new todo to the bottom of the todo list. These new todos will need the completed and delete buttons adding like normal. function addNewTodo(event) { - // The code below prevents the page from refreshing when we click the 'Add Todo' button. event.preventDefault(); - // Write your code here... and remember to reset the input field to be blank after creating a todo! + const input = document.getElementById("todoInput"); + const dateInput = document.getElementById("todoDate"); + + const value = input.value.trim(); + const deadline = dateInput.value; + + if (value) { + const li = createTodoElement(value, false, deadline); + document.getElementById("todo-list").appendChild(li); + } + + input.value = ""; + dateInput.value = ""; } -// Advanced challenge: Write a fucntion that checks the todos in the todo list and deletes the completed ones (we can check which ones are completed by seeing if they have the line-through styling applied or not). function deleteAllCompletedTodos() { - // Write your code here... + const list = document.getElementById("todo-list"); + const completedItems = list.querySelectorAll("li"); + completedItems.forEach(li => { + if (li.style.textDecoration === "line-through") { + li.remove(); + } + }); } + +// Event listeners +document.querySelector("form").addEventListener("submit", addNewTodo); +document + .getElementById("remove-all-completed") + .addEventListener("click", deleteAllCompletedTodos); From fa291a7013c6f18587e169dfd5463269feae76ae Mon Sep 17 00:00:00 2001 From: Malusi Skunyana Date: Wed, 13 Aug 2025 11:09:51 +0200 Subject: [PATCH 3/3] Add CSS styling for todo-list, badges, buttons, and countdown visuals --- Sprint-3/todo-list/style.css | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/Sprint-3/todo-list/style.css b/Sprint-3/todo-list/style.css index 8b1378917..8d535c2f5 100644 --- a/Sprint-3/todo-list/style.css +++ b/Sprint-3/todo-list/style.css @@ -1 +1,83 @@ +/* Reset and basic styling */ +body { + font-family: Arial, sans-serif; + background-color: #f8f8f8; + margin: 0; + padding: 2rem; + color: #333; +} +form { + margin-bottom: 1rem; +} + +input[type="text"], +input[type="date"] { + padding: 0.5rem; + font-size: 1rem; + margin-right: 0.5rem; +} + +button.btn { + padding: 0.5rem 1rem; + font-size: 1rem; + cursor: pointer; + margin-right: 0.5rem; + border: none; + border-radius: 4px; + background-color: #0077cc; + color: white; + transition: background-color 0.2s ease; +} + +button.btn:hover { + background-color: #005fa3; +} + +#todo-list { + list-style-type: none; + padding-left: 0; +} + +#todo-list li { + padding: 0.5rem 1rem; + margin-bottom: 0.5rem; + background-color: white; + border-radius: 4px; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +#todo-list li small { + margin-top: 0.2rem; +} + +.badge { + display: flex; + gap: 0.5rem; + cursor: pointer; +} + +.badge i { + padding: 0.2rem 0.4rem; + border-radius: 4px; + background-color: #e0e0e0; + color: #333; + transition: background-color 0.2s ease, color 0.2s ease; +} + +.badge i:hover { + background-color: #0077cc; + color: white; +} + +/* Remove all completed button styling */ +#remove-all-completed { + background-color: #cc0000; +} + +#remove-all-completed:hover { + background-color: #a30000; +}