Skip to content

Instantly share code, notes, and snippets.

@deokman420
Created November 1, 2025 01:57
Show Gist options
  • Save deokman420/55e4a6c11742731838584b969973cf11 to your computer and use it in GitHub Desktop.
Save deokman420/55e4a6c11742731838584b969973cf11 to your computer and use it in GitHub Desktop.
Countdown Timer for use in Notion
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Adjustable Countdown Timer</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.timer-container {
background: rgba(30, 30, 46, 0.95);
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
text-align: center;
max-width: 500px;
width: 100%;
border: 1px solid rgba(255, 255, 255, 0.1);
}
h1 {
color: #e0e0e0;
margin-bottom: 30px;
font-size: 28px;
}
.time-display {
font-size: 72px;
font-weight: bold;
color: #00d9ff;
margin: 30px 0;
font-family: 'Courier New', monospace;
text-shadow: 0 0 20px rgba(0, 217, 255, 0.5);
}
.controls {
display: flex;
gap: 15px;
justify-content: center;
margin-bottom: 30px;
flex-wrap: wrap;
}
.time-input-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.time-input-group label {
font-size: 12px;
color: #a0a0a0;
font-weight: 600;
text-transform: uppercase;
}
.time-input {
width: 70px;
padding: 10px;
font-size: 18px;
border: 2px solid #00d9ff;
border-radius: 8px;
text-align: center;
font-weight: bold;
transition: all 0.3s;
background: rgba(20, 20, 35, 0.8);
color: #e0e0e0;
}
.time-input:focus {
outline: none;
border-color: #00ffaa;
box-shadow: 0 0 0 3px rgba(0, 217, 255, 0.2);
}
.buttons {
display: flex;
gap: 10px;
justify-content: center;
flex-wrap: wrap;
}
button {
padding: 12px 30px;
font-size: 16px;
border: none;
border-radius: 25px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 1px;
}
.btn-start {
background: linear-gradient(135deg, #00d9ff 0%, #00ffaa 100%);
color: #1a1a2e;
}
.btn-start:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 217, 255, 0.5);
}
.btn-pause {
background: #ffa726;
color: #1a1a2e;
}
.btn-pause:hover {
background: #ffb84d;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 167, 38, 0.5);
}
.btn-reset {
background: #ff6b6b;
color: #1a1a2e;
}
.btn-reset:hover {
background: #ff8787;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 107, 107, 0.5);
}
.btn-preset {
background: rgba(0, 217, 255, 0.2);
color: #00d9ff;
padding: 8px 16px;
font-size: 14px;
border: 1px solid rgba(0, 217, 255, 0.3);
}
.btn-preset:hover {
background: rgba(0, 217, 255, 0.3);
border-color: #00d9ff;
transform: translateY(-2px);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
button:disabled:hover {
transform: none;
}
.presets {
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
}
.presets-label {
font-size: 14px;
color: #a0a0a0;
margin-bottom: 10px;
font-weight: 600;
}
.preset-buttons {
display: flex;
gap: 8px;
justify-content: center;
flex-wrap: wrap;
}
.status {
margin-top: 20px;
font-size: 14px;
color: #a0a0a0;
font-weight: 600;
}
.time-up {
animation: pulse 1s infinite;
}
@keyframes pulse {
0%, 100% {
color: #ff6b6b;
}
50% {
color: #00d9ff;
}
}
@media (max-width: 500px) {
.time-display {
font-size: 48px;
}
.timer-container {
padding: 20px;
}
}
</style>
</head>
<body>
<div class="timer-container">
<h1>⏱️ Countdown Timer</h1>
<div class="presets">
<div class="presets-label">Quick Presets:</div>
<div class="preset-buttons">
<button class="btn-preset" onclick="setPreset(5, 0)">5 min</button>
<button class="btn-preset" onclick="setPreset(10, 0)">10 min</button>
<button class="btn-preset" onclick="setPreset(15, 0)">15 min</button>
<button class="btn-preset" onclick="setPreset(25, 0)">25 min</button>
<button class="btn-preset" onclick="setPreset(30, 0)">30 min</button>
<button class="btn-preset" onclick="setPreset(60, 0)">1 hour</button>
</div>
</div>
<div class="controls">
<div class="time-input-group">
<label>Hours</label>
<input type="number" id="hours" class="time-input" min="0" max="23" value="0">
</div>
<div class="time-input-group">
<label>Minutes</label>
<input type="number" id="minutes" class="time-input" min="0" max="59" value="25">
</div>
<div class="time-input-group">
<label>Seconds</label>
<input type="number" id="seconds" class="time-input" min="0" max="59" value="0">
</div>
</div>
<div class="time-display" id="display">25:00</div>
<div class="buttons">
<button class="btn-start" id="startBtn" onclick="startTimer()">Start</button>
<button class="btn-pause" id="pauseBtn" onclick="pauseTimer()" disabled>Pause</button>
<button class="btn-reset" onclick="resetTimer()">Reset</button>
</div>
<div class="status" id="status">Ready to start</div>
</div>
<script>
let totalSeconds = 0;
let currentSeconds = 0;
let interval = null;
let isRunning = false;
let isPaused = false;
const hoursInput = document.getElementById('hours');
const minutesInput = document.getElementById('minutes');
const secondsInput = document.getElementById('seconds');
const display = document.getElementById('display');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const status = document.getElementById('status');
// Initialize display
updateDisplay();
// Update display when inputs change
[hoursInput, minutesInput, secondsInput].forEach(input => {
input.addEventListener('input', () => {
if (!isRunning) {
updateDisplay();
}
});
});
function setPreset(minutes, seconds) {
if (!isRunning) {
hoursInput.value = Math.floor(minutes / 60);
minutesInput.value = minutes % 60;
secondsInput.value = seconds;
updateDisplay();
}
}
function updateDisplay() {
if (!isRunning) {
const h = parseInt(hoursInput.value) || 0;
const m = parseInt(minutesInput.value) || 0;
const s = parseInt(secondsInput.value) || 0;
currentSeconds = h * 3600 + m * 60 + s;
}
const hours = Math.floor(currentSeconds / 3600);
const minutes = Math.floor((currentSeconds % 3600) / 60);
const seconds = currentSeconds % 60;
if (hours > 0) {
display.textContent = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
} else {
display.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
}
function startTimer() {
if (!isRunning) {
const h = parseInt(hoursInput.value) || 0;
const m = parseInt(minutesInput.value) || 0;
const s = parseInt(secondsInput.value) || 0;
totalSeconds = h * 3600 + m * 60 + s;
if (totalSeconds === 0) {
status.textContent = 'Please set a time first!';
return;
}
if (!isPaused) {
currentSeconds = totalSeconds;
}
isRunning = true;
isPaused = false;
startBtn.disabled = true;
pauseBtn.disabled = false;
hoursInput.disabled = true;
minutesInput.disabled = true;
secondsInput.disabled = true;
status.textContent = 'Timer running...';
display.classList.remove('time-up');
interval = setInterval(() => {
currentSeconds--;
updateDisplay();
if (currentSeconds <= 0) {
clearInterval(interval);
isRunning = false;
startBtn.disabled = false;
pauseBtn.disabled = true;
status.textContent = '⏰ Time\'s up!';
display.classList.add('time-up');
playSound();
}
}, 1000);
}
}
function pauseTimer() {
if (isRunning) {
clearInterval(interval);
isRunning = false;
isPaused = true;
startBtn.disabled = false;
pauseBtn.disabled = true;
startBtn.textContent = 'Resume';
status.textContent = 'Timer paused';
}
}
function resetTimer() {
clearInterval(interval);
isRunning = false;
isPaused = false;
currentSeconds = 0;
startBtn.disabled = false;
pauseBtn.disabled = true;
startBtn.textContent = 'Start';
hoursInput.disabled = false;
minutesInput.disabled = false;
secondsInput.disabled = false;
status.textContent = 'Ready to start';
display.classList.remove('time-up');
updateDisplay();
}
function playSound() {
// Create a simple beep sound using Web Audio API
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = 800;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.5);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment