Spaces:
Running
Running
| // Task Manager Class | |
| class TaskManager { | |
| constructor() { | |
| this.tasks = this.loadTasksFromStorage(); | |
| } | |
| loadTasksFromStorage() { | |
| const tasks = localStorage.getItem('tasks'); | |
| return tasks ? JSON.parse(tasks) : []; | |
| } | |
| saveTasksToStorage() { | |
| localStorage.setItem('tasks', JSON.stringify(this.tasks)); | |
| } | |
| addTask(text) { | |
| const newTask = { | |
| id: Date.now().toString(), | |
| text, | |
| completed: false, | |
| createdAt: new Date().toISOString() | |
| }; | |
| this.tasks.unshift(newTask); | |
| this.saveTasksToStorage(); | |
| return newTask; | |
| } | |
| toggleTask(id) { | |
| const task = this.tasks.find(t => t.id === id); | |
| if (task) { | |
| task.completed = !task.completed; | |
| this.saveTasksToStorage(); | |
| } | |
| } | |
| deleteTask(id) { | |
| this.tasks = this.tasks.filter(t => t.id !== id); | |
| this.saveTasksToStorage(); | |
| } | |
| getTasks() { | |
| return [...this.tasks]; | |
| } | |
| } | |
| // UI Controller | |
| class UIController { | |
| constructor() { | |
| this.taskManager = new TaskManager(); | |
| this.taskInput = document.getElementById('taskInput'); | |
| this.addTaskBtn = document.getElementById('addTaskBtn'); | |
| this.taskList = document.getElementById('taskList'); | |
| this.setupEventListeners(); | |
| } | |
| setupEventListeners() { | |
| this.addTaskBtn.addEventListener('click', () => this.handleAddTask()); | |
| this.taskInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') this.handleAddTask(); | |
| }); | |
| // Use event delegation for dynamic elements | |
| this.taskList.addEventListener('click', (e) => { | |
| const toggleBtn = e.target.closest('.toggle-btn'); | |
| const deleteBtn = e.target.closest('.delete-btn'); | |
| if (toggleBtn) { | |
| this.toggleTask(toggleBtn.dataset.id); | |
| } else if (deleteBtn) { | |
| this.deleteTask(deleteBtn.dataset.id); | |
| } | |
| }); | |
| } | |
| handleAddTask() { | |
| const taskText = this.taskInput.value.trim(); | |
| if (taskText) { | |
| const newTask = this.taskManager.addTask(taskText); | |
| this.renderTask(newTask); | |
| this.taskInput.value = ''; | |
| this.taskInput.focus(); | |
| } | |
| } | |
| renderTask(task) { | |
| const taskElement = document.createElement('div'); | |
| taskElement.className = 'task-item task-enter bg-gray-50 p-4 rounded-lg flex items-center justify-between'; | |
| taskElement.dataset.id = task.id; | |
| taskElement.innerHTML = ` | |
| <div class="flex items-center"> | |
| <button class="toggle-btn mr-3 text-gray-400 hover:text-green-500 transition" data-id="${task.id}"> | |
| <i data-feather="${task.completed ? 'check-circle' : 'circle'}" class="${task.completed ? 'text-green-500' : ''}"></i> | |
| </button> | |
| <span class="${task.completed ? 'task-complete text-gray-500' : 'text-gray-800'}">${task.text}</span> | |
| </div> | |
| <button class="delete-btn text-gray-400 hover:text-red-500 transition" data-id="${task.id}"> | |
| <i data-feather="trash-2"></i> | |
| </button> | |
| `; | |
| this.taskList.prepend(taskElement); | |
| feather.replace(); | |
| } | |
| toggleTask(id) { | |
| this.taskManager.toggleTask(id); | |
| document.dispatchEvent(new CustomEvent('taskChanged')); | |
| const taskElement = document.querySelector(`[data-id="${id}"]`); | |
| if (taskElement) { | |
| const icon = taskElement.querySelector('.toggle-btn i'); | |
| const text = taskElement.querySelector('span'); | |
| if (this.taskManager.getTasks().find(t => t.id === id).completed) { | |
| icon.setAttribute('data-feather', 'check-circle'); | |
| icon.classList.add('text-green-500'); | |
| text.classList.add('task-complete', 'text-gray-500'); | |
| text.classList.remove('text-gray-800'); | |
| } else { | |
| icon.setAttribute('data-feather', 'circle'); | |
| icon.classList.remove('text-green-500'); | |
| text.classList.remove('task-complete', 'text-gray-500'); | |
| text.classList.add('text-gray-800'); | |
| } | |
| feather.replace(); | |
| } | |
| } | |
| deleteTask(id) { | |
| this.taskManager.deleteTask(id); | |
| document.dispatchEvent(new CustomEvent('taskChanged')); | |
| const taskElement = document.querySelector(`[data-id="${id}"]`); | |
| if (taskElement) { | |
| taskElement.classList.add('opacity-0', 'translate-x-10'); | |
| setTimeout(() => { | |
| taskElement.remove(); | |
| }, 300); | |
| } | |
| } | |
| loadTasks() { | |
| this.taskList.innerHTML = ''; | |
| const tasks = this.taskManager.getTasks(); | |
| tasks.forEach(task => this.renderTask(task)); | |
| } | |
| } | |
| // Initialize the app | |
| function loadTasks() { | |
| const ui = new UIController(); | |
| ui.loadTasks(); | |
| // Update task counter in header | |
| const taskCounter = document.querySelector('custom-header').shadowRoot.querySelector('#taskCounter'); | |
| if (taskCounter) { | |
| taskCounter.textContent = `${ui.taskManager.getTasks().length} tasks`; | |
| } | |
| // Listen for task changes to update counter | |
| document.addEventListener('taskChanged', () => { | |
| taskCounter.textContent = `${ui.taskManager.getTasks().length} tasks`; | |
| }); | |
| } | |