Add Oktoberfest feature: implement CSS and JS for Oktoberfest animations and visibility control
This commit is contained in:
33
Jellyfin.Plugin.Seasonals/Web/oktoberfest.css
Normal file
33
Jellyfin.Plugin.Seasonals/Web/oktoberfest.css
Normal file
@@ -0,0 +1,33 @@
|
||||
.oktoberfest-container {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
contain: strict;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.oktoberfest-symbol {
|
||||
position: absolute;
|
||||
top: -10%;
|
||||
font-size: 2.2em;
|
||||
user-select: none;
|
||||
animation-name: oktoberfest-fall, oktoberfest-sway;
|
||||
animation-timing-function: linear, ease-in-out;
|
||||
animation-iteration-count: infinite, infinite;
|
||||
}
|
||||
|
||||
@keyframes oktoberfest-fall {
|
||||
0% { transform: translateY(0); opacity: 0; }
|
||||
10% { opacity: 1; }
|
||||
100% { transform: translateY(120vh); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes oktoberfest-sway {
|
||||
0%, 100% { margin-left: 0; }
|
||||
50% { margin-left: 50px; }
|
||||
}
|
||||
67
Jellyfin.Plugin.Seasonals/Web/oktoberfest.js
Normal file
67
Jellyfin.Plugin.Seasonals/Web/oktoberfest.js
Normal file
@@ -0,0 +1,67 @@
|
||||
const config = window.SeasonalsPluginConfig?.Oktoberfest || {};
|
||||
const oktoberfest = config.EnableOktoberfest !== undefined ? config.EnableOktoberfest : true;
|
||||
|
||||
const oktoberfestSymbols = ['🥨', '🍺', '🍻', '🥨', '🥨'];
|
||||
|
||||
let msgPrinted = false;
|
||||
|
||||
// function to check and control the oktoberfest
|
||||
function toggleOktoberfest() {
|
||||
const oktoberfestContainer = document.querySelector('.oktoberfest-container');
|
||||
if (!oktoberfestContainer) 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');
|
||||
|
||||
// hide oktoberfest if video/trailer player is active or dashboard is visible
|
||||
if (videoPlayer || trailerPlayer || isDashboard || hasUserMenu) {
|
||||
oktoberfestContainer.style.display = 'none'; // hide oktoberfest
|
||||
if (!msgPrinted) {
|
||||
console.log('Oktoberfest hidden');
|
||||
msgPrinted = true;
|
||||
}
|
||||
} else {
|
||||
oktoberfestContainer.style.display = 'block'; // show oktoberfest
|
||||
if (msgPrinted) {
|
||||
console.log('Oktoberfest visible');
|
||||
msgPrinted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// observe changes in the DOM
|
||||
const observer = new MutationObserver(toggleOktoberfest);
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true
|
||||
});
|
||||
|
||||
function createOktoberfest(container) {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const symbol = document.createElement('div');
|
||||
symbol.className = 'oktoberfest-symbol';
|
||||
symbol.textContent = oktoberfestSymbols[Math.floor(Math.random() * oktoberfestSymbols.length)];
|
||||
symbol.style.left = `${Math.random() * 100}%`;
|
||||
symbol.style.animationDelay = `${Math.random() * 10}s, ${Math.random() * 5}s`;
|
||||
const duration1 = Math.random() * 5 + 8;
|
||||
const duration2 = Math.random() * 3 + 3;
|
||||
symbol.style.animationDuration = `${duration1}s, ${duration2}s`;
|
||||
|
||||
container.appendChild(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeOktoberfest() {
|
||||
if (!oktoberfest) return;
|
||||
const container = document.querySelector('.oktoberfest-container') || document.createElement("div");
|
||||
if (!document.querySelector('.oktoberfest-container')) {
|
||||
container.className = "oktoberfest-container";
|
||||
container.setAttribute("aria-hidden", "true");
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
createOktoberfest(container);
|
||||
}
|
||||
initializeOktoberfest();
|
||||
Reference in New Issue
Block a user