| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>7-Minute Countdown Timer</title> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); |
| |
| body { |
| margin: 0; |
| padding: 0; |
| font-family: 'Poppins', sans-serif; |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| min-height: 100vh; |
| color: white; |
| } |
| |
| .timer-container { |
| text-align: center; |
| background: rgba(255, 255, 255, 0.15); |
| backdrop-filter: blur(12px); |
| border-radius: 24px; |
| padding: 60px 40px; |
| box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25); |
| border: 1px solid rgba(255, 255, 255, 0.25); |
| max-width: 480px; |
| width: 90%; |
| } |
| |
| h1 { |
| font-weight: 600; |
| margin-bottom: 30px; |
| font-size: 2rem; |
| } |
| |
| .timer-display { |
| font-size: 5rem; |
| font-weight: 600; |
| margin: 40px 0; |
| text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.2); |
| font-family: 'Poppins', sans-serif; |
| letter-spacing: 1px; |
| } |
| |
| .controls { |
| margin: 40px 0; |
| display: flex; |
| justify-content: center; |
| flex-wrap: wrap; |
| gap: 15px; |
| } |
| |
| button { |
| background: linear-gradient(45deg, #4facfe 0%, #00f2fe 100%); |
| border: none; |
| color: white; |
| padding: 16px 32px; |
| border-radius: 12px; |
| font-size: 1.1rem; |
| font-weight: 500; |
| cursor: pointer; |
| transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); |
| min-width: 120px; |
| } |
| |
| button:hover { |
| transform: translateY(-3px); |
| box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25); |
| } |
| |
| button:active { |
| transform: translateY(1px); |
| } |
| |
| button:disabled { |
| opacity: 0.7; |
| cursor: not-allowed; |
| transform: none; |
| background: linear-gradient(45deg, #bdc3c7, #2c3e50); |
| } |
| |
| .time-input { |
| margin: 30px 0; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| gap: 15px; |
| } |
| |
| .time-input input { |
| width: 80px; |
| padding: 12px; |
| border-radius: 8px; |
| border: none; |
| text-align: center; |
| font-size: 1.1rem; |
| background: rgba(255, 255, 255, 0.2); |
| color: white; |
| font-weight: 500; |
| } |
| |
| .time-input label { |
| font-weight: 400; |
| font-size: 1.1rem; |
| } |
| |
| .progress-bar { |
| width: 100%; |
| height: 10px; |
| background: rgba(255, 255, 255, 0.2); |
| border-radius: 5px; |
| margin: 30px 0; |
| overflow: hidden; |
| } |
| |
| .progress-fill { |
| height: 100%; |
| background: linear-gradient(90deg, #43e97b 0%, #38f9d7 100%); |
| border-radius: 5px; |
| transition: width 1s linear; |
| width: 100%; |
| } |
| |
| .status { |
| font-size: 1.3rem; |
| margin: 30px 0; |
| font-weight: 400; |
| } |
| |
| .alarm-modal { |
| display: none; |
| position: fixed; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background: rgba(0, 0, 0, 0.85); |
| z-index: 1000; |
| } |
| |
| .alarm-content { |
| position: absolute; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| background: linear-gradient(135deg, #ff4d4d, #f94336); |
| padding: 50px; |
| border-radius: 24px; |
| text-align: center; |
| box-shadow: 0 25px 70px rgba(0, 0, 0, 0.6); |
| animation: bounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); |
| max-width: 90%; |
| width: 400px; |
| } |
| |
| @keyframes bounce { |
| 0% { transform: translate(-50%, -50%) scale(0.5); } |
| 100% { transform: translate(-50%, -50%) scale(1); } |
| } |
| |
| .alarm-content h2 { |
| font-size: 2.8rem; |
| margin: 0 0 25px 0; |
| animation: pulse 1.2s infinite; |
| } |
| |
| @keyframes pulse { |
| 0%, 100% { transform: scale(1); } |
| 50% { transform: scale(1.05); } |
| } |
| |
| .dismiss-btn { |
| background: white; |
| color: #ff4757; |
| margin-top: 25px; |
| padding: 14px 28px; |
| border-radius: 10px; |
| font-weight: 600; |
| } |
| |
| @media (max-width: 480px) { |
| .timer-display { |
| font-size: 3.5rem; |
| } |
| |
| .controls { |
| flex-direction: column; |
| gap: 12px; |
| } |
| |
| button { |
| width: 100%; |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="timer-container"> |
| <h1>Perfect Egg Timer</h1> |
| <div class="time-input"> |
| <label for="minutes">Minutes:</label> |
| <input type="number" id="minutes" min="0" max="59" value="7"> |
| <label for="seconds">Seconds:</label> |
| <input type="number" id="seconds" min="0" max="59" value="0"> |
| </div> |
| <div class="timer-display" id="timerDisplay">07:00</div> |
| <div class="progress-bar"> |
| <div class="progress-fill" id="progressFill"></div> |
| </div> |
| <div class="status" id="status">Ready to start</div> |
| <div class="controls"> |
| <button onclick="startTimer()" id="startBtn">Start</button> |
| <button onclick="pauseTimer()" id="pauseBtn" disabled>Pause</button> |
| <button onclick="resetTimer()" id="resetBtn">Reset</button> |
| <button onclick="setCustomTime()" id="setTimeBtn">Set Time</button> |
| </div> |
| </div> |
|
|
| <div class="alarm-modal" id="alarmModal"> |
| <div class="alarm-content"> |
| <h2>⏰ TIME'S UP! ⏰</h2> |
| <p>Your 7-minute timer has finished!</p> |
| <button class="dismiss-btn" onclick="dismissAlarm()">Dismiss</button> |
| </div> |
| </div> |
|
|
| <script> |
| let totalTime = 7 * 60; |
| let currentTime = totalTime; |
| let isRunning = false; |
| let timerInterval; |
| let audioContext; |
| let alarmSound; |
| |
| |
| function initAudio() { |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
| } |
| |
| |
| function createAlarmSound() { |
| const oscillator = audioContext.createOscillator(); |
| const gainNode = audioContext.createGain(); |
| |
| oscillator.connect(gainNode); |
| gainNode.connect(audioContext.destination); |
| |
| oscillator.frequency.setValueAtTime(800, audioContext.currentTime); |
| oscillator.type = 'sine'; |
| |
| gainNode.gain.setValueAtTime(0, audioContext.currentTime); |
| gainNode.gain.linearRampToValueAtTime(0.3, audioContext.currentTime + 0.1); |
| gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.5); |
| |
| oscillator.start(audioContext.currentTime); |
| oscillator.stop(audioContext.currentTime + 0.5); |
| } |
| |
| function playAlarm() { |
| if (!audioContext) initAudio(); |
| |
| |
| for (let i = 0; i < 6; i++) { |
| setTimeout(() => createAlarmSound(), i * 600); |
| } |
| } |
| |
| function updateDisplay() { |
| const minutes = Math.floor(currentTime / 60); |
| const seconds = currentTime % 60; |
| document.getElementById('timerDisplay').textContent = |
| `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; |
| |
| |
| const progress = ((totalTime - currentTime) / totalTime) * 100; |
| document.getElementById('progressFill').style.width = `${progress}%`; |
| } |
| |
| function startTimer() { |
| if (!audioContext) initAudio(); |
| |
| isRunning = true; |
| document.getElementById('startBtn').disabled = true; |
| document.getElementById('pauseBtn').disabled = false; |
| document.getElementById('status').textContent = 'Timer running...'; |
| |
| timerInterval = setInterval(() => { |
| if (currentTime > 0) { |
| currentTime--; |
| updateDisplay(); |
| } else { |
| |
| clearInterval(timerInterval); |
| isRunning = false; |
| document.getElementById('startBtn').disabled = false; |
| document.getElementById('pauseBtn').disabled = true; |
| document.getElementById('status').textContent = 'Time\'s up!'; |
| |
| |
| document.getElementById('alarmModal').style.display = 'block'; |
| playAlarm(); |
| } |
| }, 1000); |
| } |
| |
| function pauseTimer() { |
| clearInterval(timerInterval); |
| isRunning = false; |
| document.getElementById('startBtn').disabled = false; |
| document.getElementById('pauseBtn').disabled = true; |
| document.getElementById('status').textContent = 'Timer paused'; |
| } |
| |
| function resetTimer() { |
| clearInterval(timerInterval); |
| isRunning = false; |
| currentTime = totalTime; |
| updateDisplay(); |
| document.getElementById('startBtn').disabled = false; |
| document.getElementById('pauseBtn').disabled = true; |
| document.getElementById('status').textContent = 'Ready to start'; |
| } |
| |
| function dismissAlarm() { |
| document.getElementById('alarmModal').style.display = 'none'; |
| resetTimer(); |
| } |
| |
| |
| updateDisplay(); |
| |
| |
| document.addEventListener('visibilitychange', function() { |
| if (document.hidden && isRunning) { |
| |
| localStorage.setItem('timerStartTime', Date.now() - (totalTime - currentTime) * 1000); |
| } else if (!document.hidden && isRunning) { |
| |
| const startTime = localStorage.getItem('timerStartTime'); |
| if (startTime) { |
| const elapsed = Math.floor((Date.now() - parseInt(startTime)) / 1000); |
| currentTime = Math.max(0, totalTime - elapsed); |
| updateDisplay(); |
| } |
| } |
| }); |
| </script> |
| </body> |
| </html> |