hharris928 commited on
Commit
3fb9c6b
·
verified ·
1 Parent(s): 095025a

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +348 -808
index.html CHANGED
@@ -3,965 +3,505 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Task Management Dashboard</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- .sidebar-item.active {
11
- background-color: #F3F4F6;
12
- border-left: 4px solid #4F46E5;
13
- }
14
- .status-completed {
15
- background-color: #D1FAE5;
16
- color: #065F46;
17
- }
18
- .status-in-progress {
19
- background-color: #FEF3C7;
20
- color: #92400E;
21
  }
22
- .status-pending {
23
- background-color: #FEE2E2;
24
- color: #991B1B;
25
  }
26
  .task-card:hover {
27
  transform: translateY(-2px);
28
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
29
  }
30
- .progress-bar {
31
- height: 6px;
32
- border-radius: 3px;
33
- background-color: #E5E7EB;
34
- }
35
- .progress-fill {
36
- height: 100%;
37
- border-radius: 3px;
38
- background-color: #4F46E5;
39
- }
40
- .avatar-group {
41
- display: flex;
42
- }
43
- .avatar {
44
- width: 32px;
45
- height: 32px;
46
- border-radius: 50%;
47
- border: 2px solid white;
48
- margin-left: -8px;
49
- }
50
- .avatar:first-child {
51
- margin-left: 0;
52
- }
53
- .kanban-column {
54
- min-height: 400px;
55
- background-color: #F9FAFB;
56
- border-radius: 0.5rem;
57
- }
58
- .kanban-header {
59
- border-top-left-radius: 0.5rem;
60
- border-top-right-radius: 0.5rem;
61
- padding: 0.75rem 1rem;
62
- font-weight: 600;
63
- }
64
- .kanban-task-list {
65
- min-height: 100px;
66
- padding: 0.5rem;
67
- }
68
- .kanban-task {
69
- margin-bottom: 0.75rem;
70
- cursor: grab;
71
- user-select: none;
72
- }
73
- .kanban-task.dragging {
74
  opacity: 0.5;
75
  transform: scale(1.02);
76
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
77
- }
78
- .view-toggle {
79
- background-color: #E5E7EB;
80
- border-radius: 0.375rem;
81
- padding: 0.25rem;
82
- }
83
- .view-toggle-btn {
84
- padding: 0.375rem 0.75rem;
85
- border-radius: 0.25rem;
86
- font-size: 0.875rem;
87
- font-weight: 500;
88
- }
89
- .view-toggle-btn.active {
90
- background-color: white;
91
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
92
  }
93
  .modal {
94
- transition: opacity 0.3s ease;
95
  }
96
- .modal-overlay {
97
- background-color: rgba(0, 0, 0, 0.5);
 
 
98
  }
99
  </style>
100
  </head>
101
- <body class="bg-gray-50 font-sans">
102
  <div class="flex h-screen overflow-hidden">
103
  <!-- Sidebar -->
104
- <div class="hidden md:flex md:flex-shrink-0">
105
- <div class="flex flex-col w-64 border-r border-gray-200 bg-white">
106
- <div class="flex items-center h-16 px-4 border-b border-gray-200">
107
- <div class="flex items-center">
108
- <div class="w-8 h-8 rounded-full bg-indigo-500 flex items-center justify-center text-white font-bold">T</div>
109
- <span class="ml-2 text-lg font-semibold">Task Manager</span>
110
- </div>
111
- </div>
112
- <div class="flex flex-col flex-grow pt-4 pb-4 overflow-y-auto">
113
- <nav class="flex-1 px-2 space-y-1">
114
- <a href="#" class="sidebar-item active flex items-center px-4 py-3 text-sm font-medium text-gray-900 rounded-md">
115
- <i class="fas fa-chart-pie mr-3 text-gray-500"></i>
116
- Dashboard
117
- </a>
118
- <a href="#" class="sidebar-item flex items-center px-4 py-3 text-sm font-medium text-gray-600 rounded-md">
119
- <i class="fas fa-tasks mr-3 text-gray-500"></i>
120
- Projects
121
  </a>
122
- <a href="#" class="sidebar-item flex items-center px-4 py-3 text-sm font-medium text-gray-600 rounded-md">
123
- <i class="fas fa-calendar-alt mr-3 text-gray-500"></i>
124
- Calendar
 
 
125
  </a>
126
- <a href="#" class="sidebar-item flex items-center px-4 py-3 text-sm font-medium text-gray-600 rounded-md">
127
- <i class="fas fa-users mr-3 text-gray-500"></i>
128
- Team
 
 
129
  </a>
130
- <a href="#" class="sidebar-item flex items-center px-4 py-3 text-sm font-medium text-gray-600 rounded-md">
131
- <i class="fas fa-file-alt mr-3 text-gray-500"></i>
132
- Reports
 
 
133
  </a>
134
- <a href="#" class="sidebar-item flex items-center px-4 py-3 text-sm font-medium text-gray-600 rounded-md">
135
- <i class="fas fa-cog mr-3 text-gray-500"></i>
136
- Settings
 
 
137
  </a>
138
- </nav>
139
- </div>
140
- <div class="p-4 border-t border-gray-200">
141
- <div class="flex items-center">
142
- <img class="w-10 h-10 rounded-full" src="https://randomuser.me/api/portraits/women/44.jpg" alt="User profile">
143
- <div class="ml-3">
144
- <p class="text-sm font-medium text-gray-900">Sarah Johnson</p>
145
- <p class="text-xs font-medium text-gray-500">Admin</p>
146
- </div>
147
  </div>
148
  </div>
149
  </div>
150
  </div>
151
 
152
- <!-- Main content -->
153
- <div class="flex flex-col flex-1 overflow-hidden">
154
- <!-- Top navigation -->
155
- <div class="flex items-center justify-between h-16 px-6 border-b border-gray-200 bg-white">
156
- <div class="flex items-center">
157
- <button class="md:hidden p-2 rounded-md text-gray-500 hover:text-gray-600 hover:bg-gray-100 focus:outline-none">
158
- <i class="fas fa-bars"></i>
159
- </button>
160
- <h1 class="ml-4 text-xl font-semibold text-gray-900">Dashboard</h1>
161
  </div>
162
  <div class="flex items-center space-x-4">
163
  <div class="relative">
164
- <input type="text" placeholder="Search..." class="pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
165
  <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
166
  </div>
167
- <button class="p-2 text-gray-500 rounded-full hover:bg-gray-100">
168
- <i class="fas fa-bell"></i>
169
- </button>
170
- <div class="relative">
171
- <button class="flex items-center focus:outline-none">
172
- <img class="w-8 h-8 rounded-full" src="https://randomuser.me/api/portraits/women/44.jpg" alt="User profile">
173
  </button>
174
  </div>
175
  </div>
176
- </div>
177
-
178
- <!-- Content area -->
179
- <div class="flex-1 overflow-auto p-6 bg-gray-50">
180
- <!-- Stats Cards -->
181
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
182
- <div class="bg-white p-6 rounded-lg shadow">
183
- <div class="flex items-center justify-between">
184
- <div>
185
- <p class="text-sm font-medium text-gray-500">Total Projects</p>
186
- <p class="text-2xl font-bold text-gray-900 mt-1">24</p>
187
- </div>
188
- <div class="p-3 rounded-full bg-indigo-100 text-indigo-600">
189
- <i class="fas fa-folder-open text-lg"></i>
190
- </div>
191
- </div>
192
- <div class="mt-4">
193
- <p class="text-xs text-gray-500">+2 from last week</p>
194
- </div>
195
- </div>
196
- <div class="bg-white p-6 rounded-lg shadow">
197
- <div class="flex items-center justify-between">
198
- <div>
199
- <p class="text-sm font-medium text-gray-500">Completed Tasks</p>
200
- <p class="text-2xl font-bold text-gray-900 mt-1">156</p>
201
- </div>
202
- <div class="p-3 rounded-full bg-green-100 text-green-600">
203
- <i class="fas fa-check-circle text-lg"></i>
204
- </div>
205
- </div>
206
- <div class="mt-4">
207
- <p class="text-xs text-gray-500">+12 from last week</p>
208
- </div>
209
- </div>
210
- <div class="bg-white p-6 rounded-lg shadow">
211
- <div class="flex items-center justify-between">
212
- <div>
213
- <p class="text-sm font-medium text-gray-500">Pending Tasks</p>
214
- <p class="text-2xl font-bold text-gray-900 mt-1">32</p>
215
- </div>
216
- <div class="p-3 rounded-full bg-yellow-100 text-yellow-600">
217
- <i class="fas fa-clock text-lg"></i>
218
- </div>
219
- </div>
220
- <div class="mt-4">
221
- <p class="text-xs text-gray-500">-5 from last week</p>
222
- </div>
223
- </div>
224
- <div class="bg-white p-6 rounded-lg shadow">
225
- <div class="flex items-center justify-between">
226
- <div>
227
- <p class="text-sm font-medium text-gray-500">Team Members</p>
228
- <p class="text-2xl font-bold text-gray-900 mt-1">8</p>
229
- </div>
230
- <div class="p-3 rounded-full bg-blue-100 text-blue-600">
231
- <i class="fas fa-users text-lg"></i>
232
- </div>
233
- </div>
234
- <div class="mt-4">
235
- <p class="text-xs text-gray-500">+1 from last week</p>
236
- </div>
237
- </div>
238
- </div>
239
 
240
- <!-- View Toggle -->
 
241
  <div class="flex justify-between items-center mb-6">
242
- <h2 class="text-lg font-semibold text-gray-900">My Tasks</h2>
243
- <div class="flex items-center space-x-4">
244
- <div class="view-toggle flex">
245
- <button id="list-view-btn" class="view-toggle-btn">
246
- <i class="fas fa-list mr-2"></i>List View
247
- </button>
248
- <button id="kanban-view-btn" class="view-toggle-btn active">
249
- <i class="fas fa-columns mr-2"></i>Kanban View
250
- </button>
251
- </div>
252
- <button id="add-task-btn" class="flex items-center px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
253
- <i class="fas fa-plus mr-2"></i>
254
- Add Task
255
  </button>
256
  </div>
257
- </div>
258
-
259
- <!-- List View -->
260
- <div id="list-view" class="hidden bg-white p-6 rounded-lg shadow mb-6">
261
- <div class="space-y-4" id="list-view-tasks">
262
- <!-- Tasks will be dynamically added here -->
263
  </div>
264
  </div>
265
 
266
- <!-- Kanban View -->
267
- <div id="kanban-view" class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
268
  <!-- To Do Column -->
269
- <div class="kanban-column">
270
- <div class="kanban-header bg-blue-100 text-blue-800">
271
- <div class="flex justify-between items-center">
272
- <span>To Do</span>
273
- <span class="text-xs bg-blue-200 text-blue-800 px-2 py-1 rounded-full" id="todo-count">0 tasks</span>
274
- </div>
275
  </div>
276
- <div class="kanban-task-list" id="todo-column">
277
- <!-- Tasks will be dynamically added here -->
278
  </div>
279
  </div>
280
-
281
  <!-- In Progress Column -->
282
- <div class="kanban-column">
283
- <div class="kanban-header bg-yellow-100 text-yellow-800">
284
- <div class="flex justify-between items-center">
285
- <span>In Progress</span>
286
- <span class="text-xs bg-yellow-200 text-yellow-800 px-2 py-1 rounded-full" id="inprogress-count">0 tasks</span>
287
- </div>
288
  </div>
289
- <div class="kanban-task-list" id="inprogress-column">
290
- <!-- Tasks will be dynamically added here -->
291
  </div>
292
  </div>
293
-
294
- <!-- Done Column -->
295
- <div class="kanban-column">
296
- <div class="kanban-header bg-green-100 text-green-800">
297
- <div class="flex justify-between items-center">
298
- <span>Done</span>
299
- <span class="text-xs bg-green-200 text-green-800 px-2 py-1 rounded-full" id="done-count">0 tasks</span>
300
- </div>
301
  </div>
302
- <div class="kanban-task-list" id="done-column">
303
- <!-- Tasks will be dynamically added here -->
304
  </div>
305
  </div>
306
- </div>
307
 
308
- <!-- Recent Activity -->
309
- <div class="bg-white p-6 rounded-lg shadow">
310
- <h2 class="text-lg font-semibold text-gray-900 mb-6">Recent Activity</h2>
311
- <div class="space-y-4" id="recent-activity">
312
- <!-- Activity will be dynamically added here -->
 
 
 
 
313
  </div>
314
  </div>
315
- </div>
316
  </div>
317
  </div>
318
 
319
- <!-- Add/Edit Task Modal -->
320
- <div id="task-modal" class="fixed inset-0 z-50 flex items-center justify-center modal hidden opacity-0">
321
- <div class="modal-overlay absolute inset-0 bg-gray-500 opacity-50"></div>
322
- <div class="bg-white rounded-lg shadow-xl z-50 w-full max-w-md">
323
- <div class="p-6">
324
- <div class="flex justify-between items-center mb-4">
325
- <h3 class="text-lg font-semibold text-gray-900" id="modal-title">Add New Task</h3>
326
- <button id="close-modal" class="text-gray-400 hover:text-gray-500">
327
- <i class="fas fa-times"></i>
328
- </button>
329
- </div>
330
  <form id="task-form">
331
  <input type="hidden" id="task-id">
332
  <div class="mb-4">
333
- <label for="task-title" class="block text-sm font-medium text-gray-700 mb-1">Title</label>
334
- <input type="text" id="task-title" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" required>
335
  </div>
336
  <div class="mb-4">
337
  <label for="task-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
338
- <textarea id="task-description" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"></textarea>
339
- </div>
340
- <div class="mb-4">
341
- <label for="task-project" class="block text-sm font-medium text-gray-700 mb-1">Project</label>
342
- <input type="text" id="task-project" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
343
  </div>
344
  <div class="mb-4">
345
  <label for="task-status" class="block text-sm font-medium text-gray-700 mb-1">Status</label>
346
- <select id="task-status" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
347
- <option value="pending">Pending</option>
348
- <option value="in-progress">In Progress</option>
349
- <option value="completed">Completed</option>
 
350
  </select>
351
  </div>
352
  <div class="mb-4">
353
- <label for="task-due-date" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label>
354
- <input type="date" id="task-due-date" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
355
- </div>
356
- <div class="mb-4">
357
- <label class="block text-sm font-medium text-gray-700 mb-1">Assignees</label>
358
- <div class="flex flex-wrap gap-2">
359
- <div class="flex items-center">
360
- <input type="checkbox" id="assignee-1" class="h-4 w-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500" value="1">
361
- <label for="assignee-1" class="ml-2 text-sm text-gray-700">John Smith</label>
362
- </div>
363
- <div class="flex items-center">
364
- <input type="checkbox" id="assignee-2" class="h-4 w-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500" value="2">
365
- <label for="assignee-2" class="ml-2 text-sm text-gray-700">Emma Wilson</label>
366
- </div>
367
- <div class="flex items-center">
368
- <input type="checkbox" id="assignee-3" class="h-4 w-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500" value="3">
369
- <label for="assignee-3" class="ml-2 text-sm text-gray-700">Michael Brown</label>
370
- </div>
371
- </div>
372
  </div>
373
- <div class="flex justify-end space-x-3">
374
- <button type="button" id="cancel-task" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
375
- Cancel
376
- </button>
377
- <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-md text-sm font-medium hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
378
- Save Task
379
- </button>
380
  </div>
381
  </form>
382
  </div>
383
  </div>
384
  </div>
385
 
386
- <!-- Delete Confirmation Modal -->
387
- <div id="delete-modal" class="fixed inset-0 z-50 flex items-center justify-center modal hidden opacity-0">
388
- <div class="modal-overlay absolute inset-0 bg-gray-500 opacity-50"></div>
389
- <div class="bg-white rounded-lg shadow-xl z-50 w-full max-w-md">
390
- <div class="p-6">
391
- <div class="flex justify-between items-center mb-4">
392
- <h3 class="text-lg font-semibold text-gray-900">Confirm Deletion</h3>
393
- <button id="close-delete-modal" class="text-gray-400 hover:text-gray-500">
394
- <i class="fas fa-times"></i>
395
- </button>
396
- </div>
397
- <p class="text-gray-700 mb-6">Are you sure you want to delete this task? This action cannot be undone.</p>
398
- <div class="flex justify-end space-x-3">
399
- <button type="button" id="cancel-delete" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
400
- Cancel
401
- </button>
402
- <button type="button" id="confirm-delete" class="px-4 py-2 bg-red-600 text-white rounded-md text-sm font-medium hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-red-500">
403
- Delete
404
- </button>
405
- </div>
406
- </div>
407
- </div>
408
- </div>
409
-
410
  <script>
411
- // Sample data for tasks
412
  let tasks = [
413
- {
414
- id: 1,
415
- title: "Design new homepage layout",
416
- description: "Create wireframes and mockups for the new homepage design",
417
- project: "Website Redesign",
418
- status: "pending",
419
- dueDate: "2023-06-15",
420
- assignees: [1, 2],
421
- createdAt: new Date()
422
- },
423
- {
424
- id: 2,
425
- title: "Review app prototype",
426
- description: "Test and provide feedback on the new mobile app prototype",
427
- project: "Mobile App Development",
428
- status: "completed",
429
- dueDate: "2023-06-10",
430
- assignees: [3],
431
- createdAt: new Date()
432
- },
433
- {
434
- id: 3,
435
- title: "Write blog post about launch",
436
- description: "Create content for the product launch announcement",
437
- project: "Product Launch",
438
- status: "pending",
439
- dueDate: "2023-06-18",
440
- assignees: [1],
441
- createdAt: new Date()
442
- },
443
- {
444
- id: 4,
445
- title: "Create social media content",
446
- description: "Design graphics and write captions for social media posts",
447
- project: "Content Marketing",
448
- status: "in-progress",
449
- dueDate: "2023-06-17",
450
- assignees: [2],
451
- createdAt: new Date()
452
- }
453
- ];
454
-
455
- // Sample data for team members
456
- const teamMembers = [
457
- { id: 1, name: "John Smith", avatar: "https://randomuser.me/api/portraits/men/32.jpg" },
458
- { id: 2, name: "Emma Wilson", avatar: "https://randomuser.me/api/portraits/women/12.jpg" },
459
- { id: 3, name: "Michael Brown", avatar: "https://randomuser.me/api/portraits/men/45.jpg" }
460
  ];
461
 
462
  // DOM elements
463
- const listViewBtn = document.getElementById('list-view-btn');
464
- const kanbanViewBtn = document.getElementById('kanban-view-btn');
465
- const listView = document.getElementById('list-view');
466
- const kanbanView = document.getElementById('kanban-view');
467
- const addTaskBtn = document.getElementById('add-task-btn');
468
  const taskModal = document.getElementById('task-modal');
469
- const deleteModal = document.getElementById('delete-modal');
470
  const taskForm = document.getElementById('task-form');
 
 
 
 
 
471
  const taskIdInput = document.getElementById('task-id');
472
  const taskTitleInput = document.getElementById('task-title');
473
- const taskDescriptionInput = document.getElementById('task-description');
474
- const taskProjectInput = document.getElementById('task-project');
475
  const taskStatusInput = document.getElementById('task-status');
476
- const taskDueDateInput = document.getElementById('task-due-date');
477
- const closeModalBtn = document.getElementById('close-modal');
478
- const cancelTaskBtn = document.getElementById('cancel-task');
479
- const closeDeleteModalBtn = document.getElementById('close-delete-modal');
480
- const cancelDeleteBtn = document.getElementById('cancel-delete');
481
- const confirmDeleteBtn = document.getElementById('confirm-delete');
482
- const modalTitle = document.getElementById('modal-title');
483
- const todoCount = document.getElementById('todo-count');
484
- const inprogressCount = document.getElementById('inprogress-count');
485
- const doneCount = document.getElementById('done-count');
486
- const recentActivity = document.getElementById('recent-activity');
487
 
488
- // Current task to be deleted
489
- let taskToDelete = null;
490
-
491
- // Initialize the app
492
- document.addEventListener('DOMContentLoaded', () => {
493
- renderTasks();
494
- setupDragAndDrop();
495
- setupEventListeners();
496
- renderRecentActivity();
497
- });
498
-
499
- // Render tasks in both list and kanban views
500
  function renderTasks() {
501
- renderListView();
502
- renderKanbanView();
503
- updateTaskCounts();
504
- }
505
-
506
- // Render list view
507
- function renderListView() {
508
- const listViewTasks = document.getElementById('list-view-tasks');
509
- listViewTasks.innerHTML = '';
510
-
511
- tasks.forEach(task => {
512
- const statusClass = getStatusClass(task.status);
513
- const statusText = getStatusText(task.status);
514
-
515
- const taskElement = document.createElement('div');
516
- taskElement.className = 'flex items-center justify-between p-4 border border-gray-200 rounded-lg';
517
- taskElement.dataset.taskId = task.id;
518
- taskElement.innerHTML = `
519
- <div class="flex items-center">
520
- <input type="checkbox" class="h-4 w-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500" ${task.status === 'completed' ? 'checked' : ''}>
521
- <div class="ml-4">
522
- <p class="text-sm font-medium text-gray-900">${task.title}</p>
523
- <p class="text-xs text-gray-500">${task.project} project</p>
524
- </div>
525
- </div>
526
- <div class="flex items-center">
527
- <span class="px-2 py-1 text-xs font-medium rounded-full ${statusClass} mr-4">
528
- ${statusText}
529
- </span>
530
- <span class="text-xs text-gray-500">${getDueDateText(task.dueDate)}</span>
531
- <button class="ml-4 text-gray-400 hover:text-gray-500 edit-task" data-task-id="${task.id}">
532
- <i class="fas fa-edit"></i>
533
- </button>
534
- <button class="ml-2 text-gray-400 hover:text-gray-500 delete-task" data-task-id="${task.id}">
535
- <i class="fas fa-trash"></i>
536
- </button>
537
- </div>
538
- `;
539
-
540
- listViewTasks.appendChild(taskElement);
541
- });
542
-
543
- // Add event listeners to edit and delete buttons
544
- document.querySelectorAll('.edit-task').forEach(btn => {
545
- btn.addEventListener('click', (e) => {
546
- const taskId = parseInt(btn.dataset.taskId);
547
- openEditTaskModal(taskId);
548
- });
549
- });
550
-
551
- document.querySelectorAll('.delete-task').forEach(btn => {
552
- btn.addEventListener('click', (e) => {
553
- const taskId = parseInt(btn.dataset.taskId);
554
- openDeleteTaskModal(taskId);
555
- });
556
- });
557
- }
558
-
559
- // Render kanban view
560
- function renderKanbanView() {
561
- const todoColumn = document.getElementById('todo-column');
562
- const inprogressColumn = document.getElementById('inprogress-column');
563
- const doneColumn = document.getElementById('done-column');
564
-
565
  todoColumn.innerHTML = '';
566
  inprogressColumn.innerHTML = '';
 
567
  doneColumn.innerHTML = '';
568
 
 
569
  tasks.forEach(task => {
570
- const statusClass = getStatusClass(task.status);
571
- const statusText = getStatusText(task.status);
572
- const assignees = getAssignees(task.assignees);
573
-
574
- const taskElement = document.createElement('div');
575
- taskElement.className = 'kanban-task bg-white p-4 rounded-lg shadow border border-gray-200';
576
- taskElement.draggable = true;
577
- taskElement.dataset.taskId = task.id;
578
- taskElement.innerHTML = `
579
- <div class="flex items-start justify-between mb-2">
580
- <h3 class="text-sm font-medium text-gray-900">${task.title}</h3>
581
- <span class="px-2 py-1 text-xs font-medium rounded-full ${statusClass}">
582
- ${statusText}
583
- </span>
584
- </div>
585
- <p class="text-xs text-gray-500 mb-3">${task.project} project</p>
586
- <div class="flex items-center justify-between">
587
- <div class="avatar-group">
588
- ${assignees.map(assignee => `
589
- <img class="avatar" src="${assignee.avatar}" alt="${assignee.name}" title="${assignee.name}">
590
- `).join('')}
591
- </div>
592
- <span class="text-xs text-gray-500">${getDueDateText(task.dueDate)}</span>
593
- </div>
594
- <div class="flex justify-end mt-3 space-x-2">
595
- <button class="text-gray-400 hover:text-gray-500 edit-task" data-task-id="${task.id}">
596
- <i class="fas fa-edit text-sm"></i>
597
- </button>
598
- <button class="text-gray-400 hover:text-gray-500 delete-task" data-task-id="${task.id}">
599
- <i class="fas fa-trash text-sm"></i>
600
- </button>
601
- </div>
602
- `;
603
-
604
- // Add to appropriate column based on status
605
- if (task.status === 'pending') {
606
- todoColumn.appendChild(taskElement);
607
- } else if (task.status === 'in-progress') {
608
- inprogressColumn.appendChild(taskElement);
609
- } else if (task.status === 'completed') {
610
- doneColumn.appendChild(taskElement);
611
  }
612
  });
613
 
614
- // Add event listeners to edit and delete buttons
615
- document.querySelectorAll('.edit-task').forEach(btn => {
616
- btn.addEventListener('click', (e) => {
617
- e.stopPropagation();
618
- const taskId = parseInt(btn.dataset.taskId);
619
- openEditTaskModal(taskId);
620
- });
621
- });
622
-
623
- document.querySelectorAll('.delete-task').forEach(btn => {
624
- btn.addEventListener('click', (e) => {
625
- e.stopPropagation();
626
- const taskId = parseInt(btn.dataset.taskId);
627
- openDeleteTaskModal(taskId);
628
- });
629
- });
630
  }
631
 
632
- // Update task counts in kanban view
633
- function updateTaskCounts() {
634
- const todoTasks = tasks.filter(task => task.status === 'pending').length;
635
- const inprogressTasks = tasks.filter(task => task.status === 'in-progress').length;
636
- const doneTasks = tasks.filter(task => task.status === 'completed').length;
637
-
638
- todoCount.textContent = `${todoTasks} ${todoTasks === 1 ? 'task' : 'tasks'}`;
639
- inprogressCount.textContent = `${inprogressTasks} ${inprogressTasks === 1 ? 'task' : 'tasks'}`;
640
- doneCount.textContent = `${doneTasks} ${doneTasks === 1 ? 'task' : 'tasks'}`;
641
- }
 
 
 
 
 
 
 
 
 
 
 
 
642
 
643
- // Render recent activity
644
- function renderRecentActivity() {
645
- // Sort tasks by creation date (newest first)
646
- const sortedTasks = [...tasks].sort((a, b) => b.createdAt - a.createdAt);
 
647
 
648
- // Take the 3 most recent tasks
649
- const recentTasks = sortedTasks.slice(0, 3);
650
 
651
- recentActivity.innerHTML = recentTasks.map(task => {
652
- const assignee = teamMembers.find(member => member.id === task.assignees[0]);
653
- const action = task.status === 'completed' ? 'completed' :
654
- task.status === 'in-progress' ? 'started working on' : 'created';
655
-
656
- return `
657
- <div class="flex">
658
- <div class="flex-shrink-0">
659
- <img class="h-10 w-10 rounded-full" src="${assignee.avatar}" alt="${assignee.name}">
660
- </div>
661
- <div class="ml-3">
662
- <p class="text-sm font-medium text-gray-900">${assignee.name} <span class="text-gray-500">${action}</span> "${task.title}"</p>
663
- <p class="text-xs text-gray-500">${task.project} project</p>
664
- <p class="text-xs text-gray-400 mt-1">${formatDate(task.createdAt)}</p>
665
- </div>
666
  </div>
667
- `;
668
- }).join('');
669
- }
670
-
671
- // Setup drag and drop functionality
672
- function setupDragAndDrop() {
673
- const tasks = document.querySelectorAll('.kanban-task');
674
- const columns = document.querySelectorAll('.kanban-task-list');
675
 
676
- let draggedTask = null;
 
 
677
 
678
- tasks.forEach(task => {
679
- task.addEventListener('dragstart', () => {
680
- draggedTask = task;
681
- setTimeout(() => {
682
- task.classList.add('dragging');
683
- }, 0);
684
- });
685
-
686
- task.addEventListener('dragend', () => {
687
- task.classList.remove('dragging');
688
- draggedTask = null;
689
- });
690
  });
691
 
692
- columns.forEach(column => {
693
- column.addEventListener('dragover', e => {
694
- e.preventDefault();
695
- const afterElement = getDragAfterElement(column, e.clientY);
696
- if (afterElement == null) {
697
- column.appendChild(draggedTask);
698
- } else {
699
- column.insertBefore(draggedTask, afterElement);
700
- }
701
- });
702
-
703
- column.addEventListener('drop', () => {
704
- const taskId = parseInt(draggedTask.dataset.taskId);
705
- const task = tasks.find(t => t.id === taskId);
706
-
707
- // Determine new status based on column
708
- let newStatus = 'pending';
709
- if (column.id === 'inprogress-column') {
710
- newStatus = 'in-progress';
711
- } else if (column.id === 'done-column') {
712
- newStatus = 'completed';
713
- }
714
-
715
- // Update task status
716
- task.status = newStatus;
717
-
718
- // Update UI
719
- renderTasks();
720
- renderRecentActivity();
721
- });
722
  });
723
 
724
- function getDragAfterElement(column, y) {
725
- const draggableElements = [...column.querySelectorAll('.kanban-task:not(.dragging)')];
726
-
727
- return draggableElements.reduce((closest, child) => {
728
- const box = child.getBoundingClientRect();
729
- const offset = y - box.top - box.height / 2;
730
-
731
- if (offset < 0 && offset > closest.offset) {
732
- return { offset: offset, element: child };
733
- } else {
734
- return closest;
735
- }
736
- }, { offset: Number.NEGATIVE_INFINITY }).element;
737
- }
738
  }
739
 
740
- // Setup event listeners
741
- function setupEventListeners() {
742
- // Sidebar item active state
743
- const sidebarItems = document.querySelectorAll('.sidebar-item');
744
- sidebarItems.forEach(item => {
745
- item.addEventListener('click', (e) => {
746
- e.preventDefault();
747
- sidebarItems.forEach(i => i.classList.remove('active'));
748
- item.classList.add('active');
749
- });
750
- });
751
-
752
- // View toggle functionality
753
- listViewBtn.addEventListener('click', () => {
754
- listViewBtn.classList.add('active');
755
- kanbanViewBtn.classList.remove('active');
756
- listView.classList.remove('hidden');
757
- kanbanView.classList.add('hidden');
758
- });
759
-
760
- kanbanViewBtn.addEventListener('click', () => {
761
- kanbanViewBtn.classList.add('active');
762
- listViewBtn.classList.remove('active');
763
- kanbanView.classList.remove('hidden');
764
- listView.classList.add('hidden');
765
- });
766
-
767
- // Add task button
768
- addTaskBtn.addEventListener('click', () => {
769
- openAddTaskModal();
770
- });
771
-
772
- // Task form submission
773
- taskForm.addEventListener('submit', (e) => {
774
- e.preventDefault();
775
- saveTask();
776
- });
777
 
778
- // Modal close buttons
779
- closeModalBtn.addEventListener('click', closeTaskModal);
780
- cancelTaskBtn.addEventListener('click', closeTaskModal);
781
- closeDeleteModalBtn.addEventListener('click', closeDeleteModal);
782
- cancelDeleteBtn.addEventListener('click', closeDeleteModal);
783
-
784
- // Delete confirmation
785
- confirmDeleteBtn.addEventListener('click', () => {
786
- if (taskToDelete) {
787
- deleteTask(taskToDelete);
788
- closeDeleteModal();
789
- }
790
- });
791
  }
792
 
793
- // Open add task modal
794
- function openAddTaskModal() {
795
- modalTitle.textContent = 'Add New Task';
796
- taskIdInput.value = '';
797
- taskTitleInput.value = '';
798
- taskDescriptionInput.value = '';
799
- taskProjectInput.value = '';
800
- taskStatusInput.value = 'pending';
801
- taskDueDateInput.value = '';
802
-
803
- // Clear assignee checkboxes
804
- document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
805
- checkbox.checked = false;
806
- });
807
-
808
- openModal(taskModal);
809
- }
810
 
811
- // Open edit task modal
812
- function openEditTaskModal(taskId) {
813
- const task = tasks.find(t => t.id === taskId);
814
- if (!task) return;
815
-
816
- modalTitle.textContent = 'Edit Task';
817
- taskIdInput.value = task.id;
818
- taskTitleInput.value = task.title;
819
- taskDescriptionInput.value = task.description || '';
820
- taskProjectInput.value = task.project || '';
821
- taskStatusInput.value = task.status;
822
- taskDueDateInput.value = task.dueDate || '';
823
-
824
- // Set assignee checkboxes
825
- document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
826
- checkbox.checked = task.assignees.includes(parseInt(checkbox.value));
827
- });
828
-
829
- openModal(taskModal);
830
  }
831
 
832
- // Open delete task modal
833
- function openDeleteTaskModal(taskId) {
834
- taskToDelete = taskId;
835
- openModal(deleteModal);
836
  }
837
 
838
- // Open modal
839
- function openModal(modal) {
840
- modal.classList.remove('hidden');
841
- setTimeout(() => {
842
- modal.classList.add('opacity-100');
843
- }, 10);
844
  }
845
 
846
- // Close task modal
847
- function closeTaskModal() {
848
- taskModal.classList.remove('opacity-100');
849
- setTimeout(() => {
850
- taskModal.classList.add('hidden');
851
- }, 300);
852
  }
853
 
854
- // Close delete modal
855
- function closeDeleteModal() {
856
- taskToDelete = null;
857
- deleteModal.classList.remove('opacity-100');
858
- setTimeout(() => {
859
- deleteModal.classList.add('hidden');
860
- }, 300);
861
  }
862
 
863
- // Save task (add or update)
864
- function saveTask() {
865
- const taskId = taskIdInput.value ? parseInt(taskIdInput.value) : null;
866
- const title = taskTitleInput.value;
867
- const description = taskDescriptionInput.value;
868
- const project = taskProjectInput.value;
869
- const status = taskStatusInput.value;
870
- const dueDate = taskDueDateInput.value;
871
 
872
- // Get selected assignees
873
- const assignees = [];
874
- document.querySelectorAll('input[type="checkbox"]:checked').forEach(checkbox => {
875
- assignees.push(parseInt(checkbox.value));
876
- });
877
-
878
- if (taskId) {
879
- // Update existing task
880
  const taskIndex = tasks.findIndex(t => t.id === taskId);
881
  if (taskIndex !== -1) {
882
- tasks[taskIndex] = {
883
- ...tasks[taskIndex],
884
- title,
885
- description,
886
- project,
887
- status,
888
- dueDate,
889
- assignees,
890
- createdAt: new Date()
891
- };
892
  }
893
- } else {
894
- // Add new task
895
- const newId = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1;
896
- tasks.push({
897
- id: newId,
898
- title,
899
- description,
900
- project,
901
- status,
902
- dueDate,
903
- assignees,
904
- createdAt: new Date()
905
- });
906
  }
 
907
 
908
- // Update UI
909
- renderTasks();
910
- renderRecentActivity();
911
- closeTaskModal();
 
 
 
 
 
 
 
912
  }
913
 
914
- // Delete task
915
- function deleteTask(taskId) {
916
- tasks = tasks.filter(task => task.id !== taskId);
917
- renderTasks();
918
- renderRecentActivity();
919
  }
920
 
921
- // Helper functions
922
- function getStatusClass(status) {
923
- switch (status) {
924
- case 'completed': return 'status-completed';
925
- case 'in-progress': return 'status-in-progress';
926
- default: return 'status-pending';
 
 
 
 
 
 
 
 
 
927
  }
928
  }
929
 
930
- function getStatusText(status) {
931
- switch (status) {
932
- case 'completed': return 'Completed';
933
- case 'in-progress': return 'In Progress';
934
- default: return 'Pending';
935
  }
936
  }
937
 
938
- function getDueDateText(dueDate) {
939
- if (!dueDate) return 'No due date';
940
-
941
- const today = new Date();
942
- today.setHours(0, 0, 0, 0);
943
 
944
- const due = new Date(dueDate);
945
- due.setHours(0, 0, 0, 0);
 
 
 
 
 
946
 
947
- const diffTime = due - today;
948
- const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
 
 
 
 
 
 
 
 
 
949
 
950
- if (diffDays === 0) return 'Due today';
951
- if (diffDays === 1) return 'Due tomorrow';
952
- if (diffDays === -1) return 'Due yesterday';
953
- if (diffDays < 0) return `Due ${Math.abs(diffDays)} days ago`;
954
- return `Due in ${diffDays} days`;
955
  }
956
 
957
- function getAssignees(assigneeIds) {
958
- return teamMembers.filter(member => assigneeIds.includes(member.id));
 
 
 
 
 
 
 
 
 
 
 
959
  }
960
 
961
- function formatDate(date) {
962
- const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' };
963
- return new Date(date).toLocaleDateString('en-US', options);
964
- }
 
 
 
 
 
965
  </script>
966
  <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=hharris928/task-manager-2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
967
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Kanban Task Board</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ .kanban-column {
11
+ min-height: 500px;
 
 
 
 
 
 
 
 
 
12
  }
13
+ .task-card {
14
+ transition: all 0.2s ease;
 
15
  }
16
  .task-card:hover {
17
  transform: translateY(-2px);
18
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
19
  }
20
+ .task-card.dragging {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  opacity: 0.5;
22
  transform: scale(1.02);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
  .modal {
25
+ transition: opacity 0.2s ease, transform 0.2s ease;
26
  }
27
+ .modal.hidden {
28
+ opacity: 0;
29
+ pointer-events: none;
30
+ transform: translateY(20px);
31
  }
32
  </style>
33
  </head>
34
+ <body class="bg-gray-100 font-sans">
35
  <div class="flex h-screen overflow-hidden">
36
  <!-- Sidebar -->
37
+ <div class="w-64 bg-indigo-800 text-white flex flex-col">
38
+ <div class="p-4 flex items-center justify-center border-b border-indigo-700">
39
+ <h1 class="text-2xl font-bold">TaskFlow</h1>
40
+ </div>
41
+ <nav class="flex-1 p-4">
42
+ <ul class="space-y-2">
43
+ <li>
44
+ <a href="#" class="flex items-center p-2 rounded-lg bg-indigo-700">
45
+ <i class="fas fa-tachometer-alt mr-3"></i>
46
+ <span>Overview</span>
 
 
 
 
 
 
 
47
  </a>
48
+ </li>
49
+ <li>
50
+ <a href="#" class="flex items-center p-2 rounded-lg hover:bg-indigo-700">
51
+ <i class="fas fa-tasks mr-3"></i>
52
+ <span>Tasks</span>
53
  </a>
54
+ </li>
55
+ <li>
56
+ <a href="#" class="flex items-center p-2 rounded-lg hover:bg-indigo-700">
57
+ <i class="fas fa-users mr-3"></i>
58
+ <span>Your Team</span>
59
  </a>
60
+ </li>
61
+ <li>
62
+ <a href="#" class="flex items-center p-2 rounded-lg hover:bg-indigo-700">
63
+ <i class="fas fa-envelope mr-3"></i>
64
+ <span>Messages</span>
65
  </a>
66
+ </li>
67
+ <li>
68
+ <a href="#" class="flex items-center p-2 rounded-lg hover:bg-indigo-700">
69
+ <i class="fas fa-cog mr-3"></i>
70
+ <span>Settings</span>
71
  </a>
72
+ </li>
73
+ </ul>
74
+ </nav>
75
+ <div class="p-4 border-t border-indigo-700">
76
+ <div class="flex items-center">
77
+ <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="User" class="w-10 h-10 rounded-full mr-3">
78
+ <div>
79
+ <p class="font-medium">Jane Doe</p>
80
+ <p class="text-xs text-indigo-300">Admin</p>
81
  </div>
82
  </div>
83
  </div>
84
  </div>
85
 
86
+ <!-- Main Content -->
87
+ <div class="flex-1 flex flex-col overflow-hidden">
88
+ <!-- Header -->
89
+ <header class="bg-white border-b border-gray-200 p-4 flex items-center justify-between">
90
+ <div>
91
+ <h2 class="text-xl font-semibold">Task Board</h2>
92
+ <p class="text-sm text-gray-500">Manage your tasks efficiently</p>
 
 
93
  </div>
94
  <div class="flex items-center space-x-4">
95
  <div class="relative">
96
+ <input type="text" placeholder="Search tasks..." class="pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
97
  <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
98
  </div>
99
+ <div class="flex items-center space-x-2">
100
+ <button id="theme-toggle" class="p-2 rounded-full hover:bg-gray-100">
101
+ <i class="fas fa-moon"></i>
102
+ </button>
103
+ <button class="p-2 rounded-full hover:bg-gray-100">
104
+ <i class="fas fa-bell"></i>
105
  </button>
106
  </div>
107
  </div>
108
+ </header>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
+ <!-- Content -->
111
+ <main class="flex-1 overflow-auto p-6">
112
  <div class="flex justify-between items-center mb-6">
113
+ <div class="flex space-x-2">
114
+ <button class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">
115
+ <i class="fas fa-plus mr-2"></i> Create Task
116
+ </button>
117
+ <button class="px-4 py-2 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">
118
+ <i class="fas fa-filter mr-2"></i> Filter
 
 
 
 
 
 
 
119
  </button>
120
  </div>
121
+ <div class="flex items-center space-x-2">
122
+ <span class="text-sm text-gray-500">View:</span>
123
+ <button class="px-3 py-1 bg-indigo-100 text-indigo-700 rounded-lg">Kanban</button>
124
+ <button class="px-3 py-1 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">List</button>
 
 
125
  </div>
126
  </div>
127
 
128
+ <!-- Kanban Board -->
129
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
130
  <!-- To Do Column -->
131
+ <div class="kanban-column bg-gray-50 rounded-lg p-4">
132
+ <div class="flex justify-between items-center mb-4">
133
+ <h3 class="font-semibold text-gray-700">To Do</h3>
134
+ <span class="bg-gray-200 text-gray-700 text-xs px-2 py-1 rounded-full">5</span>
 
 
135
  </div>
136
+ <div class="space-y-4" id="todo-column">
137
+ <!-- Task cards will be added here by JavaScript -->
138
  </div>
139
  </div>
140
+
141
  <!-- In Progress Column -->
142
+ <div class="kanban-column bg-gray-50 rounded-lg p-4">
143
+ <div class="flex justify-between items-center mb-4">
144
+ <h3 class="font-semibold text-gray-700">In Progress</h3>
145
+ <span class="bg-blue-200 text-blue-700 text-xs px-2 py-1 rounded-full">3</span>
 
 
146
  </div>
147
+ <div class="space-y-4" id="inprogress-column">
148
+ <!-- Task cards will be added here by JavaScript -->
149
  </div>
150
  </div>
151
+
152
+ <!-- Review Column -->
153
+ <div class="kanban-column bg-gray-50 rounded-lg p-4">
154
+ <div class="flex justify-between items-center mb-4">
155
+ <h3 class="font-semibold text-gray-700">Review</h3>
156
+ <span class="bg-yellow-200 text-yellow-700 text-xs px-2 py-1 rounded-full">2</span>
 
 
157
  </div>
158
+ <div class="space-y-4" id="review-column">
159
+ <!-- Task cards will be added here by JavaScript -->
160
  </div>
161
  </div>
 
162
 
163
+ <!-- Done Column -->
164
+ <div class="kanban-column bg-gray-50 rounded-lg p-4">
165
+ <div class="flex justify-between items-center mb-4">
166
+ <h3 class="font-semibold text-gray-700">Done</h3>
167
+ <span class="bg-green-200 text-green-700 text-xs px-2 py-1 rounded-full">4</span>
168
+ </div>
169
+ <div class="space-y-4" id="done-column">
170
+ <!-- Task cards will be added here by JavaScript -->
171
+ </div>
172
  </div>
173
  </div>
174
+ </main>
175
  </div>
176
  </div>
177
 
178
+ <!-- Task Modal -->
179
+ <div id="task-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 modal hidden">
180
+ <div class="bg-white rounded-lg w-full max-w-md">
181
+ <div class="p-4 border-b flex justify-between items-center">
182
+ <h3 class="text-lg font-semibold" id="modal-title">Create New Task</h3>
183
+ <button id="close-modal" class="text-gray-500 hover:text-gray-700">
184
+ <i class="fas fa-times"></i>
185
+ </button>
186
+ </div>
187
+ <div class="p-4">
 
188
  <form id="task-form">
189
  <input type="hidden" id="task-id">
190
  <div class="mb-4">
191
+ <label for="task-title" class="block text-sm font-medium text-gray-700 mb-1">Task Title</label>
192
+ <input type="text" id="task-title" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required>
193
  </div>
194
  <div class="mb-4">
195
  <label for="task-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
196
+ <textarea id="task-description" rows="3" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea>
 
 
 
 
197
  </div>
198
  <div class="mb-4">
199
  <label for="task-status" class="block text-sm font-medium text-gray-700 mb-1">Status</label>
200
+ <select id="task-status" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
201
+ <option value="todo">To Do</option>
202
+ <option value="inprogress">In Progress</option>
203
+ <option value="review">Review</option>
204
+ <option value="done">Done</option>
205
  </select>
206
  </div>
207
  <div class="mb-4">
208
+ <label for="task-due" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label>
209
+ <input type="date" id="task-due" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  </div>
211
+ <div class="flex justify-end space-x-2">
212
+ <button type="button" id="cancel-task" class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50">Cancel</button>
213
+ <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Save Task</button>
 
 
 
 
214
  </div>
215
  </form>
216
  </div>
217
  </div>
218
  </div>
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  <script>
221
+ // Sample tasks data
222
  let tasks = [
223
+ { id: 1, title: 'Design new homepage', description: 'Create wireframes and mockups for the new homepage design', status: 'todo', due: '2023-06-15', created: '2023-05-20' },
224
+ { id: 2, title: 'Implement user authentication', description: 'Set up login and registration functionality', status: 'inprogress', due: '2023-06-10', created: '2023-05-15' },
225
+ { id: 3, title: 'Write API documentation', description: 'Document all endpoints for the REST API', status: 'review', due: '2023-06-05', created: '2023-05-10' },
226
+ { id: 4, title: 'Fix mobile menu bug', description: 'Menu doesn\'t close properly on mobile devices', status: 'done', due: '2023-05-30', created: '2023-05-01' },
227
+ { id: 5, title: 'Optimize database queries', description: 'Review and optimize slow database queries', status: 'todo', due: '2023-06-20', created: '2023-05-25' },
228
+ { id: 6, title: 'Update dependencies', description: 'Update all project dependencies to latest versions', status: 'inprogress', due: '2023-06-12', created: '2023-05-18' },
229
+ { id: 7, title: 'Create admin dashboard', description: 'Build interface for admin to manage users and content', status: 'review', due: '2023-06-08', created: '2023-05-12' },
230
+ { id: 8, title: 'Setup CI/CD pipeline', description: 'Configure continuous integration and deployment', status: 'done', due: '2023-05-28', created: '2023-04-30' },
231
+ { id: 9, title: 'Write unit tests', description: 'Add unit tests for core functionality', status: 'done', due: '2023-05-25', created: '2023-04-20' },
232
+ { id: 10, title: 'Prepare presentation', description: 'Create slides for the upcoming client meeting', status: 'todo', due: '2023-06-18', created: '2023-05-22' }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  ];
234
 
235
  // DOM elements
236
+ const todoColumn = document.getElementById('todo-column');
237
+ const inprogressColumn = document.getElementById('inprogress-column');
238
+ const reviewColumn = document.getElementById('review-column');
239
+ const doneColumn = document.getElementById('done-column');
 
240
  const taskModal = document.getElementById('task-modal');
 
241
  const taskForm = document.getElementById('task-form');
242
+ const closeModal = document.getElementById('close-modal');
243
+ const cancelTask = document.getElementById('cancel-task');
244
+ const createTaskBtn = document.querySelector('main button:first-child');
245
+ const themeToggle = document.getElementById('theme-toggle');
246
+ const modalTitle = document.getElementById('modal-title');
247
  const taskIdInput = document.getElementById('task-id');
248
  const taskTitleInput = document.getElementById('task-title');
249
+ const taskDescInput = document.getElementById('task-description');
 
250
  const taskStatusInput = document.getElementById('task-status');
251
+ const taskDueInput = document.getElementById('task-due');
 
 
 
 
 
 
 
 
 
 
252
 
253
+ // Initialize the board
 
 
 
 
 
 
 
 
 
 
 
254
  function renderTasks() {
255
+ // Clear all columns
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  todoColumn.innerHTML = '';
257
  inprogressColumn.innerHTML = '';
258
+ reviewColumn.innerHTML = '';
259
  doneColumn.innerHTML = '';
260
 
261
+ // Render tasks in their respective columns
262
  tasks.forEach(task => {
263
+ const taskCard = createTaskCard(task);
264
+ switch(task.status) {
265
+ case 'todo':
266
+ todoColumn.appendChild(taskCard);
267
+ break;
268
+ case 'inprogress':
269
+ inprogressColumn.appendChild(taskCard);
270
+ break;
271
+ case 'review':
272
+ reviewColumn.appendChild(taskCard);
273
+ break;
274
+ case 'done':
275
+ doneColumn.appendChild(taskCard);
276
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  }
278
  });
279
 
280
+ // Update task counts
281
+ updateTaskCounts();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  }
283
 
284
+ // Create a task card element
285
+ function createTaskCard(task) {
286
+ const card = document.createElement('div');
287
+ card.className = 'task-card bg-white p-4 rounded-lg shadow cursor-move border-l-4 ';
288
+ card.draggable = true;
289
+ card.dataset.id = task.id;
290
+
291
+ // Set border color based on status
292
+ switch(task.status) {
293
+ case 'todo':
294
+ card.classList.add('border-gray-400');
295
+ break;
296
+ case 'inprogress':
297
+ card.classList.add('border-blue-500');
298
+ break;
299
+ case 'review':
300
+ card.classList.add('border-yellow-500');
301
+ break;
302
+ case 'done':
303
+ card.classList.add('border-green-500');
304
+ break;
305
+ }
306
 
307
+ // Format due date
308
+ const dueDate = new Date(task.due);
309
+ const today = new Date();
310
+ today.setHours(0, 0, 0, 0);
311
+ const isOverdue = dueDate < today && task.status !== 'done';
312
 
313
+ const dueDateStr = dueDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
 
314
 
315
+ card.innerHTML = `
316
+ <div class="flex justify-between items-start mb-2">
317
+ <h4 class="font-medium">${task.title}</h4>
318
+ <div class="flex space-x-2">
319
+ <button class="edit-task text-gray-400 hover:text-indigo-600" data-id="${task.id}">
320
+ <i class="fas fa-edit"></i>
321
+ </button>
322
+ <button class="delete-task text-gray-400 hover:text-red-600" data-id="${task.id}">
323
+ <i class="fas fa-trash"></i>
324
+ </button>
 
 
 
 
 
325
  </div>
326
+ </div>
327
+ <p class="text-sm text-gray-500 mb-3">${task.description}</p>
328
+ <div class="flex justify-between items-center text-xs">
329
+ <span class="text-gray-500">Due: <span class="${isOverdue ? 'text-red-500 font-medium' : 'text-gray-700'}">${dueDateStr}</span></span>
330
+ <span class="text-gray-500">Created: ${new Date(task.created).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}</span>
331
+ </div>
332
+ `;
 
333
 
334
+ // Add drag events
335
+ card.addEventListener('dragstart', dragStart);
336
+ card.addEventListener('dragend', dragEnd);
337
 
338
+ // Add edit and delete event listeners
339
+ card.querySelector('.edit-task').addEventListener('click', (e) => {
340
+ e.stopPropagation();
341
+ editTask(task.id);
 
 
 
 
 
 
 
 
342
  });
343
 
344
+ card.querySelector('.delete-task').addEventListener('click', (e) => {
345
+ e.stopPropagation();
346
+ deleteTask(task.id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  });
348
 
349
+ return card;
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  }
351
 
352
+ // Update task counts in each column
353
+ function updateTaskCounts() {
354
+ const todoCount = document.querySelector('#todo-column + div span');
355
+ const inprogressCount = document.querySelector('#inprogress-column + div span');
356
+ const reviewCount = document.querySelector('#review-column + div span');
357
+ const doneCount = document.querySelector('#done-column + div span');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
 
359
+ todoCount.textContent = tasks.filter(t => t.status === 'todo').length;
360
+ inprogressCount.textContent = tasks.filter(t => t.status === 'inprogress').length;
361
+ reviewCount.textContent = tasks.filter(t => t.status === 'review').length;
362
+ doneCount.textContent = tasks.filter(t => t.status === 'done').length;
 
 
 
 
 
 
 
 
 
363
  }
364
 
365
+ // Drag and drop functionality
366
+ let draggedItem = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
 
368
+ function dragStart(e) {
369
+ draggedItem = this;
370
+ this.classList.add('dragging');
371
+ e.dataTransfer.effectAllowed = 'move';
372
+ e.dataTransfer.setData('text/html', this.innerHTML);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  }
374
 
375
+ function dragEnd() {
376
+ this.classList.remove('dragging');
 
 
377
  }
378
 
379
+ function dragOver(e) {
380
+ e.preventDefault();
381
+ e.dataTransfer.dropEffect = 'move';
 
 
 
382
  }
383
 
384
+ function dragEnter(e) {
385
+ e.preventDefault();
386
+ this.classList.add('bg-gray-100');
 
 
 
387
  }
388
 
389
+ function dragLeave() {
390
+ this.classList.remove('bg-gray-100');
 
 
 
 
 
391
  }
392
 
393
+ function drop(e) {
394
+ e.preventDefault();
395
+ this.classList.remove('bg-gray-100');
 
 
 
 
 
396
 
397
+ if (draggedItem !== this) {
398
+ const taskId = parseInt(draggedItem.dataset.id);
399
+ const newStatus = this.parentElement.id.split('-')[0];
400
+
401
+ // Update task status
 
 
 
402
  const taskIndex = tasks.findIndex(t => t.id === taskId);
403
  if (taskIndex !== -1) {
404
+ tasks[taskIndex].status = newStatus;
405
+ renderTasks();
 
 
 
 
 
 
 
 
406
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
407
  }
408
+ }
409
 
410
+ // Add drag and drop events to columns
411
+ [todoColumn, inprogressColumn, reviewColumn, doneColumn].forEach(column => {
412
+ column.addEventListener('dragover', dragOver);
413
+ column.addEventListener('dragenter', dragEnter);
414
+ column.addEventListener('dragleave', dragLeave);
415
+ column.addEventListener('drop', drop);
416
+ });
417
+
418
+ // Task CRUD operations
419
+ function openModal() {
420
+ taskModal.classList.remove('hidden');
421
  }
422
 
423
+ function closeModalHandler() {
424
+ taskModal.classList.add('hidden');
425
+ taskForm.reset();
426
+ taskIdInput.value = '';
 
427
  }
428
 
429
+ function createTask() {
430
+ modalTitle.textContent = 'Create New Task';
431
+ openModal();
432
+ }
433
+
434
+ function editTask(id) {
435
+ const task = tasks.find(t => t.id === id);
436
+ if (task) {
437
+ modalTitle.textContent = 'Edit Task';
438
+ taskIdInput.value = task.id;
439
+ taskTitleInput.value = task.title;
440
+ taskDescInput.value = task.description;
441
+ taskStatusInput.value = task.status;
442
+ taskDueInput.value = task.due;
443
+ openModal();
444
  }
445
  }
446
 
447
+ function deleteTask(id) {
448
+ if (confirm('Are you sure you want to delete this task?')) {
449
+ tasks = tasks.filter(t => t.id !== id);
450
+ renderTasks();
 
451
  }
452
  }
453
 
454
+ function saveTask(e) {
455
+ e.preventDefault();
 
 
 
456
 
457
+ const taskData = {
458
+ title: taskTitleInput.value,
459
+ description: taskDescInput.value,
460
+ status: taskStatusInput.value,
461
+ due: taskDueInput.value,
462
+ created: new Date().toISOString().split('T')[0]
463
+ };
464
 
465
+ if (taskIdInput.value) {
466
+ // Update existing task
467
+ const taskIndex = tasks.findIndex(t => t.id === parseInt(taskIdInput.value));
468
+ if (taskIndex !== -1) {
469
+ tasks[taskIndex] = { ...tasks[taskIndex], ...taskData };
470
+ }
471
+ } else {
472
+ // Create new task
473
+ const newId = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1;
474
+ tasks.push({ id: newId, ...taskData });
475
+ }
476
 
477
+ closeModalHandler();
478
+ renderTasks();
 
 
 
479
  }
480
 
481
+ // Theme toggle
482
+ function toggleTheme() {
483
+ document.documentElement.classList.toggle('dark');
484
+ const icon = themeToggle.querySelector('i');
485
+ if (document.documentElement.classList.contains('dark')) {
486
+ icon.classList.replace('fa-moon', 'fa-sun');
487
+ document.body.classList.add('bg-gray-900');
488
+ document.body.classList.remove('bg-gray-100');
489
+ } else {
490
+ icon.classList.replace('fa-sun', 'fa-moon');
491
+ document.body.classList.remove('bg-gray-900');
492
+ document.body.classList.add('bg-gray-100');
493
+ }
494
  }
495
 
496
+ // Event listeners
497
+ createTaskBtn.addEventListener('click', createTask);
498
+ closeModal.addEventListener('click', closeModalHandler);
499
+ cancelTask.addEventListener('click', closeModalHandler);
500
+ taskForm.addEventListener('submit', saveTask);
501
+ themeToggle.addEventListener('click', toggleTheme);
502
+
503
+ // Initialize
504
+ renderTasks();
505
  </script>
506
  <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=hharris928/task-manager-2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
507
  </html>