Update index.html
Browse files- index.html +165 -1
index.html
CHANGED
|
@@ -626,4 +626,168 @@
|
|
| 626 |
return habits.length > 0 ? Math.max(...habits.map(h => h.id)) + 1 : 1;
|
| 627 |
}
|
| 628 |
|
| 629 |
-
habitForm.addEventListener('submit', (e) =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 626 |
return habits.length > 0 ? Math.max(...habits.map(h => h.id)) + 1 : 1;
|
| 627 |
}
|
| 628 |
|
| 629 |
+
habitForm.addEventListener('submit', (e) => {
|
| 630 |
+
e.preventDefault();
|
| 631 |
+
const name = document.getElementById('habitName').value.trim();
|
| 632 |
+
const frequency = document.getElementById('habitFrequency').value;
|
| 633 |
+
|
| 634 |
+
if (!name) return;
|
| 635 |
+
|
| 636 |
+
habits.push({
|
| 637 |
+
id: getNextId(),
|
| 638 |
+
name,
|
| 639 |
+
streak: 0,
|
| 640 |
+
frequency,
|
| 641 |
+
progress: 0,
|
| 642 |
+
checked: false
|
| 643 |
+
});
|
| 644 |
+
|
| 645 |
+
saveData();
|
| 646 |
+
renderHabits();
|
| 647 |
+
updateStats();
|
| 648 |
+
habitForm.reset();
|
| 649 |
+
addHabitModal.classList.remove('active');
|
| 650 |
+
});
|
| 651 |
+
|
| 652 |
+
function renderHabits() {
|
| 653 |
+
habitList.innerHTML = habits.map(habit => `
|
| 654 |
+
<div class="habit-item">
|
| 655 |
+
<div class="habit-check ${habit.checked ? 'checked' : ''}" data-id="${habit.id}">
|
| 656 |
+
${habit.checked ? '<i class="fas fa-check"></i>' : ''}
|
| 657 |
+
</div>
|
| 658 |
+
<div class="habit-info">
|
| 659 |
+
<div class="habit-name">${habit.name}</div>
|
| 660 |
+
<div class="habit-streak">
|
| 661 |
+
<i class="fas fa-fire"></i> ${habit.streak} day streak
|
| 662 |
+
</div>
|
| 663 |
+
</div>
|
| 664 |
+
<div class="habit-progress">
|
| 665 |
+
<div class="progress-bar" style="width: ${habit.progress}%"></div>
|
| 666 |
+
</div>
|
| 667 |
+
</div>
|
| 668 |
+
`).join('');
|
| 669 |
+
|
| 670 |
+
document.querySelectorAll('.habit-check').forEach(checkbox => {
|
| 671 |
+
checkbox.addEventListener('click', function() {
|
| 672 |
+
const habit = habits.find(h => h.id === parseInt(this.dataset.id));
|
| 673 |
+
habit.checked = !habit.checked;
|
| 674 |
+
habit.streak = habit.checked ? habit.streak + 1 : Math.max(habit.streak - 1, 0);
|
| 675 |
+
habit.progress = Math.min(Math.max(habit.progress + (habit.checked ? 20 : -20), 0), 100);
|
| 676 |
+
saveData();
|
| 677 |
+
updateStats();
|
| 678 |
+
});
|
| 679 |
+
});
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
function updateStats() {
|
| 683 |
+
const total = habits.length;
|
| 684 |
+
const completed = habits.filter(h => h.checked).length;
|
| 685 |
+
const rate = total > 0 ? Math.round((completed / total) * 100) : 0;
|
| 686 |
+
const maxStreak = habits.reduce((max, h) => Math.max(max, h.streak), 0);
|
| 687 |
+
|
| 688 |
+
currentStreak.textContent = maxStreak;
|
| 689 |
+
habitsTracked.textContent = total;
|
| 690 |
+
completionRate.textContent = `${rate}%`;
|
| 691 |
+
}
|
| 692 |
+
|
| 693 |
+
// Calendar
|
| 694 |
+
function renderCalendar() {
|
| 695 |
+
calendarGrid.innerHTML = '';
|
| 696 |
+
const monthName = new Date(currentYear, currentMonthIndex).toLocaleString('default', { month: 'long', year: 'numeric' });
|
| 697 |
+
currentMonth.textContent = monthName;
|
| 698 |
+
|
| 699 |
+
// Day headers
|
| 700 |
+
['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].forEach(day => {
|
| 701 |
+
const header = document.createElement('div');
|
| 702 |
+
header.className = 'calendar-day-header';
|
| 703 |
+
header.textContent = day;
|
| 704 |
+
calendarGrid.appendChild(header);
|
| 705 |
+
});
|
| 706 |
+
|
| 707 |
+
// Days
|
| 708 |
+
const firstDay = new Date(currentYear, currentMonthIndex, 1).getDay();
|
| 709 |
+
const daysInMonth = new Date(currentYear, currentMonthIndex + 1, 0).getDate();
|
| 710 |
+
|
| 711 |
+
for (let i = 0; i < firstDay; i++) {
|
| 712 |
+
calendarGrid.appendChild(createEmptyDay());
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
for (let day = 1; day <= daysInMonth; day++) {
|
| 716 |
+
calendarGrid.appendChild(createCalendarDay(day));
|
| 717 |
+
}
|
| 718 |
+
}
|
| 719 |
+
|
| 720 |
+
function createEmptyDay() {
|
| 721 |
+
const day = document.createElement('div');
|
| 722 |
+
day.className = 'calendar-day';
|
| 723 |
+
return day;
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
function createCalendarDay(dayNumber) {
|
| 727 |
+
const day = document.createElement('div');
|
| 728 |
+
day.className = 'calendar-day';
|
| 729 |
+
|
| 730 |
+
if (new Date(currentYear, currentMonthIndex, dayNumber).toDateString() === new Date().toDateString()) {
|
| 731 |
+
day.classList.add('today');
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
const number = document.createElement('div');
|
| 735 |
+
number.className = 'day-number';
|
| 736 |
+
number.textContent = dayNumber;
|
| 737 |
+
day.appendChild(number);
|
| 738 |
+
|
| 739 |
+
// Add habit dots based on actual data (example implementation)
|
| 740 |
+
const completedHabits = Math.random() > 0.5 ? Math.floor(Math.random() * 3) + 1 : 0;
|
| 741 |
+
if (completedHabits > 0) {
|
| 742 |
+
const dots = document.createElement('div');
|
| 743 |
+
dots.className = 'day-habits';
|
| 744 |
+
for (let i = 0; i < completedHabits; i++) {
|
| 745 |
+
const dot = document.createElement('div');
|
| 746 |
+
dot.className = 'day-habit-dot';
|
| 747 |
+
dots.appendChild(dot);
|
| 748 |
+
}
|
| 749 |
+
day.appendChild(dots);
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
return day;
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
// Month navigation
|
| 756 |
+
prevMonthBtn.addEventListener('click', () => {
|
| 757 |
+
currentMonthIndex--;
|
| 758 |
+
if (currentMonthIndex < 0) {
|
| 759 |
+
currentMonthIndex = 11;
|
| 760 |
+
currentYear--;
|
| 761 |
+
}
|
| 762 |
+
renderCalendar();
|
| 763 |
+
});
|
| 764 |
+
|
| 765 |
+
nextMonthBtn.addEventListener('click', () => {
|
| 766 |
+
currentMonthIndex++;
|
| 767 |
+
if (currentMonthIndex > 11) {
|
| 768 |
+
currentMonthIndex = 0;
|
| 769 |
+
currentYear++;
|
| 770 |
+
}
|
| 771 |
+
renderCalendar();
|
| 772 |
+
});
|
| 773 |
+
|
| 774 |
+
// Theme toggle
|
| 775 |
+
themeToggle.addEventListener('click', () => {
|
| 776 |
+
document.body.classList.toggle('dark-mode');
|
| 777 |
+
if (document.body.classList.contains('dark-mode')) {
|
| 778 |
+
localStorage.setItem('theme', 'dark');
|
| 779 |
+
themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
|
| 780 |
+
} else {
|
| 781 |
+
localStorage.setItem('theme', 'light');
|
| 782 |
+
themeToggle.innerHTML = '<i class="fas fa-moon"></i>';
|
| 783 |
+
}
|
| 784 |
+
});
|
| 785 |
+
|
| 786 |
+
// Modal controls
|
| 787 |
+
addHabitBtn.addEventListener('click', () => addHabitModal.classList.add('active'));
|
| 788 |
+
closeModal.addEventListener('click', () => addHabitModal.classList.remove('active'));
|
| 789 |
+
cancelHabit.addEventListener('click', () => addHabitModal.classList.remove('active'));
|
| 790 |
+
window.addEventListener('click', (e) => e.target === addHabitModal && addHabitModal.classList.remove('active'));
|
| 791 |
+
</script>
|
| 792 |
+
</body>
|
| 793 |
+
</html>
|