Compare commits

...

19 Commits

Author SHA1 Message Date
CodeDevMLH
0a301564ac Update manifest.json for release v2.0.0.4 [skip ci] 2026-02-28 02:11:13 +00:00
CodeDevMLH
85e69a0b34 Bump version to 2.0.0.4
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-28 03:10:22 +01:00
CodeDevMLH
5adaf202ae Refactor seasonal configuration: remove unused input fields and add Oktoberfest options 2026-02-28 03:10:05 +01:00
CodeDevMLH
99ac46a384 Update manifest.json for release v2.0.0.3 [skip ci] 2026-02-28 01:30:55 +00:00
CodeDevMLH
3a2750388b Bump version to 2.0.0.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-28 02:30:04 +01:00
CodeDevMLH
33e89ec16b Enhance seasonal options in configuration: add new seasons and improve descriptions 2026-02-28 02:29:41 +01:00
CodeDevMLH
9adbe92e7c Update manifest.json for release v2.0.0.2 [skip ci] 2026-02-28 00:56:16 +00:00
CodeDevMLH
103d63f1b1 Bump version to 2.0.0.2 in project and manifest files
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-28 01:55:24 +01:00
CodeDevMLH
49bad2e880 updated to latest settings 2026-02-28 01:55:05 +01:00
CodeDevMLH
04616c2ac4 Fix HeartSize property type in PrideOptions to double for improved precision 2026-02-28 01:54:19 +01:00
CodeDevMLH
3b73dd1728 Add comments for birthday image source and modification details [skip ci] 2026-02-28 01:40:16 +01:00
CodeDevMLH
d5df90a6ae Refactor animation delays in seasonal effects for improved performance and consistency [skip ci] 2026-02-28 01:29:49 +01:00
CodeDevMLH
494e475f42 Refactor snowflakes.js and snowflakes.css to streamline snowflake initialization and enhance mobile responsiveness 2026-02-28 01:22:18 +01:00
CodeDevMLH
4703ba48ed Refactor santa.js to improve mobile detection for snowflake count adjustment 2026-02-28 01:21:37 +01:00
CodeDevMLH
93d5686b77 Refactor resurrection.js to remove random symbol functionality and adjust symbol count initialization for mobile responsiveness 2026-02-28 01:21:33 +01:00
CodeDevMLH
71d07aa0f3 Refactor halloween.js and halloween.css to streamline symbol initialization and remove random symbol functionality 2026-02-28 01:20:02 +01:00
CodeDevMLH
c43f031617 Refactor autumn configuration to enhance leaf count settings for mobile and desktop 2026-02-28 01:19:09 +01:00
CodeDevMLH
89ce903e8a Refactor seasonal scripts to enhance mobile detection using matchMedia for responsive behavior 2026-02-28 01:16:01 +01:00
CodeDevMLH
cbf5d73629 Refactor autumn.js and autumn.css to streamline leaf initialization and enhance configuration handling 2026-02-28 01:15:03 +01:00
24 changed files with 593 additions and 1208 deletions

View File

@@ -120,10 +120,9 @@ public class PluginConfiguration : BasePluginConfiguration
} }
public class AutumnOptions { public class AutumnOptions {
public int LeafCount { get; set; } = 25;
public bool EnableAutumn { get; set; } = true; public bool EnableAutumn { get; set; } = true;
public bool EnableRandomLeaves { get; set; } = true; public int LeafCount { get; set; } = 35;
public bool EnableRandomLeavesMobile { get; set; } = false; public int LeafCountMobile { get; set; } = 10;
public bool EnableDifferentDuration { get; set; } = true; public bool EnableDifferentDuration { get; set; } = true;
public bool EnableRotation { get; set; } = false; public bool EnableRotation { get; set; } = false;
} }
@@ -153,10 +152,9 @@ public class CherryBlossomOptions {
public class ChristmasOptions { public class ChristmasOptions {
public bool EnableChristmas { get; set; } = true; public bool EnableChristmas { get; set; } = true;
public bool EnableRandomChristmas { get; set; } = true;
public bool EnableRandomChristmasMobile { get; set; } = false;
public bool EnableDifferentDuration { get; set; } = true;
public int SymbolCount { get; set; } = 25; public int SymbolCount { get; set; } = 25;
public int SymbolCountMobile { get; set; } = 10;
public bool EnableDifferentDuration { get; set; } = true;
} }
public class EarthDayOptions { public class EarthDayOptions {
@@ -210,20 +208,18 @@ public class FrostOptions {
public class HalloweenOptions { public class HalloweenOptions {
public bool EnableHalloween { get; set; } = true; public bool EnableHalloween { get; set; } = true;
public bool EnableRandomSymbols { get; set; } = true; public int SymbolCount { get; set; } = 25;
public bool EnableRandomSymbolsMobile { get; set; } = false; public int SymbolCountMobile { get; set; } = 10;
public bool EnableDifferentDuration { get; set; } = true; public bool EnableDifferentDuration { get; set; } = true;
public bool EnableSpiders { get; set; } = true; public bool EnableSpiders { get; set; } = true;
public bool EnableMice { get; set; } = true; public bool EnableMice { get; set; } = true;
public int SymbolCount { get; set; } = 25;
} }
public class HeartsOptions { public class HeartsOptions {
public bool EnableHearts { get; set; } = true; public bool EnableHearts { get; set; } = true;
public bool EnableRandomSymbols { get; set; } = true;
public bool EnableRandomSymbolsMobile { get; set; } = false;
public bool EnableDifferentDuration { get; set; } = true;
public int SymbolCount { get; set; } = 25; public int SymbolCount { get; set; } = 25;
public int SymbolCountMobile { get; set; } = 10;
public bool EnableDifferentDuration { get; set; } = true;
} }
public class MarioDayOptions { public class MarioDayOptions {
@@ -259,7 +255,7 @@ public class OscarOptions {
public class PrideOptions { public class PrideOptions {
public bool EnablePride { get; set; } = true; public bool EnablePride { get; set; } = true;
public int HeartCount { get; set; } = 20; public int HeartCount { get; set; } = 20;
public int HeartSize { get; set; } = 1.5; public double HeartSize { get; set; } = 1.5;
public bool ColorHeader { get; set; } = true; public bool ColorHeader { get; set; } = true;
} }
@@ -272,10 +268,9 @@ public class RainOptions {
public class ResurrectionOptions { public class ResurrectionOptions {
public bool EnableResurrection { get; set; } = true; public bool EnableResurrection { get; set; } = true;
public bool EnableRandomSymbols { get; set; } = true;
public bool EnableRandomSymbolsMobile { get; set; } = false;
public bool EnableDifferentDuration { get; set; } = true;
public int SymbolCount { get; set; } = 12; public int SymbolCount { get; set; } = 12;
public int SymbolCountMobile { get; set; } = 5;
public bool EnableDifferentDuration { get; set; } = true;
} }
public class SantaOptions { public class SantaOptions {
@@ -301,8 +296,7 @@ public class SnowfallOptions {
public class SnowflakesOptions { public class SnowflakesOptions {
public bool EnableSnowflakes { get; set; } = true; public bool EnableSnowflakes { get; set; } = true;
public int SnowflakeCount { get; set; } = 25; public int SnowflakeCount { get; set; } = 25;
public bool EnableRandomSnowflakes { get; set; } = true; public int SnowflakeCountMobile { get; set; } = 10;
public bool EnableRandomSnowflakesMobile { get; set; } = false;
public bool EnableColoredSnowflakes { get; set; } = true; public bool EnableColoredSnowflakes { get; set; } = true;
public bool EnableDifferentDuration { get; set; } = true; public bool EnableDifferentDuration { get; set; } = true;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> --> <!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
<Title>Jellyfin Seasonals Plugin</Title> <Title>Jellyfin Seasonals Plugin</Title>
<Authors>CodeDevMLH</Authors> <Authors>CodeDevMLH</Authors>
<Version>2.0.0.1</Version> <Version>2.0.0.4</Version>
<RepositoryUrl>https://github.com/CodeDevMLH/Jellyfin-Seasonals</RepositoryUrl> <RepositoryUrl>https://github.com/CodeDevMLH/Jellyfin-Seasonals</RepositoryUrl>
</PropertyGroup> </PropertyGroup>

View File

@@ -1,139 +1,57 @@
.autumn-container { .autumn-container {
display: block; display: block;
position: fixed; position: fixed;
overflow: hidden; overflow: hidden;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
contain: layout paint; contain: layout paint;
} }
.leaf { .leaf {
position: fixed; position: fixed;
z-index: 15; z-index: 15;
top: 0; top: 0;
will-change: transform; will-change: transform;
translate: 0 -10vh; translate: 0 -10vh;
font-size: 1em; font-size: 1em;
color: #fff; color: #fff;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
text-shadow: 0 0 5px #000; text-shadow: 0 0 5px #000;
user-select: none; user-select: none;
cursor: default; cursor: default;
animation-name: leaf-fall, leaf-shake; animation-name: leaf-fall, leaf-shake;
animation-duration: 7s, 4s; animation-duration: 7s, 4s;
animation-timing-function: linear, ease-in-out; animation-timing-function: linear, ease-in-out;
animation-iteration-count: infinite, infinite; animation-iteration-count: infinite, infinite;
} }
/* Class to disable rotation */ /* Class to disable rotation */
.no-rotation { .no-rotation {
--rotate-start: 0deg !important; --rotate-start: 0deg !important;
--rotate-end: 0deg !important; --rotate-end: 0deg !important;
} }
@keyframes leaf-fall { @keyframes leaf-fall {
0% { 0% {
translate: 0 -10vh; translate: 0 -10vh;
} }
100% { 100% {
translate: 0 100vh; translate: 0 100vh;
} }
} }
@keyframes leaf-shake { @keyframes leaf-shake {
0%, 100% { 0%, 100% {
transform: translateX(0) rotate(var(--rotate-start, -20deg)); transform: translateX(0) rotate(var(--rotate-start, -20deg));
} }
50% { 50% {
transform: translateX(80px) rotate(var(--rotate-end, 20deg)); transform: translateX(80px) rotate(var(--rotate-end, 20deg));
} }
} }
.leaf:nth-of-type(0) {
left: 0%;
animation-delay: 0s, 0s;
--rotate-start: -25deg;
--rotate-end: 22deg;
}
.leaf:nth-of-type(1) {
left: 10%;
animation-delay: 1s, 0.5s;
--rotate-start: -32deg;
--rotate-end: 35deg;
}
.leaf:nth-of-type(2) {
left: 20%;
animation-delay: 6s, 1s;
--rotate-start: -28deg;
--rotate-end: 28deg;
}
.leaf:nth-of-type(3) {
left: 30%;
animation-delay: 4s, 1.5s;
--rotate-start: -38deg;
--rotate-end: 32deg;
}
.leaf:nth-of-type(4) {
left: 40%;
animation-delay: 2s, 0.8s;
--rotate-start: -22deg;
--rotate-end: 38deg;
}
.leaf:nth-of-type(5) {
left: 50%;
animation-delay: 8s, 2s;
--rotate-start: -35deg;
--rotate-end: 25deg;
}
.leaf:nth-of-type(6) {
left: 60%;
animation-delay: 6s, 1.2s;
--rotate-start: -40deg;
--rotate-end: 40deg;
}
.leaf:nth-of-type(7) {
left: 70%;
animation-delay: 2.5s, 0.3s;
--rotate-start: -30deg;
--rotate-end: 30deg;
}
.leaf:nth-of-type(8) {
left: 80%;
animation-delay: 1s, 1.8s;
--rotate-start: -26deg;
--rotate-end: 36deg;
}
.leaf:nth-of-type(9) {
left: 90%;
animation-delay: 3s, 0.7s;
--rotate-start: -34deg;
--rotate-end: 24deg;
}
.leaf:nth-of-type(10) {
left: 25%;
animation-delay: 2s, 2.3s;
--rotate-start: -29deg;
--rotate-end: 33deg;
}
.leaf:nth-of-type(11) {
left: 65%;
animation-delay: 4s, 1.4s;
--rotate-start: -37deg;

View File

@@ -1,11 +1,10 @@
const config = window.SeasonalsPluginConfig?.Autumn || {}; const config = window.SeasonalsPluginConfig?.Autumn || {};
const leaves = config.EnableAutumn !== undefined ? config.EnableAutumn : true; // enable/disable autumn const leaves = config.EnableAutumn !== undefined ? config.EnableAutumn : true; // enable/disable autumn
const randomLeaves = config.EnableRandomLeaves !== undefined ? config.EnableRandomLeaves : true; // enable random leaves
const randomLeavesMobile = config.EnableRandomLeavesMobile !== undefined ? config.EnableRandomLeavesMobile : false; // enable random leaves on mobile
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
const enableRotation = config.EnableRotation !== undefined ? config.EnableRotation : false; // enable/disable rotation const enableRotation = config.EnableRotation !== undefined ? config.EnableRotation : false; // enable/disable rotation
const leafCount = config.LeafCount !== undefined ? config.LeafCount : 25; // count of random extra leaves const leafCount = config.LeafCount !== undefined ? config.LeafCount : 35; // count of random extra leaves
const leafCountMobile = config.LeafCountMobile !== undefined ? config.LeafCountMobile : 10; // count of random extra leaves on mobile
const images = [ const images = [
"../Seasonals/Resources/autumn_images/acorn1.png", "../Seasonals/Resources/autumn_images/acorn1.png",
@@ -64,11 +63,16 @@ observer.observe(document.body, {
}); });
function addRandomLeaves(count) { function initLeaves(count) {
const autumnContainer = document.querySelector('.autumn-container'); // get the leave container let autumnContainer = document.querySelector('.autumn-container'); // get the leave container
if (!autumnContainer) return; // exit if leave container is not found if (!autumnContainer) {
autumnContainer = document.createElement("div");
autumnContainer.className = "autumn-container";
autumnContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(autumnContainer);
}
console.log('Adding random leaves'); console.log('Adding leaves');
// Array of leave characters // Array of leave characters
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
@@ -87,6 +91,8 @@ function addRandomLeaves(count) {
// set random horizontal position, animation delay and size(uncomment lines to enable) // set random horizontal position, animation delay and size(uncomment lines to enable)
const randomLeft = Math.random() * 100; // position (0% to 100%) const randomLeft = Math.random() * 100; // position (0% to 100%)
const randomAnimationDelay = Math.random() * 12; // delay for fall (0s to 12s) const randomAnimationDelay = Math.random() * 12; // delay for fall (0s to 12s)
// Display directly symbols on full screen (below) or let it build up (above)
// const randomAnimationDelay = -(Math.random() * 16); // delay for fall (-16s to 0s)
const randomAnimationDelay2 = -(Math.random() * 4); // delay for shake+rotate (-4s to 0s) const randomAnimationDelay2 = -(Math.random() * 4); // delay for shake+rotate (-4s to 0s)
// apply styles // apply styles
@@ -115,60 +121,18 @@ function addRandomLeaves(count) {
// add the leave to the container // add the leave to the container
autumnContainer.appendChild(leaveDiv); autumnContainer.appendChild(leaveDiv);
} }
console.log('Random leaves added'); console.log('Leaves added');
} }
// initialize standard leaves // initialize leaves
function initLeaves() {
const container = document.querySelector('.autumn-container') || document.createElement("div");
if (!document.querySelector('.autumn-container')) {
container.className = "autumn-container";
container.setAttribute("aria-hidden", "true");
document.body.appendChild(container);
}
for (let i = 0; i < 12; i++) {
const leafDiv = document.createElement("div");
leafDiv.className = enableRotation ? "leaf" : "leaf no-rotation";
const img = document.createElement("img");
img.src = images[Math.floor(Math.random() * images.length)];
// set random animation duration
if (enableDiffrentDuration) {
const randomAnimationDuration = Math.random() * 10 + 6; // fall duration (6s to 16s)
const randomAnimationDuration2 = Math.random() * 3 + 2; // shake+rotate duration (2s to 5s)
leafDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
}
// set random rotation angles for standard leaves too (only if rotation is enabled)
if (enableRotation) {
const randomRotateStart = -(Math.random() * 40 + 20); // -20deg to -60deg
const randomRotateEnd = Math.random() * 40 + 20; // 20deg to 60deg
leafDiv.style.setProperty('--rotate-start', `${randomRotateStart}deg`);
leafDiv.style.setProperty('--rotate-end', `${randomRotateEnd}deg`);
} else {
// No rotation - set to 0 degrees
leafDiv.style.setProperty('--rotate-start', '0deg');
leafDiv.style.setProperty('--rotate-end', '0deg');
}
leafDiv.appendChild(img);
container.appendChild(leafDiv);
}
}
// initialize leaves and add random leaves
function initializeLeaves() { function initializeLeaves() {
if (!leaves) return; // exit if leaves are disabled if (!leaves) return; // exit if leaves are disabled
initLeaves();
toggleAutumn();
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
if (randomLeaves && (screenWidth > 768 || randomLeavesMobile)) { // add random leaves only on larger screens, unless enabled for mobile devices const count = !isMobile ? leafCount : leafCountMobile;
addRandomLeaves(leafCount);
} initLeaves(count);
toggleAutumn();
} }
initializeLeaves(); initializeLeaves();

View File

@@ -6,6 +6,10 @@ const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? c
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 5; // count of mobile balloons const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 5; // count of mobile balloons
const baseConfettiCount = config.ConfettiCount !== undefined ? config.ConfettiCount : 60; // count of confetti const baseConfettiCount = config.ConfettiCount !== undefined ? config.ConfettiCount : 60; // count of confetti
/**
* Base ballon image: https://www.flaticon.com/de/kostenloses-icon/ballon_1512470
* modified by CodeDevMLH
*/
const birthdayImages = [ const birthdayImages = [
'../Seasonals/Resources/birthday_assets/balloon_blue.gif', '../Seasonals/Resources/birthday_assets/balloon_blue.gif',
'../Seasonals/Resources/birthday_assets/balloon_green.gif', '../Seasonals/Resources/birthday_assets/balloon_green.gif',

View File

@@ -167,8 +167,8 @@ function initCarnivalObjects(count) {
function initializeCarnival() { function initializeCarnival() {
if (!carnival) return; if (!carnival) return;
const screenWidth = window.innerWidth; const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const count = screenWidth > 768 ? carnivalCount : carnivalCountMobile; const count = !isMobile ? carnivalCount : carnivalCountMobile;
initCarnivalObjects(count); initCarnivalObjects(count);
toggleCarnival(); toggleCarnival();

View File

@@ -84,8 +84,8 @@ function initObjects(count) {
function initializeCherryBlossom() { function initializeCherryBlossom() {
if (!cherryBlossom) return; if (!cherryBlossom) return;
const screenWidth = window.innerWidth; const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const count = screenWidth > 768 ? petalCount : petalCountMobile; const count = !isMobile ? petalCount : petalCountMobile;
initObjects(count); initObjects(count);
toggleCherryBlossom(); toggleCherryBlossom();

View File

@@ -1,112 +1,53 @@
.christmas-container { .christmas-container {
display: block; display: block;
position: fixed; position: fixed;
overflow: hidden; overflow: hidden;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
contain: layout paint; contain: layout paint;
} }
.christmas { .christmas {
position: fixed; position: fixed;
z-index: 15; z-index: 15;
top: 0; top: 0;
will-change: transform; will-change: transform;
translate: 0 -10vh; translate: 0 -10vh;
font-size: 1em; font-size: 1em;
color: #fff; color: #fff;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
text-shadow: 0 0 5px #000; text-shadow: 0 0 5px #000;
user-select: none; user-select: none;
cursor: default; cursor: default;
animation-name: christmas-fall, christmas-shake; animation-name: christmas-fall, christmas-shake;
animation-duration: 10s, 3s; animation-duration: 10s, 3s;
animation-timing-function: linear, ease-in-out; animation-timing-function: linear, ease-in-out;
animation-iteration-count: infinite, infinite; animation-iteration-count: infinite, infinite;
} }
@keyframes christmas-fall { @keyframes christmas-fall {
0% { 0% {
translate: 0 -10vh; translate: 0 -10vh;
} }
100% { 100% {
translate: 0 110vh; translate: 0 110vh;
} }
} }
@keyframes christmas-shake { @keyframes christmas-shake {
0%, 0%,
100% { 100% {
transform: translateX(0); transform: translateX(0);
} }
50% { 50% {
transform: translateX(80px); transform: translateX(80px);
} }
}
.christmas:nth-of-type(0) {
left: 0%;
animation-delay: 0s, 0s;
}
.christmas:nth-of-type(1) {
left: 10%;
animation-delay: 1s, 1s;
}
.christmas:nth-of-type(2) {
left: 20%;
animation-delay: 6s, 0.5s;
}
.christmas:nth-of-type(3) {
left: 30%;
animation-delay: 4s, 2s;
}
.christmas:nth-of-type(4) {
left: 40%;
animation-delay: 2s, 2s;
}
.christmas:nth-of-type(5) {
left: 50%;
animation-delay: 8s, 3s;
}
.christmas:nth-of-type(6) {
left: 60%;
animation-delay: 6s, 2s;
}
.christmas:nth-of-type(7) {
left: 70%;
animation-delay: 2.5s, 1s;
}
.christmas:nth-of-type(8) {
left: 80%;
animation-delay: 1s, 0s;
}
.christmas:nth-of-type(9) {
left: 90%;
animation-delay: 3s, 1.5s;
}
.christmas:nth-of-type(10) {
left: 25%;
animation-delay: 2s, 0s;
}
.christmas:nth-of-type(11) {
left: 65%;
} }

View File

@@ -1,10 +1,9 @@
const config = window.SeasonalsPluginConfig?.Christmas || {}; const config = window.SeasonalsPluginConfig?.Christmas || {};
const christmas = config.EnableChristmas !== undefined ? config.EnableChristmas : true; // enable/disable christmas const christmas = config.EnableChristmas !== undefined ? config.EnableChristmas : true; // enable/disable christmas
const randomChristmas = config.EnableRandomChristmas !== undefined ? config.EnableRandomChristmas : true; // enable random christmas
const randomChristmasMobile = config.EnableRandomChristmasMobile !== undefined ? config.EnableRandomChristmasMobile : false; // enable random christmas on mobile
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
const christmasCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbol const christmasCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbol
const christmasCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbol on mobile
// Array of christmas characters // Array of christmas characters
const christmasSymbols = ['❆', '🎁', '❄️', '🎁', '🎅', '🎊', '🎁', '🎉']; const christmasSymbols = ['❆', '🎁', '❄️', '🎁', '🎅', '🎊', '🎁', '🎉'];
@@ -45,11 +44,16 @@ observer.observe(document.body, {
attributes: true attributes: true
}); });
function addRandomChristmas(count) { function initChristmas(count) {
const christmasContainer = document.querySelector('.christmas-container'); // get the christmas container let christmasContainer = document.querySelector('.christmas-container'); // get the christmas container
if (!christmasContainer) return; // exit if christmas container is not found if (!christmasContainer) {
christmasContainer = document.createElement("div");
christmasContainer.className = "christmas-container";
christmasContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(christmasContainer);
}
console.log('Adding random christmas'); console.log('Adding christmas');
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
// create a new christmas element // create a new christmas element
@@ -61,8 +65,8 @@ function addRandomChristmas(count) {
// set random horizontal position, animation delay and size(uncomment lines to enable) // set random horizontal position, animation delay and size(uncomment lines to enable)
const randomLeft = Math.random() * 100; // position (0% to 100%) const randomLeft = Math.random() * 100; // position (0% to 100%)
const randomAnimationDelay = Math.random() * 12 + 8; // delay (8s to 12s) const randomAnimationDelay = -(Math.random() * 16); // delay (-16s to 0s)
const randomAnimationDelay2 = Math.random() * 5 + 3; // delay (0s to 5s) const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
// apply styles // apply styles
christmasDiv.style.left = `${randomLeft}%`; christmasDiv.style.left = `${randomLeft}%`;
@@ -78,46 +82,18 @@ function addRandomChristmas(count) {
// add the christmas to the container // add the christmas to the container
christmasContainer.appendChild(christmasDiv); christmasContainer.appendChild(christmasDiv);
} }
console.log('Random christmas added'); console.log('Christmas added');
} }
// initialize standard christmas // initialize christmas
function initChristmas() {
const christmasContainer = document.querySelector('.christmas-container') || document.createElement("div");
if (!document.querySelector('.christmas-container')) {
christmasContainer.className = "christmas-container";
christmasContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(christmasContainer);
}
// create the 12 standard christmas
for (let i = 0; i < 12; i++) {
const christmasDiv = document.createElement('div');
christmasDiv.className = 'christmas';
christmasDiv.textContent = christmasSymbols[Math.floor(Math.random() * christmasSymbols.length)];
// set random animation duration
if (enableDiffrentDuration) {
const randomAnimationDuration = Math.random() * 10 + 6; // delay (6s to 10s)
const randomAnimationDuration2 = Math.random() * 5 + 2; // delay (2s to 5s)
christmasDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
}
christmasContainer.appendChild(christmasDiv);
}
}
// initialize christmas and add random christmas symbols
function initializeChristmas() { function initializeChristmas() {
if (!christmas) return; // exit if christmas is disabled if (!christmas) return; // exit if christmas is disabled
initChristmas();
toggleChristmas();
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
if (randomChristmas && (screenWidth > 768 || randomChristmasMobile)) { // add random christmas only on larger screens, unless enabled for mobile devices const count = !isMobile ? christmasCount : christmasCountMobile;
addRandomChristmas(christmasCount);
} initChristmas(count);
toggleChristmas();
} }
initializeChristmas(); initializeChristmas();

View File

@@ -49,66 +49,6 @@
} }
} }
.halloween:nth-of-type(0) {
left: 1%;
animation-delay: 0s, 0s;
}
.halloween:nth-of-type(1) {
left: 10%;
animation-delay: -1s, -1s;
}
.halloween:nth-of-type(2) {
left: 20%;
animation-delay: -2s, -2s;
}
.halloween:nth-of-type(3) {
left: 30%;
animation-delay: -3s, -3s;
}
.halloween:nth-of-type(4) {
left: 40%;
animation-delay: -4s, -4s;
}
.halloween:nth-of-type(5) {
left: 50%;
animation-delay: -5s, -5s;
}
.halloween:nth-of-type(6) {
left: 60%;
animation-delay: -6s, -6s;
}
.halloween:nth-of-type(7) {
left: 70%;
animation-delay: -7s, -7s;
}
.halloween:nth-of-type(8) {
left: 80%;
animation-delay: -8s, -8s;
}
.halloween:nth-of-type(9) {
left: 90%;
animation-delay: -9s, -9s;
}
.halloween:nth-of-type(10) {
left: 25%;
animation-delay: -10s, -10s;
}
.halloween:nth-of-type(11) {
left: 65%;
animation-delay: -11s, -11s;
}
/* --- Fog Layer --- */ /* --- Fog Layer --- */
.halloween-fog-layer { .halloween-fog-layer {
position: absolute; position: absolute;

View File

@@ -1,12 +1,11 @@
const config = window.SeasonalsPluginConfig?.Halloween || {}; const config = window.SeasonalsPluginConfig?.Halloween || {};
const halloween = config.EnableHalloween !== undefined ? config.EnableHalloween : true; // enable/disable halloween const halloween = config.EnableHalloween !== undefined ? config.EnableHalloween : true; // enable/disable halloween
const randomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true; // enable random symbols
const randomSymbolsMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false; // enable random symbols on mobile
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
const enableSpiders = config.EnableSpiders !== undefined ? config.EnableSpiders : true; // enable/disable spiders const enableSpiders = config.EnableSpiders !== undefined ? config.EnableSpiders : true; // enable/disable spiders
const enableMice = config.EnableMice !== undefined ? config.EnableMice : true; // enable/disable mice const enableMice = config.EnableMice !== undefined ? config.EnableMice : true; // enable/disable mice
const halloweenCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbols const halloweenCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbols
const halloweenCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbols on mobile
const images = [ const images = [
"../Seasonals/Resources/halloween_images/ghost_20x20.png", "../Seasonals/Resources/halloween_images/ghost_20x20.png",
@@ -50,12 +49,16 @@ observer.observe(document.body, {
}); });
function addRandomSymbols(count) { function initHalloween(count) {
const halloweenContainer = document.querySelector('.halloween-container'); let halloweenContainer = document.querySelector('.halloween-container');
if (!halloweenContainer) return; if (!halloweenContainer) {
halloweenContainer = document.createElement("div");
console.log('Adding random halloween symbols'); halloweenContainer.className = "halloween-container";
halloweenContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(halloweenContainer);
}
console.log('Adding halloween symbols');
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const halloweenDiv = document.createElement("div"); const halloweenDiv = document.createElement("div");
@@ -69,6 +72,8 @@ function addRandomSymbols(count) {
const randomLeft = Math.random() * 100; // position (0% to 100%) const randomLeft = Math.random() * 100; // position (0% to 100%)
const randomAnimationDelay = Math.random() * 10; // delay (0s to 10s) const randomAnimationDelay = Math.random() * 10; // delay (0s to 10s)
// Display directly symbols on full screen (below) or let it build up (above)
// const randomAnimationDelay = -(Math.random() * 10); // delay (-10s to 0s)
const randomAnimationDelay2 = -(Math.random() * 3); // delay (-3s to 0s) const randomAnimationDelay2 = -(Math.random() * 3); // delay (-3s to 0s)
// apply styles // apply styles
@@ -84,37 +89,7 @@ function addRandomSymbols(count) {
halloweenContainer.appendChild(halloweenDiv); halloweenContainer.appendChild(halloweenDiv);
} }
console.log('Random halloween symbols added'); console.log('Halloween symbols added');
}
function createHalloween() {
const container = document.querySelector('.halloween-container') || document.createElement("div");
if (!document.querySelector('.halloween-container')) {
container.className = "halloween-container";
container.setAttribute("aria-hidden", "true");
document.body.appendChild(container);
}
for (let i = 0; i < 4; i++) {
images.forEach(imageSrc => {
const halloweenDiv = document.createElement("div");
halloweenDiv.className = "halloween";
const img = document.createElement("img");
img.src = imageSrc;
// set random animation duration
if (enableDiffrentDuration) {
const randomAnimationDuration = Math.random() * 10 + 6; // delay (6s to 10s)
const randomAnimationDuration2 = Math.random() * 5 + 2; // delay (2s to 5s)
halloweenDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
}
halloweenDiv.appendChild(img);
container.appendChild(halloweenDiv);
});
}
} }
// create fog layer // create fog layer
@@ -230,7 +205,11 @@ function createMouse(container) {
function initializeHalloween() { function initializeHalloween() {
if (!halloween) return; if (!halloween) return;
createHalloween();
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const count = !isMobile ? halloweenCount : halloweenCountMobile;
initHalloween(count);
toggleHalloween(); toggleHalloween();
const container = document.querySelector('.halloween-container'); const container = document.querySelector('.halloween-container');
@@ -252,11 +231,6 @@ function initializeHalloween() {
} }
} }
} }
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
if (randomSymbols && (screenWidth > 768 || randomSymbolsMobile)) {
addRandomSymbols(halloweenCount);
}
} }
initializeHalloween(); initializeHalloween();

View File

@@ -49,63 +49,3 @@
transform: translateX(80px) transform: translateX(80px)
} }
} }
.heart:nth-of-type(0) {
left: 1%;
animation-delay: 0s, 0s
}
.heart:nth-of-type(1) {
left: 10%;
animation-delay: 1s, 1s
}
.heart:nth-of-type(2) {
left: 20%;
animation-delay: 6s, .5s
}
.heart:nth-of-type(3) {
left: 30%;
animation-delay: 4s, 2s
}
.heart:nth-of-type(4) {
left: 40%;
animation-delay: 2s, 2s
}
.heart:nth-of-type(5) {
left: 50%;
animation-delay: 8s, 3s
}
.heart:nth-of-type(6) {
left: 60%;
animation-delay: 6s, 2s
}
.heart:nth-of-type(7) {
left: 70%;
animation-delay: 2.5s, 1s
}
.heart:nth-of-type(8) {
left: 80%;
animation-delay: 1s, 0s
}
.heart:nth-of-type(9) {
left: 90%;
animation-delay: 3s, 1.5s
}
.heart:nth-of-type(10) {
left: 25%;
animation-delay: 2s, 0s
}
.heart:nth-of-type(11) {
left: 65%;
animation-delay: 4s, 2.5s
}

View File

@@ -1,10 +1,9 @@
const config = window.SeasonalsPluginConfig?.Hearts || {}; const config = window.SeasonalsPluginConfig?.Hearts || {};
const hearts = config.EnableHearts !== undefined ? config.EnableHearts : true; // enable/disable hearts const hearts = config.EnableHearts !== undefined ? config.EnableHearts : true; // enable/disable hearts
const randomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true; // enable random symbols
const randomSymbolsMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false; // enable random symbols on mobile
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
const heartsCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbol const heartsCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbol
const heartsCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbol on mobile
// Array of hearts characters // Array of hearts characters
const heartSymbols = ['❤️', '💕', '💞', '💓', '💗', '💖']; const heartSymbols = ['❤️', '💕', '💞', '💓', '💗', '💖'];
@@ -46,11 +45,16 @@ observer.observe(document.body, {
}); });
function addRandomSymbols(count) { function initHearts(count) {
const heartsContainer = document.querySelector('.hearts-container'); // get the hearts container let heartsContainer = document.querySelector('.hearts-container'); // get the hearts container
if (!heartsContainer) return; // exit if hearts container is not found if (!heartsContainer) {
heartsContainer = document.createElement("div");
heartsContainer.className = "hearts-container";
heartsContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(heartsContainer);
}
console.log('Adding random heart symbols'); console.log('Adding heart symbols');
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
// create a new hearts elements // create a new hearts elements
@@ -63,8 +67,8 @@ function addRandomSymbols(count) {
// set random horizontal position, animation delay and size(uncomment lines to enable) // set random horizontal position, animation delay and size(uncomment lines to enable)
const randomLeft = Math.random() * 100; // position (0% to 100%) const randomLeft = Math.random() * 100; // position (0% to 100%)
const randomAnimationDelay = Math.random() * 14; // delay (0s to 14s) const randomAnimationDelay = -(Math.random() * 16); // delay (-16s to 0s)
const randomAnimationDelay2 = Math.random() * 5; // delay (0s to 5s) const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
// apply styles // apply styles
heartsDiv.style.left = `${randomLeft}%`; heartsDiv.style.left = `${randomLeft}%`;
@@ -80,46 +84,18 @@ function addRandomSymbols(count) {
// add the hearts to the container // add the hearts to the container
heartsContainer.appendChild(heartsDiv); heartsContainer.appendChild(heartsDiv);
} }
console.log('Random hearts symbols added'); console.log('Heart symbols added');
} }
// create hearts objects
function createHearts() {
const container = document.querySelector('.hearts-container') || document.createElement("div");
if (!document.querySelector('.hearts-container')) {
container.className = "hearts-container";
container.setAttribute("aria-hidden", "true");
document.body.appendChild(container);
}
for (let i = 0; i < 12; i++) {
const heartsDiv = document.createElement("div");
heartsDiv.className = "heart";
heartsDiv.textContent = heartSymbols[i % heartSymbols.length];
// set random animation duration
if (enableDiffrentDuration) {
const randomAnimationDuration = Math.random() * 16 + 12; // delay (12s to 16s)
const randomAnimationDuration2 = Math.random() * 7 + 3; // delay (3s to 7s)
heartsDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
}
container.appendChild(heartsDiv);
}
}
// initialize hearts // initialize hearts
function initializeHearts() { function initializeHearts() {
if (!hearts) return; // exit if hearts is disabled if (!hearts) return; // exit if hearts is disabled
createHearts();
toggleHearts();
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
if (randomSymbols && (screenWidth > 768 || randomSymbolsMobile)) { // add random heartss only on larger screens, unless enabled for mobile devices const count = !isMobile ? heartsCount : heartsCountMobile;
addRandomSymbols(heartsCount);
} initHearts(count);
toggleHearts();
} }
initializeHearts(); initializeHearts();

View File

@@ -67,8 +67,8 @@ function initializeOktoberfest() {
document.body.appendChild(container); document.body.appendChild(container);
} }
const screenWidth = window.innerWidth; const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const count = screenWidth > 768 ? symbolCount : symbolCountMobile; const count = !isMobile ? symbolCount : symbolCountMobile;
createOktoberfest(container, count); createOktoberfest(container, count);
} }

View File

@@ -1,7 +1,7 @@
const config = window.SeasonalsPluginConfig?.Rain || {}; const config = window.SeasonalsPluginConfig?.Rain || {};
const enabled = config.EnableRain !== undefined ? config.EnableRain : true; // enable/disable rain const enabled = config.EnableRain !== undefined ? config.EnableRain : true; // enable/disable rain
const isMobile = window.innerWidth <= 768; const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300); // count of raindrops const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300); // count of raindrops
const rainSpeed = config.RainSpeed !== undefined ? config.RainSpeed : 1.0; // speed of rain const rainSpeed = config.RainSpeed !== undefined ? config.RainSpeed : 1.0; // speed of rain

View File

@@ -1,10 +1,9 @@
const config = window.SeasonalsPluginConfig?.Resurrection || {}; const config = window.SeasonalsPluginConfig?.Resurrection || {};
const enableResurrection = config.EnableResurrection !== undefined ? config.EnableResurrection : true; // enable/disable resurrection const enableResurrection = config.EnableResurrection !== undefined ? config.EnableResurrection : true; // enable/disable resurrection
const enableRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true; // enable random symbols
const enableRandomSymbolsMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false; // enable random symbols on mobile
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 12; // count of symbols const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 12; // count of symbols
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 5; // count of symbols on mobile
let animationEnabled = true; let animationEnabled = true;
let statusLogged = false; let statusLogged = false;
@@ -78,20 +77,17 @@ function createSymbol(imageSrc, leftPercent, delaySeconds) {
function addSymbols(count) { function addSymbols(count) {
const container = document.querySelector('.resurrection-container'); const container = document.querySelector('.resurrection-container');
if (!container || !enableRandomSymbols) return; if (!container) return;
const isDesktop = window.innerWidth > 768;
if (!isDesktop && !enableRandomSymbolsMobile) return;
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const imageSrc = images[Math.floor(Math.random() * images.length)]; const imageSrc = images[Math.floor(Math.random() * images.length)];
const left = Math.random() * 100; const left = Math.random() * 100;
const delay = Math.random() * 12; const delay = -(Math.random() * 12);
container.appendChild(createSymbol(imageSrc, left, delay)); container.appendChild(createSymbol(imageSrc, left, delay));
} }
} }
function initResurrection() { function initResurrection(count) {
let container = document.querySelector('.resurrection-container'); let container = document.querySelector('.resurrection-container');
if (!container) { if (!container) {
container = document.createElement('div'); container = document.createElement('div');
@@ -103,17 +99,21 @@ function initResurrection() {
// Place one of each of the 8 provided resurrection images first. // Place one of each of the 8 provided resurrection images first.
images.forEach((imageSrc, index) => { images.forEach((imageSrc, index) => {
const left = (index + 1) * (100 / (images.length + 1)); const left = (index + 1) * (100 / (images.length + 1));
const delay = Math.random() * 8; const delay = -(Math.random() * 8);
container.appendChild(createSymbol(imageSrc, left, delay)); container.appendChild(createSymbol(imageSrc, left, delay));
}); });
const extraCount = Math.max(symbolCount - images.length, 0); const extraCount = Math.max(count - images.length, 0);
addSymbols(extraCount); addSymbols(extraCount);
} }
function initializeResurrection() { function initializeResurrection() {
if (!enableResurrection) return; if (!enableResurrection) return;
initResurrection();
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const count = !isMobile ? symbolCount : symbolCountMobile;
initResurrection(count);
toggleResurrection(); toggleResurrection();
} }

View File

@@ -310,8 +310,8 @@ function initializeSanta() {
} }
const container = document.querySelector('.santa-container'); const container = document.querySelector('.santa-container');
if (container) { if (container) {
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches; // check if mobile device
if (screenWidth < 768) { // lower count of snowflakes on mobile devices if (isMobile) { // lower count of snowflakes on mobile devices
isMobile = true; isMobile = true;
console.log('Mobile device detected. Reducing snowflakes count.'); console.log('Mobile device detected. Reducing snowflakes count.');
snowflakesCount = snowflakesCountMobile; snowflakesCount = snowflakesCountMobile;

View File

@@ -181,8 +181,8 @@ function initializeSnowfall() {
} }
const container = document.querySelector('.snowfall-container'); const container = document.querySelector('.snowfall-container');
if (container) { if (container) {
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches; // check if mobile device
if (screenWidth < 768) { // lower count of snowflakes on mobile devices if (isMobile) { // lower count of snowflakes on mobile devices
console.log('Mobile device detected. Reducing snowflakes count.'); console.log('Mobile device detected. Reducing snowflakes count.');
snowflakesCount = snowflakesCountMobile; snowflakesCount = snowflakesCountMobile;
} }

View File

@@ -1,112 +1,54 @@
.snowflakes { .snowflakes {
display: block; display: block;
position: fixed; position: fixed;
overflow: hidden; overflow: hidden;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
contain: layout paint; contain: layout paint;
} }
.snowflake { .snowflake {
position: fixed; position: fixed;
z-index: 15; z-index: 15;
top: 0; top: 0;
will-change: transform; will-change: transform;
translate: 0 -10vh; translate: 0 -10vh;
font-size: 1em; font-size: 1em;
color: #fff; color: #fff;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
text-shadow: 0 0 5px #000; text-shadow: 0 0 5px #000;
user-select: none; user-select: none;
cursor: default; cursor: default;
animation-name: snowflakes-fall, snowflakes-shake; animation-name: snowflakes-fall, snowflakes-shake;
animation-duration: 12s, 3s; animation-duration: 12s, 3s;
animation-timing-function: linear, ease-in-out; animation-timing-function: linear, ease-in-out;
animation-iteration-count: infinite, infinite; animation-iteration-count: infinite, infinite;
} }
@keyframes snowflakes-fall { @keyframes snowflakes-fall {
0% { 0% {
translate: 0 -10vh; translate: 0 -10vh;
} }
100% { 100% {
translate: 0 110vh; translate: 0 110vh;
} }
} }
@keyframes snowflakes-shake { @keyframes snowflakes-shake {
0%, 0%,
100% { 100% {
transform: translateX(0); transform: translateX(0);
} }
50% { 50% {
transform: translateX(80px); transform: translateX(80px);
} }
}
.snowflake:nth-of-type(0) {
left: 0%;
animation-delay: 0s, 0s;
}
.snowflake:nth-of-type(1) {
left: 10%;
animation-delay: 1s, 1s;
}
.snowflake:nth-of-type(2) {
left: 20%;
animation-delay: 6s, 0.5s;
}
.snowflake:nth-of-type(3) {
left: 30%;
animation-delay: 4s, 2s;
}
.snowflake:nth-of-type(4) {
left: 40%;
animation-delay: 2s, 2s;
}
.snowflake:nth-of-type(5) {
left: 50%;
animation-delay: 8s, 3s;
}
.snowflake:nth-of-type(6) {
left: 60%;
animation-delay: 6s, 2s;
}
.snowflake:nth-of-type(7) {
left: 70%;
animation-delay: 2.5s, 1s;
}
.snowflake:nth-of-type(8) {
left: 80%;
animation-delay: 1s, 0s;
}
.snowflake:nth-of-type(9) {
left: 90%;
animation-delay: 3s, 1.5s;
}
.snowflake:nth-of-type(10) {
left: 25%;
animation-delay: 2s, 0s;
}
.snowflake:nth-of-type(11) {
} }

View File

@@ -2,8 +2,7 @@ const config = window.SeasonalsPluginConfig?.Snowflakes || {};
const snowflakes = config.EnableSnowflakes !== undefined ? config.EnableSnowflakes : true; // enable/disable snowflakes const snowflakes = config.EnableSnowflakes !== undefined ? config.EnableSnowflakes : true; // enable/disable snowflakes
const snowflakeCount = config.SnowflakeCount !== undefined ? config.SnowflakeCount : 25; // count of snowflakes const snowflakeCount = config.SnowflakeCount !== undefined ? config.SnowflakeCount : 25; // count of snowflakes
const randomSnowflakes = config.EnableRandomSnowflakes !== undefined ? config.EnableRandomSnowflakes : true; // enable random snowflakes const snowflakeCountMobile = config.SnowflakeCountMobile !== undefined ? config.SnowflakeCountMobile : 10; // count of snowflakes on mobile
const randomSnowflakesMobile = config.EnableRandomSnowflakesMobile !== undefined ? config.EnableRandomSnowflakesMobile : false; // enable random snowflakes on mobile
const enableColoredSnowflakes = config.EnableColoredSnowflakes !== undefined ? config.EnableColoredSnowflakes : true; // enable/disable colored snowflakes const enableColoredSnowflakes = config.EnableColoredSnowflakes !== undefined ? config.EnableColoredSnowflakes : true; // enable/disable colored snowflakes
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
@@ -46,11 +45,16 @@ observer.observe(document.body, {
attributes: true attributes: true
}); });
function addRandomSnowflakes(count) { function initSnowflakes(count) {
const snowflakeContainer = document.querySelector('.snowflakes'); // get the snowflake container let snowflakeContainer = document.querySelector('.snowflakes'); // get the snowflake container
if (!snowflakeContainer) return; // exit if snowflake container is not found if (!snowflakeContainer) {
snowflakeContainer = document.createElement("div");
snowflakeContainer.className = "snowflakes";
snowflakeContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(snowflakeContainer);
}
console.log('Adding random snowflakes'); console.log('Adding snowflakes');
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
// create a new snowflake element // create a new snowflake element
@@ -66,7 +70,7 @@ function addRandomSnowflakes(count) {
// set random horizontal position, animation delay and size(uncomment lines to enable) // set random horizontal position, animation delay and size(uncomment lines to enable)
const randomLeft = Math.random() * 100; // position (0% to 100%) const randomLeft = Math.random() * 100; // position (0% to 100%)
const randomAnimationDelay = Math.random() * 8; // delay (0s to 8s) const randomAnimationDelay = -(Math.random() * 14); // delay (-14s to 0s)
const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s) const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
// apply styles // apply styles
@@ -83,49 +87,18 @@ function addRandomSnowflakes(count) {
// add the snowflake to the container // add the snowflake to the container
snowflakeContainer.appendChild(snowflake); snowflakeContainer.appendChild(snowflake);
} }
console.log('Random snowflakes added'); console.log('Snowflakes added');
} }
// initialize standard snowflakes // initialize snowflakes
function initSnowflakes() {
const snowflakesContainer = document.querySelector('.snowflakes') || document.createElement("div");
if (!document.querySelector('.snowflakes')) {
snowflakesContainer.className = "snowflakes";
snowflakesContainer.setAttribute("aria-hidden", "true");
document.body.appendChild(snowflakesContainer);
}
// Array of snowflake characters
const snowflakeSymbols = ['❅', '❆'];
// create the 12 standard snowflakes
for (let i = 0; i < 12; i++) {
const snowflake = document.createElement('div');
snowflake.className = 'snowflake';
snowflake.textContent = snowflakeSymbols[i % 2]; // change between ❅ and ❆
// set random animation duration
if (enableDiffrentDuration) {
const randomAnimationDuration = Math.random() * 14 + 10; // delay (10s to 14s)
const randomAnimationDuration2 = Math.random() * 5 + 3; // delay (3s to 5s)
snowflake.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
}
snowflakesContainer.appendChild(snowflake);
}
}
// initialize snowflakes and add random snowflakes
function initializeSnowflakes() { function initializeSnowflakes() {
if (!snowflakes) return; // exit if snowflakes are disabled if (!snowflakes) return; // exit if snowflakes are disabled
initSnowflakes();
toggleSnowflakes();
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
if (randomSnowflakes && (screenWidth > 768 || randomSnowflakesMobile)) { // add random snowflakes only on larger screens, unless enabled for mobile devices const count = !isMobile ? snowflakeCount : snowflakeCountMobile;
addRandomSnowflakes(snowflakeCount);
} initSnowflakes(count);
toggleSnowflakes();
} }
initializeSnowflakes(); initializeSnowflakes();

View File

@@ -184,8 +184,8 @@ function initializeSnowstorm() {
} }
const container = document.querySelector('.snowstorm-container'); const container = document.querySelector('.snowstorm-container');
if (container) { if (container) {
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
if (screenWidth < 768) { // lower count of snowflakes on mobile devices if (isMobile) { // lower count of snowflakes on mobile devices
console.log('Mobile device detected. Reducing snowflakes count.'); console.log('Mobile device detected. Reducing snowflakes count.');
snowflakesCount = snowflakesCountMobile; snowflakesCount = snowflakesCountMobile;
} }

View File

@@ -1,7 +1,7 @@
const config = window.SeasonalsPluginConfig?.Storm || {}; const config = window.SeasonalsPluginConfig?.Storm || {};
const enabled = config.EnableStorm !== undefined ? config.EnableStorm : true; // enable/disable storm const enabled = config.EnableStorm !== undefined ? config.EnableStorm : true; // enable/disable storm
const isMobile = window.innerWidth <= 768; const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300); // count of raindrops const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300); // count of raindrops
const enableLightning = config.EnableLightning !== undefined ? config.EnableLightning : true; // enable/disable lightning const enableLightning = config.EnableLightning !== undefined ? config.EnableLightning : true; // enable/disable lightning
const rainSpeed = config.RainSpeed !== undefined ? config.RainSpeed : 1.0; // speed of rain const rainSpeed = config.RainSpeed !== undefined ? config.RainSpeed : 1.0; // speed of rain

View File

@@ -9,12 +9,12 @@
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/logo.png", "imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/logo.png",
"versions": [ "versions": [
{ {
"version": "2.0.0.1", "version": "2.0.0.4",
"changelog": "- feat: add many themes\n- fix: improve performance", "changelog": "- feat: add new themes:\n- birthday (ballons, computer mouse interactive)\n- earthday\n- Eid al-Fitr (sugar feast/ramadan)\n- eurovision\n- Film Noir filter\n- Friday the 13\n- frost\n- Mario Day\n- Matrix\n- Oktoberfest\n- Olympia\n- Oscar Awards\n- Pride\n- Rain\n- Spooky\n- Sports (many selectable balls of ball games like handball, football (soccer) or tennis)\n- StarWars Day\n- Storm (Epilepsy Warning!!!, Thunderstorm)\n- refactored spring (new lawn with flowers), easter (new easter bunny, new lawn with flowers and ester eggs), halloween (add spiders (computer mouse sensitive), add mice, add fog) \n- fix: many improvements and bug fixes e.g. changed top to translate/transform for performance reasons",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v2.0.0.1/Jellyfin.Plugin.Seasonals.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v2.0.0.4/Jellyfin.Plugin.Seasonals.zip",
"checksum": "2eb9ce92f3aa89d133ad09cd874b7c85", "checksum": "88ec6ec690b7808499b4d368e8bce585",
"timestamp": "2026-02-27T03:27:02Z" "timestamp": "2026-02-28T02:11:13Z"
}, },
{ {
"version": "1.7.2.0", "version": "1.7.2.0",