Add Mario Day feature: implement CSS and JS for Mario animations and visibility toggle
This commit is contained in:
BIN
Jellyfin.Plugin.Seasonals/Web/mario_assets/mario.gif
Normal file
BIN
Jellyfin.Plugin.Seasonals/Web/mario_assets/mario.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
77
Jellyfin.Plugin.Seasonals/Web/marioday.css
Normal file
77
Jellyfin.Plugin.Seasonals/Web/marioday.css
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
.marioday-container {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10000;
|
||||||
|
contain: strict;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mario-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
left: -100px;
|
||||||
|
animation: mario-run 15s linear infinite;
|
||||||
|
will-change: left, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mario-runner {
|
||||||
|
width: 64px;
|
||||||
|
height: auto;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
display: block;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mario-jump {
|
||||||
|
animation: jump-arc 0.8s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8-bit coin styling */
|
||||||
|
.mario-coin {
|
||||||
|
position: absolute;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: #ffd700;
|
||||||
|
border: 4px solid #b8860b;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: inset 4px 4px 0 #fffbea, inset -4px -4px 0 #daa520;
|
||||||
|
animation: pop-up-arc 2s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mario-coin::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
left: 10px;
|
||||||
|
width: 4px;
|
||||||
|
height: 12px;
|
||||||
|
background: #daa520;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mario-run {
|
||||||
|
0% { left: -100px; transform: scaleX(1); }
|
||||||
|
45% { left: 110vw; transform: scaleX(1); }
|
||||||
|
50% { left: 110vw; transform: scaleX(-1); }
|
||||||
|
95% { left: -100px; transform: scaleX(-1); }
|
||||||
|
100% { left: -100px; transform: scaleX(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop-up-arc {
|
||||||
|
0% { transform: translateY(0) rotateY(0deg); opacity: 0; animation-timing-function: ease-out; }
|
||||||
|
20% { opacity: 1; }
|
||||||
|
50% { transform: translateY(-30vh) rotateY(360deg); opacity: 1; animation-timing-function: ease-in; }
|
||||||
|
90% { opacity: 1; }
|
||||||
|
100% { transform: translateY(20vh) rotateY(720deg); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes jump-arc {
|
||||||
|
0% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-25vh); }
|
||||||
|
100% { transform: translateY(0); }
|
||||||
|
}
|
||||||
82
Jellyfin.Plugin.Seasonals/Web/marioday.js
Normal file
82
Jellyfin.Plugin.Seasonals/Web/marioday.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
const config = window.SeasonalsPluginConfig?.MarioDay || {};
|
||||||
|
const marioday = config.EnableMarioDay !== undefined ? config.EnableMarioDay : true;
|
||||||
|
|
||||||
|
let msgPrinted = false;
|
||||||
|
|
||||||
|
function toggleMarioDay() {
|
||||||
|
const container = document.querySelector('.marioday-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) {
|
||||||
|
container.style.display = 'none';
|
||||||
|
if (!msgPrinted) {
|
||||||
|
console.log('MarioDay hidden');
|
||||||
|
msgPrinted = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container.style.display = 'block';
|
||||||
|
if (msgPrinted) {
|
||||||
|
console.log('MarioDay visible');
|
||||||
|
msgPrinted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = new MutationObserver(toggleMarioDay);
|
||||||
|
observer.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
attributes: true
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function createMarioDay(container) {
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'mario-wrapper';
|
||||||
|
|
||||||
|
const mario = document.createElement('img');
|
||||||
|
mario.className = 'mario-runner';
|
||||||
|
mario.src = '../Seasonals/Resources/mario_assets/mario.gif';
|
||||||
|
|
||||||
|
wrapper.appendChild(mario);
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
// Periodically throw out an 8-bit coin
|
||||||
|
setInterval(() => {
|
||||||
|
if (!document.querySelector('.marioday-container')) return;
|
||||||
|
const coin = document.createElement('div');
|
||||||
|
coin.className = 'mario-coin';
|
||||||
|
|
||||||
|
// Grab Mario's current screen position to lock the coin's X coordinate
|
||||||
|
const marioRect = wrapper.getBoundingClientRect();
|
||||||
|
coin.style.left = `${marioRect.left + 16}px`;
|
||||||
|
coin.style.bottom = '35px'; // Adjust for wrapper's bottom offset
|
||||||
|
|
||||||
|
container.appendChild(coin);
|
||||||
|
setTimeout(() => coin.remove(), 2000);
|
||||||
|
|
||||||
|
}, 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function initializeMarioDay() {
|
||||||
|
if (!marioday) return;
|
||||||
|
|
||||||
|
const container = document.querySelector('.marioday-container') || document.createElement("div");
|
||||||
|
|
||||||
|
if (!document.querySelector('.marioday-container')) {
|
||||||
|
container.className = "marioday-container";
|
||||||
|
container.setAttribute("aria-hidden", "true");
|
||||||
|
document.body.appendChild(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
createMarioDay(container);
|
||||||
|
toggleMarioDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeMarioDay();
|
||||||
Reference in New Issue
Block a user