DoraWill commited on
Commit
b6e0e8b
·
verified ·
1 Parent(s): 335ac82

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +898 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Deepsite Todo App
3
- emoji: 🏃
4
  colorFrom: green
5
- colorTo: purple
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: deepsite-todo-app
3
+ emoji: 🐳
4
  colorFrom: green
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,898 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ZenFocus - Elegant Todo App</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
+ <script>
10
+ tailwind.config = {
11
+ theme: {
12
+ extend: {
13
+ colors: {
14
+ primary: {
15
+ 50: '#f0f9ff',
16
+ 100: '#e0f2fe',
17
+ 200: '#bae6fd',
18
+ 300: '#7dd3fc',
19
+ 400: '#38bdf8',
20
+ 500: '#0ea5e9',
21
+ 600: '#0284c7',
22
+ 700: '#0369a1',
23
+ 800: '#075985',
24
+ 900: '#0c4a6e',
25
+ }
26
+ },
27
+ fontFamily: {
28
+ sans: ['"Inter"', 'system-ui', '-apple-system', 'sans-serif'],
29
+ },
30
+ boxShadow: {
31
+ 'soft': '0 4px 20px -2px rgba(0, 0, 0, 0.08)',
32
+ 'inner-glow': 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)'
33
+ }
34
+ }
35
+ }
36
+ }
37
+ </script>
38
+ <style>
39
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
40
+
41
+ body {
42
+ font-family: 'Inter', sans-serif;
43
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
44
+ min-height: 100vh;
45
+ }
46
+
47
+ .task-item {
48
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
49
+ }
50
+
51
+ .task-item:hover {
52
+ transform: translateY(-1px);
53
+ box-shadow: 0 2px 8px -1px rgba(0, 0, 0, 0.05);
54
+ }
55
+
56
+ .task-item:hover .task-actions {
57
+ opacity: 1;
58
+ }
59
+
60
+ .task-actions {
61
+ opacity: 0;
62
+ transition: opacity 0.2s ease;
63
+ }
64
+
65
+ .checkbox-custom {
66
+ appearance: none;
67
+ -webkit-appearance: none;
68
+ width: 18px;
69
+ height: 18px;
70
+ border: 2px solid #e2e8f0;
71
+ border-radius: 4px;
72
+ cursor: pointer;
73
+ position: relative;
74
+ transition: all 0.2s ease;
75
+ }
76
+
77
+ .checkbox-custom:checked {
78
+ background-color: #0ea5e9;
79
+ border-color: #0ea5e9;
80
+ }
81
+
82
+ .checkbox-custom:checked::after {
83
+ content: "";
84
+ position: absolute;
85
+ left: 5px;
86
+ top: 1px;
87
+ width: 4px;
88
+ height: 8px;
89
+ border: solid white;
90
+ border-width: 0 2px 2px 0;
91
+ transform: rotate(45deg);
92
+ }
93
+
94
+ .priority-high {
95
+ border-left: 3px solid #ef4444;
96
+ background-color: rgba(239, 68, 68, 0.03);
97
+ }
98
+
99
+ .priority-medium {
100
+ border-left: 3px solid #f59e0b;
101
+ background-color: rgba(245, 158, 11, 0.03);
102
+ }
103
+
104
+ .priority-low {
105
+ border-left: 3px solid #10b981;
106
+ background-color: rgba(16, 185, 129, 0.03);
107
+ }
108
+
109
+ /* Animation for new task */
110
+ @keyframes fadeIn {
111
+ from { opacity: 0; transform: translateY(8px); }
112
+ to { opacity: 1; transform: translateY(0); }
113
+ }
114
+
115
+ .task-animate {
116
+ animation: fadeIn 0.3s ease-out forwards;
117
+ }
118
+
119
+ /* Pulse animation for empty state */
120
+ @keyframes pulse {
121
+ 0% { opacity: 0.8; }
122
+ 50% { opacity: 1; }
123
+ 100% { opacity: 0.8; }
124
+ }
125
+
126
+ .empty-pulse {
127
+ animation: pulse 2s ease-in-out infinite;
128
+ }
129
+
130
+ /* Custom scrollbar */
131
+ .task-list::-webkit-scrollbar {
132
+ width: 6px;
133
+ }
134
+
135
+ .task-list::-webkit-scrollbar-track {
136
+ background: #f1f5f9;
137
+ border-radius: 10px;
138
+ }
139
+
140
+ .task-list::-webkit-scrollbar-thumb {
141
+ background: #cbd5e1;
142
+ border-radius: 10px;
143
+ }
144
+
145
+ .task-list::-webkit-scrollbar-thumb:hover {
146
+ background: #94a3b8;
147
+ }
148
+
149
+ /* Floating action button */
150
+ .fab {
151
+ box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.15);
152
+ transition: all 0.2s ease;
153
+ }
154
+
155
+ .fab:hover {
156
+ transform: translateY(-2px);
157
+ box-shadow: 0 6px 16px -2px rgba(0, 0, 0, 0.2);
158
+ }
159
+
160
+ /* Gradient text */
161
+ .gradient-text {
162
+ background: linear-gradient(90deg, #0ea5e9 0%, #3b82f6 100%);
163
+ -webkit-background-clip: text;
164
+ background-clip: text;
165
+ -webkit-text-fill-color: transparent;
166
+ }
167
+
168
+ /* Ripple effect */
169
+ .ripple {
170
+ position: relative;
171
+ overflow: hidden;
172
+ }
173
+
174
+ .ripple:after {
175
+ content: "";
176
+ display: block;
177
+ position: absolute;
178
+ width: 100%;
179
+ height: 100%;
180
+ top: 0;
181
+ left: 0;
182
+ pointer-events: none;
183
+ background-image: radial-gradient(circle, #fff 10%, transparent 10.01%);
184
+ background-repeat: no-repeat;
185
+ background-position: 50%;
186
+ transform: scale(10, 10);
187
+ opacity: 0;
188
+ transition: transform .5s, opacity 1s;
189
+ }
190
+
191
+ .ripple:active:after {
192
+ transform: scale(0, 0);
193
+ opacity: 0.2;
194
+ transition: 0s;
195
+ }
196
+
197
+ /* Shimmer effect */
198
+ .shimmer {
199
+ position: relative;
200
+ overflow: hidden;
201
+ }
202
+
203
+ .shimmer::before {
204
+ content: '';
205
+ position: absolute;
206
+ top: 0;
207
+ left: -100%;
208
+ width: 100%;
209
+ height: 100%;
210
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
211
+ animation: shimmer 1.5s infinite;
212
+ }
213
+
214
+ @keyframes shimmer {
215
+ 100% {
216
+ left: 100%;
217
+ }
218
+ }
219
+ </style>
220
+ </head>
221
+ <body class="antialiased text-gray-800">
222
+ <div class="container mx-auto px-4 py-8 md:py-12 max-w-2xl">
223
+ <!-- Header -->
224
+ <header class="mb-10">
225
+ <div class="text-center mb-6">
226
+ <div class="flex justify-center mb-3">
227
+ <div class="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center shadow-soft">
228
+ <i class="fas fa-check-circle text-2xl gradient-text"></i>
229
+ </div>
230
+ </div>
231
+ <h1 class="text-4xl font-extrabold gradient-text mb-1">ZenFocus</h1>
232
+ <p class="text-gray-500 text-lg">Organize your day with simplicity</p>
233
+ </div>
234
+
235
+ <div class="relative w-full mb-1">
236
+ <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
237
+ <i class="fas fa-plus-circle text-gray-400"></i>
238
+ </div>
239
+ <input
240
+ type="text"
241
+ id="new-task-input"
242
+ placeholder="Add a new task..."
243
+ class="w-full pl-10 pr-4 py-3 rounded-xl border border-gray-200 bg-white focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent shadow-sm transition duration-200"
244
+ autocomplete="off"
245
+ >
246
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3">
247
+ <button
248
+ id="add-task-btn"
249
+ class="fab p-2 bg-gradient-to-r from-primary-500 to-primary-600 text-white rounded-xl hover:shadow-md"
250
+ >
251
+ <i class="fas fa-paper-plane text-sm"></i>
252
+ </button>
253
+ </div>
254
+ </div>
255
+ <p class="text-xs text-gray-400 pl-3 mt-1">Tip: Press Enter to add quickly</p>
256
+ </header>
257
+
258
+ <!-- Stats Cards -->
259
+ <div class="grid grid-cols-1 sm:grid-cols-3 gap-3 md:gap-4 mb-6">
260
+ <div class="bg-white p-4 rounded-xl shadow-soft transition hover:shadow-md">
261
+ <div class="flex items-center">
262
+ <div class="p-2 mr-3 rounded-lg bg-primary-50">
263
+ <i class="fas fa-tasks text-primary-500"></i>
264
+ </div>
265
+ <div>
266
+ <p class="text-sm text-gray-500">Total Tasks</p>
267
+ <h3 class="text-xl font-semibold" id="total-tasks">0</h3>
268
+ </div>
269
+ </div>
270
+ </div>
271
+ <div class="bg-white p-4 rounded-xl shadow-soft transition hover:shadow-md">
272
+ <div class="flex items-center">
273
+ <div class="p-2 mr-3 rounded-lg bg-green-50">
274
+ <i class="fas fa-check-circle text-green-500"></i>
275
+ </div>
276
+ <div>
277
+ <p class="text-sm text-gray-500">Completed</p>
278
+ <h3 class="text-xl font-semibold" id="completed-tasks">0</h3>
279
+ </div>
280
+ </div>
281
+ </div>
282
+ <div class="bg-white p-4 rounded-xl shadow-soft transition hover:shadow-md">
283
+ <div class="flex items-center">
284
+ <div class="p-2 mr-3 rounded-lg bg-amber-50">
285
+ <i class="fas fa-clock text-amber-500"></i>
286
+ </div>
287
+ <div>
288
+ <p class="text-sm text-gray-500">Pending</p>
289
+ <h3 class="text-xl font-semibold" id="pending-tasks">0</h3>
290
+ </div>
291
+ </div>
292
+ </div>
293
+ </div>
294
+
295
+ <!-- Filters -->
296
+ <div class="flex flex-wrap justify-between items-center mb-6 bg-white p-4 rounded-xl shadow-soft">
297
+ <div class="flex space-x-1 mb-2 sm:mb-0">
298
+ <button
299
+ id="filter-all"
300
+ class="filter-btn active px-3 py-1.5 rounded-lg bg-primary-100 text-primary-800 font-medium text-sm ripple"
301
+ >
302
+ All
303
+ </button>
304
+ <button
305
+ id="filter-active"
306
+ class="filter-btn px-3 py-1.5 rounded-lg hover:bg-gray-50 text-gray-600 text-sm ripple"
307
+ >
308
+ Active
309
+ </button>
310
+ <button
311
+ id="filter-completed"
312
+ class="filter-btn px-3 py-1.5 rounded-lg hover:bg-gray-50 text-gray-600 text-sm ripple"
313
+ >
314
+ Completed
315
+ </button>
316
+ </div>
317
+ <div class="flex items-center">
318
+ <div class="relative">
319
+ <select
320
+ id="sort-tasks"
321
+ class="appearance-none text-sm border border-gray-200 rounded-lg px-3 py-1.5 pr-8 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white"
322
+ >
323
+ <option value="date">Date Added</option>
324
+ <option value="priority">Priority</option>
325
+ <option value="name">Name</option>
326
+ </select>
327
+ <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
328
+ <i class="fas fa-chevron-down text-xs"></i>
329
+ </div>
330
+ </div>
331
+ </div>
332
+ </div>
333
+
334
+ <!-- Task List -->
335
+ <div class="bg-white rounded-xl shadow-soft overflow-hidden">
336
+ <div id="task-list" class="task-list max-h-[480px] overflow-y-auto">
337
+ <!-- Empty state -->
338
+ <div class="p-8 text-center" id="empty-state">
339
+ <div class="mb-4 empty-pulse">
340
+ <svg class="mx-auto h-16 w-16 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
341
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
342
+ </svg>
343
+ </div>
344
+ <h3 class="text-lg font-medium text-gray-700 mb-1">No tasks yet</h3>
345
+ <p class="text-gray-500">Get started by adding your first task</p>
346
+ <div class="mt-4">
347
+ <button class="text-sm text-primary-600 hover:text-primary-800 flex items-center justify-center mx-auto" id="sample-task-btn">
348
+ <i class="fas fa-magic mr-1.5"></i> Add sample task
349
+ </button>
350
+ </div>
351
+ </div>
352
+ </div>
353
+
354
+ <!-- Footer Actions -->
355
+ <div class="border-t border-gray-100 p-4 flex justify-between items-center bg-gray-50 rounded-b-xl">
356
+ <div class="text-sm text-gray-600 font-medium" id="remaining-count">0 items left</div>
357
+ <button
358
+ id="clear-completed"
359
+ class="text-sm text-primary-600 hover:text-primary-800 font-medium ripple"
360
+ >
361
+ <i class="fas fa-broom mr-1"></i> Clear completed
362
+ </button>
363
+ </div>
364
+ </div>
365
+ </div>
366
+
367
+ <!-- Priority Modal -->
368
+ <div id="priority-modal" class="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center hidden z-50 backdrop-blur-sm">
369
+ <div class="bg-white rounded-xl p-6 w-full max-w-sm mx-4 shadow-2xl transform transition-all" id="modal-content">
370
+ <h3 class="text-lg font-semibold text-gray-900 mb-4">Set Priority</h3>
371
+ <div class="space-y-2">
372
+ <button
373
+ class="priority-option w-full text-left px-4 py-3 rounded-lg border border-red-100 bg-red-50 hover:bg-red-100 transition-colors group ripple"
374
+ data-priority="high"
375
+ >
376
+ <div class="flex items-center">
377
+ <div class="w-8 h-8 rounded-lg bg-red-100 flex items-center justify-center mr-3 group-hover:bg-red-200 transition-colors">
378
+ <i class="fas fa-exclamation-circle text-red-600 text-sm"></i>
379
+ </div>
380
+ <div>
381
+ <div class="font-medium text-red-800">High Priority</div>
382
+ <div class="text-xs text-red-600">Urgent and important</div>
383
+ </div>
384
+ </div>
385
+ </button>
386
+ <button
387
+ class="priority-option w-full text-left px-4 py-3 rounded-lg border border-amber-100 bg-amber-50 hover:bg-amber-100 transition-colors group ripple"
388
+ data-priority="medium"
389
+ >
390
+ <div class="flex items-center">
391
+ <div class="w-8 h-8 rounded-lg bg-amber-100 flex items-center justify-center mr-3 group-hover:bg-amber-200 transition-colors">
392
+ <i class="fas fa-exclamation text-amber-600 text-sm"></i>
393
+ </div>
394
+ <div>
395
+ <div class="font-medium text-amber-800">Medium Priority</div>
396
+ <div class="text-xs text-amber-600">Important but not urgent</div>
397
+ </div>
398
+ </div>
399
+ </button>
400
+ <button
401
+ class="priority-option w-full text-left px-4 py-3 rounded-lg border border-green-100 bg-green-50 hover:bg-green-100 transition-colors group ripple"
402
+ data-priority="low"
403
+ >
404
+ <div class="flex items-center">
405
+ <div class="w-8 h-8 rounded-lg bg-green-100 flex items-center justify-center mr-3 group-hover:bg-green-200 transition-colors">
406
+ <i class="fas fa-arrow-down text-green-600 text-sm"></i>
407
+ </div>
408
+ <div>
409
+ <div class="font-medium text-green-800">Low Priority</div>
410
+ <div class="text-xs text-green-600">Neither urgent nor important</div>
411
+ </div>
412
+ </div>
413
+ </button>
414
+ </div>
415
+ <div class="mt-6 flex justify-end">
416
+ <button
417
+ id="cancel-priority"
418
+ class="px-4 py-2 text-gray-600 hover:text-gray-800 font-medium ripple"
419
+ >
420
+ Cancel
421
+ </button>
422
+ </div>
423
+ </div>
424
+ </div>
425
+
426
+ <!-- Confirmation Modal -->
427
+ <div id="confirm-modal" class="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center hidden z-50 backdrop-blur-sm">
428
+ <div class="bg-white rounded-xl p-6 w-full max-w-sm mx-4 shadow-2xl">
429
+ <div class="text-center">
430
+ <div class="mx-auto h-12 w-12 rounded-full bg-red-100 flex items-center justify-center mb-4">
431
+ <i class="fas fa-exclamation text-red-600"></i>
432
+ </div>
433
+ <h3 class="text-lg font-medium text-gray-900 mb-2" id="confirm-title">Are you sure?</h3>
434
+ <p class="text-sm text-gray-500 mb-4" id="confirm-message">This action cannot be undone.</p>
435
+ <div class="flex justify-center space-x-3">
436
+ <button
437
+ id="confirm-cancel"
438
+ class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 font-medium ripple"
439
+ >
440
+ Cancel
441
+ </button>
442
+ <button
443
+ id="confirm-ok"
444
+ class="px-4 py-2 bg-red-600 rounded-lg text-white hover:bg-red-700 font-medium ripple"
445
+ >
446
+ Confirm
447
+ </button>
448
+ </div>
449
+ </div>
450
+ </div>
451
+ </div>
452
+
453
+ <script>
454
+ document.addEventListener('DOMContentLoaded', function() {
455
+ // DOM Elements
456
+ const taskInput = document.getElementById('new-task-input');
457
+ const addTaskBtn = document.getElementById('add-task-btn');
458
+ const taskList = document.getElementById('task-list');
459
+ const emptyState = document.getElementById('empty-state');
460
+ const filterAll = document.getElementById('filter-all');
461
+ const filterActive = document.getElementById('filter-active');
462
+ const filterCompleted = document.getElementById('filter-completed');
463
+ const clearCompleted = document.getElementById('clear-completed');
464
+ const remainingCount = document.getElementById('remaining-count');
465
+ const totalTasksEl = document.getElementById('total-tasks');
466
+ const completedTasksEl = document.getElementById('completed-tasks');
467
+ const pendingTasksEl = document.getElementById('pending-tasks');
468
+ const sortSelect = document.getElementById('sort-tasks');
469
+ const priorityModal = document.getElementById('priority-modal');
470
+ const priorityOptions = document.querySelectorAll('.priority-option');
471
+ const cancelPriority = document.getElementById('cancel-priority');
472
+ const sampleTaskBtn = document.getElementById('sample-task-btn');
473
+ const confirmModal = document.getElementById('confirm-modal');
474
+ const confirmTitle = document.getElementById('confirm-title');
475
+ const confirmMessage = document.getElementById('confirm-message');
476
+ const confirmCancel = document.getElementById('confirm-cancel');
477
+ const confirmOk = document.getElementById('confirm-ok');
478
+
479
+ // State
480
+ let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
481
+ let currentFilter = 'all';
482
+ let currentSort = 'date';
483
+ let currentTaskIdForPriority = null;
484
+ let confirmCallback = null;
485
+
486
+ // Initialize
487
+ updateTaskList();
488
+ updateStats();
489
+
490
+ // Event Listeners
491
+ addTaskBtn.addEventListener('click', addTask);
492
+ taskInput.addEventListener('keypress', function(e) {
493
+ if (e.key === 'Enter') addTask();
494
+ });
495
+
496
+ filterAll.addEventListener('click', () => setFilter('all'));
497
+ filterActive.addEventListener('click', () => setFilter('active'));
498
+ filterCompleted.addEventListener('click', () => setFilter('completed'));
499
+
500
+ clearCompleted.addEventListener('click', () => {
501
+ showConfirm(
502
+ 'Clear completed tasks?',
503
+ 'This will remove all completed tasks from your list.',
504
+ clearCompletedTasks
505
+ );
506
+ });
507
+
508
+ sortSelect.addEventListener('change', (e) => {
509
+ currentSort = e.target.value;
510
+ updateTaskList();
511
+ });
512
+
513
+ cancelPriority.addEventListener('click', () => {
514
+ priorityModal.classList.add('hidden');
515
+ });
516
+
517
+ priorityOptions.forEach(option => {
518
+ option.addEventListener('click', function() {
519
+ const priority = this.getAttribute('data-priority');
520
+ setTaskPriority(currentTaskIdForPriority, priority);
521
+ priorityModal.classList.add('hidden');
522
+ });
523
+ });
524
+
525
+ sampleTaskBtn.addEventListener('click', addSampleTasks);
526
+
527
+ confirmCancel.addEventListener('click', () => {
528
+ confirmModal.classList.add('hidden');
529
+ });
530
+
531
+ confirmOk.addEventListener('click', () => {
532
+ if (confirmCallback) confirmCallback();
533
+ confirmModal.classList.add('hidden');
534
+ });
535
+
536
+ // Functions
537
+ function addTask() {
538
+ const taskText = taskInput.value.trim();
539
+ if (taskText === '') return;
540
+
541
+ const newTask = {
542
+ id: Date.now(),
543
+ text: taskText,
544
+ completed: false,
545
+ priority: 'medium', // default priority
546
+ createdAt: new Date().toISOString()
547
+ };
548
+
549
+ tasks.unshift(newTask);
550
+ saveTasks();
551
+ taskInput.value = '';
552
+ updateTaskList();
553
+ updateStats();
554
+ taskInput.focus();
555
+
556
+ // Animate the add button
557
+ addTaskBtn.classList.add('animate-ping');
558
+ setTimeout(() => {
559
+ addTaskBtn.classList.remove('animate-ping');
560
+ }, 300);
561
+
562
+ // Show priority modal for new task after a slight delay
563
+ setTimeout(() => {
564
+ currentTaskIdForPriority = newTask.id;
565
+ showPriorityModal();
566
+ }, 50);
567
+ }
568
+
569
+ function addSampleTasks() {
570
+ const sampleTasks = [
571
+ { text: "Complete project presentation", priority: "high" },
572
+ { text: "Reply to important emails", priority: "high" },
573
+ { text: "Buy groceries for the week", priority: "medium" },
574
+ { text: "Schedule dentist appointment", priority: "medium" },
575
+ { text: "Read 20 pages of book", priority: "low" },
576
+ { text: "Organize workspace", priority: "low" }
577
+ ];
578
+
579
+ sampleTasks.forEach(task => {
580
+ const newTask = {
581
+ id: Date.now() + Math.random(),
582
+ text: task.text,
583
+ completed: false,
584
+ priority: task.priority,
585
+ createdAt: new Date().toISOString()
586
+ };
587
+ tasks.unshift(newTask);
588
+ });
589
+
590
+ saveTasks();
591
+ updateTaskList();
592
+ updateStats();
593
+ setFilter('all');
594
+
595
+ // Show shimmer effect on empty state before it disappears
596
+ emptyState.classList.add('shimmer');
597
+ setTimeout(() => {
598
+ emptyState.classList.remove('shimmer');
599
+ }, 300);
600
+ }
601
+
602
+ function setTaskPriority(taskId, priority) {
603
+ const taskIndex = tasks.findIndex(task => task.id === taskId);
604
+ if (taskIndex !== -1) {
605
+ tasks[taskIndex].priority = priority;
606
+ saveTasks();
607
+ updateTaskList();
608
+
609
+ // Show priority indicator
610
+ const priorityEl = document.querySelector(`.priority-btn[data-id="${taskId}"]`);
611
+ if (priorityEl) {
612
+ priorityEl.classList.add('animate-bounce');
613
+ setTimeout(() => {
614
+ priorityEl.classList.remove('animate-bounce');
615
+ }, 1000);
616
+ }
617
+ }
618
+ }
619
+
620
+ function toggleTaskComplete(taskId) {
621
+ const task = tasks.find(task => task.id === taskId);
622
+ if (task) {
623
+ task.completed = !task.completed;
624
+ saveTasks();
625
+ updateTaskList();
626
+ updateStats();
627
+
628
+ // Play completion sound if completed
629
+ if (task.completed) {
630
+ playCompletionSound();
631
+ }
632
+ }
633
+ }
634
+
635
+ function playCompletionSound() {
636
+ const audio = new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU' + Array(1e3).join('123'));
637
+ audio.volume = 0.2;
638
+ audio.play().catch(e => console.log('Sound playback prevented:', e));
639
+ }
640
+
641
+ function deleteTask(taskId) {
642
+ showConfirm(
643
+ 'Delete this task?',
644
+ 'This task will be permanently removed from your list.',
645
+ () => {
646
+ tasks = tasks.filter(task => task.id !== taskId);
647
+ saveTasks();
648
+ updateTaskList();
649
+ updateStats();
650
+ }
651
+ );
652
+ }
653
+
654
+ function editTask(taskId, newText) {
655
+ const task = tasks.find(task => task.id === taskId);
656
+ if (task && newText.trim() !== '') {
657
+ task.text = newText.trim();
658
+ saveTasks();
659
+ updateTaskList();
660
+ }
661
+ }
662
+
663
+ function clearCompletedTasks() {
664
+ tasks = tasks.filter(task => !task.completed);
665
+ saveTasks();
666
+ updateTaskList();
667
+ updateStats();
668
+ }
669
+
670
+ function setFilter(filter) {
671
+ currentFilter = filter;
672
+
673
+ // Update active filter button
674
+ document.querySelectorAll('.filter-btn').forEach(btn => {
675
+ btn.classList.remove('active', 'bg-primary-100', 'text-primary-800');
676
+ btn.classList.add('hover:bg-gray-50', 'text-gray-600');
677
+ });
678
+
679
+ const activeBtn = document.getElementById(`filter-${filter}`);
680
+ activeBtn.classList.add('active', 'bg-primary-100', 'text-primary-800');
681
+ activeBtn.classList.remove('hover:bg-gray-50', 'text-gray-600');
682
+
683
+ updateTaskList();
684
+ }
685
+
686
+ function saveTasks() {
687
+ localStorage.setItem('tasks', JSON.stringify(tasks));
688
+ }
689
+
690
+ function updateStats() {
691
+ const total = tasks.length;
692
+ const completed = tasks.filter(task => task.completed).length;
693
+ const pending = total - completed;
694
+
695
+ totalTasksEl.textContent = total;
696
+ completedTasksEl.textContent = completed;
697
+ pendingTasksEl.textContent = pending;
698
+ remainingCount.textContent = `${pending} ${pending === 1 ? 'item' : 'items'} left`;
699
+ }
700
+
701
+ function updateTaskList() {
702
+ // Filter tasks
703
+ let filteredTasks = [...tasks];
704
+
705
+ if (currentFilter === 'active') {
706
+ filteredTasks = filteredTasks.filter(task => !task.completed);
707
+ } else if (currentFilter === 'completed') {
708
+ filteredTasks = filteredTasks.filter(task => task.completed);
709
+ }
710
+
711
+ // Sort tasks
712
+ filteredTasks.sort((a, b) => {
713
+ if (currentSort === 'date') {
714
+ return new Date(b.createdAt) - new Date(a.createdAt);
715
+ } else if (currentSort === 'priority') {
716
+ const priorityOrder = { high: 3, medium: 2, low: 1 };
717
+ return priorityOrder[b.priority] - priorityOrder[a.priority];
718
+ } else if (currentSort === 'name') {
719
+ return a.text.localeCompare(b.text);
720
+ }
721
+ return 0;
722
+ });
723
+
724
+ // Render tasks
725
+ if (filteredTasks.length === 0) {
726
+ emptyState.classList.remove('hidden');
727
+ taskList.innerHTML = '';
728
+ taskList.appendChild(emptyState);
729
+ } else {
730
+ emptyState.classList.add('hidden');
731
+ taskList.innerHTML = '';
732
+
733
+ filteredTasks.forEach((task, index) => {
734
+ const taskElement = createTaskElement(task);
735
+ taskList.appendChild(taskElement);
736
+
737
+ // Add slight delay for staggered animation
738
+ setTimeout(() => {
739
+ taskElement.classList.add('task-animate');
740
+ }, index * 50);
741
+ });
742
+ }
743
+ }
744
+
745
+ function createTaskElement(task) {
746
+ const taskElement = document.createElement('div');
747
+ taskElement.className = `task-item border-b border-gray-100 last:border-0 ${task.priority}-priority`;
748
+
749
+ taskElement.innerHTML = `
750
+ <div class="p-5 flex items-start group">
751
+ <div class="flex items-center h-5 mr-3 mt-0.5">
752
+ <input
753
+ type="checkbox"
754
+ class="checkbox-custom"
755
+ ${task.completed ? 'checked' : ''}
756
+ data-id="${task.id}"
757
+ >
758
+ </div>
759
+ <div class="flex-1 min-w-0">
760
+ <div
761
+ class="task-text ${task.completed ? 'line-through text-gray-400' : 'text-gray-800'} font-medium"
762
+ data-id="${task.id}"
763
+ >
764
+ ${task.text}
765
+ </div>
766
+ <div class="flex items-center mt-1.5">
767
+ <div class="text-xs text-gray-500">
768
+ <i class="far fa-clock mr-1"></i>${formatDate(task.createdAt)}
769
+ </div>
770
+ <span class="ml-2 px-2 py-0.5 rounded-full text-xs font-medium ${getPriorityBadgeClass(task.priority)}">
771
+ ${getPriorityLabel(task.priority)}
772
+ </span>
773
+ </div>
774
+ </div>
775
+ <div class="task-actions flex space-x-1 ml-3">
776
+ <button
777
+ class="edit-btn p-1.5 rounded-lg text-gray-500 hover:bg-gray-100 hover:text-primary-600 transition-colors ripple"
778
+ data-id="${task.id}"
779
+ title="Edit task"
780
+ >
781
+ <i class="fas fa-pencil-alt text-sm"></i>
782
+ </button>
783
+ <button
784
+ class="priority-btn p-1.5 rounded-lg text-gray-500 hover:bg-gray-100 ${getPriorityBtnClass(task.priority)} transition-colors ripple"
785
+ data-id="${task.id}"
786
+ title="Change priority"
787
+ >
788
+ <i class="fas fa-flag text-sm"></i>
789
+ </button>
790
+ <button
791
+ class="delete-btn p-1.5 rounded-lg text-gray-500 hover:bg-gray-100 hover:text-red-600 transition-colors ripple"
792
+ data-id="${task.id}"
793
+ title="Delete task"
794
+ >
795
+ <i class="fas fa-trash-alt text-sm"></i>
796
+ </button>
797
+ </div>
798
+ </div>
799
+ `;
800
+
801
+ // Add event listeners to the new task
802
+ const checkbox = taskElement.querySelector('.checkbox-custom');
803
+ const editBtn = taskElement.querySelector('.edit-btn');
804
+ const deleteBtn = taskElement.querySelector('.delete-btn');
805
+ const priorityBtn = taskElement.querySelector('.priority-btn');
806
+ const taskText = taskElement.querySelector('.task-text');
807
+
808
+ checkbox.addEventListener('change', () => toggleTaskComplete(task.id));
809
+
810
+ deleteBtn.addEventListener('click', () => deleteTask(task.id));
811
+
812
+ priorityBtn.addEventListener('click', () => {
813
+ currentTaskIdForPriority = task.id;
814
+ showPriorityModal();
815
+ });
816
+
817
+ editBtn.addEventListener('click', () => {
818
+ const currentText = task.text;
819
+ const input = document.createElement('input');
820
+ input.type = 'text';
821
+ input.value = currentText;
822
+ input.className = 'w-full px-2 py-1.5 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 focus:ring-primary-500';
823
+
824
+ taskText.innerHTML = '';
825
+ taskText.appendChild(input);
826
+ input.focus();
827
+
828
+ const handleBlur = () => {
829
+ editTask(task.id, input.value);
830
+ };
831
+
832
+ const handleKeyPress = (e) => {
833
+ if (e.key === 'Enter') {
834
+ editTask(task.id, input.value);
835
+ }
836
+ };
837
+
838
+ input.addEventListener('blur', handleBlur);
839
+ input.addEventListener('keypress', handleKeyPress);
840
+ });
841
+
842
+ return taskElement;
843
+ }
844
+
845
+ function formatDate(dateString) {
846
+ const date = new Date(dateString);
847
+ return date.toLocaleDateString('en-US', {
848
+ month: 'short',
849
+ day: 'numeric'
850
+ });
851
+ }
852
+
853
+ function getPriorityLabel(priority) {
854
+ const labels = {
855
+ high: 'High',
856
+ medium: 'Medium',
857
+ low: 'Low'
858
+ };
859
+ return labels[priority] || priority;
860
+ }
861
+
862
+ function getPriorityBadgeClass(priority) {
863
+ switch (priority) {
864
+ case 'high': return 'bg-red-100 text-red-800';
865
+ case 'medium': return 'bg-amber-100 text-amber-800';
866
+ case 'low': return 'bg-green-100 text-green-800';
867
+ default: return 'bg-gray-100 text-gray-800';
868
+ }
869
+ }
870
+
871
+ function getPriorityBtnClass(priority) {
872
+ switch (priority) {
873
+ case 'high': return 'hover:text-red-600';
874
+ case 'medium': return 'hover:text-amber-600';
875
+ case 'low': return 'hover:text-green-600';
876
+ default: return '';
877
+ }
878
+ }
879
+
880
+ function showConfirm(title, message, callback) {
881
+ confirmTitle.textContent = title;
882
+ confirmMessage.textContent = message;
883
+ confirmCallback = callback;
884
+ confirmModal.classList.remove('hidden');
885
+ }
886
+
887
+ function showPriorityModal() {
888
+ priorityModal.classList.remove('hidden');
889
+
890
+ // Add animation to modal
891
+ const modalContent = document.getElementById('modal-content');
892
+ modalContent.classList.remove('opacity-0', 'scale-95');
893
+ modalContent.classList.add('opacity-100', 'scale-100');
894
+ }
895
+ });
896
+ </script>
897
+ <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=DoraWill/deepsite-todo-app" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
898
+ </html>