Sebbe33 commited on
Commit
75a3ef0
·
verified ·
1 Parent(s): f7a114e

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +540 -85
index.html CHANGED
@@ -1,9 +1,72 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <!-- ... (keep existing head content) ... -->
 
 
 
5
  <style>
6
- /* Add new button styles */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  .header-controls {
8
  display: flex;
9
  gap: 0.5rem;
@@ -25,7 +88,360 @@
25
  transform: rotate(15deg);
26
  }
27
 
28
- /* ... (keep existing styles) ... */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  </style>
30
  </head>
31
  <body>
@@ -44,131 +460,170 @@
44
  </button>
45
  </div>
46
  </header>
47
- <!-- ... (keep rest of body content) ... -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  </div>
49
 
50
- <!-- Add hidden file input for import -->
51
  <input type="file" id="fileInput" hidden accept=".json">
52
 
53
  <script>
54
- // Initialize empty habits array
55
  let habits = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
- // Load data from localStorage if available
58
  document.addEventListener('DOMContentLoaded', () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  const savedData = localStorage.getItem('habits');
60
  if (savedData) {
61
  try {
62
  habits = JSON.parse(savedData);
63
  } catch (e) {
64
- console.error('Error loading saved data:', e);
65
  }
66
  }
67
- renderHabits();
68
- renderCalendar();
69
- updateStats();
70
-
71
- // ... (keep existing theme initialization) ...
72
- });
73
 
74
- // Save data to localStorage
75
  function saveData() {
76
  localStorage.setItem('habits', JSON.stringify(habits));
77
  }
78
 
79
- // Export functionality
80
- document.getElementById('exportBtn').addEventListener('click', () => {
81
- const dataStr = JSON.stringify(habits);
82
- const blob = new Blob([dataStr], { type: 'application/json' });
 
 
 
 
83
  const url = URL.createObjectURL(blob);
84
  const a = document.createElement('a');
85
  a.href = url;
86
- a.download = `zenhabit_export_${new Date().toISOString().split('T')[0]}.json`;
87
  document.body.appendChild(a);
88
  a.click();
89
  document.body.removeChild(a);
90
  URL.revokeObjectURL(url);
91
- });
92
-
93
- // Import functionality
94
- document.getElementById('importBtn').addEventListener('click', () => {
95
- document.getElementById('fileInput').click();
96
- });
97
 
98
- document.getElementById('fileInput').addEventListener('change', function(e) {
99
  const file = e.target.files[0];
100
  if (!file) return;
101
 
102
  const reader = new FileReader();
103
  reader.onload = (event) => {
104
  try {
105
- const importedData = JSON.parse(event.target.result);
106
- habits = importedData;
107
  saveData();
108
  renderHabits();
109
- renderCalendar();
110
  updateStats();
 
111
  } catch (error) {
112
- alert('Error importing file. Please check the file format.');
113
  }
114
  };
115
  reader.readAsText(file);
116
- });
117
 
118
- // Update ID generation to handle imported data
119
  function getNextId() {
120
  return habits.length > 0 ? Math.max(...habits.map(h => h.id)) + 1 : 1;
121
  }
122
 
123
- // Modified add habit function
124
- habitForm.addEventListener('submit', (e) => {
125
- e.preventDefault();
126
-
127
- const name = document.getElementById('habitName').value;
128
- const frequency = document.getElementById('habitFrequency').value;
129
-
130
- const newHabit = {
131
- id: getNextId(),
132
- name: name,
133
- streak: 0,
134
- frequency: frequency,
135
- progress: 0,
136
- checked: false
137
- };
138
-
139
- habits.push(newHabit);
140
- saveData();
141
- renderHabits();
142
- updateStats();
143
- renderCalendar();
144
-
145
- habitForm.reset();
146
- addHabitModal.classList.remove('active');
147
- });
148
-
149
- // Modified habit toggle to save data
150
- function renderHabits() {
151
- // ... (existing renderHabits code) ...
152
-
153
- document.querySelectorAll('.habit-check').forEach(checkbox => {
154
- checkbox.addEventListener('click', function() {
155
- const habitId = parseInt(this.getAttribute('data-id'));
156
- const habit = habits.find(h => h.id === habitId);
157
-
158
- habit.checked = !habit.checked;
159
- habit.streak = habit.checked ? habit.streak + 1 : Math.max(habit.streak - 1, 0);
160
- habit.progress = Math.min(Math.max(
161
- habit.progress + (habit.checked ? 20 : -20), 0
162
- ), 100);
163
-
164
- saveData();
165
- renderHabits();
166
- updateStats();
167
- });
168
- });
169
- }
170
-
171
- // ... (keep remaining existing JavaScript code) ...
172
- </script>
173
- </body>
174
- </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>ZenHabit | Minimal Habit Tracker</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
  <style>
9
+ :root {
10
+ --primary: #6366f1;
11
+ --primary-light: #818cf8;
12
+ --text: #1e293b;
13
+ --text-light: #64748b;
14
+ --bg: #f8fafc;
15
+ --card: #ffffff;
16
+ --border: #e2e8f0;
17
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
18
+ --success: #10b981;
19
+ --warning: #f59e0b;
20
+ --danger: #ef4444;
21
+ }
22
+
23
+ .dark-mode {
24
+ --primary: #818cf8;
25
+ --primary-light: #a5b4fc;
26
+ --text: #e2e8f0;
27
+ --text-light: #94a3b8;
28
+ --bg: #0f172a;
29
+ --card: #1e293b;
30
+ --border: #334155;
31
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
32
+ }
33
+
34
+ * {
35
+ margin: 0;
36
+ padding: 0;
37
+ box-sizing: border-box;
38
+ transition: background-color 0.3s, color 0.3s;
39
+ }
40
+
41
+ body {
42
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
43
+ background-color: var(--bg);
44
+ color: var(--text);
45
+ line-height: 1.6;
46
+ }
47
+
48
+ .container {
49
+ max-width: 800px;
50
+ margin: 0 auto;
51
+ padding: 2rem;
52
+ }
53
+
54
+ header {
55
+ display: flex;
56
+ justify-content: space-between;
57
+ align-items: center;
58
+ margin-bottom: 2rem;
59
+ }
60
+
61
+ h1 {
62
+ font-size: 1.8rem;
63
+ font-weight: 700;
64
+ color: var(--primary);
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 0.5rem;
68
+ }
69
+
70
  .header-controls {
71
  display: flex;
72
  gap: 0.5rem;
 
88
  transform: rotate(15deg);
89
  }
90
 
91
+ .stats {
92
+ display: grid;
93
+ grid-template-columns: repeat(3, 1fr);
94
+ gap: 1rem;
95
+ margin-bottom: 2rem;
96
+ }
97
+
98
+ .stat-card {
99
+ background-color: var(--card);
100
+ border-radius: 0.5rem;
101
+ padding: 1rem;
102
+ box-shadow: var(--shadow);
103
+ text-align: center;
104
+ }
105
+
106
+ .stat-card h3 {
107
+ font-size: 0.9rem;
108
+ color: var(--text-light);
109
+ margin-bottom: 0.5rem;
110
+ }
111
+
112
+ .stat-card p {
113
+ font-size: 1.5rem;
114
+ font-weight: 700;
115
+ color: var(--primary);
116
+ }
117
+
118
+ .habits {
119
+ margin-bottom: 2rem;
120
+ }
121
+
122
+ .habits-header {
123
+ display: flex;
124
+ justify-content: space-between;
125
+ align-items: center;
126
+ margin-bottom: 1rem;
127
+ }
128
+
129
+ .habits-header h2 {
130
+ font-size: 1.3rem;
131
+ }
132
+
133
+ .add-habit {
134
+ background-color: var(--primary);
135
+ color: white;
136
+ border: none;
137
+ border-radius: 0.3rem;
138
+ padding: 0.5rem 1rem;
139
+ font-size: 0.9rem;
140
+ cursor: pointer;
141
+ display: flex;
142
+ align-items: center;
143
+ gap: 0.5rem;
144
+ transition: background-color 0.3s;
145
+ }
146
+
147
+ .add-habit:hover {
148
+ background-color: var(--primary-light);
149
+ }
150
+
151
+ .habit-list {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.5rem;
155
+ }
156
+
157
+ .habit-item {
158
+ background-color: var(--card);
159
+ border-radius: 0.5rem;
160
+ padding: 1rem;
161
+ box-shadow: var(--shadow);
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 1rem;
165
+ position: relative;
166
+ overflow: hidden;
167
+ }
168
+
169
+ .habit-item::before {
170
+ content: '';
171
+ position: absolute;
172
+ top: 0;
173
+ left: 0;
174
+ height: 100%;
175
+ width: 0.3rem;
176
+ background-color: var(--primary);
177
+ }
178
+
179
+ .habit-check {
180
+ width: 1.5rem;
181
+ height: 1.5rem;
182
+ border: 2px solid var(--border);
183
+ border-radius: 0.3rem;
184
+ cursor: pointer;
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: center;
188
+ transition: all 0.3s;
189
+ }
190
+
191
+ .habit-check.checked {
192
+ background-color: var(--primary);
193
+ border-color: var(--primary);
194
+ color: white;
195
+ }
196
+
197
+ .habit-info {
198
+ flex: 1;
199
+ }
200
+
201
+ .habit-name {
202
+ font-weight: 600;
203
+ margin-bottom: 0.2rem;
204
+ }
205
+
206
+ .habit-streak {
207
+ font-size: 0.8rem;
208
+ color: var(--text-light);
209
+ display: flex;
210
+ align-items: center;
211
+ gap: 0.3rem;
212
+ }
213
+
214
+ .habit-streak i {
215
+ color: var(--warning);
216
+ }
217
+
218
+ .habit-progress {
219
+ width: 100px;
220
+ height: 0.3rem;
221
+ background-color: var(--border);
222
+ border-radius: 1rem;
223
+ overflow: hidden;
224
+ }
225
+
226
+ .progress-bar {
227
+ height: 100%;
228
+ background-color: var(--primary);
229
+ border-radius: 1rem;
230
+ transition: width 0.5s ease;
231
+ }
232
+
233
+ .calendar {
234
+ background-color: var(--card);
235
+ border-radius: 0.5rem;
236
+ padding: 1rem;
237
+ box-shadow: var(--shadow);
238
+ }
239
+
240
+ .calendar-header {
241
+ display: flex;
242
+ justify-content: space-between;
243
+ align-items: center;
244
+ margin-bottom: 1rem;
245
+ }
246
+
247
+ .calendar-nav {
248
+ display: flex;
249
+ gap: 1rem;
250
+ }
251
+
252
+ .calendar-nav button {
253
+ background: none;
254
+ border: none;
255
+ color: var(--text-light);
256
+ cursor: pointer;
257
+ font-size: 1rem;
258
+ }
259
+
260
+ .calendar-nav button:hover {
261
+ color: var(--primary);
262
+ }
263
+
264
+ .calendar-grid {
265
+ display: grid;
266
+ grid-template-columns: repeat(7, 1fr);
267
+ gap: 0.5rem;
268
+ }
269
+
270
+ .calendar-day-header {
271
+ text-align: center;
272
+ font-size: 0.8rem;
273
+ color: var(--text-light);
274
+ padding: 0.5rem 0;
275
+ }
276
+
277
+ .calendar-day {
278
+ aspect-ratio: 1;
279
+ display: flex;
280
+ flex-direction: column;
281
+ align-items: center;
282
+ justify-content: center;
283
+ border-radius: 0.3rem;
284
+ cursor: pointer;
285
+ position: relative;
286
+ }
287
+
288
+ .calendar-day:hover {
289
+ background-color: var(--border);
290
+ }
291
+
292
+ .calendar-day.today {
293
+ background-color: var(--primary);
294
+ color: white;
295
+ }
296
+
297
+ .day-number {
298
+ font-size: 0.9rem;
299
+ font-weight: 500;
300
+ }
301
+
302
+ .day-habits {
303
+ position: absolute;
304
+ bottom: 0.2rem;
305
+ display: flex;
306
+ gap: 0.2rem;
307
+ }
308
+
309
+ .day-habit-dot {
310
+ width: 0.3rem;
311
+ height: 0.3rem;
312
+ border-radius: 50%;
313
+ background-color: var(--success);
314
+ }
315
+
316
+ .modal {
317
+ position: fixed;
318
+ top: 0;
319
+ left: 0;
320
+ width: 100%;
321
+ height: 100%;
322
+ background-color: rgba(0, 0, 0, 0.5);
323
+ display: flex;
324
+ align-items: center;
325
+ justify-content: center;
326
+ z-index: 1000;
327
+ opacity: 0;
328
+ pointer-events: none;
329
+ transition: opacity 0.3s;
330
+ }
331
+
332
+ .modal.active {
333
+ opacity: 1;
334
+ pointer-events: all;
335
+ }
336
+
337
+ .modal-content {
338
+ background-color: var(--card);
339
+ border-radius: 0.5rem;
340
+ padding: 1.5rem;
341
+ width: 90%;
342
+ max-width: 400px;
343
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
344
+ transform: translateY(-20px);
345
+ transition: transform 0.3s;
346
+ }
347
+
348
+ .modal.active .modal-content {
349
+ transform: translateY(0);
350
+ }
351
+
352
+ .modal-header {
353
+ display: flex;
354
+ justify-content: space-between;
355
+ align-items: center;
356
+ margin-bottom: 1rem;
357
+ }
358
+
359
+ .modal-header h3 {
360
+ font-size: 1.2rem;
361
+ }
362
+
363
+ .close-modal {
364
+ background: none;
365
+ border: none;
366
+ font-size: 1.2rem;
367
+ color: var(--text-light);
368
+ cursor: pointer;
369
+ }
370
+
371
+ .form-group {
372
+ margin-bottom: 1rem;
373
+ }
374
+
375
+ .form-group label {
376
+ display: block;
377
+ margin-bottom: 0.5rem;
378
+ font-size: 0.9rem;
379
+ color: var(--text-light);
380
+ }
381
+
382
+ .form-group input,
383
+ .form-group select {
384
+ width: 100%;
385
+ padding: 0.5rem;
386
+ border: 1px solid var(--border);
387
+ border-radius: 0.3rem;
388
+ background-color: var(--bg);
389
+ color: var(--text);
390
+ }
391
+
392
+ .modal-actions {
393
+ display: flex;
394
+ justify-content: flex-end;
395
+ gap: 0.5rem;
396
+ margin-top: 1rem;
397
+ }
398
+
399
+ .btn {
400
+ padding: 0.5rem 1rem;
401
+ border-radius: 0.3rem;
402
+ cursor: pointer;
403
+ font-size: 0.9rem;
404
+ border: none;
405
+ transition: background-color 0.3s;
406
+ }
407
+
408
+ .btn-primary {
409
+ background-color: var(--primary);
410
+ color: white;
411
+ }
412
+
413
+ .btn-primary:hover {
414
+ background-color: var(--primary-light);
415
+ }
416
+
417
+ .btn-secondary {
418
+ background-color: var(--border);
419
+ color: var(--text);
420
+ }
421
+
422
+ .btn-secondary:hover {
423
+ background-color: #d1d5db;
424
+ }
425
+
426
+ @media (max-width: 600px) {
427
+ .stats {
428
+ grid-template-columns: 1fr;
429
+ }
430
+
431
+ .container {
432
+ padding: 1rem;
433
+ }
434
+ }
435
+
436
+ @keyframes pulse {
437
+ 0% { transform: scale(1); }
438
+ 50% { transform: scale(1.1); }
439
+ 100% { transform: scale(1); }
440
+ }
441
+
442
+ .habit-check.checked {
443
+ animation: pulse 0.3s ease;
444
+ }
445
  </style>
446
  </head>
447
  <body>
 
460
  </button>
461
  </div>
462
  </header>
463
+
464
+ <div class="stats">
465
+ <div class="stat-card">
466
+ <h3>Current Streak</h3>
467
+ <p id="currentStreak">0</p>
468
+ </div>
469
+ <div class="stat-card">
470
+ <h3>Habits Tracked</h3>
471
+ <p id="habitsTracked">0</p>
472
+ </div>
473
+ <div class="stat-card">
474
+ <h3>Completion Rate</h3>
475
+ <p id="completionRate">0%</p>
476
+ </div>
477
+ </div>
478
+
479
+ <div class="habits">
480
+ <div class="habits-header">
481
+ <h2>Today's Habits</h2>
482
+ <button class="add-habit" id="addHabitBtn">
483
+ <i class="fas fa-plus"></i> Add Habit
484
+ </button>
485
+ </div>
486
+ <div class="habit-list" id="habitList">
487
+ <!-- Habit items will be added here by JavaScript -->
488
+ </div>
489
+ </div>
490
+
491
+ <div class="calendar">
492
+ <div class="calendar-header">
493
+ <h3 id="currentMonth"></h3>
494
+ <div class="calendar-nav">
495
+ <button id="prevMonth"><i class="fas fa-chevron-left"></i></button>
496
+ <button id="nextMonth"><i class="fas fa-chevron-right"></i></button>
497
+ </div>
498
+ </div>
499
+ <div class="calendar-grid" id="calendarGrid">
500
+ <!-- Calendar days will be added here by JavaScript -->
501
+ </div>
502
+ </div>
503
+ </div>
504
+
505
+ <!-- Add Habit Modal -->
506
+ <div class="modal" id="addHabitModal">
507
+ <div class="modal-content">
508
+ <div class="modal-header">
509
+ <h3>Add New Habit</h3>
510
+ <button class="close-modal" id="closeModal">&times;</button>
511
+ </div>
512
+ <form id="habitForm">
513
+ <div class="form-group">
514
+ <label for="habitName">Habit Name</label>
515
+ <input type="text" id="habitName" placeholder="e.g. Drink water" required>
516
+ </div>
517
+ <div class="form-group">
518
+ <label for="habitFrequency">Frequency</label>
519
+ <select id="habitFrequency" required>
520
+ <option value="daily">Daily</option>
521
+ <option value="weekly">Weekly</option>
522
+ <option value="monthly">Monthly</option>
523
+ </select>
524
+ </div>
525
+ <div class="modal-actions">
526
+ <button type="button" class="btn btn-secondary" id="cancelHabit">Cancel</button>
527
+ <button type="submit" class="btn btn-primary">Add Habit</button>
528
+ </div>
529
+ </form>
530
+ </div>
531
  </div>
532
 
 
533
  <input type="file" id="fileInput" hidden accept=".json">
534
 
535
  <script>
 
536
  let habits = [];
537
+ let currentDate = new Date();
538
+ let currentYear = currentDate.getFullYear();
539
+ let currentMonthIndex = currentDate.getMonth();
540
+
541
+ // DOM Elements
542
+ const themeToggle = document.getElementById('themeToggle');
543
+ const addHabitBtn = document.getElementById('addHabitBtn');
544
+ const addHabitModal = document.getElementById('addHabitModal');
545
+ const closeModal = document.getElementById('closeModal');
546
+ const cancelHabit = document.getElementById('cancelHabit');
547
+ const habitForm = document.getElementById('habitForm');
548
+ const habitList = document.getElementById('habitList');
549
+ const currentStreak = document.getElementById('currentStreak');
550
+ const habitsTracked = document.getElementById('habitsTracked');
551
+ const completionRate = document.getElementById('completionRate');
552
+ const currentMonth = document.getElementById('currentMonth');
553
+ const calendarGrid = document.getElementById('calendarGrid');
554
+ const prevMonthBtn = document.getElementById('prevMonth');
555
+ const nextMonthBtn = document.getElementById('nextMonth');
556
 
557
+ // Initialize
558
  document.addEventListener('DOMContentLoaded', () => {
559
+ loadData();
560
+ renderHabits();
561
+ renderCalendar();
562
+ updateStats();
563
+
564
+ if (localStorage.getItem('theme') === 'dark') {
565
+ document.body.classList.add('dark-mode');
566
+ themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
567
+ }
568
+ });
569
+
570
+ // Data handling
571
+ function loadData() {
572
  const savedData = localStorage.getItem('habits');
573
  if (savedData) {
574
  try {
575
  habits = JSON.parse(savedData);
576
  } catch (e) {
577
+ console.error('Error loading data:', e);
578
  }
579
  }
580
+ }
 
 
 
 
 
581
 
 
582
  function saveData() {
583
  localStorage.setItem('habits', JSON.stringify(habits));
584
  }
585
 
586
+ // Import/Export
587
+ document.getElementById('exportBtn').addEventListener('click', exportData);
588
+ document.getElementById('importBtn').addEventListener('click', () => document.getElementById('fileInput').click());
589
+ document.getElementById('fileInput').addEventListener('change', importData);
590
+
591
+ function exportData() {
592
+ const data = JSON.stringify(habits, null, 2);
593
+ const blob = new Blob([data], { type: 'application/json' });
594
  const url = URL.createObjectURL(blob);
595
  const a = document.createElement('a');
596
  a.href = url;
597
+ a.download = `zenhabit-${new Date().toISOString().split('T')[0]}.json`;
598
  document.body.appendChild(a);
599
  a.click();
600
  document.body.removeChild(a);
601
  URL.revokeObjectURL(url);
602
+ }
 
 
 
 
 
603
 
604
+ function importData(e) {
605
  const file = e.target.files[0];
606
  if (!file) return;
607
 
608
  const reader = new FileReader();
609
  reader.onload = (event) => {
610
  try {
611
+ const imported = JSON.parse(event.target.result);
612
+ habits = imported;
613
  saveData();
614
  renderHabits();
 
615
  updateStats();
616
+ renderCalendar();
617
  } catch (error) {
618
+ alert('Invalid file format. Please import a valid JSON file.');
619
  }
620
  };
621
  reader.readAsText(file);
622
+ }
623
 
624
+ // Habit management
625
  function getNextId() {
626
  return habits.length > 0 ? Math.max(...habits.map(h => h.id)) + 1 : 1;
627
  }
628
 
629
+ habitForm.addEventListener('submit', (e) =>