// DOM Elements const navButtons = document.querySelectorAll('.nav-btn'); const tabContents = document.querySelectorAll('.tab-content'); // Tab Navigation navButtons.forEach(button => { button.addEventListener('click', (e) => { e.preventDefault(); const targetTab = button.getAttribute('data-tab'); // Update active states navButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); // Show target tab content tabContents.forEach(content => { content.classList.remove('active'); if (content.id === targetTab) { content.classList.add('active'); } }); }); }); // Alarm Feature class Alarm { constructor() { this.alarmInput = document.querySelector('.alarm_time-input'); this.setAlarmBtn = document.querySelector('.alarm-container .button-main'); this.alarmsWrap = document.querySelector('.alarms-wrap'); this.alarms = []; this.activeSounds = new Map(); // Add styles for glowing effect this.addGlowStyles(); // Clear any static alarms on page load this.alarmsWrap.innerHTML = ''; this.init(); } addGlowStyles() { const style = document.createElement('style'); style.textContent = ` .glowing-card { animation: glow 1.5s ease-in-out infinite alternate; box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); } @keyframes glow { from { box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); } to { box-shadow: 0 0 20px rgba(255, 0, 0, 0.8), 0 0 30px rgba(255, 0, 0, 0.6); } } `; document.head.appendChild(style); } init() { this.setAlarmBtn.addEventListener('click', () => this.setAlarm()); } setAlarm() { const time = this.alarmInput.value; if (!time) return; const alarm = { id: Date.now(), time: time, active: true, createdAt: new Date() }; this.alarms.push(alarm); this.createAlarmElement(alarm); this.startAlarmCheck(alarm); this.updateProgressBar(alarm); } createAlarmElement(alarm) { const alarmElement = document.createElement('div'); alarmElement.className = 'alarms-alarm-wrap'; alarmElement.setAttribute('data-alarm-id', alarm.id); alarmElement.innerHTML = `
Alarm ${this.alarms.length}
${this.formatTime(alarm.time)}
Remove `; const removeBtn = alarmElement.querySelector('.button-main.red'); removeBtn.addEventListener('click', (e) => { e.preventDefault(); this.removeAlarm(alarm.id); }); this.alarmsWrap.appendChild(alarmElement); } formatTime(time) { const [hours, minutes] = time.split(':'); const date = new Date(); date.setHours(hours); date.setMinutes(minutes); return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } updateProgressBar(alarm) { const alarmElement = document.querySelector(`[data-alarm-id="${alarm.id}"]`); if (!alarmElement) return; const progressBar = alarmElement.querySelector('.progress-bar'); if (!progressBar) return; const updateProgress = () => { if (!alarm.active) return; const now = new Date(); const [hours, minutes] = alarm.time.split(':'); const alarmTime = new Date(); alarmTime.setHours(hours); alarmTime.setMinutes(minutes); alarmTime.setSeconds(0); // If alarm time has passed for today, set it for tomorrow if (now > alarmTime) { alarmTime.setDate(alarmTime.getDate() + 1); } const totalTime = alarmTime - alarm.createdAt; const elapsedTime = now - alarm.createdAt; const progress = Math.min(100, Math.max(0, (elapsedTime / totalTime) * 100)); progressBar.style.width = `${progress}%`; }; // Update progress every second const interval = setInterval(() => { if (!alarm.active) { clearInterval(interval); return; } updateProgress(); }, 1000); // Initial update updateProgress(); } startAlarmCheck(alarm) { const checkAlarm = () => { if (!alarm.active) return; const now = new Date(); const [hours, minutes] = alarm.time.split(':'); const alarmTime = new Date(); alarmTime.setHours(hours); alarmTime.setMinutes(minutes); alarmTime.setSeconds(0); if (now.getHours() === alarmTime.getHours() && now.getMinutes() === alarmTime.getMinutes() && now.getSeconds() === 0) { this.triggerAlarm(alarm); } }; // Check every second const interval = setInterval(() => { if (!alarm.active) { clearInterval(interval); return; } checkAlarm(); }, 1000); } triggerAlarm(alarm) { if (this.activeSounds.has(alarm.id)) return; const audio = new Audio('https://assets.mixkit.co/active_storage/sfx/2869/2869-preview.mp3'); audio.loop = true; this.activeSounds.set(alarm.id, audio); if ('Notification' in window) { Notification.requestPermission().then(permission => { if (permission === 'granted') { new Notification('Alarm', { body: `It's ${this.formatTime(alarm.time)}!` }); } }); } const alarmElement = document.querySelector(`[data-alarm-id="${alarm.id}"]`); if (alarmElement) { // Add glowing effect alarmElement.classList.add('glowing-card'); const stopButton = document.createElement('a'); stopButton.href = '#'; stopButton.className = 'button-main w-button'; stopButton.textContent = 'Stop Alarm'; stopButton.style.marginTop = '10px'; stopButton.addEventListener('click', (e) => { e.preventDefault(); this.stopAlarmSound(alarm.id); // Remove glowing effect alarmElement.classList.remove('glowing-card'); stopButton.remove(); }); alarmElement.appendChild(stopButton); } audio.play().catch(error => { console.error('Error playing alarm sound:', error); this.activeSounds.delete(alarm.id); }); } stopAlarmSound(alarmId) { const audio = this.activeSounds.get(alarmId); if (audio) { audio.pause(); audio.currentTime = 0; this.activeSounds.delete(alarmId); // Remove glowing effect const alarmElement = document.querySelector(`[data-alarm-id="${alarmId}"]`); if (alarmElement) { alarmElement.classList.remove('glowing-card'); } } } removeAlarm(id) { const alarm = this.alarms.find(a => a.id === id); if (alarm) { alarm.active = false; const alarmElement = document.querySelector(`[data-alarm-id="${id}"]`); if (alarmElement) { alarmElement.remove(); } this.alarms = this.alarms.filter(a => a.id !== id); // Stop any playing sound for this alarm this.stopAlarmSound(id); } } } // Timer Feature class Timer { constructor() { this.hoursInput = document.getElementById('hours'); this.minutesInput = document.getElementById('minutes'); this.secondsInput = document.getElementById('seconds'); this.setTimerBtn = document.querySelector('.timer-container .button-main'); this.timersWrap = document.querySelector('.timer-container .alarms-wrap'); this.timers = []; this.activeSounds = new Map(); // Add styles for glowing effect this.addGlowStyles(); if (this.timersWrap) { this.timersWrap.innerHTML = ''; } this.init(); } addGlowStyles() { const style = document.createElement('style'); style.textContent = ` .glowing-card { animation: glow 1.5s ease-in-out infinite alternate; box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); } @keyframes glow { from { box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); } to { box-shadow: 0 0 20px rgba(255, 0, 0, 0.8), 0 0 30px rgba(255, 0, 0, 0.6); } } `; document.head.appendChild(style); } init() { if (this.setTimerBtn) { this.setTimerBtn.addEventListener('click', (e) => { e.preventDefault(); this.setTimer(); }); } } setTimer() { if (!this.hoursInput || !this.minutesInput || !this.secondsInput) { return; } const hours = parseInt(this.hoursInput.value) || 0; const minutes = parseInt(this.minutesInput.value) || 0; const seconds = parseInt(this.secondsInput.value) || 0; if (hours === 0 && minutes === 0 && seconds === 0) return; const totalSeconds = (hours * 3600) + (minutes * 60) + seconds; const timer = { id: Date.now(), totalSeconds: totalSeconds, remainingSeconds: totalSeconds, active: true, createdAt: new Date() }; this.timers.push(timer); this.createTimerElement(timer); this.startTimer(timer); this.hoursInput.value = ''; this.minutesInput.value = ''; this.secondsInput.value = ''; } createTimerElement(timer) { const timerElement = document.createElement('div'); timerElement.className = 'alarms-alarm-wrap'; timerElement.setAttribute('data-timer-id', timer.id); timerElement.innerHTML = `
Timer ${this.timers.length}
${this.formatTime(timer.remainingSeconds)}
Pause Remove
`; const pauseBtn = timerElement.querySelector('.pause-btn'); const removeBtn = timerElement.querySelector('.remove-btn'); pauseBtn.addEventListener('click', (e) => { e.preventDefault(); this.togglePause(timer.id); }); removeBtn.addEventListener('click', (e) => { e.preventDefault(); this.removeTimer(timer.id); }); this.timersWrap.appendChild(timerElement); } formatTime(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; const parts = []; if (hours > 0) parts.push(hours.toString().padStart(2, '0')); parts.push(minutes.toString().padStart(2, '0')); parts.push(secs.toString().padStart(2, '0')); return parts.join(' : '); } startTimer(timer) { const timerElement = document.querySelector(`[data-timer-id="${timer.id}"]`); if (!timerElement) return; const timeDisplay = timerElement.querySelector('.alarms-number'); const progressBar = timerElement.querySelector('.progress-bar'); const totalSeconds = timer.totalSeconds; const updateTimer = () => { if (!timer.active) return; timer.remainingSeconds--; timeDisplay.textContent = this.formatTime(timer.remainingSeconds); const progress = (timer.remainingSeconds / totalSeconds) * 100; progressBar.style.width = `${progress}%`; if (timer.remainingSeconds <= 0) { clearInterval(timer.interval); this.triggerTimerComplete(timer); } }; timer.interval = setInterval(updateTimer, 1000); updateTimer(); } togglePause(timerId) { const timer = this.timers.find(t => t.id === timerId); if (!timer) return; timer.active = !timer.active; const timerElement = document.querySelector(`[data-timer-id="${timerId}"]`); if (!timerElement) return; const pauseBtn = timerElement.querySelector('.pause-btn'); pauseBtn.textContent = timer.active ? 'Pause' : 'Resume'; } stopTimerSound(timerId) { const audio = this.activeSounds.get(timerId); if (audio) { audio.pause(); audio.currentTime = 0; this.activeSounds.delete(timerId); // Remove glowing effect const timerElement = document.querySelector(`[data-timer-id="${timerId}"]`); if (timerElement) { timerElement.classList.remove('glowing-card'); } } } triggerTimerComplete(timer) { if (this.activeSounds.has(timer.id)) return; const audio = new Audio('https://assets.mixkit.co/active_storage/sfx/270/270-preview.mp3'); audio.loop = true; this.activeSounds.set(timer.id, audio); if ('Notification' in window) { Notification.requestPermission().then(permission => { if (permission === 'granted') { new Notification('Timer Complete', { body: 'Your timer has finished!' }); } }); } const timerElement = document.querySelector(`[data-timer-id="${timer.id}"]`); if (timerElement) { // Add glowing effect timerElement.classList.add('glowing-card'); const stopButton = document.createElement('a'); stopButton.href = '#'; stopButton.className = 'button-main w-button'; stopButton.textContent = 'Stop Sound'; stopButton.style.marginTop = '10px'; stopButton.addEventListener('click', (e) => { e.preventDefault(); this.stopTimerSound(timer.id); // Remove glowing effect timerElement.classList.remove('glowing-card'); stopButton.remove(); }); timerElement.appendChild(stopButton); } audio.play().catch(error => { console.error('Error playing timer sound:', error); this.activeSounds.delete(timer.id); }); } removeTimer(id) { const timer = this.timers.find(t => t.id === id); if (!timer) return; timer.active = false; clearInterval(timer.interval); const timerElement = document.querySelector(`[data-timer-id="${id}"]`); if (timerElement) { timerElement.remove(); } this.timers = this.timers.filter(t => t.id !== id); this.stopTimerSound(id); } } // Stopwatch Feature class Stopwatch { constructor() { this.startBtn = document.querySelector('.stopwatch-buttons .button-main'); this.pauseBtn = document.querySelector('.stopwatch-buttons .button-main:nth-child(2)'); this.resetBtn = document.querySelector('.stopwatch-buttons .button-main:nth-child(3)'); this.lapBtn = document.querySelector('.stopwatch-buttons .button-main:nth-child(4)'); this.stopwatchTime = document.querySelector('.stopwatch-time'); this.stopwatchLaps = document.querySelector('.stopwatch-laps'); this.stopwatches = []; this.interval = null; // Add monospace font style this.addMonospaceStyle(); if (this.stopwatchLaps) { this.stopwatchLaps.innerHTML = ''; } if (this.stopwatchTime) { this.stopwatchTime.textContent = '00:00:00:00'; } this.init(); } addMonospaceStyle() { const style = document.createElement('style'); style.textContent = ` .stopwatch-time { font-family: 'Courier New', monospace; letter-spacing: 1px; } .stopwatch-lap-time { font-family: 'Courier New', monospace; letter-spacing: 1px; font-size: 1.2em; } .stopwatch-lap { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid #eee; } .stopwatch-lap-num { font-weight: bold; } .stopwatch-lap-time { min-width: 150px; text-align: right; } `; document.head.appendChild(style); } init() { if (!this.startBtn || !this.pauseBtn || !this.resetBtn || !this.lapBtn) { return; } this.startBtn.addEventListener('click', () => this.startStopwatch()); this.pauseBtn.addEventListener('click', () => this.togglePause()); this.resetBtn.addEventListener('click', () => this.resetStopwatch()); this.lapBtn.addEventListener('click', () => this.addLap()); this.updateButtonStates(false); } updateButtonStates(isRunning, isPaused = false) { this.startBtn.disabled = isRunning; this.startBtn.style.opacity = isRunning ? '0.5' : '1'; this.pauseBtn.disabled = !isRunning; this.pauseBtn.style.opacity = isRunning ? '1' : '0.5'; this.lapBtn.disabled = !isRunning || isPaused; this.lapBtn.style.opacity = (!isRunning || isPaused) ? '0.5' : '1'; this.resetBtn.disabled = !isRunning; this.resetBtn.style.opacity = isRunning ? '1' : '0.5'; } startStopwatch() { if (this.stopwatches.some(s => s.active)) { return; } const stopwatch = { id: Date.now(), startTime: new Date(), elapsedTime: 0, active: true, laps: [], lastUpdateTime: new Date() }; this.stopwatches = [stopwatch]; this.startTimer(); this.updateButtonStates(true); } formatTime(milliseconds) { const totalSeconds = Math.floor(milliseconds / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; const ms = Math.floor((milliseconds % 1000) / 10); // Use consistent width for all numbers const parts = [ hours.toString().padStart(2, '0'), minutes.toString().padStart(2, '0'), seconds.toString().padStart(2, '0'), ms.toString().padStart(2, '0') ]; return parts.join(':'); } startTimer() { if (this.interval) { clearInterval(this.interval); } const updateTime = () => { const activeStopwatch = this.stopwatches.find(s => s.active); if (!activeStopwatch) return; const now = new Date(); const timeDiff = now - activeStopwatch.lastUpdateTime; activeStopwatch.elapsedTime += timeDiff; activeStopwatch.lastUpdateTime = now; if (this.stopwatchTime) { this.stopwatchTime.textContent = this.formatTime(activeStopwatch.elapsedTime); } }; this.interval = setInterval(updateTime, 10); updateTime(); } addLap() { const activeStopwatch = this.stopwatches.find(s => s.active); if (!activeStopwatch) return; const lapTime = activeStopwatch.elapsedTime; const lapNumber = activeStopwatch.laps.length + 1; activeStopwatch.laps.push({ number: lapNumber, time: lapTime }); if (this.stopwatchLaps) { const lapElement = document.createElement('div'); lapElement.className = 'stopwatch-lap'; lapElement.innerHTML = `
Lap ${lapNumber.toString().padStart(2, '0')}
${this.formatTime(lapTime)}
`; this.stopwatchLaps.insertBefore(lapElement, this.stopwatchLaps.firstChild); } } togglePause() { const stopwatch = this.stopwatches[0]; if (!stopwatch) return; stopwatch.active = !stopwatch.active; if (stopwatch.active) { stopwatch.lastUpdateTime = new Date(); this.pauseBtn.textContent = 'Pause'; this.updateButtonStates(true, false); this.startTimer(); } else { if (this.interval) { clearInterval(this.interval); this.interval = null; } this.pauseBtn.textContent = 'Resume'; this.updateButtonStates(true, true); } } resetStopwatch() { if (this.interval) { clearInterval(this.interval); this.interval = null; } this.stopwatches = []; if (this.stopwatchTime) { this.stopwatchTime.textContent = '00:00:00:00'; } if (this.stopwatchLaps) { this.stopwatchLaps.innerHTML = ''; } this.updateButtonStates(false); this.pauseBtn.textContent = 'Pause'; } } // Holidays Feature class Holidays { constructor() { this.holidays = { 'international': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Valentine's Day", date: "2025-02-14" }, { name: "International Women's Day", date: "2025-03-08" }, { name: "Earth Day", date: "2025-04-22" }, { name: "World Environment Day", date: "2025-06-05" } ], 'us': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Martin Luther King Jr. Day", date: "2025-01-20" }, { name: "Presidents' Day", date: "2025-02-17" }, { name: "Memorial Day", date: "2025-05-26" }, { name: "Independence Day", date: "2025-07-04" }, { name: "Thanksgiving", date: "2025-11-27" } ], 'uk': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Good Friday", date: "2025-04-18" }, { name: "Easter Monday", date: "2025-04-21" }, { name: "Spring Bank Holiday", date: "2025-05-26" }, { name: "Christmas Day", date: "2025-12-25" }, { name: "Boxing Day", date: "2025-12-26" } ], 'chinese': [ { name: "Chinese New Year", date: "2025-01-29" }, { name: "Qingming Festival", date: "2025-04-05" }, { name: "Labor Day", date: "2025-05-01" }, { name: "Dragon Boat Festival", date: "2025-06-10" }, { name: "National Day", date: "2025-10-01" } ], 'indian': [ { name: "Republic Day", date: "2025-01-26" }, { name: "Holi", date: "2025-03-14" }, { name: "Independence Day", date: "2025-08-15" }, { name: "Gandhi Jayanti", date: "2025-10-02" }, { name: "Diwali", date: "2025-11-01" } ], 'japanese': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Coming of Age Day", date: "2025-01-13" }, { name: "National Foundation Day", date: "2025-02-11" }, { name: "Golden Week", date: "2025-05-03" }, { name: "Marine Day", date: "2025-07-21" } ], 'german': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Good Friday", date: "2025-04-18" }, { name: "Easter Monday", date: "2025-04-21" }, { name: "Labor Day", date: "2025-05-01" }, { name: "German Unity Day", date: "2025-10-03" }, { name: "Christmas Day", date: "2025-12-25" } ], 'french': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Easter Monday", date: "2025-04-21" }, { name: "Labor Day", date: "2025-05-01" }, { name: "Victory in Europe Day", date: "2025-05-08" }, { name: "Bastille Day", date: "2025-07-14" }, { name: "Christmas Day", date: "2025-12-25" } ], 'australian': [ { name: "New Year's Day", date: "2025-01-01" }, { name: "Australia Day", date: "2025-01-26" }, { name: "Good Friday", date: "2025-04-18" }, { name: "Easter Monday", date: "2025-04-21" }, { name: "ANZAC Day", date: "2025-04-25" }, { name: "Christmas Day", date: "2025-12-25" } ] }; this.init(); } init() { this.loadHolidays(); setInterval(() => this.updateCountdowns(), 1000); } loadHolidays() { Object.entries(this.holidays).forEach(([category, holidays]) => { const container = document.querySelector(`#${category}-holidays .holidays-grid`); if (container) { container.innerHTML = ''; holidays.forEach(holiday => { const card = this.createHolidayCard(holiday); container.appendChild(card); }); } }); } createHolidayCard(holiday) { const card = document.createElement('div'); card.className = 'holiday-card'; card.innerHTML = `
${holiday.name}
${this.getCountdown(holiday.date)}
${this.formatDate(holiday.date)}
`; return card; } getCountdown(date) { const now = new Date(); const target = new Date(date); // If the date has passed this year, calculate for next year if (target < now) { target.setFullYear(target.getFullYear() + 1); } const diff = target - now; 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); return `${days} days, ${hours} hours, ${minutes} minutes`; } formatDate(date) { return new Date(date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); } updateCountdowns() { document.querySelectorAll('.holiday-card').forEach(card => { const countdownElement = card.querySelector('.holiday-countdown'); const dateElement = card.querySelector('.holiday-date'); const date = new Date(dateElement.textContent); countdownElement.textContent = this.getCountdown(date); }); } } // Initialize features document.addEventListener('DOMContentLoaded', () => { // Initialize other features const alarm = new Alarm(); const timer = new Timer(); const stopwatch = new Stopwatch(); const holidays = new Holidays(); // Tab switching functionality const tabButtons = document.querySelectorAll('.nav-btn'); const tabContents = document.querySelectorAll('.tab-content'); tabButtons.forEach(button => { button.addEventListener('click', (e) => { e.preventDefault(); const targetTab = button.getAttribute('data-tab'); // Update active states tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); button.classList.add('active'); document.getElementById(targetTab).classList.add('active'); }); }); });