Habit-tracking Calendar JavaScript, HTML, CSS
👤 Sharing: AI
```javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Habit Tracker</title>
<style>
body {
font-family: sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f0f0f0;
}
.container {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 20px;
width: 80%;
max-width: 800px;
}
.calendar {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
margin-top: 20px;
}
.day {
padding: 10px;
border: 1px solid #ddd;
text-align: center;
cursor: pointer;
}
.day.current {
background-color: #e0f7fa; /* Light teal */
}
.day.completed {
background-color: #a5d6a7; /* Light green */
}
.controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.controls button {
padding: 8px 16px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.controls button:hover {
background-color: #388e3c;
}
#habit-name {
font-size: 24px;
margin-bottom: 15px;
}
.day.incomplete {
background-color: #ffcdd2; /* light red */
}
</style>
</head>
<body>
<div class="container">
<h1 id="habit-name">Track Your Habit</h1>
<div class="controls">
<button id="prev-month">Previous Month</button>
<h2 id="current-month-year"></h2>
<button id="next-month">Next Month</button>
</div>
<div class="calendar" id="calendar"></div>
<script>
const habitNameElement = document.getElementById('habit-name');
const calendarElement = document.getElementById('calendar');
const currentMonthYearElement = document.getElementById('current-month-year');
const prevMonthButton = document.getElementById('prev-month');
const nextMonthButton = document.getElementById('next-month');
let currentDate = new Date();
let habitName = "Exercise"; // Default habit name
let completedDays = {}; // Store completion status for each day (YYYY-MM-DD: true/false)
// Function to update the habit name (you can connect this to a form later)
function updateHabitName(newHabitName) {
habitName = newHabitName;
habitNameElement.textContent = `Track Your ${habitName}`;
}
function generateCalendar(year, month) {
calendarElement.innerHTML = ''; // Clear existing calendar
const firstDayOfMonth = new Date(year, month, 1);
const lastDayOfMonth = new Date(year, month + 1, 0);
const daysInMonth = lastDayOfMonth.getDate();
const startingDayOfWeek = firstDayOfMonth.getDay(); // 0 (Sunday) to 6 (Saturday)
currentMonthYearElement.textContent = `${new Intl.DateTimeFormat('en-US', { month: 'long', year: 'numeric' }).format(firstDayOfMonth)}`;
// Create day names (Sunday to Saturday)
const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
dayNames.forEach(dayName => {
const dayNameElement = document.createElement('div');
dayNameElement.textContent = dayName;
dayNameElement.classList.add('day'); // Use class 'day' for styling
calendarElement.appendChild(dayNameElement);
});
// Add empty days for the days before the first day of the month
for (let i = 0; i < startingDayOfWeek; i++) {
const emptyDay = document.createElement('div');
emptyDay.classList.add('day');
calendarElement.appendChild(emptyDay);
}
// Add the days of the month
for (let day = 1; day <= daysInMonth; day++) {
const dayElement = document.createElement('div');
dayElement.textContent = day;
dayElement.classList.add('day');
const fullDateString = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
if (year === currentDate.getFullYear() && month === currentDate.getMonth() && day === currentDate.getDate()) {
dayElement.classList.add('current');
}
if (completedDays[fullDateString] === true) {
dayElement.classList.add('completed');
} else if (completedDays[fullDateString] === false) {
dayElement.classList.add('incomplete');
}
dayElement.addEventListener('click', () => {
if(completedDays[fullDateString] === true) {
completedDays[fullDateString] = false;
dayElement.classList.remove('completed');
dayElement.classList.add('incomplete');
} else if (completedDays[fullDateString] === false){
completedDays[fullDateString] = null; //reset to neutral state
dayElement.classList.remove('incomplete');
}
else {
completedDays[fullDateString] = true;
dayElement.classList.add('completed');
}
saveHabitData();
});
calendarElement.appendChild(dayElement);
}
}
prevMonthButton.addEventListener('click', () => {
currentDate.setMonth(currentDate.getMonth() - 1);
generateCalendar(currentDate.getFullYear(), currentDate.getMonth());
});
nextMonthButton.addEventListener('click', () => {
currentDate.setMonth(currentDate.getMonth() + 1);
generateCalendar(currentDate.getFullYear(), currentDate.getMonth());
});
// Local Storage Functions
function saveHabitData() {
const data = {
habitName: habitName,
completedDays: completedDays
};
localStorage.setItem('habitData', JSON.stringify(data));
}
function loadHabitData() {
const storedData = localStorage.getItem('habitData');
if (storedData) {
const data = JSON.parse(storedData);
habitName = data.habitName;
completedDays = data.completedDays;
updateHabitName(habitName);
}
}
// Initial Calendar Generation and Data Loading
loadHabitData();
generateCalendar(currentDate.getFullYear(), currentDate.getMonth());
</script>
</div>
</body>
</html>
```
👁️ Viewed: 9
Comments