// 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)}
`;
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');
});
});
});