studyfocus / index.html
PyQuarX's picture
Update index.html (#1)
14a4b11 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZenFocus - Lofi Study Timer</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>
@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: #0f172a;
color: #f8fafc;
transition: background-color 0.5s ease;
}
.timer-container {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
}
.progress-ring__circle {
transition: stroke-dashoffset 0.5s;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.music-controls {
backdrop-filter: blur(10px);
background-color: rgba(15, 23, 42, 0.7);
}
.time-option:hover {
transform: scale(1.05);
transition: transform 0.2s ease;
}
.time-option.active {
background-color: #3b82f6;
color: white;
}
.glow {
animation: glow 2s infinite alternate;
}
@keyframes glow {
from {
box-shadow: 0 0 5px rgba(59, 130, 246, 0.5);
}
to {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
}
}
</style>
</head>
<body class="min-h-screen flex flex-col items-center justify-center p-4">
<div class="max-w-md w-full space-y-8">
<div class="text-center">
<h1 class="text-4xl font-bold mb-2 text-blue-400">ZenFocus</h1>
<p class="text-slate-300">Stay focused, stay productive</p>
</div>
<div class="timer-container bg-slate-800 rounded-2xl p-8 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-blue-900/20 to-slate-900/50"></div>
<div class="relative z-10 flex flex-col items-center">
<div class="relative w-64 h-64 mb-8">
<svg class="w-full h-full" viewBox="0 0 100 100">
<circle
class="text-slate-700"
stroke-width="8"
stroke="currentColor"
fill="transparent"
r="40"
cx="50"
cy="50"
/>
<circle
class="progress-ring__circle text-blue-500"
stroke-width="8"
stroke-linecap="round"
stroke="currentColor"
fill="transparent"
r="40"
cx="50"
cy="50"
/>
</svg>
<div class="absolute inset-0 flex items-center justify-center flex-col">
<div id="time-display" class="text-5xl font-bold">25:00</div>
<div id="timer-state" class="text-blue-400 font-medium mt-2">Ready</div>
</div>
</div>
<div class="flex space-x-4 mb-8">
<button id="start-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-full font-medium flex items-center glow">
<i class="fas fa-play mr-2"></i> Start
</button>
<button id="reset-btn" class="bg-slate-700 hover:bg-slate-600 text-white px-6 py-3 rounded-full font-medium flex items-center">
<i class="fas fa-redo mr-2"></i> Reset
</button>
</div>
<div class="w-full">
<h3 class="text-lg font-medium mb-4 text-center">Select Duration</h3>
<div class="grid grid-cols-3 gap-3">
<button class="time-option py-2 px-4 rounded-lg bg-slate-700 hover:bg-slate-600" data-minutes="15">15 min</button>
<button class="time-option py-2 px-4 rounded-lg bg-slate-700 hover:bg-slate-600 active" data-minutes="25">25 min</button>
<button class="time-option py-2 px-4 rounded-lg bg-slate-700 hover:bg-slate-600" data-minutes="45">45 min</button>
<button class="time-option py-2 px-4 rounded-lg bg-slate-700 hover:bg-slate-600" data-minutes="60">60 min</button>
<button class="time-option py-2 px-4 rounded-lg bg-slate-700 hover:bg-slate-600" data-minutes="90">90 min</button>
<button class="time-option py-2 px-4 rounded-lg bg-slate-700 hover:bg-slate-600" data-minutes="120">120 min</button>
</div>
</div>
</div>
</div>
<div class="music-controls rounded-xl p-4 border border-slate-700">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fas fa-music text-blue-400 mr-3 text-xl"></i>
<div>
<h3 class="font-medium">Lofi Study Beats</h3>
<p class="text-sm text-slate-400">Chill focus music</p>
</div>
</div>
<div class="flex items-center space-x-2">
<button id="volume-down" class="p-2 text-slate-300 hover:text-white">
<i class="fas fa-volume-down"></i>
</button>
<button id="play-music" class="p-2 text-slate-300 hover:text-white">
<i class="fas fa-play"></i>
</button>
<button id="volume-up" class="p-2 text-slate-300 hover:text-white">
<i class="fas fa-volume-up"></i>
</button>
</div>
</div>
<audio id="lofi-audio" loop>
<source src="https://lofi.stream.laut.fm/zwei" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>
<div class="text-center text-slate-500 text-sm mt-8">
<p>Take breaks between sessions for maximum productivity</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Timer elements
const timeDisplay = document.getElementById('time-display');
const timerState = document.getElementById('timer-state');
const startBtn = document.getElementById('start-btn');
const resetBtn = document.getElementById('reset-btn');
const timeOptions = document.querySelectorAll('.time-option');
// Music elements
const playMusicBtn = document.getElementById('play-music');
const volumeUpBtn = document.getElementById('volume-up');
const volumeDownBtn = document.getElementById('volume-down');
const lofiAudio = document.getElementById('lofi-audio');
// Timer variables
let timer;
let totalSeconds = 25 * 60; // Default 25 minutes
let remainingSeconds = totalSeconds;
let isRunning = false;
let isMusicPlaying = false;
// Progress ring
const circle = document.querySelector('.progress-ring__circle');
const radius = circle.r.baseVal.value;
const circumference = 2 * Math.PI * radius;
circle.style.strokeDasharray = circumference;
circle.style.strokeDashoffset = circumference;
// Initialize timer display
updateTimerDisplay();
// Time selection
timeOptions.forEach(option => {
option.addEventListener('click', function() {
timeOptions.forEach(opt => opt.classList.remove('active'));
this.classList.add('active');
const minutes = parseInt(this.dataset.minutes);
totalSeconds = minutes * 60;
remainingSeconds = totalSeconds;
updateTimerDisplay();
updateProgressRing();
// Reset timer state
if (isRunning) {
clearInterval(timer);
isRunning = false;
startBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Start';
timerState.textContent = 'Ready';
}
});
});
// Start/Pause timer
startBtn.addEventListener('click', function() {
if (isRunning) {
// Pause timer
clearInterval(timer);
isRunning = false;
this.innerHTML = '<i class="fas fa-play mr-2"></i> Resume';
timerState.textContent = 'Paused';
// Pause music if playing
if (isMusicPlaying) {
lofiAudio.pause();
playMusicBtn.innerHTML = '<i class="fas fa-play"></i>';
isMusicPlaying = false;
}
} else {
// Start timer
isRunning = true;
this.innerHTML = '<i class="fas fa-pause mr-2"></i> Pause';
timerState.textContent = 'Focusing...';
// Start music if not already playing
if (!isMusicPlaying) {
lofiAudio.play().catch(e => console.log("Autoplay prevented:", e));
playMusicBtn.innerHTML = '<i class="fas fa-pause"></i>';
isMusicPlaying = true;
}
timer = setInterval(() => {
if (remainingSeconds > 0) {
remainingSeconds--;
updateTimerDisplay();
updateProgressRing();
} else {
// Timer completed
clearInterval(timer);
isRunning = false;
startBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Start';
timerState.textContent = 'Completed!';
document.querySelector('.timer-container').classList.add('animate-pulse');
// Play completion sound
const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-alarm-digital-clock-beep-989.mp3');
audio.play();
// Stop music
lofiAudio.pause();
playMusicBtn.innerHTML = '<i class="fas fa-play"></i>';
isMusicPlaying = false;
}
}, 1000);
}
});
// Reset timer
resetBtn.addEventListener('click', function() {
clearInterval(timer);
isRunning = false;
remainingSeconds = totalSeconds;
updateTimerDisplay();
updateProgressRing();
startBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Start';
timerState.textContent = 'Ready';
document.querySelector('.timer-container').classList.remove('animate-pulse');
// Stop music
lofiAudio.pause();
playMusicBtn.innerHTML = '<i class="fas fa-play"></i>';
isMusicPlaying = false;
});
// Music controls
playMusicBtn.addEventListener('click', function() {
if (isMusicPlaying) {
lofiAudio.pause();
this.innerHTML = '<i class="fas fa-play"></i>';
isMusicPlaying = false;
} else {
lofiAudio.play().catch(e => console.log("Play prevented:", e));
this.innerHTML = '<i class="fas fa-pause"></i>';
isMusicPlaying = true;
}
});
volumeUpBtn.addEventListener('click', function() {
if (lofiAudio.volume < 0.9) {
lofiAudio.volume += 0.1;
}
});
volumeDownBtn.addEventListener('click', function() {
if (lofiAudio.volume > 0.1) {
lofiAudio.volume -= 0.1;
}
});
// Helper functions
function updateTimerDisplay() {
const minutes = Math.floor(remainingSeconds / 60);
const seconds = remainingSeconds % 60;
timeDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
function updateProgressRing() {
const offset = circumference - (remainingSeconds / totalSeconds) * circumference;
circle.style.strokeDashoffset = offset;
}
// Try to autoplay music (may be blocked by browser)
lofiAudio.volume = 0.5;
document.addEventListener('click', function initAudio() {
// This is needed to unlock audio on mobile devices
lofiAudio.play().then(() => {
lofiAudio.pause();
playMusicBtn.innerHTML = '<i class="fas fa-play"></i>';
isMusicPlaying = false;
}).catch(e => {
console.log("Audio initialization failed:", e);
});
document.removeEventListener('click', initAudio);
}, { once: true });
});
</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=PyQuarX/studyfocus" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>