document.addEventListener('DOMContentLoaded', () => { // DOM Elements const taskForm = document.getElementById('task-form'); const taskInput = document.getElementById('task-input'); const taskList = document.getElementById('task-list'); const garden = document.getElementById('garden'); const soundToggle = document.getElementById('sound-toggle'); const ambientSound = document.getElementById('ambient-sound'); const shareBtn = document.getElementById('share-btn'); // App State let tasks = JSON.parse(localStorage.getItem('tasks')) || []; let gardenElements = JSON.parse(localStorage.getItem('gardenElements')) || []; const flowerColors = ['pink', 'yellow', 'purple', 'white']; // --- Initialization --- function init() { tasks.forEach(renderTask); // Filter out garden elements whose tasks are no longer completed or no longer exist const completedTaskIds = new Set(tasks.filter(t => t.completed).map(t => t.id)); gardenElements = gardenElements.filter(el => completedTaskIds.has(el.taskId)); gardenElements.forEach(renderGardenElement); saveState(); // Resync localStorage with the filtered elements } // --- State Management --- function saveState() { localStorage.setItem('tasks', JSON.stringify(tasks)); localStorage.setItem('gardenElements', JSON.stringify(gardenElements)); } // --- Task Management --- taskForm.addEventListener('submit', e => { e.preventDefault(); const title = taskInput.value.trim(); if (title) { const newTask = { id: Date.now(), title, completed: false }; tasks.push(newTask); renderTask(newTask); saveState(); taskInput.value = ''; } }); function renderTask(task) { const li = document.createElement('li'); li.dataset.id = task.id; if (task.completed) { li.classList.add('completed'); } li.innerHTML = ` ${escapeHTML(task.title)} `; taskList.appendChild(li); li.querySelector('input[type="checkbox"]').addEventListener('change', (e) => { toggleTaskCompletion(task.id, e.target.checked); }); li.querySelector('.delete-btn').addEventListener('click', () => { deleteTask(task.id); }); } function toggleTaskCompletion(id, isCompleted) { const taskIndex = tasks.findIndex(t => t.id === id); if (taskIndex > -1) { tasks[taskIndex].completed = isCompleted; const taskElement = taskList.querySelector(`[data-id='${id}']`); if (taskElement) { taskElement.classList.toggle('completed', isCompleted); } if (isCompleted) { addGardenElement(id); } else { removeGardenElement(id); } saveState(); } } function deleteTask(id) { tasks = tasks.filter(t => t.id !== id); const taskElement = taskList.querySelector(`[data-id='${id}']`); if (taskElement) { taskElement.remove(); } removeGardenElement(id); saveState(); } // --- Garden Management --- function addGardenElement(taskId) { if (gardenElements.some(el => el.taskId === taskId)) return; const newElement = { id: Date.now(), taskId: taskId, x: Math.random() * 80 + 10, // 10% to 90% to avoid edges color: flowerColors[Math.floor(Math.random() * flowerColors.length)] }; gardenElements.push(newElement); renderGardenElement(newElement); saveState(); } function renderGardenElement(element) { const el = document.createElement('div'); el.dataset.id = element.id; el.classList.add('garden-element', 'grow'); el.style.left = `${element.x}%`; el.innerHTML = `
`; // Find the ground element to append to const ground = garden.querySelector('.ground'); if (ground) { ground.appendChild(el); } else { garden.appendChild(el); // Fallback } } function removeGardenElement(taskId) { const elementToRemoveIdx = gardenElements.findIndex(el => el.taskId === taskId); if (elementToRemoveIdx > -1) { const elementToRemove = gardenElements[elementToRemoveIdx]; const el = garden.querySelector(`[data-id='${elementToRemove.id}']`); if (el) { el.classList.remove('grow'); el.classList.add('shrink'); setTimeout(() => { el.remove(); }, 500); } gardenElements.splice(elementToRemoveIdx, 1); saveState(); } } // --- Controls --- soundToggle.addEventListener('click', () => { if (ambientSound.paused) { ambientSound.play().catch(e => console.error("Audio play failed: ", e)); soundToggle.textContent = 'Pause Sound'; } else { ambientSound.pause(); soundToggle.textContent = 'Play Sound'; } }); shareBtn.addEventListener('click', () => { const gardenPanel = document.querySelector('.garden-panel'); const controls = gardenPanel.querySelector('.garden-controls'); controls.style.visibility = 'hidden'; html2canvas(gardenPanel, { useCORS: true, backgroundColor: '#a7d8f0' // Match sky color }).then(canvas => { const link = document.createElement('a'); link.download = 'my-mindful-garden.png'; link.href = canvas.toDataURL(); link.click(); controls.style.visibility = 'visible'; }).catch(err => { console.error('Could not share garden:', err); controls.style.visibility = 'visible'; }); }); // --- Utility --- function escapeHTML(str) { return str.replace(/[&<>"']/g, s => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'" : ''' }[s])); } // --- Run App --- init(); });