tim / index.html
AlexYehorov's picture
Add 3 files
81bc44a verified
Raw
History Blame Contribute Delete
15.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sobriety 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">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#00ff9d',
secondary: '#00b4ff',
cyan: '#00f7ff',
purple: '#a855f7',
magenta: '#ec4899',
dark: '#0a0a0a',
darker: '#050505',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
background-color: #050505;
}
.glow-text {
text-shadow: 0 0 8px rgba(0, 255, 157, 0.6);
}
.card-glow {
box-shadow: 0 0 15px rgba(0, 180, 255, 0.3);
}
.progress-ring__circle {
transition: stroke-dashoffset 0.35s;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.progress-ring__gradient {
stroke: url(#progressGradient);
filter: drop-shadow(0 0 6px rgba(168, 85, 247, 0.7));
}
.floating {
animation: floating 3s ease-in-out infinite;
}
@keyframes floating {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
.outer-glow {
filter: drop-shadow(0 0 8px rgba(0, 247, 255, 0.4));
}
</style>
</head>
<body class="min-h-screen bg-dark text-white flex flex-col items-center justify-center p-4">
<div class="max-w-3xl w-full space-y-8">
<!-- Header -->
<div class="text-center">
<h1 class="text-4xl font-bold mb-2 glow-text">SOBRIETY JOURNEY</h1>
<p class="text-gray-400">Every second counts towards a healthier you</p>
</div>
<!-- Timer -->
<div class="bg-darker rounded-2xl p-8 card-glow relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-primary/10 to-secondary/10 opacity-30"></div>
<div class="relative z-10">
<div class="flex flex-col items-center">
<div class="relative w-64 h-64 mb-6 outer-glow">
<svg class="w-full h-full" viewBox="0 0 100 100">
<defs>
<linearGradient id="progressGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00f7ff" />
<stop offset="50%" stop-color="#a855f7" />
<stop offset="100%" stop-color="#ec4899" />
</linearGradient>
</defs>
<circle class="text-gray-800" stroke-width="8" stroke="currentColor" fill="transparent" r="45" cx="50" cy="50" />
<circle class="progress-ring__circle progress-ring__gradient" stroke-width="8" stroke-dasharray="283" stroke-dashoffset="0" stroke-linecap="round" fill="transparent" r="45" cx="50" cy="50" />
</svg>
<div class="absolute inset-0 flex flex-col items-center justify-center">
<div class="text-5xl font-bold tracking-tighter glow-text" id="days">00</div>
<div class="text-gray-400 text-sm uppercase tracking-wider">Days</div>
</div>
</div>
<div class="grid grid-cols-3 gap-4 text-center">
<div>
<div class="text-3xl font-bold glow-text" id="hours">00</div>
<div class="text-gray-400 text-sm uppercase tracking-wider">Hours</div>
</div>
<div>
<div class="text-3xl font-bold glow-text" id="minutes">00</div>
<div class="text-gray-400 text-sm uppercase tracking-wider">Minutes</div>
</div>
<div>
<div class="text-3xl font-bold glow-text" id="seconds">00</div>
<div class="text-gray-400 text-sm uppercase tracking-wider">Seconds</div>
</div>
</div>
</div>
</div>
</div>
<!-- Money Saved Card -->
<div class="bg-darker rounded-2xl p-6 card-glow relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-secondary/10 to-primary/10 opacity-30"></div>
<div class="relative z-10">
<h2 class="text-xl font-semibold mb-4 flex items-center">
<i class="fas fa-coins text-secondary mr-2"></i>
<span>Money Saved</span>
</h2>
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<div class="bg-gradient-to-br from-primary to-secondary p-3 rounded-xl floating">
<i class="fas fa-wallet text-white text-2xl"></i>
</div>
<div>
<div class="text-gray-400 text-sm">Total Savings</div>
<div class="text-3xl font-bold glow-text" id="money-saved">$0.00</div>
</div>
</div>
<div class="bg-gray-800/50 p-3 rounded-lg">
<div class="text-gray-400 text-sm mb-1">Daily Average</div>
<div class="text-lg font-medium" id="daily-average">$0.00/day</div>
</div>
</div>
<div class="mt-6">
<div class="flex justify-between text-sm text-gray-400 mb-1">
<span>Savings Progress</span>
<span id="savings-percent">0%</span>
</div>
<div class="w-full bg-gray-800 rounded-full h-2.5">
<div class="bg-gradient-to-r from-cyan via-purple to-magenta h-2.5 rounded-full" id="savings-progress" style="width: 0%"></div>
</div>
</div>
</div>
</div>
<!-- Settings Panel -->
<div class="bg-darker rounded-2xl p-6 card-glow">
<h2 class="text-xl font-semibold mb-4 flex items-center">
<i class="fas fa-cog text-gray-400 mr-2"></i>
<span>Settings</span>
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-gray-400 text-sm mb-1">Start Date</label>
<input type="datetime-local" id="start-date" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-primary">
</div>
<div>
<label class="block text-gray-400 text-sm mb-1">Daily Spending Before ($)</label>
<input type="number" id="daily-spend" value="15" min="0" step="0.01" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-primary">
</div>
</div>
<div class="mt-6 flex justify-end space-x-3">
<button id="reset-btn" class="px-4 py-2 bg-gray-800 hover:bg-gray-700 rounded-lg transition">
<i class="fas fa-redo mr-2"></i> Reset
</button>
<button id="save-btn" class="px-4 py-2 bg-gradient-to-r from-primary to-secondary hover:opacity-90 rounded-lg transition">
<i class="fas fa-save mr-2"></i> Save
</button>
</div>
</div>
</div>
<script>
// Elements
const daysEl = document.getElementById('days');
const hoursEl = document.getElementById('hours');
const minutesEl = document.getElementById('minutes');
const secondsEl = document.getElementById('seconds');
const moneySavedEl = document.getElementById('money-saved');
const dailyAverageEl = document.getElementById('daily-average');
const savingsPercentEl = document.getElementById('savings-percent');
const savingsProgressEl = document.getElementById('savings-progress');
const startDateInput = document.getElementById('start-date');
const dailySpendInput = document.getElementById('daily-spend');
const saveBtn = document.getElementById('save-btn');
const resetBtn = document.getElementById('reset-btn');
const progressCircle = document.querySelector('.progress-ring__circle');
// Default values
let startDate = new Date();
let dailySpend = 15;
let targetSavings = 1000; // Example target
// Load saved data from localStorage
function loadData() {
const savedStartDate = localStorage.getItem('sobrietyStartDate');
const savedDailySpend = localStorage.getItem('dailySpend');
if (savedStartDate) {
startDate = new Date(savedStartDate);
startDateInput.value = formatDateTimeLocal(startDate);
} else {
// Set default to now
startDate = new Date();
startDateInput.value = formatDateTimeLocal(startDate);
}
if (savedDailySpend) {
dailySpend = parseFloat(savedDailySpend);
dailySpendInput.value = dailySpend;
}
updateTimer();
updateSavings();
}
// Format date for datetime-local input
function formatDateTimeLocal(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
}
// Update timer
function updateTimer() {
const now = new Date();
const diff = now - startDate;
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
daysEl.textContent = String(days).padStart(2, '0');
hoursEl.textContent = String(hours).padStart(2, '0');
minutesEl.textContent = String(minutes).padStart(2, '0');
secondsEl.textContent = String(seconds).padStart(2, '0');
// Update progress circle (for days - max 365 days)
const dayProgress = Math.min(days / 365, 1);
const circumference = 2 * Math.PI * 45;
const offset = circumference - dayProgress * circumference;
progressCircle.style.strokeDashoffset = offset;
}
// Update savings
function updateSavings() {
const now = new Date();
const diff = now - startDate;
const days = diff / (1000 * 60 * 60 * 24);
const totalSaved = days * dailySpend;
const avgPerDay = days > 0 ? totalSaved / days : 0;
moneySavedEl.textContent = `$${totalSaved.toFixed(2)}`;
dailyAverageEl.textContent = `$${avgPerDay.toFixed(2)}/day`;
// Update progress bar
const savingsPercent = Math.min((totalSaved / targetSavings) * 100, 100);
savingsPercentEl.textContent = `${Math.floor(savingsPercent)}%`;
savingsProgressEl.style.width = `${savingsPercent}%`;
}
// Save settings
saveBtn.addEventListener('click', () => {
const newStartDate = new Date(startDateInput.value);
const newDailySpend = parseFloat(dailySpendInput.value);
if (isNaN(newStartDate.getTime())) {
alert('Please enter a valid start date');
return;
}
if (isNaN(newDailySpend) || newDailySpend < 0) {
alert('Please enter a valid daily spending amount');
return;
}
startDate = newStartDate;
dailySpend = newDailySpend;
localStorage.setItem('sobrietyStartDate', startDate.toISOString());
localStorage.setItem('dailySpend', dailySpend.toString());
updateTimer();
updateSavings();
// Show confirmation
const originalText = saveBtn.innerHTML;
saveBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Saved!';
setTimeout(() => {
saveBtn.innerHTML = originalText;
}, 2000);
});
// Reset everything
resetBtn.addEventListener('click', () => {
if (confirm('Are you sure you want to reset all data? This cannot be undone.')) {
localStorage.removeItem('sobrietyStartDate');
localStorage.removeItem('dailySpend');
startDate = new Date();
startDateInput.value = formatDateTimeLocal(startDate);
dailySpendInput.value = '15';
loadData();
}
});
// Initialize
loadData();
setInterval(updateTimer, 1000);
setInterval(updateSavings, 60000); // Update savings every minute
</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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=AlexYehorov/tim" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>