akhaliq HF Staff commited on
Commit
9fbd70e
·
verified ·
1 Parent(s): 52133ae

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +924 -19
index.html CHANGED
@@ -1,19 +1,924 @@
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>TaskFlow - Modern Todo App</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ :root {
15
+ --primary-color: #667eea;
16
+ --primary-dark: #5a67d8;
17
+ --secondary-color: #48bb78;
18
+ --danger-color: #f56565;
19
+ --warning-color: #ed8936;
20
+ --bg-color: #f7fafc;
21
+ --card-bg: #ffffff;
22
+ --text-primary: #2d3748;
23
+ --text-secondary: #718096;
24
+ --border-color: #e2e8f0;
25
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.12);
26
+ --shadow-md: 0 4px 6px rgba(0,0,0,0.1);
27
+ --shadow-lg: 0 10px 15px rgba(0,0,0,0.1);
28
+ --shadow-xl: 0 20px 25px rgba(0,0,0,0.1);
29
+ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
30
+ }
31
+
32
+ body {
33
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
34
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
35
+ min-height: 100vh;
36
+ display: flex;
37
+ flex-direction: column;
38
+ color: var(--text-primary);
39
+ line-height: 1.6;
40
+ }
41
+
42
+ .background-pattern {
43
+ position: fixed;
44
+ top: 0;
45
+ left: 0;
46
+ width: 100%;
47
+ height: 100%;
48
+ opacity: 0.1;
49
+ background-image:
50
+ repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(255,255,255,.1) 35px, rgba(255,255,255,.1) 70px);
51
+ pointer-events: none;
52
+ }
53
+
54
+ header {
55
+ background: rgba(255, 255, 255, 0.95);
56
+ backdrop-filter: blur(10px);
57
+ padding: 1.5rem 0;
58
+ box-shadow: var(--shadow-md);
59
+ position: relative;
60
+ z-index: 100;
61
+ }
62
+
63
+ .header-content {
64
+ max-width: 1200px;
65
+ margin: 0 auto;
66
+ padding: 0 2rem;
67
+ display: flex;
68
+ justify-content: space-between;
69
+ align-items: center;
70
+ }
71
+
72
+ .logo {
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 0.75rem;
76
+ font-size: 1.5rem;
77
+ font-weight: 700;
78
+ color: var(--primary-color);
79
+ }
80
+
81
+ .logo-icon {
82
+ width: 40px;
83
+ height: 40px;
84
+ background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
85
+ border-radius: 12px;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ color: white;
90
+ font-size: 1.5rem;
91
+ }
92
+
93
+ .header-link {
94
+ color: var(--text-secondary);
95
+ text-decoration: none;
96
+ font-size: 0.875rem;
97
+ transition: var(--transition);
98
+ padding: 0.5rem 1rem;
99
+ border-radius: 8px;
100
+ }
101
+
102
+ .header-link:hover {
103
+ color: var(--primary-color);
104
+ background: rgba(102, 126, 234, 0.1);
105
+ }
106
+
107
+ main {
108
+ flex: 1;
109
+ padding: 2rem;
110
+ max-width: 800px;
111
+ width: 100%;
112
+ margin: 0 auto;
113
+ }
114
+
115
+ .todo-container {
116
+ background: var(--card-bg);
117
+ border-radius: 20px;
118
+ box-shadow: var(--shadow-xl);
119
+ overflow: hidden;
120
+ animation: slideUp 0.5s ease-out;
121
+ }
122
+
123
+ @keyframes slideUp {
124
+ from {
125
+ opacity: 0;
126
+ transform: translateY(30px);
127
+ }
128
+ to {
129
+ opacity: 1;
130
+ transform: translateY(0);
131
+ }
132
+ }
133
+
134
+ .todo-header {
135
+ background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
136
+ color: white;
137
+ padding: 2rem;
138
+ }
139
+
140
+ .todo-title {
141
+ font-size: 2rem;
142
+ margin-bottom: 0.5rem;
143
+ }
144
+
145
+ .todo-subtitle {
146
+ opacity: 0.9;
147
+ font-size: 1rem;
148
+ }
149
+
150
+ .stats-container {
151
+ display: grid;
152
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
153
+ gap: 1rem;
154
+ padding: 1.5rem 2rem;
155
+ background: var(--bg-color);
156
+ border-bottom: 1px solid var(--border-color);
157
+ }
158
+
159
+ .stat-card {
160
+ background: white;
161
+ padding: 1rem;
162
+ border-radius: 12px;
163
+ text-align: center;
164
+ transition: var(--transition);
165
+ }
166
+
167
+ .stat-card:hover {
168
+ transform: translateY(-2px);
169
+ box-shadow: var(--shadow-md);
170
+ }
171
+
172
+ .stat-number {
173
+ font-size: 2rem;
174
+ font-weight: 700;
175
+ color: var(--primary-color);
176
+ }
177
+
178
+ .stat-label {
179
+ font-size: 0.875rem;
180
+ color: var(--text-secondary);
181
+ margin-top: 0.25rem;
182
+ }
183
+
184
+ .input-section {
185
+ padding: 2rem;
186
+ border-bottom: 1px solid var(--border-color);
187
+ }
188
+
189
+ .input-wrapper {
190
+ display: flex;
191
+ gap: 1rem;
192
+ margin-bottom: 1rem;
193
+ }
194
+
195
+ .todo-input {
196
+ flex: 1;
197
+ padding: 1rem 1.5rem;
198
+ border: 2px solid var(--border-color);
199
+ border-radius: 12px;
200
+ font-size: 1rem;
201
+ transition: var(--transition);
202
+ background: white;
203
+ }
204
+
205
+ .todo-input:focus {
206
+ outline: none;
207
+ border-color: var(--primary-color);
208
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
209
+ }
210
+
211
+ .priority-select {
212
+ padding: 1rem;
213
+ border: 2px solid var(--border-color);
214
+ border-radius: 12px;
215
+ font-size: 1rem;
216
+ background: white;
217
+ cursor: pointer;
218
+ transition: var(--transition);
219
+ }
220
+
221
+ .priority-select:focus {
222
+ outline: none;
223
+ border-color: var(--primary-color);
224
+ }
225
+
226
+ .add-btn {
227
+ padding: 1rem 2rem;
228
+ background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
229
+ color: white;
230
+ border: none;
231
+ border-radius: 12px;
232
+ font-size: 1rem;
233
+ font-weight: 600;
234
+ cursor: pointer;
235
+ transition: var(--transition);
236
+ display: flex;
237
+ align-items: center;
238
+ gap: 0.5rem;
239
+ }
240
+
241
+ .add-btn:hover {
242
+ transform: translateY(-2px);
243
+ box-shadow: var(--shadow-lg);
244
+ }
245
+
246
+ .add-btn:active {
247
+ transform: translateY(0);
248
+ }
249
+
250
+ .filter-tabs {
251
+ display: flex;
252
+ gap: 0.5rem;
253
+ padding: 1rem 2rem;
254
+ background: var(--bg-color);
255
+ border-bottom: 1px solid var(--border-color);
256
+ }
257
+
258
+ .filter-tab {
259
+ padding: 0.75rem 1.5rem;
260
+ background: transparent;
261
+ border: none;
262
+ border-radius: 8px;
263
+ font-size: 0.875rem;
264
+ font-weight: 600;
265
+ color: var(--text-secondary);
266
+ cursor: pointer;
267
+ transition: var(--transition);
268
+ position: relative;
269
+ }
270
+
271
+ .filter-tab:hover {
272
+ background: rgba(102, 126, 234, 0.1);
273
+ }
274
+
275
+ .filter-tab.active {
276
+ color: var(--primary-color);
277
+ background: white;
278
+ box-shadow: var(--shadow-sm);
279
+ }
280
+
281
+ .filter-tab .count {
282
+ display: inline-block;
283
+ margin-left: 0.5rem;
284
+ padding: 0.125rem 0.5rem;
285
+ background: var(--bg-color);
286
+ border-radius: 12px;
287
+ font-size: 0.75rem;
288
+ }
289
+
290
+ .todo-list {
291
+ padding: 1rem;
292
+ max-height: 400px;
293
+ overflow-y: auto;
294
+ }
295
+
296
+ .todo-list::-webkit-scrollbar {
297
+ width: 8px;
298
+ }
299
+
300
+ .todo-list::-webkit-scrollbar-track {
301
+ background: var(--bg-color);
302
+ border-radius: 10px;
303
+ }
304
+
305
+ .todo-list::-webkit-scrollbar-thumb {
306
+ background: var(--border-color);
307
+ border-radius: 10px;
308
+ }
309
+
310
+ .todo-list::-webkit-scrollbar-thumb:hover {
311
+ background: var(--text-secondary);
312
+ }
313
+
314
+ .todo-item {
315
+ display: flex;
316
+ align-items: center;
317
+ padding: 1rem;
318
+ margin-bottom: 0.5rem;
319
+ background: white;
320
+ border: 2px solid var(--border-color);
321
+ border-radius: 12px;
322
+ transition: var(--transition);
323
+ animation: fadeIn 0.3s ease-out;
324
+ }
325
+
326
+ @keyframes fadeIn {
327
+ from {
328
+ opacity: 0;
329
+ transform: translateX(-20px);
330
+ }
331
+ to {
332
+ opacity: 1;
333
+ transform: translateX(0);
334
+ }
335
+ }
336
+
337
+ .todo-item:hover {
338
+ border-color: var(--primary-color);
339
+ box-shadow: var(--shadow-md);
340
+ transform: translateX(4px);
341
+ }
342
+
343
+ .todo-item.completed {
344
+ opacity: 0.7;
345
+ background: var(--bg-color);
346
+ }
347
+
348
+ .todo-item.completed .todo-text {
349
+ text-decoration: line-through;
350
+ color: var(--text-secondary);
351
+ }
352
+
353
+ .checkbox-wrapper {
354
+ position: relative;
355
+ margin-right: 1rem;
356
+ }
357
+
358
+ .todo-checkbox {
359
+ width: 24px;
360
+ height: 24px;
361
+ appearance: none;
362
+ border: 2px solid var(--border-color);
363
+ border-radius: 6px;
364
+ cursor: pointer;
365
+ transition: var(--transition);
366
+ position: relative;
367
+ }
368
+
369
+ .todo-checkbox:checked {
370
+ background: linear-gradient(135deg, var(--secondary-color), #38a169);
371
+ border-color: var(--secondary-color);
372
+ }
373
+
374
+ .todo-checkbox:checked::after {
375
+ content: '✓';
376
+ position: absolute;
377
+ top: 50%;
378
+ left: 50%;
379
+ transform: translate(-50%, -50%);
380
+ color: white;
381
+ font-size: 14px;
382
+ font-weight: bold;
383
+ }
384
+
385
+ .todo-content {
386
+ flex: 1;
387
+ display: flex;
388
+ flex-direction: column;
389
+ gap: 0.25rem;
390
+ }
391
+
392
+ .todo-text {
393
+ font-size: 1rem;
394
+ color: var(--text-primary);
395
+ word-break: break-word;
396
+ }
397
+
398
+ .todo-meta {
399
+ display: flex;
400
+ gap: 1rem;
401
+ align-items: center;
402
+ font-size: 0.75rem;
403
+ color: var(--text-secondary);
404
+ }
405
+
406
+ .priority-badge {
407
+ padding: 0.25rem 0.75rem;
408
+ border-radius: 12px;
409
+ font-weight: 600;
410
+ font-size: 0.75rem;
411
+ text-transform: uppercase;
412
+ }
413
+
414
+ .priority-high {
415
+ background: rgba(245, 101, 101, 0.1);
416
+ color: var(--danger-color);
417
+ }
418
+
419
+ .priority-medium {
420
+ background: rgba(237, 137, 54, 0.1);
421
+ color: var(--warning-color);
422
+ }
423
+
424
+ .priority-low {
425
+ background: rgba(72, 187, 120, 0.1);
426
+ color: var(--secondary-color);
427
+ }
428
+
429
+ .todo-actions {
430
+ display: flex;
431
+ gap: 0.5rem;
432
+ }
433
+
434
+ .action-btn {
435
+ width: 36px;
436
+ height: 36px;
437
+ border: none;
438
+ background: var(--bg-color);
439
+ border-radius: 8px;
440
+ cursor: pointer;
441
+ display: flex;
442
+ align-items: center;
443
+ justify-content: center;
444
+ transition: var(--transition);
445
+ color: var(--text-secondary);
446
+ }
447
+
448
+ .action-btn:hover {
449
+ background: var(--primary-color);
450
+ color: white;
451
+ transform: scale(1.1);
452
+ }
453
+
454
+ .action-btn.delete:hover {
455
+ background: var(--danger-color);
456
+ }
457
+
458
+ .empty-state {
459
+ text-align: center;
460
+ padding: 3rem;
461
+ color: var(--text-secondary);
462
+ }
463
+
464
+ .empty-icon {
465
+ font-size: 4rem;
466
+ margin-bottom: 1rem;
467
+ opacity: 0.3;
468
+ }
469
+
470
+ .clear-completed {
471
+ padding: 1rem 2rem;
472
+ background: var(--danger-color);
473
+ color: white;
474
+ border: none;
475
+ border-radius: 12px;
476
+ font-size: 0.875rem;
477
+ font-weight: 600;
478
+ cursor: pointer;
479
+ transition: var(--transition);
480
+ margin: 1rem 2rem;
481
+ }
482
+
483
+ .clear-completed:hover {
484
+ background: #e53e3e;
485
+ transform: translateY(-2px);
486
+ box-shadow: var(--shadow-md);
487
+ }
488
+
489
+ @media (max-width: 768px) {
490
+ .header-content {
491
+ padding: 0 1rem;
492
+ }
493
+
494
+ main {
495
+ padding: 1rem;
496
+ }
497
+
498
+ .todo-title {
499
+ font-size: 1.5rem;
500
+ }
501
+
502
+ .input-wrapper {
503
+ flex-direction: column;
504
+ }
505
+
506
+ .stats-container {
507
+ grid-template-columns: 1fr;
508
+ }
509
+
510
+ .filter-tabs {
511
+ overflow-x: auto;
512
+ padding: 1rem;
513
+ }
514
+
515
+ .todo-meta {
516
+ flex-direction: column;
517
+ align-items: flex-start;
518
+ gap: 0.5rem;
519
+ }
520
+
521
+ .todo-actions {
522
+ flex-direction: column;
523
+ }
524
+ }
525
+
526
+ .toast {
527
+ position: fixed;
528
+ bottom: 2rem;
529
+ right: 2rem;
530
+ background: white;
531
+ padding: 1rem 1.5rem;
532
+ border-radius: 12px;
533
+ box-shadow: var(--shadow-xl);
534
+ display: flex;
535
+ align-items: center;
536
+ gap: 1rem;
537
+ transform: translateX(400px);
538
+ transition: transform 0.3s ease-out;
539
+ z-index: 1000;
540
+ }
541
+
542
+ .toast.show {
543
+ transform: translateX(0);
544
+ }
545
+
546
+ .toast-icon {
547
+ font-size: 1.5rem;
548
+ }
549
+
550
+ .toast.success .toast-icon {
551
+ color: var(--secondary-color);
552
+ }
553
+
554
+ .toast.error .toast-icon {
555
+ color: var(--danger-color);
556
+ }
557
+
558
+ .edit-input {
559
+ flex: 1;
560
+ padding: 0.75rem;
561
+ border: 2px solid var(--primary-color);
562
+ border-radius: 8px;
563
+ font-size: 1rem;
564
+ background: white;
565
+ }
566
+
567
+ .edit-input:focus {
568
+ outline: none;
569
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
570
+ }
571
+ </style>
572
+ </head>
573
+ <body>
574
+ <div class="background-pattern"></div>
575
+
576
+ <header>
577
+ <div class="header-content">
578
+ <div class="logo">
579
+ <div class="logo-icon">✓</div>
580
+ <span>TaskFlow</span>
581
+ </div>
582
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="header-link">
583
+ Built with anycoder
584
+ </a>
585
+ </div>
586
+ </header>
587
+
588
+ <main>
589
+ <div class="todo-container">
590
+ <div class="todo-header">
591
+ <h1 class="todo-title">My Tasks</h1>
592
+ <p class="todo-subtitle">Organize your day, achieve your goals</p>
593
+ </div>
594
+
595
+ <div class="stats-container">
596
+ <div class="stat-card">
597
+ <div class="stat-number" id="totalTasks">0</div>
598
+ <div class="stat-label">Total Tasks</div>
599
+ </div>
600
+ <div class="stat-card">
601
+ <div class="stat-number" id="activeTasks">0</div>
602
+ <div class="stat-label">Active</div>
603
+ </div>
604
+ <div class="stat-card">
605
+ <div class="stat-number" id="completedTasks">0</div>
606
+ <div class="stat-label">Completed</div>
607
+ </div>
608
+ <div class="stat-card">
609
+ <div class="stat-number" id="completionRate">0%</div>
610
+ <div class="stat-label">Completion Rate</div>
611
+ </div>
612
+ </div>
613
+
614
+ <div class="input-section">
615
+ <div class="input-wrapper">
616
+ <input
617
+ type="text"
618
+ class="todo-input"
619
+ id="todoInput"
620
+ placeholder="What needs to be done today?"
621
+ autocomplete="off"
622
+ >
623
+ <select class="priority-select" id="prioritySelect">
624
+ <option value="low">Low Priority</option>
625
+ <option value="medium" selected>Medium Priority</option>
626
+ <option value="high">High Priority</option>
627
+ </select>
628
+ <button class="add-btn" id="addBtn">
629
+ <span>+</span>
630
+ <span>Add Task</span>
631
+ </button>
632
+ </div>
633
+ </div>
634
+
635
+ <div class="filter-tabs">
636
+ <button class="filter-tab active" data-filter="all">
637
+ All <span class="count" id="allCount">0</span>
638
+ </button>
639
+ <button class="filter-tab" data-filter="active">
640
+ Active <span class="count" id="activeCount">0</span>
641
+ </button>
642
+ <button class="filter-tab" data-filter="completed">
643
+ Completed <span class="count" id="completedCount">0</span>
644
+ </button>
645
+ </div>
646
+
647
+ <div class="todo-list" id="todoList">
648
+ <div class="empty-state">
649
+ <div class="empty-icon">📝</div>
650
+ <p>No tasks yet. Add your first task above!</p>
651
+ </div>
652
+ </div>
653
+
654
+ <button class="clear-completed" id="clearCompleted" style="display: none;">
655
+ Clear Completed Tasks
656
+ </button>
657
+ </div>
658
+ </main>
659
+
660
+ <div class="toast" id="toast">
661
+ <span class="toast-icon"></span>
662
+ <span class="toast-message"></span>
663
+ </div>
664
+
665
+ <script>
666
+ class TodoApp {
667
+ constructor() {
668
+ this.todos = this.loadTodos();
669
+ this.currentFilter = 'all';
670
+ this.init();
671
+ }
672
+
673
+ init() {
674
+ this.setupEventListeners();
675
+ this.render();
676
+ this.updateStats();
677
+ }
678
+
679
+ setupEventListeners() {
680
+ // Add task
681
+ document.getElementById('addBtn').addEventListener('click', () => this.addTodo());
682
+ document.getElementById('todoInput').addEventListener('keypress', (e) => {
683
+ if (e.key === 'Enter') this.addTodo();
684
+ });
685
+
686
+ // Filter tabs
687
+ document.querySelectorAll('.filter-tab').forEach(tab => {
688
+ tab.addEventListener('click', (e) => {
689
+ document.querySelectorAll('.filter-tab').forEach(t => t.classList.remove('active'));
690
+ e.target.classList.add('active');
691
+ this.currentFilter = e.target.dataset.filter;
692
+ this.render();
693
+ });
694
+ });
695
+
696
+ // Clear completed
697
+ document.getElementById('clearCompleted').addEventListener('click', () => this.clearCompleted());
698
+ }
699
+
700
+ generateId() {
701
+ return '_' + Math.random().toString(36).substr(2, 9);
702
+ }
703
+
704
+ addTodo() {
705
+ const input = document.getElementById('todoInput');
706
+ const priority = document.getElementById('prioritySelect').value;
707
+ const text = input.value.trim();
708
+
709
+ if (!text) {
710
+ this.showToast('Please enter a task', 'error');
711
+ return;
712
+ }
713
+
714
+ const todo = {
715
+ id: this.generateId(),
716
+ text: text,
717
+ completed: false,
718
+ priority: priority,
719
+ createdAt: new Date().toISOString()
720
+ };
721
+
722
+ this.todos.unshift(todo);
723
+ this.saveTodos();
724
+ this.render();
725
+ this.updateStats();
726
+
727
+ input.value = '';
728
+ input.focus();
729
+
730
+ this.showToast('Task added successfully!', 'success');
731
+ }
732
+
733
+ toggleTodo(id) {
734
+ const todo = this.todos.find(t => t.id === id);
735
+ if (todo) {
736
+ todo.completed = !todo.completed;
737
+ this.saveTodos();
738
+ this.render();
739
+ this.updateStats();
740
+ }
741
+ }
742
+
743
+ deleteTodo(id) {
744
+ this.todos = this.todos.filter(t => t.id !== id);
745
+ this.saveTodos();
746
+ this.render();
747
+ this.updateStats();
748
+ this.showToast('Task deleted', 'success');
749
+ }
750
+
751
+ editTodo(id) {
752
+ const todo = this.todos.find(t => t.id === id);
753
+ if (!todo) return;
754
+
755
+ const todoItem = document.querySelector(`[data-id="${id}"]`);
756
+ const content = todoItem.querySelector('.todo-content');
757
+
758
+ const input = document.createElement('input');
759
+ input.type = 'text';
760
+ input.className = 'edit-input';
761
+ input.value = todo.text;
762
+
763
+ content.innerHTML = '';
764
+ content.appendChild(input);
765
+ input.focus();
766
+ input.select();
767
+
768
+ const saveEdit = () => {
769
+ const newText = input.value.trim();
770
+ if (newText && newText !== todo.text) {
771
+ todo.text = newText;
772
+ this.saveTodos();
773
+ this.showToast('Task updated', 'success');
774
+ }
775
+ this.render();
776
+ };
777
+
778
+ input.addEventListener('blur', saveEdit);
779
+ input.addEventListener('keypress', (e) => {
780
+ if (e.key === 'Enter') {
781
+ saveEdit();
782
+ }
783
+ });
784
+ }
785
+
786
+ clearCompleted() {
787
+ const completedCount = this.todos.filter(t => t.completed).length;
788
+ if (completedCount === 0) return;
789
+
790
+ this.todos = this.todos.filter(t => !t.completed);
791
+ this.saveTodos();
792
+ this.render();
793
+ this.updateStats();
794
+ this.showToast(`Cleared ${completedCount} completed task(s)`, 'success');
795
+ }
796
+
797
+ getFilteredTodos() {
798
+ switch (this.currentFilter) {
799
+ case 'active':
800
+ return this.todos.filter(t => !t.completed);
801
+ case 'completed':
802
+ return this.todos.filter(t => t.completed);
803
+ default:
804
+ return this.todos;
805
+ }
806
+ }
807
+
808
+ render() {
809
+ const todoList = document.getElementById('todoList');
810
+ const filteredTodos = this.getFilteredTodos();
811
+
812
+ if (filteredTodos.length === 0) {
813
+ todoList.innerHTML = `
814
+ <div class="empty-state">
815
+ <div class="empty-icon">📝</div>
816
+ <p>${this.currentFilter === 'all' ? 'No tasks yet. Add your first task above!' :
817
+ this.currentFilter === 'active' ? 'No active tasks!' :
818
+ 'No completed tasks!'}</p>
819
+ </div>
820
+ `;
821
+ } else {
822
+ todoList.innerHTML = filteredTodos.map(todo => `
823
+ <div class="todo-item ${todo.completed ? 'completed' : ''}" data-id="${todo.id}">
824
+ <div class="checkbox-wrapper">
825
+ <input
826
+ type="checkbox"
827
+ class="todo-checkbox"
828
+ ${todo.completed ? 'checked' : ''}
829
+ onchange="app.toggleTodo('${todo.id}')"
830
+ >
831
+ </div>
832
+ <div class="todo-content">
833
+ <div class="todo-text">${this.escapeHtml(todo.text)}</div>
834
+ <div class="todo-meta">
835
+ <span class="priority-badge priority-${todo.priority}">${todo.priority}</span>
836
+ <span>📅 ${this.formatDate(todo.createdAt)}</span>
837
+ </div>
838
+ </div>
839
+ <div class="todo-actions">
840
+ <button class="action-btn edit" onclick="app.editTodo('${todo.id}')">
841
+ ✏️
842
+ </button>
843
+ <button class="action-btn delete" onclick="app.deleteTodo('${todo.id}')">
844
+ 🗑️
845
+ </button>
846
+ </div>
847
+ </div>
848
+ `).join('');
849
+ }
850
+
851
+ // Update filter counts
852
+ document.getElementById('allCount').textContent = this.todos.length;
853
+ document.getElementById('activeCount').textContent = this.todos.filter(t => !t.completed).length;
854
+ document.getElementById('completedCount').textContent = this.todos.filter(t => t.completed).length;
855
+
856
+ // Show/hide clear button
857
+ const clearBtn = document.getElementById('clearCompleted');
858
+ clearBtn.style.display = this.todos.some(t => t.completed) ? 'block' : 'none';
859
+ }
860
+
861
+ updateStats() {
862
+ const total = this.todos.length;
863
+ const completed = this.todos.filter(t => t.completed).length;
864
+ const active = total - completed;
865
+ const rate = total > 0 ? Math.round((completed / total) * 100) : 0;
866
+
867
+ document.getElementById('totalTasks').textContent = total;
868
+ document.getElementById('activeTasks').textContent = active;
869
+ document.getElementById('completedTasks').textContent = completed;
870
+ document.getElementById('completionRate').textContent = rate + '%';
871
+ }
872
+
873
+ formatDate(dateString) {
874
+ const date = new Date(dateString);
875
+ const today = new Date();
876
+ const yesterday = new Date(today);
877
+ yesterday.setDate(yesterday.getDate() - 1);
878
+
879
+ if (date.toDateString() === today.toDateString()) {
880
+ return 'Today';
881
+ } else if (date.toDateString() === yesterday.toDateString()) {
882
+ return 'Yesterday';
883
+ } else {
884
+ return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
885
+ }
886
+ }
887
+
888
+ escapeHtml(text) {
889
+ const div = document.createElement('div');
890
+ div.textContent = text;
891
+ return div.innerHTML;
892
+ }
893
+
894
+ showToast(message, type = 'success') {
895
+ const toast = document.getElementById('toast');
896
+ const icon = toast.querySelector('.toast-icon');
897
+ const msg = toast.querySelector('.toast-message');
898
+
899
+ toast.className = `toast ${type}`;
900
+ icon.textContent = type === 'success' ? '✓' : '⚠️';
901
+ msg.textContent = message;
902
+
903
+ toast.classList.add('show');
904
+
905
+ setTimeout(() => {
906
+ toast.classList.remove('show');
907
+ }, 3000);
908
+ }
909
+
910
+ saveTodos() {
911
+ localStorage.setItem('todos', JSON.stringify(this.todos));
912
+ }
913
+
914
+ loadTodos() {
915
+ const stored = localStorage.getItem('todos');
916
+ return stored ? JSON.parse(stored) : [];
917
+ }
918
+ }
919
+
920
+ // Initialize the app
921
+ const app = new TodoApp();
922
+ </script>
923
+ </body>
924
+ </html>