igoraguiar commited on
Commit
edabd86
·
verified ·
1 Parent(s): e61e0d2

A full featured task / todo list app. Local persistence. Due date, categories, priority, lists. Post-Neumorphism: depth with clarity. Light/Dark. - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +897 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Todo Lists
3
- emoji: 📚
4
  colorFrom: pink
5
- colorTo: gray
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: todo-lists
3
+ emoji: 🐳
4
  colorFrom: pink
5
+ colorTo: purple
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,897 @@
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" class="light">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>TaskSphere | Modern 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
+ darkMode: 'class',
12
+ theme: {
13
+ extend: {
14
+ colors: {
15
+ primary: {
16
+ light: '#6366f1',
17
+ dark: '#818cf8'
18
+ },
19
+ secondary: {
20
+ light: '#f43f5e',
21
+ dark: '#fb7185'
22
+ },
23
+ surface: {
24
+ light: '#f8fafc',
25
+ dark: '#1e293b'
26
+ },
27
+ card: {
28
+ light: '#ffffff',
29
+ dark: '#334155'
30
+ }
31
+ },
32
+ boxShadow: {
33
+ 'neumorph-light': '8px 8px 15px #d1d5db, -8px -8px 15px #ffffff',
34
+ 'neumorph-dark': '8px 8px 15px #0f172a, -8px -8px 15px #475569',
35
+ 'inner-neumorph-light': 'inset 3px 3px 5px #d1d5db, inset -3px -3px 5px #ffffff',
36
+ 'inner-neumorph-dark': 'inset 3px 3px 5px #0f172a, inset -3px -3px 5px #475569'
37
+ }
38
+ }
39
+ }
40
+ }
41
+ </script>
42
+ <style>
43
+ .priority-high { border-left-color: #ef4444; }
44
+ .priority-medium { border-left-color: #f59e0b; }
45
+ .priority-low { border-left-color: #10b981; }
46
+
47
+ .category-work { background-color: rgba(99, 102, 241, 0.1); }
48
+ .category-personal { background-color: rgba(16, 185, 129, 0.1); }
49
+ .category-shopping { background-color: rgba(236, 72, 153, 0.1); }
50
+ .category-health { background-color: rgba(244, 63, 94, 0.1); }
51
+ .category-other { background-color: rgba(156, 163, 175, 0.1); }
52
+
53
+ .task-checkbox:checked + .task-label {
54
+ text-decoration: line-through;
55
+ opacity: 0.7;
56
+ }
57
+
58
+ .date-picker {
59
+ -webkit-appearance: none;
60
+ -moz-appearance: none;
61
+ appearance: none;
62
+ }
63
+
64
+ .scrollbar-hide::-webkit-scrollbar {
65
+ display: none;
66
+ }
67
+
68
+ .scrollbar-hide {
69
+ -ms-overflow-style: none;
70
+ scrollbar-width: none;
71
+ }
72
+ </style>
73
+ </head>
74
+ <body class="bg-surface-light dark:bg-surface-dark min-h-screen transition-colors duration-300">
75
+ <div class="container mx-auto px-4 py-8 max-w-6xl">
76
+ <!-- Header -->
77
+ <header class="flex justify-between items-center mb-8">
78
+ <div>
79
+ <h1 class="text-3xl font-bold text-gray-800 dark:text-white">TaskSphere</h1>
80
+ <p class="text-gray-600 dark:text-gray-300">Your productivity companion</p>
81
+ </div>
82
+ <div class="flex items-center space-x-4">
83
+ <button id="theme-toggle" class="p-2 rounded-full bg-card-light dark:bg-card-dark shadow-neumorph-light dark:shadow-neumorph-dark hover:shadow-inner-neumorph-light dark:hover:shadow-inner-neumorph-dark transition-all duration-300">
84
+ <i class="fas fa-moon text-gray-700 dark:text-yellow-300"></i>
85
+ </button>
86
+ <div class="relative">
87
+ <button id="list-dropdown-btn" class="px-4 py-2 rounded-lg bg-card-light dark:bg-card-dark shadow-neumorph-light dark:shadow-neumorph-dark hover:shadow-inner-neumorph-light dark:hover:shadow-inner-neumorph-dark transition-all duration-300 flex items-center">
88
+ <span id="current-list" class="font-medium text-gray-700 dark:text-gray-200">My Tasks</span>
89
+ <i class="fas fa-chevron-down ml-2 text-sm text-gray-500 dark:text-gray-400"></i>
90
+ </button>
91
+ <div id="list-dropdown" class="absolute hidden right-0 mt-2 w-48 rounded-lg bg-card-light dark:bg-card-dark shadow-neumorph-light dark:shadow-neumorph-dark z-10 overflow-hidden">
92
+ <div id="list-container" class="max-h-60 overflow-y-auto scrollbar-hide">
93
+ <!-- Lists will be populated here -->
94
+ </div>
95
+ <div class="border-t border-gray-200 dark:border-gray-700 p-2">
96
+ <button id="add-list-btn" class="w-full text-left px-3 py-2 text-sm text-primary-light dark:text-primary-dark hover:bg-gray-100 dark:hover:bg-gray-700 rounded">
97
+ <i class="fas fa-plus mr-2"></i> New List
98
+ </button>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </header>
104
+
105
+ <!-- Main Content -->
106
+ <div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
107
+ <!-- Sidebar -->
108
+ <div class="lg:col-span-1">
109
+ <div class="bg-card-light dark:bg-card-dark rounded-xl p-6 shadow-neumorph-light dark:shadow-neumorph-dark mb-6">
110
+ <h2 class="text-xl font-semibold text-gray-800 dark:text-white mb-4">Filters</h2>
111
+
112
+ <div class="mb-4">
113
+ <h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Priority</h3>
114
+ <div class="space-y-2">
115
+ <label class="flex items-center">
116
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="priority" value="high">
117
+ <span class="ml-2 text-gray-700 dark:text-gray-300">High</span>
118
+ </label>
119
+ <label class="flex items-center">
120
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="priority" value="medium">
121
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Medium</span>
122
+ </label>
123
+ <label class="flex items-center">
124
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="priority" value="low">
125
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Low</span>
126
+ </label>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="mb-4">
131
+ <h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Categories</h3>
132
+ <div class="space-y-2">
133
+ <label class="flex items-center">
134
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="category" value="work">
135
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Work</span>
136
+ </label>
137
+ <label class="flex items-center">
138
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="category" value="personal">
139
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Personal</span>
140
+ </label>
141
+ <label class="flex items-center">
142
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="category" value="shopping">
143
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Shopping</span>
144
+ </label>
145
+ <label class="flex items-center">
146
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="category" value="health">
147
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Health</span>
148
+ </label>
149
+ <label class="flex items-center">
150
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="category" value="other">
151
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Other</span>
152
+ </label>
153
+ </div>
154
+ </div>
155
+
156
+ <div>
157
+ <h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Status</h3>
158
+ <div class="space-y-2">
159
+ <label class="flex items-center">
160
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="status" value="completed">
161
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Completed</span>
162
+ </label>
163
+ <label class="flex items-center">
164
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="status" value="pending">
165
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Pending</span>
166
+ </label>
167
+ <label class="flex items-center">
168
+ <input type="checkbox" class="form-checkbox rounded text-primary-light dark:text-primary-dark" data-filter="status" value="overdue">
169
+ <span class="ml-2 text-gray-700 dark:text-gray-300">Overdue</span>
170
+ </label>
171
+ </div>
172
+ </div>
173
+ </div>
174
+
175
+ <div class="bg-card-light dark:bg-card-dark rounded-xl p-6 shadow-neumorph-light dark:shadow-neumorph-dark">
176
+ <h2 class="text-xl font-semibold text-gray-800 dark:text-white mb-4">Stats</h2>
177
+ <div class="space-y-4">
178
+ <div>
179
+ <div class="flex justify-between text-sm text-gray-600 dark:text-gray-400 mb-1">
180
+ <span>Tasks Completed</span>
181
+ <span id="completed-count">0</span>
182
+ </div>
183
+ <div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
184
+ <div id="completed-bar" class="bg-primary-light dark:bg-primary-dark h-2 rounded-full" style="width: 0%"></div>
185
+ </div>
186
+ </div>
187
+ <div>
188
+ <div class="flex justify-between text-sm text-gray-600 dark:text-gray-400 mb-1">
189
+ <span>Tasks Pending</span>
190
+ <span id="pending-count">0</span>
191
+ </div>
192
+ <div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
193
+ <div id="pending-bar" class="bg-yellow-500 h-2 rounded-full" style="width: 0%"></div>
194
+ </div>
195
+ </div>
196
+ <div>
197
+ <div class="flex justify-between text-sm text-gray-600 dark:text-gray-400 mb-1">
198
+ <span>Tasks Overdue</span>
199
+ <span id="overdue-count">0</span>
200
+ </div>
201
+ <div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
202
+ <div id="overdue-bar" class="bg-secondary-light dark:bg-secondary-dark h-2 rounded-full" style="width: 0%"></div>
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ <!-- Task List -->
210
+ <div class="lg:col-span-3">
211
+ <div class="bg-card-light dark:bg-card-dark rounded-xl p-6 shadow-neumorph-light dark:shadow-neumorph-dark mb-6">
212
+ <form id="task-form" class="flex flex-col sm:flex-row gap-4">
213
+ <div class="flex-grow">
214
+ <input type="text" id="task-input" placeholder="Add a new task..." class="w-full px-4 py-3 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white">
215
+ </div>
216
+ <div class="flex gap-2">
217
+ <div class="relative">
218
+ <select id="priority-select" class="appearance-none px-3 py-3 pr-8 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white text-sm">
219
+ <option value="low">Low</option>
220
+ <option value="medium" selected>Medium</option>
221
+ <option value="high">High</option>
222
+ </select>
223
+ <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 dark:text-gray-300">
224
+ <i class="fas fa-chevron-down text-xs"></i>
225
+ </div>
226
+ </div>
227
+ <div class="relative">
228
+ <select id="category-select" class="appearance-none px-3 py-3 pr-8 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white text-sm">
229
+ <option value="work">Work</option>
230
+ <option value="personal">Personal</option>
231
+ <option value="shopping">Shopping</option>
232
+ <option value="health">Health</option>
233
+ <option value="other" selected>Other</option>
234
+ </select>
235
+ <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 dark:text-gray-300">
236
+ <i class="fas fa-chevron-down text-xs"></i>
237
+ </div>
238
+ </div>
239
+ <div class="relative">
240
+ <input type="date" id="due-date" class="date-picker px-3 py-3 pr-8 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white text-sm">
241
+ <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 dark:text-gray-300">
242
+ <i class="far fa-calendar text-xs"></i>
243
+ </div>
244
+ </div>
245
+ <button type="submit" class="px-4 py-3 rounded-lg bg-primary-light dark:bg-primary-dark text-white hover:bg-opacity-90 transition-colors duration-300">
246
+ <i class="fas fa-plus"></i>
247
+ </button>
248
+ </div>
249
+ </form>
250
+ </div>
251
+
252
+ <div class="bg-card-light dark:bg-card-dark rounded-xl p-6 shadow-neumorph-light dark:shadow-neumorph-dark">
253
+ <div class="flex justify-between items-center mb-6">
254
+ <h2 class="text-xl font-semibold text-gray-800 dark:text-white">Tasks</h2>
255
+ <div class="flex items-center space-x-2">
256
+ <button id="clear-completed" class="text-sm text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-white transition-colors duration-300">
257
+ Clear Completed
258
+ </button>
259
+ <button id="sort-tasks" class="text-sm text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-white transition-colors duration-300 flex items-center">
260
+ <span>Sort By</span>
261
+ <i class="fas fa-chevron-down ml-1 text-xs"></i>
262
+ </button>
263
+ <div id="sort-dropdown" class="hidden absolute right-6 mt-8 w-40 rounded-lg bg-card-light dark:bg-card-dark shadow-neumorph-light dark:shadow-neumorph-dark z-10 py-1">
264
+ <button data-sort="due-date" class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700">Due Date</button>
265
+ <button data-sort="priority" class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700">Priority</button>
266
+ <button data-sort="category" class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700">Category</button>
267
+ <button data-sort="date-added" class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700">Date Added</button>
268
+ </div>
269
+ </div>
270
+ </div>
271
+
272
+ <div id="task-container" class="space-y-3">
273
+ <!-- Tasks will be populated here -->
274
+ <div class="text-center py-10 text-gray-500 dark:text-gray-400" id="empty-state">
275
+ <i class="fas fa-tasks text-4xl mb-3"></i>
276
+ <p class="text-lg">No tasks found</p>
277
+ <p class="text-sm">Add a new task to get started</p>
278
+ </div>
279
+ </div>
280
+ </div>
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <!-- Add List Modal -->
286
+ <div id="add-list-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
287
+ <div class="bg-card-light dark:bg-card-dark rounded-xl p-6 shadow-neumorph-light dark:shadow-neumorph-dark w-full max-w-md">
288
+ <div class="flex justify-between items-center mb-4">
289
+ <h3 class="text-xl font-semibold text-gray-800 dark:text-white">Create New List</h3>
290
+ <button id="close-list-modal" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">
291
+ <i class="fas fa-times"></i>
292
+ </button>
293
+ </div>
294
+ <form id="add-list-form">
295
+ <div class="mb-4">
296
+ <label for="list-name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">List Name</label>
297
+ <input type="text" id="list-name" class="w-full px-4 py-2 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white">
298
+ </div>
299
+ <div class="flex justify-end space-x-3">
300
+ <button type="button" id="cancel-list" class="px-4 py-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-white hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors duration-300">
301
+ Cancel
302
+ </button>
303
+ <button type="submit" class="px-4 py-2 rounded-lg bg-primary-light dark:bg-primary-dark text-white hover:bg-opacity-90 transition-colors duration-300">
304
+ Create List
305
+ </button>
306
+ </div>
307
+ </form>
308
+ </div>
309
+ </div>
310
+
311
+ <!-- Edit Task Modal -->
312
+ <div id="edit-task-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
313
+ <div class="bg-card-light dark:bg-card-dark rounded-xl p-6 shadow-neumorph-light dark:shadow-neumorph-dark w-full max-w-md">
314
+ <div class="flex justify-between items-center mb-4">
315
+ <h3 class="text-xl font-semibold text-gray-800 dark:text-white">Edit Task</h3>
316
+ <button id="close-edit-modal" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">
317
+ <i class="fas fa-times"></i>
318
+ </button>
319
+ </div>
320
+ <form id="edit-task-form">
321
+ <input type="hidden" id="edit-task-id">
322
+ <div class="mb-4">
323
+ <label for="edit-task-title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Task Title</label>
324
+ <input type="text" id="edit-task-title" class="w-full px-4 py-2 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white">
325
+ </div>
326
+ <div class="grid grid-cols-2 gap-4 mb-4">
327
+ <div>
328
+ <label for="edit-priority-select" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Priority</label>
329
+ <select id="edit-priority-select" class="w-full px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white text-sm">
330
+ <option value="low">Low</option>
331
+ <option value="medium">Medium</option>
332
+ <option value="high">High</option>
333
+ </select>
334
+ </div>
335
+ <div>
336
+ <label for="edit-category-select" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Category</label>
337
+ <select id="edit-category-select" class="w-full px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white text-sm">
338
+ <option value="work">Work</option>
339
+ <option value="personal">Personal</option>
340
+ <option value="shopping">Shopping</option>
341
+ <option value="health">Health</option>
342
+ <option value="other">Other</option>
343
+ </select>
344
+ </div>
345
+ </div>
346
+ <div class="mb-4">
347
+ <label for="edit-due-date" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Due Date</label>
348
+ <input type="date" id="edit-due-date" class="w-full px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-light dark:focus:ring-primary-dark focus:border-transparent text-gray-800 dark:text-white text-sm">
349
+ </div>
350
+ <div class="flex justify-end space-x-3">
351
+ <button type="button" id="delete-task" class="px-4 py-2 rounded-lg bg-red-100 dark:bg-red-900 text-red-700 dark:text-red-200 hover:bg-red-200 dark:hover:bg-red-800 transition-colors duration-300">
352
+ Delete
353
+ </button>
354
+ <button type="submit" class="px-4 py-2 rounded-lg bg-primary-light dark:bg-primary-dark text-white hover:bg-opacity-90 transition-colors duration-300">
355
+ Save Changes
356
+ </button>
357
+ </div>
358
+ </form>
359
+ </div>
360
+ </div>
361
+
362
+ <script>
363
+ // DOM Elements
364
+ const themeToggle = document.getElementById('theme-toggle');
365
+ const taskForm = document.getElementById('task-form');
366
+ const taskInput = document.getElementById('task-input');
367
+ const prioritySelect = document.getElementById('priority-select');
368
+ const categorySelect = document.getElementById('category-select');
369
+ const dueDate = document.getElementById('due-date');
370
+ const taskContainer = document.getElementById('task-container');
371
+ const emptyState = document.getElementById('empty-state');
372
+ const clearCompletedBtn = document.getElementById('clear-completed');
373
+ const sortTasksBtn = document.getElementById('sort-tasks');
374
+ const sortDropdown = document.getElementById('sort-dropdown');
375
+ const listDropdownBtn = document.getElementById('list-dropdown-btn');
376
+ const listDropdown = document.getElementById('list-dropdown');
377
+ const currentList = document.getElementById('current-list');
378
+ const listContainer = document.getElementById('list-container');
379
+ const addListBtn = document.getElementById('add-list-btn');
380
+ const addListModal = document.getElementById('add-list-modal');
381
+ const closeListModal = document.getElementById('close-list-modal');
382
+ const cancelList = document.getElementById('cancel-list');
383
+ const addListForm = document.getElementById('add-list-form');
384
+ const listName = document.getElementById('list-name');
385
+ const editTaskModal = document.getElementById('edit-task-modal');
386
+ const closeEditModal = document.getElementById('close-edit-modal');
387
+ const editTaskForm = document.getElementById('edit-task-form');
388
+ const editTaskTitle = document.getElementById('edit-task-title');
389
+ const editPrioritySelect = document.getElementById('edit-priority-select');
390
+ const editCategorySelect = document.getElementById('edit-category-select');
391
+ const editDueDate = document.getElementById('edit-due-date');
392
+ const editTaskId = document.getElementById('edit-task-id');
393
+ const deleteTaskBtn = document.getElementById('delete-task');
394
+ const completedCount = document.getElementById('completed-count');
395
+ const pendingCount = document.getElementById('pending-count');
396
+ const overdueCount = document.getElementById('overdue-count');
397
+ const completedBar = document.getElementById('completed-bar');
398
+ const pendingBar = document.getElementById('pending-bar');
399
+ const overdueBar = document.getElementById('overdue-bar');
400
+
401
+ // Filter checkboxes
402
+ const filterCheckboxes = document.querySelectorAll('input[data-filter]');
403
+
404
+ // State
405
+ let tasks = [];
406
+ let lists = ['My Tasks', 'Work', 'Personal'];
407
+ let currentListName = 'My Tasks';
408
+ let currentSort = 'date-added';
409
+ let activeFilters = {
410
+ priority: [],
411
+ category: [],
412
+ status: []
413
+ };
414
+
415
+ // Initialize
416
+ document.addEventListener('DOMContentLoaded', () => {
417
+ loadFromLocalStorage();
418
+ renderLists();
419
+ renderTasks();
420
+ updateStats();
421
+
422
+ // Set default due date to today
423
+ const today = new Date().toISOString().split('T')[0];
424
+ dueDate.value = today;
425
+ dueDate.min = today;
426
+ });
427
+
428
+ // Theme Toggle
429
+ themeToggle.addEventListener('click', () => {
430
+ document.documentElement.classList.toggle('dark');
431
+ localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light');
432
+ });
433
+
434
+ // Add Task
435
+ taskForm.addEventListener('submit', (e) => {
436
+ e.preventDefault();
437
+
438
+ if (taskInput.value.trim() === '') return;
439
+
440
+ const newTask = {
441
+ id: Date.now().toString(),
442
+ title: taskInput.value.trim(),
443
+ completed: false,
444
+ priority: prioritySelect.value,
445
+ category: categorySelect.value,
446
+ dueDate: dueDate.value,
447
+ list: currentListName,
448
+ createdAt: new Date().toISOString()
449
+ };
450
+
451
+ tasks.push(newTask);
452
+ saveToLocalStorage();
453
+ renderTasks();
454
+ updateStats();
455
+
456
+ // Reset form
457
+ taskInput.value = '';
458
+ prioritySelect.value = 'medium';
459
+ categorySelect.value = 'other';
460
+ dueDate.value = new Date().toISOString().split('T')[0];
461
+ });
462
+
463
+ // Toggle Task Completion
464
+ taskContainer.addEventListener('change', (e) => {
465
+ if (e.target.classList.contains('task-checkbox')) {
466
+ const taskId = e.target.dataset.id;
467
+ const task = tasks.find(task => task.id === taskId);
468
+
469
+ if (task) {
470
+ task.completed = e.target.checked;
471
+ saveToLocalStorage();
472
+ renderTasks();
473
+ updateStats();
474
+ }
475
+ }
476
+ });
477
+
478
+ // Edit Task
479
+ taskContainer.addEventListener('click', (e) => {
480
+ if (e.target.classList.contains('edit-task') || e.target.parentElement.classList.contains('edit-task')) {
481
+ const taskId = e.target.closest('[data-id]').dataset.id;
482
+ const task = tasks.find(task => task.id === taskId);
483
+
484
+ if (task) {
485
+ editTaskId.value = task.id;
486
+ editTaskTitle.value = task.title;
487
+ editPrioritySelect.value = task.priority;
488
+ editCategorySelect.value = task.category;
489
+ editDueDate.value = task.dueDate;
490
+
491
+ editTaskModal.classList.remove('hidden');
492
+ }
493
+ }
494
+ });
495
+
496
+ // Save Edited Task
497
+ editTaskForm.addEventListener('submit', (e) => {
498
+ e.preventDefault();
499
+
500
+ const taskId = editTaskId.value;
501
+ const task = tasks.find(task => task.id === taskId);
502
+
503
+ if (task) {
504
+ task.title = editTaskTitle.value.trim();
505
+ task.priority = editPrioritySelect.value;
506
+ task.category = editCategorySelect.value;
507
+ task.dueDate = editDueDate.value;
508
+
509
+ saveToLocalStorage();
510
+ renderTasks();
511
+ updateStats();
512
+ editTaskModal.classList.add('hidden');
513
+ }
514
+ });
515
+
516
+ // Delete Task
517
+ deleteTaskBtn.addEventListener('click', () => {
518
+ const taskId = editTaskId.value;
519
+ tasks = tasks.filter(task => task.id !== taskId);
520
+
521
+ saveToLocalStorage();
522
+ renderTasks();
523
+ updateStats();
524
+ editTaskModal.classList.add('hidden');
525
+ });
526
+
527
+ // Clear Completed Tasks
528
+ clearCompletedBtn.addEventListener('click', () => {
529
+ tasks = tasks.filter(task => !task.completed || task.list !== currentListName);
530
+ saveToLocalStorage();
531
+ renderTasks();
532
+ updateStats();
533
+ });
534
+
535
+ // Sort Tasks
536
+ sortTasksBtn.addEventListener('click', () => {
537
+ sortDropdown.classList.toggle('hidden');
538
+ });
539
+
540
+ // Close sort dropdown when clicking outside
541
+ document.addEventListener('click', (e) => {
542
+ if (!sortTasksBtn.contains(e.target) && !sortDropdown.contains(e.target)) {
543
+ sortDropdown.classList.add('hidden');
544
+ }
545
+ });
546
+
547
+ // Sort Tasks by selected option
548
+ sortDropdown.addEventListener('click', (e) => {
549
+ if (e.target.tagName === 'BUTTON') {
550
+ currentSort = e.target.dataset.sort;
551
+ renderTasks();
552
+ sortDropdown.classList.add('hidden');
553
+ }
554
+ });
555
+
556
+ // List Dropdown
557
+ listDropdownBtn.addEventListener('click', () => {
558
+ listDropdown.classList.toggle('hidden');
559
+ });
560
+
561
+ // Close list dropdown when clicking outside
562
+ document.addEventListener('click', (e) => {
563
+ if (!listDropdownBtn.contains(e.target) && !listDropdown.contains(e.target)) {
564
+ listDropdown.classList.add('hidden');
565
+ }
566
+ });
567
+
568
+ // Change List
569
+ listContainer.addEventListener('click', (e) => {
570
+ if (e.target.classList.contains('list-item') || e.target.parentElement.classList.contains('list-item')) {
571
+ const listName = e.target.closest('[data-list]').dataset.list;
572
+ currentListName = listName;
573
+ currentList.textContent = listName;
574
+ renderTasks();
575
+ updateStats();
576
+ listDropdown.classList.add('hidden');
577
+ }
578
+ });
579
+
580
+ // Add List Modal
581
+ addListBtn.addEventListener('click', () => {
582
+ addListModal.classList.remove('hidden');
583
+ listName.focus();
584
+ });
585
+
586
+ closeListModal.addEventListener('click', () => {
587
+ addListModal.classList.add('hidden');
588
+ });
589
+
590
+ cancelList.addEventListener('click', () => {
591
+ addListModal.classList.add('hidden');
592
+ });
593
+
594
+ // Close edit modal
595
+ closeEditModal.addEventListener('click', () => {
596
+ editTaskModal.classList.add('hidden');
597
+ });
598
+
599
+ // Close modals when clicking outside
600
+ window.addEventListener('click', (e) => {
601
+ if (e.target === addListModal) {
602
+ addListModal.classList.add('hidden');
603
+ }
604
+ if (e.target === editTaskModal) {
605
+ editTaskModal.classList.add('hidden');
606
+ }
607
+ });
608
+
609
+ // Add New List
610
+ addListForm.addEventListener('submit', (e) => {
611
+ e.preventDefault();
612
+
613
+ const name = listName.value.trim();
614
+ if (name && !lists.includes(name)) {
615
+ lists.push(name);
616
+ currentListName = name;
617
+ currentList.textContent = name;
618
+ saveToLocalStorage();
619
+ renderLists();
620
+ renderTasks();
621
+ addListModal.classList.add('hidden');
622
+ listName.value = '';
623
+ }
624
+ });
625
+
626
+ // Filter Tasks
627
+ filterCheckboxes.forEach(checkbox => {
628
+ checkbox.addEventListener('change', () => {
629
+ const filterType = checkbox.dataset.filter;
630
+ const value = checkbox.value;
631
+
632
+ if (checkbox.checked) {
633
+ if (!activeFilters[filterType].includes(value)) {
634
+ activeFilters[filterType].push(value);
635
+ }
636
+ } else {
637
+ activeFilters[filterType] = activeFilters[filterType].filter(item => item !== value);
638
+ }
639
+
640
+ renderTasks();
641
+ });
642
+ });
643
+
644
+ // Render Tasks
645
+ function renderTasks() {
646
+ // Filter tasks by current list
647
+ let filteredTasks = tasks.filter(task => task.list === currentListName);
648
+
649
+ // Apply filters
650
+ if (activeFilters.priority.length > 0) {
651
+ filteredTasks = filteredTasks.filter(task => activeFilters.priority.includes(task.priority));
652
+ }
653
+
654
+ if (activeFilters.category.length > 0) {
655
+ filteredTasks = filteredTasks.filter(task => activeFilters.category.includes(task.category));
656
+ }
657
+
658
+ if (activeFilters.status.length > 0) {
659
+ filteredTasks = filteredTasks.filter(task => {
660
+ if (activeFilters.status.includes('completed') && task.completed) return true;
661
+ if (activeFilters.status.includes('pending') && !task.completed) {
662
+ const today = new Date().toISOString().split('T')[0];
663
+ return !task.dueDate || task.dueDate >= today;
664
+ }
665
+ if (activeFilters.status.includes('overdue') && !task.completed && task.dueDate) {
666
+ const today = new Date().toISOString().split('T')[0];
667
+ return task.dueDate < today;
668
+ }
669
+ return false;
670
+ });
671
+ }
672
+
673
+ // Sort tasks
674
+ filteredTasks.sort((a, b) => {
675
+ if (currentSort === 'due-date') {
676
+ if (!a.dueDate && !b.dueDate) return 0;
677
+ if (!a.dueDate) return 1;
678
+ if (!b.dueDate) return -1;
679
+ return new Date(a.dueDate) - new Date(b.dueDate);
680
+ } else if (currentSort === 'priority') {
681
+ const priorityOrder = { high: 1, medium: 2, low: 3 };
682
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
683
+ } else if (currentSort === 'category') {
684
+ return a.category.localeCompare(b.category);
685
+ } else { // date-added
686
+ return new Date(b.createdAt) - new Date(a.createdAt);
687
+ }
688
+ });
689
+
690
+ // Clear task container
691
+ taskContainer.innerHTML = '';
692
+
693
+ // Show empty state if no tasks
694
+ if (filteredTasks.length === 0) {
695
+ taskContainer.appendChild(emptyState);
696
+ return;
697
+ }
698
+
699
+ // Group tasks by date (Today, Tomorrow, Upcoming, Overdue, No Date)
700
+ const today = new Date().toISOString().split('T')[0];
701
+ const tomorrow = new Date();
702
+ tomorrow.setDate(tomorrow.getDate() + 1);
703
+ const tomorrowStr = tomorrow.toISOString().split('T')[0];
704
+
705
+ const todayTasks = filteredTasks.filter(task => task.dueDate === today && !task.completed);
706
+ const tomorrowTasks = filteredTasks.filter(task => task.dueDate === tomorrowStr && !task.completed);
707
+ const upcomingTasks = filteredTasks.filter(task => task.dueDate > tomorrowStr && !task.completed);
708
+ const overdueTasks = filteredTasks.filter(task => task.dueDate && task.dueDate < today && !task.completed);
709
+ const noDateTasks = filteredTasks.filter(task => !task.dueDate && !task.completed);
710
+ const completedTasks = filteredTasks.filter(task => task.completed);
711
+
712
+ // Render task groups
713
+ if (overdueTasks.length > 0) {
714
+ renderTaskGroup('Overdue', overdueTasks);
715
+ }
716
+
717
+ if (todayTasks.length > 0) {
718
+ renderTaskGroup('Today', todayTasks);
719
+ }
720
+
721
+ if (tomorrowTasks.length > 0) {
722
+ renderTaskGroup('Tomorrow', tomorrowTasks);
723
+ }
724
+
725
+ if (upcomingTasks.length > 0) {
726
+ renderTaskGroup('Upcoming', upcomingTasks);
727
+ }
728
+
729
+ if (noDateTasks.length > 0) {
730
+ renderTaskGroup('No Date', noDateTasks);
731
+ }
732
+
733
+ if (completedTasks.length > 0) {
734
+ renderTaskGroup('Completed', completedTasks, true);
735
+ }
736
+ }
737
+
738
+ function renderTaskGroup(title, tasks, isCompleted = false) {
739
+ const groupDiv = document.createElement('div');
740
+ groupDiv.className = 'mb-6';
741
+
742
+ const groupTitle = document.createElement('h3');
743
+ groupTitle.className = 'text-sm font-medium text-gray-500 dark:text-gray-400 mb-3 uppercase tracking-wider';
744
+ groupTitle.textContent = title;
745
+
746
+ groupDiv.appendChild(groupTitle);
747
+
748
+ const tasksList = document.createElement('div');
749
+ tasksList.className = 'space-y-2';
750
+
751
+ tasks.forEach(task => {
752
+ const taskElement = document.createElement('div');
753
+ taskElement.className = `bg-gray-50 dark:bg-gray-700 rounded-lg p-4 flex items-start border-l-4 ${isCompleted ? 'opacity-70' : ''} ${task.priority === 'high' ? 'priority-high' : task.priority === 'medium' ? 'priority-medium' : 'priority-low'}`;
754
+ taskElement.dataset.id = task.id;
755
+
756
+ const checkbox = document.createElement('input');
757
+ checkbox.type = 'checkbox';
758
+ checkbox.className = 'task-checkbox mt-1 h-4 w-4 rounded border-gray-300 text-primary-light dark:text-primary-dark focus:ring-primary-light dark:focus:ring-primary-dark';
759
+ checkbox.dataset.id = task.id;
760
+ checkbox.checked = task.completed;
761
+
762
+ const taskContent = document.createElement('div');
763
+ taskContent.className = 'ml-3 flex-1';
764
+
765
+ const taskTitle = document.createElement('label');
766
+ taskTitle.className = `task-label block text-gray-800 dark:text-gray-200 ${isCompleted ? 'line-through' : ''}`;
767
+ taskTitle.textContent = task.title;
768
+ taskTitle.htmlFor = `task-${task.id}`;
769
+
770
+ const taskMeta = document.createElement('div');
771
+ taskMeta.className = 'flex flex-wrap items-center mt-1 text-xs text-gray-500 dark:text-gray-400 space-x-3';
772
+
773
+ const categorySpan = document.createElement('span');
774
+ categorySpan.className = `px-2 py-1 rounded-full ${task.category}-${task.category} capitalize`;
775
+ categorySpan.textContent = task.category;
776
+
777
+ const dueDateSpan = document.createElement('span');
778
+ dueDateSpan.className = 'flex items-center';
779
+
780
+ if (task.dueDate) {
781
+ const dueDate = new Date(task.dueDate);
782
+ const today = new Date();
783
+ today.setHours(0, 0, 0, 0);
784
+
785
+ const dueDateStr = dueDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
786
+
787
+ if (dueDate < today && !task.completed) {
788
+ dueDateSpan.innerHTML = `<i class="fas fa-exclamation-circle text-red-500 mr-1"></i> ${dueDateStr}`;
789
+ } else {
790
+ dueDateSpan.innerHTML = `<i class="far fa-calendar-alt mr-1"></i> ${dueDateStr}`;
791
+ }
792
+ }
793
+
794
+ taskMeta.appendChild(categorySpan);
795
+ if (task.dueDate) taskMeta.appendChild(dueDateSpan);
796
+
797
+ taskContent.appendChild(taskTitle);
798
+ taskContent.appendChild(taskMeta);
799
+
800
+ const taskActions = document.createElement('div');
801
+ taskActions.className = 'ml-2 flex items-center space-x-2';
802
+
803
+ const editBtn = document.createElement('button');
804
+ editBtn.className = 'edit-task text-gray-400 hover:text-primary-light dark:hover:text-primary-dark transition-colors duration-300';
805
+ editBtn.innerHTML = '<i class="fas fa-pencil-alt"></i>';
806
+ editBtn.title = 'Edit task';
807
+
808
+ taskActions.appendChild(editBtn);
809
+
810
+ taskElement.appendChild(checkbox);
811
+ taskElement.appendChild(taskContent);
812
+ taskElement.appendChild(taskActions);
813
+
814
+ tasksList.appendChild(taskElement);
815
+ });
816
+
817
+ groupDiv.appendChild(tasksList);
818
+ taskContainer.appendChild(groupDiv);
819
+ }
820
+
821
+ // Render Lists
822
+ function renderLists() {
823
+ listContainer.innerHTML = '';
824
+
825
+ lists.forEach(list => {
826
+ const listItem = document.createElement('div');
827
+ listItem.className = `list-item px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer flex items-center ${list === currentListName ? 'bg-gray-100 dark:bg-gray-700' : ''}`;
828
+ listItem.dataset.list = list;
829
+
830
+ const listIcon = document.createElement('i');
831
+ listIcon.className = 'far fa-list-alt mr-2';
832
+
833
+ const listName = document.createElement('span');
834
+ listName.textContent = list;
835
+
836
+ const taskCount = document.createElement('span');
837
+ taskCount.className = 'ml-auto text-xs bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300 rounded-full px-2 py-1';
838
+ taskCount.textContent = tasks.filter(task => task.list === list).length;
839
+
840
+ listItem.appendChild(listIcon);
841
+ listItem.appendChild(listName);
842
+ listItem.appendChild(taskCount);
843
+
844
+ listContainer.appendChild(listItem);
845
+ });
846
+ }
847
+
848
+ // Update Stats
849
+ function updateStats() {
850
+ const currentTasks = tasks.filter(task => task.list === currentListName);
851
+ const totalTasks = currentTasks.length;
852
+ const completedTasks = currentTasks.filter(task => task.completed).length;
853
+ const pendingTasks = currentTasks.filter(task => !task.completed).length;
854
+
855
+ const today = new Date().toISOString().split('T')[0];
856
+ const overdueTasks = currentTasks.filter(task => !task.completed && task.dueDate && task.dueDate < today).length;
857
+
858
+ completedCount.textContent = completedTasks;
859
+ pendingCount.textContent = pendingTasks;
860
+ overdueCount.textContent = overdueTasks;
861
+
862
+ const completedPercentage = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
863
+ const pendingPercentage = totalTasks > 0 ? Math.round((pendingTasks / totalTasks) * 100) : 0;
864
+ const overduePercentage = totalTasks > 0 ? Math.round((overdueTasks / totalTasks) * 100) : 0;
865
+
866
+ completedBar.style.width = `${completedPercentage}%`;
867
+ pendingBar.style.width = `${pendingPercentage}%`;
868
+ overdueBar.style.width = `${overduePercentage}%`;
869
+ }
870
+
871
+ // Local Storage
872
+ function saveToLocalStorage() {
873
+ localStorage.setItem('tasks', JSON.stringify(tasks));
874
+ localStorage.setItem('lists', JSON.stringify(lists));
875
+ localStorage.setItem('currentList', currentListName);
876
+ }
877
+
878
+ function loadFromLocalStorage() {
879
+ const savedTasks = localStorage.getItem('tasks');
880
+ const savedLists = localStorage.getItem('lists');
881
+ const savedCurrentList = localStorage.getItem('currentList');
882
+
883
+ if (savedTasks) tasks = JSON.parse(savedTasks);
884
+ if (savedLists) lists = JSON.parse(savedLists);
885
+ if (savedCurrentList) currentListName = savedCurrentList;
886
+
887
+ // Set theme from localStorage
888
+ const savedTheme = localStorage.getItem('theme');
889
+ if (savedTheme === 'dark') {
890
+ document.documentElement.classList.add('dark');
891
+ } else {
892
+ document.documentElement.classList.remove('dark');
893
+ }
894
+ }
895
+ </script>
896
+ <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=igoraguiar/todo-lists" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
897
+ </html>