akhaliq HF Staff commited on
Commit
54178aa
·
verified ·
1 Parent(s): 4f07dc5

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +803 -19
index.html CHANGED
@@ -1,19 +1,803 @@
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>TodoFlow - Modern Todo App</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
8
+ <style>
9
+ :root {
10
+ --bg-primary: #f8fafc;
11
+ --bg-secondary: #ffffff;
12
+ --bg-tertiary: #f1f5f9;
13
+ --text-primary: #0f172a;
14
+ --text-secondary: #64748b;
15
+ --accent: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
16
+ --accent-hover: linear-gradient(135deg, #1d4ed8 0%, #1e40af 100%);
17
+ --success: linear-gradient(135deg, #10b981 0%, #059669 100%);
18
+ --danger: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
19
+ --warning: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
20
+ --border: #e2e8f0;
21
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
22
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
23
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
24
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
25
+ --glass-bg: rgba(255, 255, 255, 0.25);
26
+ --glass-border: rgba(255, 255, 255, 0.18);
27
+ --radius: 16px;
28
+ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
29
+ }
30
+
31
+ [data-theme="dark"] {
32
+ --bg-primary: #0f0f23;
33
+ --bg-secondary: #1a1a2e;
34
+ --bg-tertiary: #16213e;
35
+ --text-primary: #f8fafc;
36
+ --text-secondary: #cbd5e1;
37
+ --border: #334155;
38
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
39
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.3), 0 2px 4px -2px rgb(0 0 0 / 0.3);
40
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.4);
41
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.5), 0 8px 10px -6px rgb(0 0 0 / 0.5);
42
+ --glass-bg: rgba(26, 26, 46, 0.4);
43
+ --glass-border: rgba(99, 102, 241, 0.2);
44
+ }
45
+
46
+ * {
47
+ margin: 0;
48
+ padding: 0;
49
+ box-sizing: border-box;
50
+ }
51
+
52
+ body {
53
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
54
+ background: linear-gradient(-45deg, var(--bg-primary), var(--bg-secondary), var(--bg-tertiary), var(--bg-primary));
55
+ background-size: 400% 400%;
56
+ animation: gradientShift 15s ease infinite;
57
+ color: var(--text-primary);
58
+ min-height: 100vh;
59
+ padding: 1rem;
60
+ line-height: 1.6;
61
+ transition: var(--transition);
62
+ }
63
+
64
+ @keyframes gradientShift {
65
+ 0% { background-position: 0% 50%; }
66
+ 50% { background-position: 100% 50%; }
67
+ 100% { background-position: 0% 50%; }
68
+ }
69
+
70
+ .container {
71
+ max-width: 600px;
72
+ margin: 0 auto;
73
+ min-height: 100vh;
74
+ display: flex;
75
+ flex-direction: column;
76
+ gap: 2rem;
77
+ padding: 2rem 0;
78
+ }
79
+
80
+ header {
81
+ display: flex;
82
+ justify-content: space-between;
83
+ align-items: center;
84
+ background: var(--glass-bg);
85
+ backdrop-filter: blur(20px);
86
+ -webkit-backdrop-filter: blur(20px);
87
+ border: 1px solid var(--glass-border);
88
+ border-radius: var(--radius);
89
+ padding: 1.5rem 2rem;
90
+ box-shadow: var(--shadow-lg);
91
+ position: relative;
92
+ overflow: hidden;
93
+ }
94
+
95
+ header::before {
96
+ content: '';
97
+ position: absolute;
98
+ top: 0;
99
+ left: 0;
100
+ right: 0;
101
+ bottom: 0;
102
+ background: var(--accent);
103
+ opacity: 0.1;
104
+ border-radius: var(--radius);
105
+ }
106
+
107
+ h1 {
108
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
109
+ font-weight: 800;
110
+ background: var(--accent);
111
+ -webkit-background-clip: text;
112
+ -webkit-text-fill-color: transparent;
113
+ background-clip: text;
114
+ position: relative;
115
+ z-index: 1;
116
+ }
117
+
118
+ .header-actions {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: 1rem;
122
+ }
123
+
124
+ .theme-toggle {
125
+ background: none;
126
+ border: none;
127
+ font-size: 1.25rem;
128
+ color: var(--text-primary);
129
+ cursor: pointer;
130
+ padding: 0.5rem;
131
+ border-radius: 50%;
132
+ transition: var(--transition);
133
+ width: 44px;
134
+ height: 44px;
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: center;
138
+ }
139
+
140
+ .theme-toggle:hover {
141
+ background: var(--glass-bg);
142
+ transform: scale(1.05);
143
+ }
144
+
145
+ .built-with {
146
+ font-size: 0.875rem;
147
+ color: var(--text-secondary);
148
+ text-decoration: none;
149
+ position: relative;
150
+ z-index: 1;
151
+ }
152
+
153
+ .built-with:hover {
154
+ color: var(--text-primary);
155
+ }
156
+
157
+ .input-section {
158
+ background: var(--glass-bg);
159
+ backdrop-filter: blur(20px);
160
+ -webkit-backdrop-filter: blur(20px);
161
+ border: 1px solid var(--glass-border);
162
+ border-radius: var(--radius);
163
+ padding: 1.5rem;
164
+ box-shadow: var(--shadow-xl);
165
+ position: relative;
166
+ overflow: hidden;
167
+ }
168
+
169
+ .input-section::before {
170
+ content: '';
171
+ position: absolute;
172
+ top: 0;
173
+ left: 0;
174
+ right: 0;
175
+ height: 4px;
176
+ background: var(--accent);
177
+ }
178
+
179
+ .input-wrapper {
180
+ display: flex;
181
+ gap: 1rem;
182
+ align-items: center;
183
+ }
184
+
185
+ #todoInput {
186
+ flex: 1;
187
+ padding: 1rem 1.5rem;
188
+ border: 2px solid transparent;
189
+ border-radius: 12px;
190
+ font-size: 1rem;
191
+ background: rgba(255, 255, 255, 0.5);
192
+ color: var(--text-primary);
193
+ outline: none;
194
+ transition: var(--transition);
195
+ backdrop-filter: blur(10px);
196
+ }
197
+
198
+ #todoInput::placeholder {
199
+ color: var(--text-secondary);
200
+ }
201
+
202
+ #todoInput:focus {
203
+ border-color: hsl(217, 91%, 60%);
204
+ box-shadow: 0 0 0 3px hsl(217, 91%, 80% / 0.5);
205
+ background: rgba(255, 255, 255, 0.8);
206
+ }
207
+
208
+ #addBtn {
209
+ background: var(--accent);
210
+ color: white;
211
+ border: none;
212
+ padding: 1rem 1.5rem;
213
+ border-radius: 12px;
214
+ font-size: 1rem;
215
+ font-weight: 600;
216
+ cursor: pointer;
217
+ transition: var(--transition);
218
+ box-shadow: var(--shadow-md);
219
+ white-space: nowrap;
220
+ display: flex;
221
+ align-items: center;
222
+ gap: 0.5rem;
223
+ }
224
+
225
+ #addBtn:hover {
226
+ background: var(--accent-hover);
227
+ transform: translateY(-2px);
228
+ box-shadow: var(--shadow-lg);
229
+ }
230
+
231
+ #addBtn:active {
232
+ transform: translateY(0);
233
+ }
234
+
235
+ .todo-list {
236
+ flex: 1;
237
+ display: flex;
238
+ flex-direction: column;
239
+ gap: 1rem;
240
+ }
241
+
242
+ .todo-item {
243
+ background: var(--glass-bg);
244
+ backdrop-filter: blur(20px);
245
+ -webkit-backdrop-filter: blur(20px);
246
+ border: 1px solid var(--glass-border);
247
+ border-radius: var(--radius);
248
+ padding: 1.25rem;
249
+ box-shadow: var(--shadow-lg);
250
+ opacity: 0;
251
+ transform: translateX(-20px);
252
+ animation: slideIn 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
253
+ transition: var(--transition);
254
+ display: grid;
255
+ grid-template-columns: auto 1fr auto;
256
+ gap: 1rem;
257
+ align-items: center;
258
+ }
259
+
260
+ .todo-item.show {
261
+ opacity: 1;
262
+ transform: translateX(0);
263
+ }
264
+
265
+ .todo-item:hover {
266
+ transform: translateY(-4px);
267
+ box-shadow: var(--shadow-xl);
268
+ }
269
+
270
+ .todo-item.done {
271
+ opacity: 0.7;
272
+ background: rgba(16, 185, 129, 0.1);
273
+ border-color: rgba(16, 185, 129, 0.3);
274
+ }
275
+
276
+ .todo-item.done .todo-text {
277
+ text-decoration: line-through;
278
+ color: var(--text-secondary);
279
+ }
280
+
281
+ @keyframes slideIn {
282
+ to {
283
+ opacity: 1;
284
+ transform: translateX(0);
285
+ }
286
+ }
287
+
288
+ .checkbox {
289
+ width: 24px;
290
+ height: 24px;
291
+ border-radius: 50%;
292
+ border: 2px solid var(--border);
293
+ background: transparent;
294
+ cursor: pointer;
295
+ transition: var(--transition);
296
+ display: flex;
297
+ align-items: center;
298
+ justify-content: center;
299
+ font-size: 0.75rem;
300
+ position: relative;
301
+ }
302
+
303
+ .checkbox:hover {
304
+ background: var(--glass-bg);
305
+ }
306
+
307
+ .checkbox.checked {
308
+ background: var(--success);
309
+ border-color: var(--success);
310
+ color: white;
311
+ }
312
+
313
+ .todo-text {
314
+ font-size: 1.1rem;
315
+ cursor: pointer;
316
+ transition: var(--transition);
317
+ padding: 0.5rem 0;
318
+ word-break: break-word;
319
+ }
320
+
321
+ .todo-text.editing {
322
+ padding: 0.5rem;
323
+ border-radius: 8px;
324
+ background: rgba(255, 255, 255, 0.6);
325
+ border: 2px solid transparent;
326
+ }
327
+
328
+ .actions {
329
+ display: flex;
330
+ gap: 0.5rem;
331
+ opacity: 0;
332
+ transition: var(--transition);
333
+ }
334
+
335
+ .todo-item:hover .actions {
336
+ opacity: 1;
337
+ }
338
+
339
+ .action-btn {
340
+ width: 40px;
341
+ height: 40px;
342
+ border: none;
343
+ border-radius: 50%;
344
+ cursor: pointer;
345
+ font-size: 0.875rem;
346
+ display: flex;
347
+ align-items: center;
348
+ justify-content: center;
349
+ transition: var(--transition);
350
+ color: var(--text-secondary);
351
+ }
352
+
353
+ .action-btn:hover {
354
+ color: white;
355
+ transform: scale(1.1);
356
+ }
357
+
358
+ .edit-btn {
359
+ background: var(--warning);
360
+ }
361
+
362
+ .edit-btn:hover {
363
+ background: #f59e0b;
364
+ }
365
+
366
+ .delete-btn {
367
+ background: var(--danger);
368
+ }
369
+
370
+ .delete-btn:hover {
371
+ background: #ef4444;
372
+ }
373
+
374
+ .filters {
375
+ display: flex;
376
+ gap: 0.5rem;
377
+ justify-content: center;
378
+ flex-wrap: wrap;
379
+ }
380
+
381
+ .filter-btn {
382
+ padding: 0.75rem 1.5rem;
383
+ border: 2px solid transparent;
384
+ background: var(--glass-bg);
385
+ color: var(--text-secondary);
386
+ border-radius: 50px;
387
+ cursor: pointer;
388
+ font-weight: 500;
389
+ transition: var(--transition);
390
+ backdrop-filter: blur(10px);
391
+ white-space: nowrap;
392
+ }
393
+
394
+ .filter-btn.active,
395
+ .filter-btn:hover {
396
+ background: var(--glass-bg);
397
+ color: var(--text-primary);
398
+ border-color: hsl(217, 91%, 60%);
399
+ box-shadow: 0 0 0 3px hsl(217, 91%, 80% / 0.3);
400
+ }
401
+
402
+ .footer {
403
+ background: var(--glass-bg);
404
+ backdrop-filter: blur(20px);
405
+ -webkit-backdrop-filter: blur(20px);
406
+ border: 1px solid var(--glass-border);
407
+ border-radius: var(--radius);
408
+ padding: 1.5rem;
409
+ box-shadow: var(--shadow-lg);
410
+ display: flex;
411
+ justify-content: space-between;
412
+ align-items: center;
413
+ flex-wrap: wrap;
414
+ gap: 1rem;
415
+ }
416
+
417
+ .stats {
418
+ color: var(--text-secondary);
419
+ font-weight: 500;
420
+ }
421
+
422
+ .clear-btn {
423
+ background: var(--danger);
424
+ color: white;
425
+ border: none;
426
+ padding: 0.75rem 1.5rem;
427
+ border-radius: 50px;
428
+ cursor: pointer;
429
+ font-weight: 500;
430
+ transition: var(--transition);
431
+ opacity: 0.8;
432
+ }
433
+
434
+ .clear-btn:hover:not(:disabled) {
435
+ opacity: 1;
436
+ transform: translateY(-2px);
437
+ box-shadow: var(--shadow-md);
438
+ }
439
+
440
+ .clear-btn:disabled {
441
+ opacity: 0.5;
442
+ cursor: not-allowed;
443
+ }
444
+
445
+ .empty-state {
446
+ text-align: center;
447
+ padding: 3rem 1rem;
448
+ color: var(--text-secondary);
449
+ }
450
+
451
+ .empty-state i {
452
+ font-size: 4rem;
453
+ margin-bottom: 1rem;
454
+ opacity: 0.5;
455
+ }
456
+
457
+ /* Responsive */
458
+ @media (max-width: 768px) {
459
+ .container {
460
+ padding: 1rem 0;
461
+ gap: 1.5rem;
462
+ }
463
+
464
+ header,
465
+ .input-section,
466
+ .footer {
467
+ padding: 1.25rem;
468
+ }
469
+
470
+ .input-wrapper {
471
+ flex-direction: column;
472
+ }
473
+
474
+ #addBtn {
475
+ width: 100%;
476
+ justify-content: center;
477
+ }
478
+
479
+ .todo-item {
480
+ grid-template-columns: 1fr;
481
+ gap: 1rem;
482
+ text-align: center;
483
+ }
484
+
485
+ .actions {
486
+ opacity: 1;
487
+ justify-content: center;
488
+ }
489
+
490
+ .footer {
491
+ flex-direction: column;
492
+ text-align: center;
493
+ }
494
+ }
495
+
496
+ @media (max-width: 480px) {
497
+ body {
498
+ padding: 0.5rem;
499
+ }
500
+
501
+ h1 {
502
+ font-size: 1.75rem;
503
+ }
504
+ }
505
+
506
+ /* Hide scrollbar for webkit */
507
+ ::-webkit-scrollbar {
508
+ width: 6px;
509
+ }
510
+
511
+ ::-webkit-scrollbar-track {
512
+ background: transparent;
513
+ }
514
+
515
+ ::-webkit-scrollbar-thumb {
516
+ background: var(--text-secondary);
517
+ border-radius: 3px;
518
+ }
519
+
520
+ ::-webkit-scrollbar-thumb:hover {
521
+ background: var(--text-primary);
522
+ }
523
+ </style>
524
+ </head>
525
+ <body>
526
+ <div class="container">
527
+ <header>
528
+ <h1><i class="fas fa-tasks"></i> TodoFlow</h1>
529
+ <div class="header-actions">
530
+ <button class="theme-toggle" id="themeToggle" title="Toggle Theme">
531
+ <i class="fas fa-moon"></i>
532
+ </button>
533
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with" title="Built with anycoder">
534
+ Built with <i class="fab fa-hugging-face"></i> anycoder
535
+ </a>
536
+ </div>
537
+ </header>
538
+
539
+ <section class="input-section" role="search">
540
+ <div class="input-wrapper">
541
+ <input type="text" id="todoInput" placeholder="What needs to be done today? ✨" maxlength="200">
542
+ <button id="addBtn" aria-label="Add Todo">
543
+ <i class="fas fa-plus"></i> Add
544
+ </button>
545
+ </div>
546
+ </section>
547
+
548
+ <main class="todo-list" id="todoList">
549
+ <!-- Todos will be dynamically inserted here -->
550
+ </main>
551
+
552
+ <nav class="filters" id="filters">
553
+ <button class="filter-btn active" data-filter="all">All</button>
554
+ <button class="filter-btn" data-filter="active">Active</button>
555
+ <button class="filter-btn" data-filter="completed">Completed</button>
556
+ </nav>
557
+
558
+ <footer class="footer" id="footer" style="display: none;">
559
+ <span class="stats" id="stats"></span>
560
+ <button class="clear-btn" id="clearBtn" disabled>Clear Completed</button>
561
+ </footer>
562
+ </div>
563
+
564
+ <script>
565
+ class TodoApp {
566
+ constructor() {
567
+ this.todos = [];
568
+ this.currentFilter = 'all';
569
+ this.editingId = null;
570
+ this.init();
571
+ }
572
+
573
+ init() {
574
+ this.load();
575
+ this.bindEvents();
576
+ this.render();
577
+ }
578
+
579
+ bindEvents() {
580
+ const addBtn = document.getElementById('addBtn');
581
+ const todoInput = document.getElementById('todoInput');
582
+ const filters = document.getElementById('filters');
583
+ const themeToggle = document.getElementById('themeToggle');
584
+ const clearBtn = document.getElementById('clearBtn');
585
+
586
+ addBtn.addEventListener('click', () => this.addTodo());
587
+ todoInput.addEventListener('keypress', (e) => {
588
+ if (e.key === 'Enter') this.addTodo();
589
+ });
590
+ filters.addEventListener('click', (e) => {
591
+ if (e.target.dataset.filter) {
592
+ this.setFilter(e.target.dataset.filter);
593
+ }
594
+ });
595
+ themeToggle.addEventListener('click', () => this.toggleTheme());
596
+ clearBtn.addEventListener('click', () => this.clearCompleted());
597
+ document.addEventListener('click', (e) => {
598
+ if (e.target.closest('.checkbox')) this.toggleTodo(e.target.closest('.todo-item').dataset.id);
599
+ if (e.target.closest('.edit-btn')) this.startEdit(e.target.closest('.todo-item').dataset.id);
600
+ if (e.target.closest('.delete-btn')) this.deleteTodo(e.target.closest('.todo-item').dataset.id);
601
+ });
602
+ todoInput.addEventListener('input', () => {
603
+ todoInput.style.height = 'auto';
604
+ todoInput.style.height = todoInput.scrollHeight + 'px';
605
+ });
606
+ }
607
+
608
+ addTodo() {
609
+ const input = document.getElementById('todoInput');
610
+ const text = input.value.trim();
611
+ if (!text) return;
612
+
613
+ const todo = {
614
+ id: Date.now().toString(),
615
+ text,
616
+ done: false
617
+ };
618
+
619
+ this.todos.unshift(todo);
620
+ input.value = '';
621
+ this.save();
622
+ this.render();
623
+ }
624
+
625
+ toggleTodo(id) {
626
+ const todo = this.todos.find(t => t.id === id);
627
+ if (todo) {
628
+ todo.done = !todo.done;
629
+ this.save();
630
+ this.render();
631
+ }
632
+ }
633
+
634
+ deleteTodo(id) {
635
+ this.todos = this.todos.filter(t => t.id !== id);
636
+ this.save();
637
+ this.render();
638
+ }
639
+
640
+ startEdit(id) {
641
+ if (this.editingId) return;
642
+ this.editingId = id;
643
+ this.render();
644
+ const input = document.querySelector(`[data-id="${id}"] .todo-text`);
645
+ if (input) {
646
+ input.focus();
647
+ const range = document.createRange();
648
+ range.selectNodeContents(input);
649
+ range.collapse(false);
650
+ const sel = window.getSelection();
651
+ sel.removeAllRanges();
652
+ sel.addRange(range);
653
+ }
654
+ }
655
+
656
+ handleEdit(e) {
657
+ if (e.key === 'Enter' && !e.shiftKey) {
658
+ e.preventDefault();
659
+ this.finishEdit(e.target);
660
+ } else if (e.key === 'Escape') {
661
+ this.finishEdit(e.target);
662
+ }
663
+ }
664
+
665
+ finishEdit(target) {
666
+ const id = target.closest('.todo-item').dataset.id;
667
+ const newText = target.textContent.trim();
668
+ if (newText) {
669
+ const todo = this.todos.find(t => t.id === id);
670
+ if (todo) todo.text = newText;
671
+ }
672
+ this.editingId = null;
673
+ this.save();
674
+ this.render();
675
+ }
676
+
677
+ setFilter(filter) {
678
+ this.currentFilter = filter;
679
+ document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
680
+ document.querySelector(`[data-filter="${filter}"]`).classList.add('active');
681
+ this.render();
682
+ }
683
+
684
+ clearCompleted() {
685
+ this.todos = this.todos.filter(t => !t.done);
686
+ this.save();
687
+ this.render();
688
+ }
689
+
690
+ getFilteredTodos() {
691
+ switch (this.currentFilter) {
692
+ case 'active': return this.todos.filter(t => !t.done);
693
+ case 'completed': return this.todos.filter(t => t.done);
694
+ default: return this.todos;
695
+ }
696
+ }
697
+
698
+ updateStats() {
699
+ const activeCount = this.todos.filter(t => !t.done).length;
700
+ document.getElementById('stats').textContent = `${activeCount} ${activeCount === 1 ? 'item' : 'items'} left`;
701
+ }
702
+
703
+ render() {
704
+ const list = document.getElementById('todoList');
705
+ const filtered = this.getFilteredTodos();
706
+ const footer = document.getElementById('footer');
707
+ const clearBtn = document.getElementById('clearBtn');
708
+
709
+ if (this.todos.length === 0) {
710
+ list.innerHTML = `
711
+ <div class="empty-state">
712
+ <i class="fas fa-clipboard-list"></i>
713
+ <h2>No todos yet</h2>
714
+ <p>Add one above to get started! 🚀</p>
715
+ </div>
716
+ `;
717
+ footer.style.display = 'none';
718
+ return;
719
+ }
720
+
721
+ list.innerHTML = filtered.map((todo, index) => {
722
+ const editing = this.editingId === todo.id;
723
+ return `
724
+ <article class="todo-item ${todo.done ? 'done' : ''}" data-id="${todo.id}">
725
+ <button class="checkbox ${todo.done ? 'checked' : ''}" aria-label="${todo.done ? 'Mark incomplete' : 'Mark complete'}">
726
+ ${todo.done ? '<i class="fas fa-check"></i>' : ''}
727
+ </button>
728
+ <div class="todo-text ${editing ? 'editing' : ''} ${todo.done ? 'done' : ''}"
729
+ contenteditable="${editing}"
730
+ ${editing ? `onkeydown="app.handleEdit(event)"` : ''}>
731
+ ${todo.text}
732
+ </div>
733
+ <div class="actions">
734
+ <button class="action-btn edit-btn" aria-label="Edit" ${editing ? 'disabled' : ''}>
735
+ <i class="fas fa-edit"></i>
736
+ </button>
737
+ <button class="action-btn delete-btn" aria-label="Delete">
738
+ <i class="fas fa-trash"></i>
739
+ </button>
740
+ </div>
741
+ </article>
742
+ `;
743
+ }).join('');
744
+
745
+ // Animate new items
746
+ filtered.slice(-3).forEach((_, i) => {
747
+ setTimeout(() => {
748
+ const item = list.querySelectorAll('.todo-item')[filtered.length - 1 - i];
749
+ if (item) item.classList.add('show');
750
+ }, i * 100);
751
+ });
752
+
753
+ footer.style.display = 'flex';
754
+ clearBtn.disabled = this.todos.every(t => !t.done);
755
+ this.updateStats();
756
+ }
757
+
758
+ save() {
759
+ localStorage.setItem('todoflow', JSON.stringify(this.todos));
760
+ localStorage.setItem('todoflow-filter', this.currentFilter);
761
+ }
762
+
763
+ load() {
764
+ const saved = localStorage.getItem('todoflow');
765
+ if (saved) {
766
+ this.todos = JSON.parse(saved);
767
+ }
768
+ const savedFilter = localStorage.getItem('todoflow-filter');
769
+ if (savedFilter) {
770
+ this.currentFilter = savedFilter;
771
+ document.querySelector(`[data-filter="${this.currentFilter}"]`).classList.add('active');
772
+ document.querySelector(`[data-filter="all"]`).classList.remove('active');
773
+ }
774
+ }
775
+
776
+ toggleTheme() {
777
+ const body = document.body;
778
+ const isDark = body.dataset.theme === 'dark';
779
+ const icon = document.getElementById('themeToggle').querySelector('i');
780
+ if (isDark) {
781
+ body.removeAttribute('data-theme');
782
+ icon.className = 'fas fa-moon';
783
+ localStorage.removeItem('todoflow-theme');
784
+ } else {
785
+ body.dataset.theme = 'dark';
786
+ icon.className = 'fas fa-sun';
787
+ localStorage.setItem('todoflow-theme', 'dark');
788
+ }
789
+ }
790
+ }
791
+
792
+ // Global app for event handlers
793
+ const app = new TodoApp();
794
+
795
+ // Load theme
796
+ const savedTheme = localStorage.getItem('todoflow-theme');
797
+ if (savedTheme === 'dark') {
798
+ document.body.dataset.theme = 'dark';
799
+ document.getElementById('themeToggle').querySelector('i').className = 'fas fa-sun';
800
+ }
801
+ </script>
802
+ </body>
803
+ </html>