Files
CodeDevMLH e4b3a132b1
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 45s
Add seasonal effects for Pi Day, Pride, Rain, and Storm; enhance existing styles
- Introduced new CSS and JS files for Pi Day, Pride, Rain, and Storm effects.
- Updated existing seasonal styles (e.g., Halloween, Hearts, Resurrection) to improve performance with 'contain: layout paint'.
- Enhanced animations for seasonal effects, including adjustments to keyframes and element creation logic.
- Added configuration options for new effects in the main seasonals.js file.
- Updated test-site.html to include new seasonal options in the dropdown.
2026-02-23 01:31:52 +01:00

166 lines
5.1 KiB
JavaScript

// 1. Read Configuration
const config = window.SeasonalsPluginConfig?.PiDay || {};
const enabled = config.EnablePiDay !== undefined ? config.EnablePiDay : true;
const maxTrails = config.SymbolCount || 25; // Directly mapped, smaller default
let msgPrinted = false;
let isHidden = false;
// 2. Toggle Function
function togglePiDay() {
const container = document.querySelector('.piday-container');
if (!container) return;
const videoPlayer = document.querySelector('.videoPlayerContainer');
const trailerPlayer = document.querySelector('.youtubePlayerContainer');
const isDashboard = document.body.classList.contains('dashboardDocument');
const hasUserMenu = document.querySelector('#app-user-menu');
if (videoPlayer || trailerPlayer || isDashboard || hasUserMenu) {
if (!isHidden) {
container.style.display = 'none';
isHidden = true;
if (!msgPrinted) {
console.log('PiDay hidden');
msgPrinted = true;
}
}
} else {
if (isHidden) {
container.style.display = 'block';
isHidden = false;
if (msgPrinted) {
console.log('PiDay visible');
msgPrinted = false;
}
}
}
}
// 3. MutationObserver
const observer = new MutationObserver(togglePiDay);
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true
});
// 4. Element Creation
function createElements() {
const container = document.querySelector('.piday-container') || document.createElement('div');
if (!document.querySelector('.piday-container')) {
container.className = 'piday-container';
container.setAttribute('aria-hidden', 'true');
document.body.appendChild(container);
}
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.display = 'block';
container.appendChild(canvas);
const ctx = canvas.getContext('2d');
// const chars = '0123456789πABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const chars = '0123456789'.split('');
const fontSize = 18;
class Trail {
constructor() {
this.reset();
this.y = Math.random() * -100; // Allow initial staggered start
}
reset() {
const cols = Math.floor(canvas.width / fontSize);
this.x = Math.floor(Math.random() * cols);
this.y = -Math.round(Math.random() * 20);
this.speed = 0.5 + Math.random() * 0.5;
this.len = 10 + Math.floor(Math.random() * 20);
this.chars = [];
for(let i=0; i<this.len; i++) {
this.chars.push(chars[Math.floor(Math.random() * chars.length)]);
}
}
update() {
const oldY = Math.floor(this.y);
this.y += this.speed;
const newY = Math.floor(this.y);
// If crossed a full vertical unit, push a new character and pop the old one to preserve screen positions
if (newY > oldY) {
this.chars.unshift(chars[Math.floor(Math.random() * chars.length)]);
this.chars.pop();
}
// Randomly mutate some characters (heads mutate faster)
for (let i = 0; i < this.len; i++) {
const chance = i < 3 ? 0.90 : 0.98;
if (Math.random() > chance) {
this.chars[i] = chars[Math.floor(Math.random() * chars.length)];
}
}
if (this.y - this.len > Math.ceil(canvas.height / fontSize)) {
this.reset();
}
}
draw(ctx) {
const headY = Math.floor(this.y);
for (let i = 0; i < this.len; i++) {
const charY = headY - i;
if (charY < 0 || charY * fontSize > canvas.height + fontSize) continue;
const ratio = i / this.len;
const alpha = 1 - ratio;
if (i === 0) {
ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
ctx.shadowBlur = 8;
ctx.shadowColor = '#0F0';
} else if (i === 1) {
ctx.fillStyle = `rgba(150, 255, 150, ${alpha})`;
ctx.shadowBlur = 4;
ctx.shadowColor = '#0F0';
} else {
ctx.fillStyle = `rgba(0, 255, 0, ${alpha * 0.8})`;
ctx.shadowBlur = 0;
}
ctx.fillText(this.chars[i], this.x * fontSize + fontSize/2, charY * fontSize);
}
}
}
const trails = [];
for(let i=0; i<maxTrails; i++) trails.push(new Trail());
function loop() {
if (isHidden) return; // Pause drawing when hidden
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = 'bold ' + fontSize + 'px monospace';
ctx.textAlign = 'center';
for (const t of trails) {
t.update();
t.draw(ctx);
}
}
if (window.pidayInterval) clearInterval(window.pidayInterval);
window.pidayInterval = setInterval(loop, 50);
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
}
// 5. Initialization
function initializePiDay() {
if (!enabled) return;
createElements();
togglePiDay();
}
initializePiDay();