| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>AquaTrack - Water Intake Tracker</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .water-drop { |
| transition: all 0.3s ease; |
| } |
| .water-drop:hover { |
| transform: translateY(-5px); |
| } |
| .progress-wave { |
| background: linear-gradient(0deg, rgba(22, 160, 133, 0.8) 0%, rgba(22, 160, 133, 0.5) 50%, rgba(22, 160, 133, 0) 100%); |
| animation: wave 8s linear infinite; |
| transform-origin: 50% 0; |
| } |
| @keyframes wave { |
| 0% { transform: scaleY(0.8) translateY(0); } |
| 50% { transform: scaleY(1.2) translateY(-20px); } |
| 100% { transform: scaleY(0.8) translateY(0); } |
| } |
| .fill-animation { |
| transition: height 1s ease-out; |
| } |
| .goal-complete { |
| animation: pulse 1.5s infinite; |
| } |
| @keyframes pulse { |
| 0% { transform: scale(1); } |
| 50% { transform: scale(1.05); } |
| 100% { transform: scale(1); } |
| } |
| </style> |
| </head> |
| <body class="bg-blue-50 min-h-screen flex items-center justify-center p-4"> |
| <div class="max-w-md w-full bg-white rounded-3xl shadow-xl overflow-hidden"> |
| |
| <div class="bg-gradient-to-r from-blue-500 to-cyan-500 p-6 text-white"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <h1 class="text-2xl font-bold">AquaTrack</h1> |
| <p class="text-blue-100">Daily Water Intake Tracker</p> |
| </div> |
| <div class="bg-white bg-opacity-20 p-3 rounded-full"> |
| <i class="fas fa-tint text-2xl"></i> |
| </div> |
| </div> |
| |
| |
| <div class="mt-4 text-sm font-medium"> |
| <i class="far fa-calendar-alt mr-2"></i> |
| <span id="current-date"></span> |
| </div> |
| </div> |
| |
| |
| <div class="p-6 relative"> |
| <div class="bg-blue-100 rounded-2xl p-4 flex flex-col items-center"> |
| |
| <div class="text-center mb-4"> |
| <h2 class="text-4xl font-bold text-blue-700" id="percentage">0%</h2> |
| <p class="text-blue-500">of daily goal</p> |
| </div> |
| |
| |
| <div class="relative w-32 h-64 bg-white rounded-b-3xl rounded-t-lg border-4 border-blue-300 overflow-hidden"> |
| |
| <div id="water-level" class="absolute bottom-0 w-full bg-blue-400 transition-all duration-1000 ease-out" style="height: 0%"> |
| <div class="absolute top-0 w-full h-full overflow-hidden"> |
| <div class="progress-wave w-[200%] h-full" style="border-radius: 40%"></div> |
| </div> |
| </div> |
| |
| |
| <div class="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-end"> |
| <div class="w-4 h-4 rounded-full border-2 border-blue-300 mb-2"></div> |
| <div class="w-2 h-8 border-l-2 border-r-2 border-blue-300"></div> |
| </div> |
| </div> |
| |
| |
| <div class="mt-6 text-center"> |
| <p class="text-blue-700 font-medium">You've consumed</p> |
| <div class="flex items-center justify-center"> |
| <span id="consumed-amount" class="text-3xl font-bold text-blue-800">0</span> |
| <span class="text-blue-600 ml-1">ml</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="px-6 pb-4"> |
| <h3 class="text-gray-700 font-medium mb-3">Quick Add</h3> |
| <div class="grid grid-cols-4 gap-3"> |
| <button onclick="addWater(100)" class="water-drop bg-blue-100 text-blue-700 py-3 rounded-xl font-bold hover:bg-blue-200"> |
| 100ml |
| </button> |
| <button onclick="addWater(250)" class="water-drop bg-blue-100 text-blue-700 py-3 rounded-xl font-bold hover:bg-blue-200"> |
| 250ml |
| </button> |
| <button onclick="addWater(500)" class="water-drop bg-blue-100 text-blue-700 py-3 rounded-xl font-bold hover:bg-blue-200"> |
| 500ml |
| </button> |
| <button onclick="addWater(1000)" class="water-drop bg-blue-100 text-blue-700 py-3 rounded-xl font-bold hover:bg-blue-200"> |
| 1L |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="px-6 pb-6"> |
| <h3 class="text-gray-700 font-medium mb-3">Custom Amount</h3> |
| <div class="flex"> |
| <input type="number" id="custom-amount" placeholder="Enter ml" |
| class="flex-1 border-2 border-blue-200 rounded-l-xl px-4 py-3 focus:outline-none focus:border-blue-400"> |
| <button onclick="addCustomWater()" class="bg-blue-500 text-white px-4 rounded-r-xl font-bold hover:bg-blue-600"> |
| Add |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="bg-gray-50 p-6 border-t border-gray-200"> |
| <div class="flex items-center justify-between mb-3"> |
| <h3 class="text-gray-700 font-medium"> |
| <i class="fas fa-bullseye mr-2 text-blue-500"></i>Daily Goal |
| </h3> |
| <div class="flex items-center"> |
| <span id="daily-goal" class="text-blue-700 font-bold mr-2">2000</span> |
| <span class="text-gray-500">ml</span> |
| </div> |
| </div> |
| |
| <div class="flex space-x-2"> |
| <button onclick="adjustGoal(-250)" class="flex-1 bg-gray-200 text-gray-700 py-2 rounded-lg font-bold hover:bg-gray-300"> |
| -250ml |
| </button> |
| <button onclick="adjustGoal(250)" class="flex-1 bg-gray-200 text-gray-700 py-2 rounded-lg font-bold hover:bg-gray-300"> |
| +250ml |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="bg-white p-6 border-t border-gray-200 max-h-40 overflow-y-auto"> |
| <div class="flex items-center justify-between mb-3"> |
| <h3 class="text-gray-700 font-medium"> |
| <i class="far fa-clock mr-2 text-blue-500"></i>Today's History |
| </h3> |
| <button onclick="clearTodayHistory()" class="text-sm text-blue-500 hover:text-blue-700"> |
| <i class="fas fa-trash-alt mr-1"></i>Clear |
| </button> |
| </div> |
| |
| <div id="history-list" class="space-y-2"> |
| |
| <div class="text-center text-gray-400 py-4"> |
| <i class="fas fa-tint mr-2"></i>No entries yet |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="celebration-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden"> |
| <div class="bg-white p-8 rounded-2xl max-w-sm w-full text-center animate__animated animate__zoomIn"> |
| <div class="text-6xl text-blue-500 mb-4"> |
| <i class="fas fa-trophy"></i> |
| </div> |
| <h2 class="text-2xl font-bold text-gray-800 mb-2">Goal Achieved!</h2> |
| <p class="text-gray-600 mb-6">Congratulations on reaching your daily water intake goal!</p> |
| <button onclick="hideCelebration()" class="bg-blue-500 text-white px-6 py-2 rounded-xl font-bold hover:bg-blue-600"> |
| Awesome! |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| let waterConsumed = 0; |
| let dailyGoal = 2000; |
| let todayHistory = []; |
| let goalReached = false; |
| |
| |
| const waterLevel = document.getElementById('water-level'); |
| const percentageEl = document.getElementById('percentage'); |
| const consumedAmountEl = document.getElementById('consumed-amount'); |
| const dailyGoalEl = document.getElementById('daily-goal'); |
| const historyList = document.getElementById('history-list'); |
| const currentDateEl = document.getElementById('current-date'); |
| const customAmountInput = document.getElementById('custom-amount'); |
| const celebrationModal = document.getElementById('celebration-modal'); |
| |
| |
| function init() { |
| |
| const savedData = localStorage.getItem('aquaTrackData'); |
| if (savedData) { |
| const data = JSON.parse(savedData); |
| waterConsumed = data.waterConsumed || 0; |
| dailyGoal = data.dailyGoal || 2000; |
| todayHistory = data.todayHistory || []; |
| |
| |
| const lastUpdated = new Date(data.lastUpdated || 0); |
| const today = new Date(); |
| if (lastUpdated.getDate() !== today.getDate() || |
| lastUpdated.getMonth() !== today.getMonth() || |
| lastUpdated.getFullYear() !== today.getFullYear()) { |
| |
| waterConsumed = 0; |
| todayHistory = []; |
| } |
| } |
| |
| |
| const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; |
| currentDateEl.textContent = new Date().toLocaleDateString(undefined, options); |
| |
| updateUI(); |
| } |
| |
| |
| function addWater(amount) { |
| waterConsumed += amount; |
| addHistoryEntry(amount); |
| checkGoalCompletion(); |
| updateUI(); |
| saveData(); |
| } |
| |
| |
| function addCustomWater() { |
| const amount = parseInt(customAmountInput.value); |
| if (!isNaN(amount) && amount > 0) { |
| addWater(amount); |
| customAmountInput.value = ''; |
| } |
| } |
| |
| |
| function addHistoryEntry(amount) { |
| const now = new Date(); |
| const timeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); |
| todayHistory.unshift({ |
| amount, |
| time: timeString |
| }); |
| updateHistoryList(); |
| } |
| |
| |
| function adjustGoal(change) { |
| dailyGoal = Math.max(500, dailyGoal + change); |
| checkGoalCompletion(); |
| updateUI(); |
| saveData(); |
| } |
| |
| |
| function checkGoalCompletion() { |
| if (waterConsumed >= dailyGoal && !goalReached) { |
| goalReached = true; |
| showCelebration(); |
| } else if (waterConsumed < dailyGoal) { |
| goalReached = false; |
| } |
| } |
| |
| |
| function updateUI() { |
| |
| const percentage = Math.min(Math.round((waterConsumed / dailyGoal) * 100), 100); |
| |
| |
| waterLevel.style.height = `${percentage}%`; |
| |
| |
| percentageEl.textContent = `${percentage}%`; |
| |
| |
| consumedAmountEl.textContent = waterConsumed; |
| |
| |
| dailyGoalEl.textContent = dailyGoal; |
| |
| |
| if (goalReached) { |
| waterLevel.classList.remove('bg-blue-400'); |
| waterLevel.classList.add('bg-green-400'); |
| percentageEl.classList.add('text-green-600'); |
| percentageEl.classList.remove('text-blue-700'); |
| } else { |
| waterLevel.classList.add('bg-blue-400'); |
| waterLevel.classList.remove('bg-green-400'); |
| percentageEl.classList.remove('text-green-600'); |
| percentageEl.classList.add('text-blue-700'); |
| } |
| } |
| |
| |
| function updateHistoryList() { |
| if (todayHistory.length === 0) { |
| historyList.innerHTML = ` |
| <div class="text-center text-gray-400 py-4"> |
| <i class="fas fa-tint mr-2"></i>No entries yet |
| </div> |
| `; |
| return; |
| } |
| |
| historyList.innerHTML = ''; |
| todayHistory.forEach(entry => { |
| const entryEl = document.createElement('div'); |
| entryEl.className = 'flex items-center justify-between bg-blue-50 p-3 rounded-lg'; |
| entryEl.innerHTML = ` |
| <div class="flex items-center"> |
| <div class="bg-blue-100 p-2 rounded-full mr-3"> |
| <i class="fas fa-tint text-blue-500"></i> |
| </div> |
| <div> |
| <p class="font-medium text-gray-800">${entry.amount}ml</p> |
| <p class="text-xs text-gray-500">${entry.time}</p> |
| </div> |
| </div> |
| <div class="text-blue-500 font-bold"> |
| +${entry.amount}ml |
| </div> |
| `; |
| historyList.appendChild(entryEl); |
| }); |
| } |
| |
| |
| function clearTodayHistory() { |
| waterConsumed = 0; |
| todayHistory = []; |
| goalReached = false; |
| updateUI(); |
| updateHistoryList(); |
| saveData(); |
| } |
| |
| |
| function showCelebration() { |
| celebrationModal.classList.remove('hidden'); |
| } |
| |
| |
| function hideCelebration() { |
| celebrationModal.classList.add('hidden'); |
| } |
| |
| |
| function saveData() { |
| const data = { |
| waterConsumed, |
| dailyGoal, |
| todayHistory, |
| lastUpdated: new Date().getTime() |
| }; |
| localStorage.setItem('aquaTrackData', JSON.stringify(data)); |
| } |
| |
| |
| customAmountInput.addEventListener('keypress', function(e) { |
| if (e.key === 'Enter') { |
| addCustomWater(); |
| } |
| }); |
| |
| |
| window.addEventListener('DOMContentLoaded', init); |
| </script> |
| </body> |
| </html> |