Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Daily Task Manager</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .task-column { | |
| min-height: 400px; | |
| transition: all 0.3s ease; | |
| } | |
| .task-item { | |
| transition: transform 0.2s ease, box-shadow 0.2s ease; | |
| } | |
| .task-item:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| .task-item.dragging { | |
| opacity: 0.5; | |
| transform: scale(1.05); | |
| box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2); | |
| } | |
| .column-hover { | |
| background-color: rgba(209, 213, 219, 0.3); | |
| border: 2px dashed #6b7280; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <header class="mb-8 text-center"> | |
| <h1 class="text-4xl font-bold text-indigo-700 mb-2">Daily Task Manager</h1> | |
| <p class="text-gray-600">Organize your day with drag and drop</p> | |
| <div class="mt-4 flex justify-center"> | |
| <div class="relative w-full max-w-md"> | |
| <input type="text" id="newTaskInput" placeholder="Add a new task..." | |
| class="w-full px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500"> | |
| <button id="addTaskBtn" class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-indigo-600 text-white px-4 py-1 rounded-lg hover:bg-indigo-700 transition"> | |
| <i class="fas fa-plus"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-6"> | |
| <!-- To Do Column --> | |
| <div class="bg-white rounded-lg shadow-md p-4 task-column" id="todo-column" data-status="todo"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="text-xl font-semibold text-red-500">To Do</h2> | |
| <span id="todo-count" class="bg-red-100 text-red-800 text-xs font-medium px-2.5 py-0.5 rounded-full">0</span> | |
| </div> | |
| <div class="space-y-3" id="todo-tasks"></div> | |
| </div> | |
| <!-- In Progress Column --> | |
| <div class="bg-white rounded-lg shadow-md p-4 task-column" id="inprogress-column" data-status="inprogress"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="text-xl font-semibold text-yellow-500">In Progress</h2> | |
| <span id="inprogress-count" class="bg-yellow-100 text-yellow-800 text-xs font-medium px-2.5 py-0.5 rounded-full">0</span> | |
| </div> | |
| <div class="space-y-3" id="inprogress-tasks"></div> | |
| </div> | |
| <!-- Review Column --> | |
| <div class="bg-white rounded-lg shadow-md p-4 task-column" id="review-column" data-status="review"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="text-xl font-semibold text-blue-500">Review</h2> | |
| <span id="review-count" class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full">0</span> | |
| </div> | |
| <div class="space-y-3" id="review-tasks"></div> | |
| </div> | |
| <!-- Done Column --> | |
| <div class="bg-white rounded-lg shadow-md p-4 task-column" id="done-column" data-status="done"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="text-xl font-semibold text-green-500">Done</h2> | |
| <span id="done-count" class="bg-green-100 text-green-800 text-xs font-medium px-2.5 py-0.5 rounded-full">0</span> | |
| </div> | |
| <div class="space-y-3" id="done-tasks"></div> | |
| </div> | |
| </div> | |
| <div class="mt-8 bg-white rounded-lg shadow-md p-6"> | |
| <h2 class="text-xl font-semibold mb-4">Daily Summary</h2> | |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-4"> | |
| <div class="bg-red-50 p-4 rounded-lg"> | |
| <h3 class="text-red-500 font-medium">To Do</h3> | |
| <p class="text-2xl font-bold" id="summary-todo">0</p> | |
| </div> | |
| <div class="bg-yellow-50 p-4 rounded-lg"> | |
| <h3 class="text-yellow-500 font-medium">In Progress</h3> | |
| <p class="text-2xl font-bold" id="summary-inprogress">0</p> | |
| </div> | |
| <div class="bg-blue-50 p-4 rounded-lg"> | |
| <h3 class="text-blue-500 font-medium">Review</h3> | |
| <p class="text-2xl font-bold" id="summary-review">0</p> | |
| </div> | |
| <div class="bg-green-50 p-4 rounded-lg"> | |
| <h3 class="text-green-500 font-medium">Completed</h3> | |
| <p class="text-2xl font-bold" id="summary-done">0</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const newTaskInput = document.getElementById('newTaskInput'); | |
| const addTaskBtn = document.getElementById('addTaskBtn'); | |
| const columns = document.querySelectorAll('.task-column'); | |
| // Sample tasks data | |
| let tasks = JSON.parse(localStorage.getItem('tasks')) || [ | |
| { id: 1, text: 'Complete project proposal', status: 'todo', timestamp: new Date().toISOString() }, | |
| { id: 2, text: 'Review team updates', status: 'inprogress', timestamp: new Date().toISOString() }, | |
| { id: 3, text: 'Schedule meeting with client', status: 'review', timestamp: new Date().toISOString() }, | |
| { id: 4, text: 'Prepare presentation slides', status: 'done', timestamp: new Date().toISOString() } | |
| ]; | |
| // Initialize the app | |
| initApp(); | |
| // Event Listeners | |
| addTaskBtn.addEventListener('click', addTask); | |
| newTaskInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') addTask(); | |
| }); | |
| // Initialize drag and drop | |
| setupDragAndDrop(); | |
| // Functions | |
| function initApp() { | |
| renderTasks(); | |
| updateCounters(); | |
| updateSummary(); | |
| } | |
| function addTask() { | |
| const taskText = newTaskInput.value.trim(); | |
| if (taskText) { | |
| const newTask = { | |
| id: Date.now(), | |
| text: taskText, | |
| status: 'todo', | |
| timestamp: new Date().toISOString() | |
| }; | |
| tasks.push(newTask); | |
| saveTasks(); | |
| renderTasks(); | |
| updateCounters(); | |
| updateSummary(); | |
| newTaskInput.value = ''; | |
| } | |
| } | |
| function renderTasks() { | |
| // Clear all task lists | |
| document.querySelectorAll('[id$="-tasks"]').forEach(el => el.innerHTML = ''); | |
| // Render each task | |
| tasks.forEach(task => { | |
| const taskElement = createTaskElement(task); | |
| document.getElementById(`${task.status}-tasks`).appendChild(taskElement); | |
| }); | |
| } | |
| function createTaskElement(task) { | |
| const taskElement = document.createElement('div'); | |
| taskElement.className = 'task-item bg-white p-3 rounded-lg border border-gray-200 cursor-move flex items-center justify-between'; | |
| taskElement.draggable = true; | |
| taskElement.dataset.taskId = task.id; | |
| // Add drag events | |
| taskElement.addEventListener('dragstart', dragStart); | |
| taskElement.addEventListener('dragend', dragEnd); | |
| // Task content | |
| taskElement.innerHTML = ` | |
| <div class="flex items-center"> | |
| <span class="drag-handle mr-2 text-gray-400 cursor-move"> | |
| <i class="fas fa-grip-vertical"></i> | |
| </span> | |
| <span class="task-text">${task.text}</span> | |
| </div> | |
| <button class="delete-btn text-gray-400 hover:text-red-500"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| `; | |
| // Add delete functionality | |
| const deleteBtn = taskElement.querySelector('.delete-btn'); | |
| deleteBtn.addEventListener('click', () => deleteTask(task.id)); | |
| return taskElement; | |
| } | |
| function deleteTask(taskId) { | |
| tasks = tasks.filter(task => task.id !== taskId); | |
| saveTasks(); | |
| renderTasks(); | |
| updateCounters(); | |
| updateSummary(); | |
| } | |
| function updateCounters() { | |
| const counts = { | |
| todo: 0, | |
| inprogress: 0, | |
| review: 0, | |
| done: 0 | |
| }; | |
| tasks.forEach(task => counts[task.status]++); | |
| document.getElementById('todo-count').textContent = counts.todo; | |
| document.getElementById('inprogress-count').textContent = counts.inprogress; | |
| document.getElementById('review-count').textContent = counts.review; | |
| document.getElementById('done-count').textContent = counts.done; | |
| } | |
| function updateSummary() { | |
| const counts = { | |
| todo: 0, | |
| inprogress: 0, | |
| review: 0, | |
| done: 0 | |
| }; | |
| tasks.forEach(task => counts[task.status]++); | |
| document.getElementById('summary-todo').textContent = counts.todo; | |
| document.getElementById('summary-inprogress').textContent = counts.inprogress; | |
| document.getElementById('summary-review').textContent = counts.review; | |
| document.getElementById('summary-done').textContent = counts.done; | |
| } | |
| function saveTasks() { | |
| localStorage.setItem('tasks', JSON.stringify(tasks)); | |
| } | |
| function setupDragAndDrop() { | |
| // Add dragover and drop events to columns | |
| columns.forEach(column => { | |
| column.addEventListener('dragover', dragOver); | |
| column.addEventListener('dragenter', dragEnter); | |
| column.addEventListener('dragleave', dragLeave); | |
| column.addEventListener('drop', drop); | |
| }); | |
| } | |
| // Drag and Drop Functions | |
| let draggedItem = null; | |
| function dragStart(e) { | |
| draggedItem = this; | |
| this.classList.add('dragging'); | |
| e.dataTransfer.setData('text/plain', this.dataset.taskId); | |
| e.dataTransfer.effectAllowed = 'move'; | |
| } | |
| function dragEnd() { | |
| this.classList.remove('dragging'); | |
| } | |
| function dragOver(e) { | |
| e.preventDefault(); | |
| e.dataTransfer.dropEffect = 'move'; | |
| } | |
| function dragEnter(e) { | |
| e.preventDefault(); | |
| this.classList.add('column-hover'); | |
| } | |
| function dragLeave() { | |
| this.classList.remove('column-hover'); | |
| } | |
| function drop(e) { | |
| e.preventDefault(); | |
| this.classList.remove('column-hover'); | |
| const taskId = parseInt(e.dataTransfer.getData('text/plain')); | |
| const newStatus = this.dataset.status; | |
| // Update task status | |
| const taskIndex = tasks.findIndex(task => task.id === taskId); | |
| if (taskIndex !== -1) { | |
| tasks[taskIndex].status = newStatus; | |
| tasks[taskIndex].timestamp = new Date().toISOString(); | |
| saveTasks(); | |
| renderTasks(); | |
| updateCounters(); | |
| updateSummary(); | |
| } | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=yanmarcosgtm/prueba" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |