mirror of
https://github.com/jlengrand/is-it-christmas.git
synced 2026-03-10 00:11:19 +00:00
246 lines
6.2 KiB
JavaScript
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();
|
|
}
|