Files
is-it-christmas/frontend/script.js
Julien Lengrand-Lambert 16ae2a1430 Creating the project
2025-11-11 10:06:56 +01:00

246 lines
6.2 KiB
JavaScript

// Christmas Checker Application
/**
* Check if today is Christmas using client-side date logic
* Christmas is December 25th or 26th (Boxing Day)
*/
function isChristmas() {
const today = new Date();
const month = today.getMonth() + 1; // getMonth() returns 0-11
const day = today.getDate();
return month === 12 && (day === 25 || day === 26);
}
/**
* Get current date in YYYY-MM-DD format
*/
function getCurrentDate() {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
/**
* Render the Non-Christmas UI (364 days/year)
*/
function renderNonChristmas() {
const content = document.getElementById('content');
content.innerHTML = `
<div class="message-container">
<h1 class="answer no-answer">NO</h1>
<div class="smiley sad-smiley" role="img" aria-label="Sad face">☹️</div>
<p class="subtitle">It's not Christmas yet...</p>
<p class="date">Today is ${getCurrentDate()}</p>
</div>
`;
}
/**
* Render the Christmas UI (1 day/year)
*/
function renderChristmas() {
const content = document.getElementById('content');
content.innerHTML = `
<div class="message-container">
<h1 class="answer yes-answer">YES</h1>
<p class="subtitle festive">🎄 Merry Christmas! 🎄</p>
<p class="date">Today is ${getCurrentDate()}</p>
</div>
`;
// Show and start snow animation
const canvas = document.getElementById('snowCanvas');
canvas.style.display = 'block';
initSnowAnimation(canvas);
}
/**
* Initialize the application
*/
function init() {
// Hide loading, show content
document.getElementById('loading').style.display = 'none';
document.getElementById('content').style.display = 'block';
// Check if it's Christmas
const christmas = isChristmas();
// Render appropriate UI
if (christmas) {
renderChristmas();
} else {
renderNonChristmas();
}
// Setup midnight transition checker
setupMidnightChecker();
}
/**
* Check for midnight transitions to update the display
*/
function setupMidnightChecker() {
setInterval(() => {
const now = new Date();
// If we're within 1 second of midnight, reload
if (now.getHours() === 0 && now.getMinutes() === 0 && now.getSeconds() === 0) {
location.reload();
}
}, 1000);
}
/**
* Snow Animation System
*/
let snowParticles = [];
let animationFrameId = null;
let canvas = null;
let ctx = null;
/**
* Initialize snow animation
*/
function initSnowAnimation(canvasElement) {
canvas = canvasElement;
ctx = canvas.getContext('2d');
// Set canvas size to window size
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Check for reduced motion preference
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
console.log('Snow animation disabled due to prefers-reduced-motion');
return;
}
// Create snow particles
createSnowParticles();
// Start animation loop
animateSnow();
// Pause animation when page is hidden
document.addEventListener('visibilitychange', handleVisibilityChange);
}
/**
* Resize canvas to match window size
*/
function resizeCanvas() {
if (!canvas) return;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Recreate particles on resize
if (snowParticles.length > 0) {
createSnowParticles();
}
}
/**
* Create snow particles based on screen size
*/
function createSnowParticles() {
snowParticles = [];
// Optimize particle count based on screen size
const isMobile = window.innerWidth < 768;
const particleCount = isMobile ? 75 : 150;
for (let i = 0; i < particleCount; i++) {
snowParticles.push(createSnowParticle());
}
}
/**
* Create a single snow particle
*/
function createSnowParticle() {
return {
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
radius: Math.random() * 3 + 1,
speed: Math.random() * 1 + 0.5,
wobble: Math.random() * 0.5,
wobbleSpeed: Math.random() * 0.02 + 0.01
};
}
/**
* Update snow particle positions
*/
function updateSnowParticles() {
for (let particle of snowParticles) {
// Move particle down
particle.y += particle.speed;
// Add horizontal wobble
particle.x += Math.sin(particle.y * particle.wobbleSpeed) * particle.wobble;
// Reset particle if it falls off screen
if (particle.y > canvas.height) {
particle.y = -10;
particle.x = Math.random() * canvas.width;
}
// Wrap horizontally
if (particle.x > canvas.width) {
particle.x = 0;
} else if (particle.x < 0) {
particle.x = canvas.width;
}
}
}
/**
* Render snow particles
*/
function renderSnowParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
ctx.shadowBlur = 5;
ctx.shadowColor = 'rgba(255, 255, 255, 0.5)';
for (let particle of snowParticles) {
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
ctx.fill();
}
}
/**
* Animation loop
*/
function animateSnow() {
updateSnowParticles();
renderSnowParticles();
animationFrameId = requestAnimationFrame(animateSnow);
}
/**
* Handle page visibility changes
*/
function handleVisibilityChange() {
if (document.hidden && animationFrameId) {
// Pause animation when page is hidden
cancelAnimationFrame(animationFrameId);
animationFrameId = null;
} else if (!document.hidden && canvas && canvas.style.display === 'block' && !animationFrameId) {
// Resume animation when page becomes visible
animateSnow();
}
}
// Run initialization when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}