/**
* Countdown Timer for LeafBox Technologies Website
* Creates an animated countdown to New Year
*/
class CountdownTimer {
constructor() {
this.targetDate = this.getNewYearDate();
this.elements = {
days: document.getElementById('days'),
hours: document.getElementById('hours'),
minutes: document.getElementById('minutes'),
seconds: document.getElementById('seconds')
};
this.interval = null;
this.isActive = false;
this.init();
}
init() {
if (this.hasValidElements()) {
this.start();
} else {
console.warn('Countdown elements not found');
}
}
hasValidElements() {
return this.elements.days &&
this.elements.hours &&
this.elements.minutes &&
this.elements.seconds;
}
getNewYearDate() {
const now = new Date();
const currentYear = now.getFullYear();
const nextYear = currentYear + 1;
// New Year is January 1st of next year at 00:00:00
return new Date(nextYear, 0, 1, 0, 0, 0, 0);
}
start() {
if (this.isActive) return;
this.isActive = true;
this.updateCountdown(); // Initial update
this.interval = setInterval(() => this.updateCountdown(), 1000);
}
stop() {
if (!this.isActive) return;
this.isActive = false;
clearInterval(this.interval);
this.interval = null;
}
updateCountdown() {
const now = new Date().getTime();
const timeLeft = this.targetDate.getTime() - now;
if (timeLeft <= 0) {
this.handleCountdownComplete();
return;
}
const timeComponents = this.calculateTimeComponents(timeLeft);
this.displayTime(timeComponents);
this.addAnimationEffects(timeComponents);
}
calculateTimeComponents(timeLeft) {
const days = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
const hours = Math.floor((timeLeft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
return {days, hours, minutes, seconds};
}
displayTime({days, hours, minutes, seconds}) {
this.updateElement(this.elements.days, this.padNumber(days));
this.updateElement(this.elements.hours, this.padNumber(hours));
this.updateElement(this.elements.minutes, this.padNumber(minutes));
this.updateElement(this.elements.seconds, this.padNumber(seconds));
}
updateElement(element, value) {
if (!element) return;
const currentValue = element.textContent;
if (currentValue !== value) {
// Add flash effect when number changes
element.parentElement.classList.add('number-change');
element.textContent = value;
// Remove flash effect after animation
setTimeout(() => {
element.parentElement.classList.remove('number-change');
}, 500);
}
}
padNumber(number) {
return number.toString().padStart(2, '0');
}
addAnimationEffects({days, hours, minutes, seconds}) {
// Add special effects for certain values
if (seconds === 0) {
// New minute reached
this.addMinuteEffect();
}
if (minutes === 0 && seconds === 0) {
// New hour reached
this.addHourEffect();
}
if (hours === 0 && minutes === 0 && seconds === 0) {
// New day reached
this.addDayEffect();
}
// Add glow effect when we're close to New Year
const daysUntilNewYear = Math.floor((this.targetDate.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24));
if (daysUntilNewYear <= 7) {
this.addNearNewYearEffect();
}
}
addMinuteEffect() {
const countdownContainer = document.querySelector('.countdown');
if (countdownContainer) {
countdownContainer.style.animation = 'none';
setTimeout(() => {
countdownContainer.style.animation = 'pulse 0.5s ease-in-out';
}, 10);
setTimeout(() => {
countdownContainer.style.animation = '';
}, 500);
}
}
addHourEffect() {
// Add a more pronounced effect for hours
const countdownNumbers = document.querySelectorAll('.countdown-number');
countdownNumbers.forEach(number => {
number.style.animation = 'bounce 0.6s ease-in-out';
setTimeout(() => {
number.style.animation = '';
}, 600);
});
}
addDayEffect() {
// Add special effect for days
const daysElement = this.elements.days;
if (daysElement) {
daysElement.style.color = '#B89B5F';
daysElement.style.textShadow = '0 0 10px #B89B5F';
setTimeout(() => {
daysElement.style.color = '';
daysElement.style.textShadow = '';
}, 2000);
}
}
addNearNewYearEffect() {
const countdownItems = document.querySelectorAll('.countdown-item');
countdownItems.forEach(item => {
item.style.border = '1px solid #B89B5F';
item.style.boxShadow = '0 0 15px rgba(184, 155, 95, 0.3)';
});
}
handleCountdownComplete() {
this.stop();
this.displayNewYearMessage();
this.addCelebrationEffect();
}
displayNewYearMessage() {
const countdownContainer = document.querySelector('.countdown-container');
if (countdownContainer) {
const message = document.createElement('div');
message.className = 'new-year-message';
message.innerHTML = `
<h3 style="color: #B89B5F; margin: 16px 0 8px; font-size: 24px;">
🎉 Happy New Year! 🎉
</h3>
<p style="color: #6B7280; font-size: 16px;">
Wishing you innovation and success in ${this.targetDate.getFullYear()}!
</p>
`;
countdownContainer.appendChild(message);
// Remove countdown
const countdown = document.getElementById('countdown');
if (countdown) {
countdown.style.display = 'none';
}
}
}
addCelebrationEffect() {
// Add confetti effect (simplified version)
this.createConfetti();
// Update page title temporarily
const originalTitle = document.title;
document.title = '🎊 Happy New Year - LeafBox Technologies! 🎊';
setTimeout(() => {
document.title = originalTitle;
}, 10000);
}
createConfetti() {
const confettiContainer = document.createElement('div');
confettiContainer.style.position = 'fixed';
confettiContainer.style.top = '0';
confettiContainer.style.left = '0';
confettiContainer.style.width = '100%';
confettiContainer.style.height = '100%';
confettiContainer.style.pointerEvents = 'none';
confettiContainer.style.zIndex = '9999';
document.body.appendChild(confettiContainer);
// Create confetti pieces
for (let i = 0; i < 50; i++) {
const confetti = document.createElement('div');
confetti.style.position = 'absolute';
confetti.style.width = '10px';
confetti.style.height = '10px';
confetti.style.backgroundColor = this.getRandomColor();
confetti.style.left = Math.random() * 100 + '%';
confetti.style.top = '-10px';
confetti.style.borderRadius = '50%';
confetti.style.animation = `confettiFall ${Math.random() * 3 + 2}s linear forwards`;
confettiContainer.appendChild(confetti);
}
// Add confetti animation
if (!document.getElementById('confetti-styles')) {
const style = document.createElement('style');
style.id = 'confetti-styles';
style.textContent = `
@keyframes confettiFall {
to {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
`;
document.head.appendChild(style);
}
// Remove confetti after animation
setTimeout(() => {
confettiContainer.remove();
}, 5000);
}
getRandomColor() {
const colors = ['#B89B5F', '#2A4B3A', '#FDFDFC', '#5F87B8'];
return colors[Math.floor(Math.random() * colors.length)];
}
// Public methods
pause() {
this.stop();
}
resume() {
this.start();
}
setTargetDate(date) {
this.targetDate = date;
if (this.isActive) {
this.stop();
this.start();
}
}
destroy() {
this.stop();
// Clean up DOM
const newYearMessage = document.querySelector('.new-year-message');
if (newYearMessage) {
newYearMessage.remove();
}
const countdown = document.getElementById('countdown');
if (countdown) {
countdown.style.display = '';
}
}
// Utility method to format time for display
formatTime(ms) {
const components = this.calculateTimeComponents(ms);
return `${this.padNumber(components.days)}d ${this.padNumber(components.hours)}h ${this.padNumber(components.minutes)}m ${this.padNumber(components.seconds)}s`;
}
// Get time remaining
getTimeRemaining() {
const now = new Date().getTime();
const timeLeft = this.targetDate.getTime() - now;
return Math.max(0, timeLeft);
}
// Check if countdown is complete
isComplete() {
return this.getTimeRemaining() <= 0;
}
}
// Initialize countdown when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
// Check if we're close to New Year
const now = new Date();
const newYear = new Date(now.getFullYear() + 1, 0, 1);
const daysUntilNewYear = Math.floor((newYear.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
// Only show countdown if we're within 60 days of New Year
if (daysUntilNewYear <= 60) {
const countdownTimer = new CountdownTimer();
// Make it globally accessible for debugging
window.countdownTimer = countdownTimer;
// Add keyboard controls for accessibility
document.addEventListener('keydown', (e) => {
if (e.key === ' ') { // Spacebar
e.preventDefault();
if (countdownTimer.isActive) {
countdownTimer.pause();
} else {
countdownTimer.resume();
}
}
});
// Handle visibility change for performance
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
countdownTimer.pause();
} else {
countdownTimer.resume();
}
});
} else {
// Hide countdown if we're too far from New Year
const countdownContainer = document.querySelector('.countdown-container');
if (countdownContainer) {
countdownContainer.style.display = 'none';
}
}
});
// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
module.exports = CountdownTimer;
}