File size: 19,829 Bytes
bea8b55 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>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-completed {
text-decoration: line-through;
color: #9ca3af;
}
.priority-high {
border-left: 4px solid #ef4444;
}
.priority-medium {
border-left: 4px solid #f59e0b;
}
.priority-low {
border-left: 4px solid #10b981;
}
.fade-in {
animation: fadeIn 0.3s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<div class="flex justify-between items-center mb-8">
<h1 class="text-3xl font-bold text-gray-800">My Tasks</h1>
<button id="addTaskBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center transition-colors">
<i class="fas fa-plus mr-2"></i> Add Task
</button>
</div>
<!-- Task Filters -->
<div class="bg-white rounded-lg shadow p-4 mb-6">
<div class="flex flex-wrap items-center gap-4">
<div class="flex-1 min-w-[200px]">
<label class="block text-sm font-medium text-gray-700 mb-1">Search</label>
<input type="text" id="searchInput" placeholder="Filter tasks..." class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Priority</label>
<select id="priorityFilter" class="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="all">All Priorities</option>
<option value="high">High</option>
<option value="medium">Medium</option>
<option value="low">Low</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Status</label>
<select id="statusFilter" class="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="all">All Statuses</option>
<option value="completed">Completed</option>
<option value="pending">Pending</option>
</select>
</div>
</div>
</div>
<!-- Task Table -->
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Task</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Priority</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Due Date</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody id="taskTableBody" class="bg-white divide-y divide-gray-200">
<!-- Tasks will be added here dynamically -->
</tbody>
</table>
</div>
<div id="emptyState" class="py-12 text-center">
<i class="fas fa-tasks text-4xl text-gray-300 mb-4"></i>
<h3 class="text-lg font-medium text-gray-500">No tasks found</h3>
<p class="text-gray-400 mt-1">Add your first task by clicking the button above</p>
</div>
</div>
</div>
<!-- Add/Edit Task Modal -->
<div id="taskModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg shadow-xl w-full max-w-md">
<div class="flex justify-between items-center border-b px-6 py-4">
<h3 id="modalTitle" class="text-lg font-semibold text-gray-800">Add New Task</h3>
<button id="closeModalBtn" class="text-gray-400 hover:text-gray-500">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-6">
<form id="taskForm">
<input type="hidden" id="taskId">
<div class="mb-4">
<label for="taskTitle" class="block text-sm font-medium text-gray-700 mb-1">Task Title</label>
<input type="text" id="taskTitle" required class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="taskDescription" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
<textarea id="taskDescription" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label for="taskPriority" class="block text-sm font-medium text-gray-700 mb-1">Priority</label>
<select id="taskPriority" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="high">High</option>
<option value="medium" selected>Medium</option>
<option value="low">Low</option>
</select>
</div>
<div>
<label for="taskDueDate" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label>
<input type="date" id="taskDueDate" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
</div>
<div class="flex justify-end space-x-3 mt-6">
<button type="button" id="cancelTaskBtn" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">Cancel</button>
<button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">Save Task</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Sample tasks data
let tasks = [
{ id: 1, title: 'Complete project proposal', description: 'Finish the draft and send for review', priority: 'high', dueDate: '2023-06-15', completed: false },
{ id: 2, title: 'Buy groceries', description: 'Milk, eggs, bread, fruits', priority: 'medium', dueDate: '2023-06-10', completed: true },
{ id: 3, title: 'Schedule team meeting', description: 'Discuss quarterly goals', priority: 'low', dueDate: '2023-06-12', completed: false },
{ id: 4, title: 'Update portfolio website', description: 'Add new projects and testimonials', priority: 'medium', dueDate: '2023-06-20', completed: false }
];
// DOM elements
const taskTableBody = document.getElementById('taskTableBody');
const emptyState = document.getElementById('emptyState');
const searchInput = document.getElementById('searchInput');
const priorityFilter = document.getElementById('priorityFilter');
const statusFilter = document.getElementById('statusFilter');
const addTaskBtn = document.getElementById('addTaskBtn');
const taskModal = document.getElementById('taskModal');
const closeModalBtn = document.getElementById('closeModalBtn');
const cancelTaskBtn = document.getElementById('cancelTaskBtn');
const taskForm = document.getElementById('taskForm');
const modalTitle = document.getElementById('modalTitle');
const taskIdInput = document.getElementById('taskId');
const taskTitleInput = document.getElementById('taskTitle');
const taskDescriptionInput = document.getElementById('taskDescription');
const taskPriorityInput = document.getElementById('taskPriority');
const taskDueDateInput = document.getElementById('taskDueDate');
// Current date for due date input
const today = new Date().toISOString().split('T')[0];
taskDueDateInput.min = today;
// Render tasks
function renderTasks() {
const searchTerm = searchInput.value.toLowerCase();
const priorityFilterValue = priorityFilter.value;
const statusFilterValue = statusFilter.value;
const filteredTasks = tasks.filter(task => {
const matchesSearch = task.title.toLowerCase().includes(searchTerm) ||
task.description.toLowerCase().includes(searchTerm);
const matchesPriority = priorityFilterValue === 'all' || task.priority === priorityFilterValue;
const matchesStatus = statusFilterValue === 'all' ||
(statusFilterValue === 'completed' && task.completed) ||
(statusFilterValue === 'pending' && !task.completed);
return matchesSearch && matchesPriority && matchesStatus;
});
if (filteredTasks.length === 0) {
taskTableBody.innerHTML = '';
emptyState.classList.remove('hidden');
return;
}
emptyState.classList.add('hidden');
taskTableBody.innerHTML = '';
filteredTasks.forEach(task => {
const row = document.createElement('tr');
row.className = `fade-in ${task.completed ? 'bg-gray-50' : ''} priority-${task.priority}`;
// Status cell
const statusCell = document.createElement('td');
statusCell.className = 'px-6 py-4 whitespace-nowrap';
const statusCheckbox = document.createElement('input');
statusCheckbox.type = 'checkbox';
statusCheckbox.className = 'h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded cursor-pointer';
statusCheckbox.checked = task.completed;
statusCheckbox.addEventListener('change', () => toggleTaskStatus(task.id));
statusCell.appendChild(statusCheckbox);
row.appendChild(statusCell);
// Task title cell
const titleCell = document.createElement('td');
titleCell.className = 'px-6 py-4';
const titleDiv = document.createElement('div');
titleDiv.className = 'flex items-center';
const titleText = document.createElement('div');
titleText.className = 'ml-4';
const title = document.createElement('div');
title.className = `text-sm font-medium ${task.completed ? 'task-completed' : 'text-gray-900'}`;
title.textContent = task.title;
const description = document.createElement('div');
description.className = `text-sm ${task.completed ? 'task-completed' : 'text-gray-500'}`;
description.textContent = task.description;
titleText.appendChild(title);
titleText.appendChild(description);
titleDiv.appendChild(titleText);
titleCell.appendChild(titleDiv);
row.appendChild(titleCell);
// Priority cell
const priorityCell = document.createElement('td');
priorityCell.className = 'px-6 py-4 whitespace-nowrap';
const priorityBadge = document.createElement('span');
priorityBadge.className = `px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
task.priority === 'high' ? 'bg-red-100 text-red-800' :
task.priority === 'medium' ? 'bg-yellow-100 text-yellow-800' :
'bg-green-100 text-green-800'
}`;
priorityBadge.textContent = task.priority.charAt(0).toUpperCase() + task.priority.slice(1);
priorityCell.appendChild(priorityBadge);
row.appendChild(priorityCell);
// Due date cell
const dueDateCell = document.createElement('td');
dueDateCell.className = 'px-6 py-4 whitespace-nowrap';
const dueDateDiv = document.createElement('div');
dueDateDiv.className = `text-sm ${task.completed ? 'task-completed' : 'text-gray-900'}`;
const dueDate = new Date(task.dueDate);
const now = new Date();
now.setHours(0, 0, 0, 0);
if (dueDate < now && !task.completed) {
dueDateDiv.innerHTML = `<span class="text-red-600">${formatDate(task.dueDate)} (Overdue)</span>`;
} else {
dueDateDiv.textContent = formatDate(task.dueDate);
}
dueDateCell.appendChild(dueDateDiv);
row.appendChild(dueDateCell);
// Actions cell
const actionsCell = document.createElement('td');
actionsCell.className = 'px-6 py-4 whitespace-nowrap text-right text-sm font-medium';
const editBtn = document.createElement('button');
editBtn.className = 'text-blue-600 hover:text-blue-900 mr-4';
editBtn.innerHTML = '<i class="fas fa-edit"></i>';
editBtn.addEventListener('click', () => openEditModal(task.id));
const deleteBtn = document.createElement('button');
deleteBtn.className = 'text-red-600 hover:text-red-900';
deleteBtn.innerHTML = '<i class="fas fa-trash"></i>';
deleteBtn.addEventListener('click', () => deleteTask(task.id));
actionsCell.appendChild(editBtn);
actionsCell.appendChild(deleteBtn);
row.appendChild(actionsCell);
taskTableBody.appendChild(row);
});
}
// Format date
function formatDate(dateString) {
const options = { year: 'numeric', month: 'short', day: 'numeric' };
return new Date(dateString).toLocaleDateString(undefined, options);
}
// Toggle task status
function toggleTaskStatus(taskId) {
const taskIndex = tasks.findIndex(task => task.id === taskId);
if (taskIndex !== -1) {
tasks[taskIndex].completed = !tasks[taskIndex].completed;
renderTasks();
}
}
// Delete task
function deleteTask(taskId) {
if (confirm('Are you sure you want to delete this task?')) {
tasks = tasks.filter(task => task.id !== taskId);
renderTasks();
}
}
// Open add task modal
function openAddModal() {
taskIdInput.value = '';
taskTitleInput.value = '';
taskDescriptionInput.value = '';
taskPriorityInput.value = 'medium';
taskDueDateInput.value = '';
modalTitle.textContent = 'Add New Task';
taskModal.classList.remove('hidden');
}
// Open edit task modal
function openEditModal(taskId) {
const task = tasks.find(task => task.id === taskId);
if (task) {
taskIdInput.value = task.id;
taskTitleInput.value = task.title;
taskDescriptionInput.value = task.description;
taskPriorityInput.value = task.priority;
taskDueDateInput.value = task.dueDate;
modalTitle.textContent = 'Edit Task';
taskModal.classList.remove('hidden');
}
}
// Close modal
function closeModal() {
taskModal.classList.add('hidden');
}
// Handle form submission
function handleFormSubmit(e) {
e.preventDefault();
const taskData = {
id: taskIdInput.value ? parseInt(taskIdInput.value) : Date.now(),
title: taskTitleInput.value,
description: taskDescriptionInput.value,
priority: taskPriorityInput.value,
dueDate: taskDueDateInput.value,
completed: false
};
if (taskIdInput.value) {
// Update existing task
const taskIndex = tasks.findIndex(task => task.id === parseInt(taskIdInput.value));
if (taskIndex !== -1) {
tasks[taskIndex] = taskData;
}
} else {
// Add new task
tasks.push(taskData);
}
closeModal();
renderTasks();
}
// Event listeners
addTaskBtn.addEventListener('click', openAddModal);
closeModalBtn.addEventListener('click', closeModal);
cancelTaskBtn.addEventListener('click', closeModal);
taskForm.addEventListener('submit', handleFormSubmit);
searchInput.addEventListener('input', renderTasks);
priorityFilter.addEventListener('change', renderTasks);
statusFilter.addEventListener('change', renderTasks);
// Initial render
renderTasks();
</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=Hamid-x/share" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html> |