zenhabit / indexx.html
Sebbe33's picture
Rename index.html to indexx.html
68a74b6 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZenHabit | Minimal Habit Tracker</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #6366f1;
--primary-light: #818cf8;
--text: #1e293b;
--text-light: #64748b;
--bg: #f8fafc;
--card: #ffffff;
--border: #e2e8f0;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
}
.dark-mode {
--primary: #818cf8;
--primary-light: #a5b4fc;
--text: #e2e8f0;
--text-light: #94a3b8;
--bg: #0f172a;
--card: #1e293b;
--border: #334155;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
transition: background-color 0.3s, color 0.3s;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--bg);
color: var(--text);
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
h1 {
font-size: 1.8rem;
font-weight: 700;
color: var(--primary);
display: flex;
align-items: center;
gap: 0.5rem;
}
.theme-toggle {
background: none;
border: none;
color: var(--text-light);
font-size: 1.2rem;
cursor: pointer;
transition: transform 0.3s;
}
.theme-toggle:hover {
transform: rotate(30deg);
color: var(--primary);
}
.stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-bottom: 2rem;
}
.stat-card {
background-color: var(--card);
border-radius: 0.5rem;
padding: 1rem;
box-shadow: var(--shadow);
text-align: center;
}
.stat-card h3 {
font-size: 0.9rem;
color: var(--text-light);
margin-bottom: 0.5rem;
}
.stat-card p {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary);
}
.habits {
margin-bottom: 2rem;
}
.habits-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.habits-header h2 {
font-size: 1.3rem;
}
.add-habit {
background-color: var(--primary);
color: white;
border: none;
border-radius: 0.3rem;
padding: 0.5rem 1rem;
font-size: 0.9rem;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
transition: background-color 0.3s;
}
.add-habit:hover {
background-color: var(--primary-light);
}
.habit-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.habit-item {
background-color: var(--card);
border-radius: 0.5rem;
padding: 1rem;
box-shadow: var(--shadow);
display: flex;
align-items: center;
gap: 1rem;
position: relative;
overflow: hidden;
}
.habit-item::before {
content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 0.3rem;
background-color: var(--primary);
}
.habit-check {
width: 1.5rem;
height: 1.5rem;
border: 2px solid var(--border);
border-radius: 0.3rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
}
.habit-check.checked {
background-color: var(--primary);
border-color: var(--primary);
color: white;
}
.habit-info {
flex: 1;
}
.habit-name {
font-weight: 600;
margin-bottom: 0.2rem;
}
.habit-streak {
font-size: 0.8rem;
color: var(--text-light);
display: flex;
align-items: center;
gap: 0.3rem;
}
.habit-streak i {
color: var(--warning);
}
.habit-progress {
width: 100px;
height: 0.3rem;
background-color: var(--border);
border-radius: 1rem;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: var(--primary);
border-radius: 1rem;
transition: width 0.5s ease;
}
.calendar {
background-color: var(--card);
border-radius: 0.5rem;
padding: 1rem;
box-shadow: var(--shadow);
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.calendar-nav {
display: flex;
gap: 1rem;
}
.calendar-nav button {
background: none;
border: none;
color: var(--text-light);
cursor: pointer;
font-size: 1rem;
}
.calendar-nav button:hover {
color: var(--primary);
}
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 0.5rem;
}
.calendar-day-header {
text-align: center;
font-size: 0.8rem;
color: var(--text-light);
padding: 0.5rem 0;
}
.calendar-day {
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 0.3rem;
cursor: pointer;
position: relative;
}
.calendar-day:hover {
background-color: var(--border);
}
.calendar-day.today {
background-color: var(--primary);
color: white;
}
.day-number {
font-size: 0.9rem;
font-weight: 500;
}
.day-habits {
position: absolute;
bottom: 0.2rem;
display: flex;
gap: 0.2rem;
}
.day-habit-dot {
width: 0.3rem;
height: 0.3rem;
border-radius: 50%;
background-color: var(--success);
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.modal.active {
opacity: 1;
pointer-events: all;
}
.modal-content {
background-color: var(--card);
border-radius: 0.5rem;
padding: 1.5rem;
width: 90%;
max-width: 400px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
transform: translateY(-20px);
transition: transform 0.3s;
}
.modal.active .modal-content {
transform: translateY(0);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.modal-header h3 {
font-size: 1.2rem;
}
.close-modal {
background: none;
border: none;
font-size: 1.2rem;
color: var(--text-light);
cursor: pointer;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: var(--text-light);
}
.form-group input,
.form-group select {
width: 100%;
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.3rem;
background-color: var(--bg);
color: var(--text);
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
margin-top: 1rem;
}
.btn {
padding: 0.5rem 1rem;
border-radius: 0.3rem;
cursor: pointer;
font-size: 0.9rem;
border: none;
transition: background-color 0.3s;
}
.btn-primary {
background-color: var(--primary);
color: white;
}
.btn-primary:hover {
background-color: var(--primary-light);
}
.btn-secondary {
background-color: var(--border);
color: var(--text);
}
.btn-secondary:hover {
background-color: #d1d5db;
}
@media (max-width: 600px) {
.stats {
grid-template-columns: 1fr;
}
.container {
padding: 1rem;
}
}
/* Animation for habit completion */
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.habit-check.checked {
animation: pulse 0.3s ease;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1><i class="fas fa-leaf"></i> ZenHabit</h1>
<button class="theme-toggle" id="themeToggle">
<i class="fas fa-moon"></i>
</button>
</header>
<div class="stats">
<div class="stat-card">
<h3>Current Streak</h3>
<p id="currentStreak">5</p>
</div>
<div class="stat-card">
<h3>Habits Tracked</h3>
<p id="habitsTracked">8</p>
</div>
<div class="stat-card">
<h3>Completion Rate</h3>
<p id="completionRate">72%</p>
</div>
</div>
<div class="habits">
<div class="habits-header">
<h2>Today's Habits</h2>
<button class="add-habit" id="addHabitBtn">
<i class="fas fa-plus"></i> Add Habit
</button>
</div>
<div class="habit-list" id="habitList">
<!-- Habit items will be added here by JavaScript -->
</div>
</div>
<div class="calendar">
<div class="calendar-header">
<h3 id="currentMonth">June 2023</h3>
<div class="calendar-nav">
<button id="prevMonth"><i class="fas fa-chevron-left"></i></button>
<button id="nextMonth"><i class="fas fa-chevron-right"></i></button>
</div>
</div>
<div class="calendar-grid" id="calendarGrid">
<!-- Calendar days will be added here by JavaScript -->
</div>
</div>
</div>
<!-- Add Habit Modal -->
<div class="modal" id="addHabitModal">
<div class="modal-content">
<div class="modal-header">
<h3>Add New Habit</h3>
<button class="close-modal" id="closeModal">&times;</button>
</div>
<form id="habitForm">
<div class="form-group">
<label for="habitName">Habit Name</label>
<input type="text" id="habitName" placeholder="e.g. Drink water" required>
</div>
<div class="form-group">
<label for="habitFrequency">Frequency</label>
<select id="habitFrequency" required>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</select>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="cancelHabit">Cancel</button>
<button type="submit" class="btn btn-primary">Add Habit</button>
</div>
</form>
</div>
</div>
<script>
// Sample data
let habits = [
{ id: 1, name: "Morning Meditation", streak: 7, frequency: "daily", progress: 85, checked: false },
{ id: 2, name: "Drink 2L water", streak: 14, frequency: "daily", progress: 60, checked: true },
{ id: 3, name: "Read 30 minutes", streak: 21, frequency: "daily", progress: 90, checked: false },
{ id: 4, name: "Workout", streak: 5, frequency: "weekly", progress: 75, checked: false },
{ id: 5, name: "Journaling", streak: 10, frequency: "daily", progress: 50, checked: true }
];
// DOM elements
const themeToggle = document.getElementById('themeToggle');
const addHabitBtn = document.getElementById('addHabitBtn');
const addHabitModal = document.getElementById('addHabitModal');
const closeModal = document.getElementById('closeModal');
const cancelHabit = document.getElementById('cancelHabit');
const habitForm = document.getElementById('habitForm');
const habitList = document.getElementById('habitList');
const currentStreak = document.getElementById('currentStreak');
const habitsTracked = document.getElementById('habitsTracked');
const completionRate = document.getElementById('completionRate');
const currentMonth = document.getElementById('currentMonth');
const calendarGrid = document.getElementById('calendarGrid');
const prevMonthBtn = document.getElementById('prevMonth');
const nextMonthBtn = document.getElementById('nextMonth');
// Current date
let currentDate = new Date();
let currentYear = currentDate.getFullYear();
let currentMonthIndex = currentDate.getMonth();
// Initialize
document.addEventListener('DOMContentLoaded', () => {
renderHabits();
renderCalendar();
updateStats();
// Check for saved theme preference
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-mode');
themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
}
});
// Theme toggle
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
if (document.body.classList.contains('dark-mode')) {
localStorage.setItem('theme', 'dark');
themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
} else {
localStorage.setItem('theme', 'light');
themeToggle.innerHTML = '<i class="fas fa-moon"></i>';
}
});
// Modal controls
addHabitBtn.addEventListener('click', () => {
addHabitModal.classList.add('active');
});
closeModal.addEventListener('click', () => {
addHabitModal.classList.remove('active');
});
cancelHabit.addEventListener('click', () => {
addHabitModal.classList.remove('active');
});
// Add new habit
habitForm.addEventListener('submit', (e) => {
e.preventDefault();
const name = document.getElementById('habitName').value;
const frequency = document.getElementById('habitFrequency').value;
const newHabit = {
id: habits.length + 1,
name: name,
streak: 0,
frequency: frequency,
progress: 0,
checked: false
};
habits.push(newHabit);
renderHabits();
updateStats();
renderCalendar();
// Reset form and close modal
habitForm.reset();
addHabitModal.classList.remove('active');
});
// Render habits list
function renderHabits() {
habitList.innerHTML = '';
habits.forEach(habit => {
const habitItem = document.createElement('div');
habitItem.className = 'habit-item';
habitItem.innerHTML = `
<div class="habit-check ${habit.checked ? 'checked' : ''}" data-id="${habit.id}">
${habit.checked ? '<i class="fas fa-check"></i>' : ''}
</div>
<div class="habit-info">
<div class="habit-name">${habit.name}</div>
<div class="habit-streak">
<i class="fas fa-fire"></i> ${habit.streak} day streak
</div>
</div>
<div class="habit-progress">
<div class="progress-bar" style="width: ${habit.progress}%"></div>
</div>
`;
habitList.appendChild(habitItem);
});
// Add event listeners to checkboxes
document.querySelectorAll('.habit-check').forEach(checkbox => {
checkbox.addEventListener('click', function() {
const habitId = parseInt(this.getAttribute('data-id'));
const habit = habits.find(h => h.id === habitId);
habit.checked = !habit.checked;
if (habit.checked) {
habit.streak += 1;
habit.progress = Math.min(habit.progress + 20, 100);
} else {
habit.streak = Math.max(habit.streak - 1, 0);
habit.progress = Math.max(habit.progress - 20, 0);
}
renderHabits();
updateStats();
});
});
}
// Update stats
function updateStats() {
const totalHabits = habits.length;
const completedHabits = habits.filter(h => h.checked).length;
const completionPercentage = Math.round((completedHabits / totalHabits) * 100);
// Find the longest streak
const longestStreak = habits.reduce((max, habit) => Math.max(max, habit.streak), 0);
currentStreak.textContent = longestStreak;
habitsTracked.textContent = totalHabits;
completionRate.textContent = `${completionPercentage}%`;
}
// Calendar functions
function renderCalendar() {
// Clear previous calendar
calendarGrid.innerHTML = '';
// Set month and year display
const monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
currentMonth.textContent = `${monthNames[currentMonthIndex]} ${currentYear}`;
// Get first day of month and total days in month
const firstDay = new Date(currentYear, currentMonthIndex, 1).getDay();
const daysInMonth = new Date(currentYear, currentMonthIndex + 1, 0).getDate();
// Add day headers
const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
dayNames.forEach(day => {
const dayHeader = document.createElement('div');
dayHeader.className = 'calendar-day-header';
dayHeader.textContent = day;
calendarGrid.appendChild(dayHeader);
});
// Add empty cells for days before the first day of the month
for (let i = 0; i < firstDay; i++) {
const emptyDay = document.createElement('div');
emptyDay.className = 'calendar-day';
calendarGrid.appendChild(emptyDay);
}
// Add days of the month
for (let i = 1; i <= daysInMonth; i++) {
const dayElement = document.createElement('div');
dayElement.className = 'calendar-day';
// Check if this is today
const today = new Date();
if (i === today.getDate() && currentMonthIndex === today.getMonth() && currentYear === today.getFullYear()) {
dayElement.classList.add('today');
}
// Add day number
const dayNumber = document.createElement('div');
dayNumber.className = 'day-number';
dayNumber.textContent = i;
dayElement.appendChild(dayNumber);
// Add habit dots (sample - in a real app, this would come from your data)
const habitsCompleted = Math.floor(Math.random() * 3); // Random for demo
if (habitsCompleted > 0) {
const dayHabits = document.createElement('div');
dayHabits.className = 'day-habits';
for (let j = 0; j < habitsCompleted; j++) {
const habitDot = document.createElement('div');
habitDot.className = 'day-habit-dot';
dayHabits.appendChild(habitDot);
}
dayElement.appendChild(dayHabits);
}
calendarGrid.appendChild(dayElement);
}
}
// Month navigation
prevMonthBtn.addEventListener('click', () => {
currentMonthIndex--;
if (currentMonthIndex < 0) {
currentMonthIndex = 11;
currentYear--;
}
renderCalendar();
});
nextMonthBtn.addEventListener('click', () => {
currentMonthIndex++;
if (currentMonthIndex > 11) {
currentMonthIndex = 0;
currentYear++;
}
renderCalendar();
});
// Close modal when clicking outside
window.addEventListener('click', (e) => {
if (e.target === addHabitModal) {
addHabitModal.classList.remove('active');
}
});
</script>
<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 <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
</html>