mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Set modal size before opening
This commit is contained in:
@@ -154,7 +154,7 @@
|
||||
<button class="emby-button raised block button-submit" id="save-custommenulinks-config-btn">Save</button>
|
||||
`;
|
||||
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Custom Menu Links Configuration',
|
||||
content: content,
|
||||
@@ -162,6 +162,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-custommenulinks-config-btn');
|
||||
if (saveBtn) {
|
||||
@@ -182,12 +185,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Custom Menu Links configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening custom menu links config modal:', error);
|
||||
|
||||
@@ -5283,6 +5283,9 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modalInstance) => {
|
||||
// Attach tab switching
|
||||
attachTabListeners(modalInstance);
|
||||
@@ -5332,12 +5335,6 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
mainModalInstance.dialog.style.maxWidth = '90vw';
|
||||
mainModalInstance.dialog.style.width = '1400px';
|
||||
mainModalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Main configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening config modal:', error);
|
||||
@@ -5353,7 +5350,6 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
if (Array.isArray(section.items) && section.items.length > 0) return false;
|
||||
if (Array.isArray(section.externalListUrls) && section.externalListUrls.length > 0) return false;
|
||||
if (section.discoveryType) return true;
|
||||
if (section.discoveryEnabled === true) return true;
|
||||
const type = String(section.type || '').toLowerCase();
|
||||
return ['genre', 'studio', 'person', 'collection', 'similar', 'watchlist', 'tag'].includes(type);
|
||||
}
|
||||
@@ -5736,9 +5732,9 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
size: 'large',
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
dialogStyle: { width: '1400px' },
|
||||
onOpen: async (modalInstance) => {
|
||||
const container = modalInstance.dialogContent.querySelector('#preview-container');
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
await renderSectionPreviewInto(previewSection, items, container);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
`;
|
||||
|
||||
// Create modal
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Search Configuration',
|
||||
content: content,
|
||||
@@ -115,6 +115,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
// Save button
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-search-config-btn');
|
||||
@@ -135,12 +138,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Search configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening search config modal:', error);
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
`;
|
||||
|
||||
// Create modal
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Episodes On Series Page Configuration',
|
||||
content: content,
|
||||
@@ -116,6 +116,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
// Save button
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-seriesepisodes-config-btn');
|
||||
@@ -135,12 +138,6 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Series Episodes configuration modal opened');
|
||||
} catch (error) {
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
`;
|
||||
|
||||
// Create modal
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Series Info Configuration',
|
||||
content: content,
|
||||
@@ -116,6 +116,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
// Save button
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-seriesinfo-config-btn');
|
||||
@@ -135,12 +138,6 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Series Info configuration modal opened');
|
||||
} catch (error) {
|
||||
|
||||
@@ -598,7 +598,7 @@
|
||||
`;
|
||||
|
||||
// Create modal
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Skin Manager Configuration',
|
||||
content: content,
|
||||
@@ -606,6 +606,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
attachListeners(modal);
|
||||
|
||||
@@ -628,12 +631,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Skin Manager configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening skin manager config modal:', error);
|
||||
|
||||
@@ -246,7 +246,7 @@
|
||||
`;
|
||||
|
||||
// Create modal
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Thumbnail Scrubber Configuration',
|
||||
content: content,
|
||||
@@ -254,6 +254,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '800px', height: 'auto' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
// Save button
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-thumbnailscrubber-config-btn');
|
||||
@@ -274,12 +277,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '800px';
|
||||
modalInstance.dialog.style.height = 'auto';
|
||||
}
|
||||
|
||||
LOG('Thumbnail Scrubber configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening thumbnail scrubber config modal:', error);
|
||||
|
||||
@@ -469,6 +469,7 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: { maxWidth: '420px', width: '90vw' },
|
||||
onOpen: (m) => {
|
||||
const input = m.dialogContent.querySelector('#um-tag-input');
|
||||
const finish = (val) => {
|
||||
@@ -489,10 +490,6 @@
|
||||
},
|
||||
onClose: () => resolve(null)
|
||||
});
|
||||
if (modal?.dialog) {
|
||||
modal.dialog.style.maxWidth = '420px';
|
||||
modal.dialog.style.width = '90vw';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -535,6 +532,7 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: { maxWidth: '420px', width: '90vw' },
|
||||
onOpen: (m) => {
|
||||
m.dialogFooter.querySelector('#um-sched-cancel')?.addEventListener('click', () => finish(null));
|
||||
m.dialogFooter.querySelector('#um-sched-ok')?.addEventListener('click', () => {
|
||||
@@ -550,10 +548,6 @@
|
||||
},
|
||||
onClose: () => finish(null)
|
||||
});
|
||||
if (modal?.dialog) {
|
||||
modal.dialog.style.maxWidth = '420px';
|
||||
modal.dialog.style.width = '90vw';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -723,13 +717,10 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
if (window.innerWidth >= 900) {
|
||||
modal.dialog.style.maxWidth = '90vw';
|
||||
modal.dialog.style.width = '1400px';
|
||||
modal.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
modal.dialogFooter.querySelector('#um-editor-cancel')?.addEventListener('click', () => {
|
||||
window.ModalSystem.close(EDITOR_MODAL_ID);
|
||||
});
|
||||
@@ -839,20 +830,18 @@
|
||||
footer.style.cssText = 'display:flex;gap:0.75em;justify-content:flex-end;';
|
||||
footer.innerHTML = `<button class="emby-button raised" onclick="window.ModalSystem.close('${CONFIG_MODAL_ID}')">Close</button>`;
|
||||
|
||||
const modal = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: CONFIG_MODAL_ID,
|
||||
title: 'User Manager',
|
||||
content,
|
||||
footer,
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined
|
||||
});
|
||||
if (modal?.dialog && window.innerWidth >= 900) {
|
||||
modal.dialog.style.maxWidth = '90vw';
|
||||
modal.dialog.style.width = '1400px';
|
||||
modal.dialog.style.height = '90vh';
|
||||
}
|
||||
LOG('User Manager config opened');
|
||||
} catch (e) {
|
||||
ERR('Error opening User Manager config', e);
|
||||
|
||||
@@ -443,7 +443,7 @@
|
||||
<button class="emby-button raised block button-submit" id="save-versionpreferences-config-btn">Save</button>
|
||||
`;
|
||||
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Item Version Preferences',
|
||||
content,
|
||||
@@ -451,6 +451,9 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', height: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modal) => {
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-versionpreferences-config-btn');
|
||||
saveBtn?.addEventListener('click', async () => {
|
||||
@@ -468,12 +471,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth >= 900) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.height = '90vh';
|
||||
}
|
||||
|
||||
LOG('Version Preferences configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening version preferences config modal:', error);
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<button class="emby-button raised block button-submit" id="save-watchtogether-config-btn">Save</button>
|
||||
`;
|
||||
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Watch Together',
|
||||
content,
|
||||
@@ -96,6 +96,7 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: { maxWidth: '90vw', width: '560px' },
|
||||
onOpen: (modal) => {
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-watchtogether-config-btn');
|
||||
if (saveBtn) {
|
||||
@@ -112,11 +113,6 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (modalInstance?.dialog) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '560px';
|
||||
}
|
||||
LOG('Watch Together configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening Watch Together config modal:', error);
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
<button class="emby-button raised block button-submit" id="save-watchlist-config-btn">Save</button>
|
||||
`;
|
||||
|
||||
const modalInstance = window.ModalSystem.create({
|
||||
window.ModalSystem.create({
|
||||
id: MODAL_ID,
|
||||
title: 'Watchlist',
|
||||
content,
|
||||
@@ -171,6 +171,7 @@
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
showCloseButton: true,
|
||||
dialogStyle: { maxWidth: '90vw', width: '560px' },
|
||||
onOpen: (modal) => {
|
||||
attachToggleHandlers(modal.dialogContent || content);
|
||||
const saveBtn = modal.dialogFooter.querySelector('#save-watchlist-config-btn');
|
||||
@@ -188,11 +189,6 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (modalInstance?.dialog) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '560px';
|
||||
}
|
||||
LOG('Watchlist configuration modal opened');
|
||||
} catch (error) {
|
||||
ERR('Error opening Watchlist config modal:', error);
|
||||
|
||||
+202
-146
@@ -9,7 +9,6 @@
|
||||
|
||||
.spotlight-banner-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@@ -56,7 +55,6 @@
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
transition: opacity 0.8s ease-in-out;
|
||||
contain: paint;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
@@ -90,14 +88,6 @@
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* Dual-backdrop background with masked crossfade */
|
||||
.spotlight-background-dual {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Border"] .spotlight-background-dual {
|
||||
border-radius: 8px;
|
||||
}
|
||||
@@ -128,12 +118,20 @@
|
||||
}
|
||||
|
||||
/* Single backdrop (when tileCount is 1 or only one image) */
|
||||
.spotlight-background-single {
|
||||
.spotlight-background-single,
|
||||
.spotlight-background-dual {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 160%;
|
||||
transform: translateY(-15%);
|
||||
-webkit-mask-image: linear-gradient( to bottom, transparent 0%, black calc(var(--spotlight-fullscreen-vertical) * 8), black calc(100% - calc(var(--spotlight-fullscreen-vertical) * 8)), transparent 100% );
|
||||
mask-image: linear-gradient( to bottom, transparent 0%, black calc(var(--spotlight-fullscreen-vertical) * 8), black calc(100% - calc(var(--spotlight-fullscreen-vertical) * 8)), transparent 100% );
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
-webkit-mask-position: 0 0;
|
||||
mask-position: 0 0;
|
||||
}
|
||||
|
||||
.spotlight-background-single img {
|
||||
@@ -158,7 +156,7 @@
|
||||
|
||||
@keyframes kenBurnsZoomIn {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 0);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.12, 1.12, 1);
|
||||
@@ -167,7 +165,7 @@
|
||||
|
||||
@keyframes kenBurnsZoomOut {
|
||||
from {
|
||||
transform: scale3d(1.15, 1.15, 1);
|
||||
transform: scale3d(1.15, 1.15, 0);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.02, 1.02, 1);
|
||||
@@ -177,7 +175,7 @@
|
||||
/* Full-screen: start images pre-scaled so they extend past edges from the start (no hard edge before zoom) */
|
||||
@keyframes kenBurnsZoomInFullscreen {
|
||||
from {
|
||||
transform: scale3d(1.08, 1.08, 1);
|
||||
transform: scale3d(1.08, 1.08, 0);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.12, 1.12, 1);
|
||||
@@ -186,7 +184,7 @@
|
||||
|
||||
@keyframes kenBurnsZoomOutFullscreen {
|
||||
from {
|
||||
transform: scale3d(1.15, 1.15, 1);
|
||||
transform: scale3d(1.15, 1.15, 0);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.08, 1.08, 1);
|
||||
@@ -205,7 +203,7 @@
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale3d(1, 1, 1) translateY(30px);
|
||||
transform: scale3d(1, 1, 0) translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
@@ -216,7 +214,7 @@
|
||||
@keyframes fadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale3d(1, 1, 1) translateY(-30px);
|
||||
transform: scale3d(1, 1, 0) translateY(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
@@ -226,7 +224,7 @@
|
||||
|
||||
@keyframes kenBurnsPanRight {
|
||||
from {
|
||||
transform: scale3d(1.1, 1.1, 1) translateX(-5%);
|
||||
transform: scale3d(1.1, 1.1, 0) translateX(-5%);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.1, 1.1, 1) translateX(5%);
|
||||
@@ -235,46 +233,46 @@
|
||||
|
||||
@keyframes kenBurnsPanLeft {
|
||||
from {
|
||||
transform: scale3d(1.1, 1.1, 1) translateX(5%);
|
||||
transform: scale3d(1.1, 1.1, 0) translateX(5%);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.1, 1.1, 1) translateX(-5%);
|
||||
transform: scale3d(1.1, 1.1, 0) translateX(-5%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes kenBurnsPanUp {
|
||||
from {
|
||||
transform: scale3d(1.1, 1.1, 1) translateY(5%);
|
||||
transform: scale3d(1.1, 1.1, 0) translateY(5%);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.1, 1.1, 1) translateY(-5%);
|
||||
transform: scale3d(1.1, 1.1, 0) translateY(-5%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes kenBurnsDiagonal {
|
||||
from {
|
||||
transform: scale3d(1.08, 1.08, 1) translate(-5%, 5%);
|
||||
transform: scale3d(1.08, 1.08, 0) translate(-5%, 5%);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.13, 1.13, 1) translate(5%, -5%);
|
||||
transform: scale3d(1.13, 1.13, 0) translate(5%, -5%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInScale {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale3d(0.95, 0.95, 1);
|
||||
transform: scale3d(0.95, 0.95, 0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes parallaxFloat {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale3d(1, 1, 1) translateY(0);
|
||||
transform: scale3d(1, 1, 0) translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: scale3d(1, 1, 1) translateY(-12px);
|
||||
@@ -284,7 +282,7 @@
|
||||
@keyframes depthPulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 0);
|
||||
}
|
||||
50% {
|
||||
transform: scale3d(1.03, 1.03, 1);
|
||||
@@ -293,7 +291,7 @@
|
||||
|
||||
@keyframes slowRotate {
|
||||
from {
|
||||
transform: scale3d(1.15, 1.15, 1) rotate(0deg);
|
||||
transform: scale3d(1.15, 1.15, 0) rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1.15, 1.15, 1) rotate(3deg);
|
||||
@@ -303,7 +301,7 @@
|
||||
@keyframes breathe {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 0);
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
@@ -330,7 +328,7 @@
|
||||
filter: saturate(1) brightness(1);
|
||||
}
|
||||
50% {
|
||||
filter: saturate(1.2) brightness(1.05);
|
||||
filter: saturate(1.5) brightness(1.25);
|
||||
}
|
||||
100% {
|
||||
filter: saturate(1) brightness(1);
|
||||
@@ -451,7 +449,6 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 45%;
|
||||
background: linear-gradient(to right, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.7) 40%, transparent 100%);
|
||||
padding: 40px;
|
||||
color: white;
|
||||
display: grid;
|
||||
@@ -603,6 +600,10 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.spotlight-metadata-row .sectionTabs {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.spotlight-metadata-row .itemDetailsGroup,
|
||||
.spotlight-metadata-row .sectionTabs {
|
||||
flex-shrink: 0;
|
||||
@@ -844,7 +845,8 @@
|
||||
min-width: 300px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s;
|
||||
transition: opacity 0.2s ease;
|
||||
transition-delay: 0s;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
|
||||
word-wrap: break-word;
|
||||
@@ -852,6 +854,14 @@
|
||||
|
||||
.spotlight-info-button:hover .spotlight-overview-tooltip {
|
||||
opacity: 1;
|
||||
transition-delay: 0.5s;
|
||||
}
|
||||
|
||||
/* Hover overview only on Normal desktop spotlights */
|
||||
.spotlight-section[data-size="large"] .spotlight-overview-tooltip,
|
||||
.spotlight-section[data-size="full"] .spotlight-overview-tooltip,
|
||||
.layout-mobile .spotlight-overview-tooltip {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.spotlight-section:not(.hide)[data-section-id] .spotlight-nav-container {
|
||||
@@ -958,7 +968,6 @@
|
||||
width: calc(100% - 2rem);
|
||||
padding: 5rem 1rem 3rem !important;
|
||||
align-items: center;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.spotlight-tagline {
|
||||
@@ -972,7 +981,6 @@
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
animation: skeleton-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
.cardText-first .skeleton-text-line {
|
||||
padding: 0 22.5% !important;
|
||||
@@ -998,6 +1006,50 @@
|
||||
margin-top: 0.15em;
|
||||
}
|
||||
|
||||
/* One shimmer overlay per skeleton section — gated by .skeleton-shimmer-active (IO) */
|
||||
.itemsContainer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.skeleton-section .itemsContainer::after,
|
||||
.skeleton-section .spotlight-items-container::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.08) 45%,
|
||||
rgba(255, 255, 255, 0.16) 50%,
|
||||
rgba(255, 255, 255, 0.08) 55%,
|
||||
transparent 100%
|
||||
);
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.skeleton-section.skeleton-shimmer-active .itemsContainer::after,
|
||||
.skeleton-section.skeleton-shimmer-active .spotlight-items-container::after {
|
||||
opacity: 1;
|
||||
animation: skeleton-shimmer-sweep 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.skeleton-section.skeleton-shimmer-active .itemsContainer::after,
|
||||
.skeleton-section.skeleton-shimmer-active .spotlight-items-container::after {
|
||||
animation: none !important;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Localize style/layout invalidation to section shells during enhance/lazy paint */
|
||||
.emby-scroller-container.custom-scroller-container,
|
||||
.spotlight-section {
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
/* Tagline always 1 line - Movie-specific override kept for any edge cases */
|
||||
[data-item-type="Movie"] .spotlight-tagline {
|
||||
-webkit-line-clamp: 1;
|
||||
@@ -1481,7 +1533,7 @@
|
||||
/* Borderless layout: full width, no border, negative margins for overlap.
|
||||
Banner has NO padding so the background image overflows edge-to-edge; only content is inset. */
|
||||
.spotlight-section[data-layout="Borderless"] {
|
||||
--spotlight-fullscreen-vertical: 4%;
|
||||
--spotlight-fullscreen-vertical: 20px;
|
||||
--spotlight-fullscreen-horizontal: max(env(safe-area-inset-left), env(safe-area-inset-right), 4%);
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
@@ -1496,51 +1548,55 @@
|
||||
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-banner-container {
|
||||
border-radius: 0;
|
||||
/* No padding: background fills full size so image extends edge-to-edge and into overlap zone */
|
||||
position: relative;
|
||||
/* Wider mask so backdrop fades gradually at top/bottom (no visible solid edge during animation) */
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
black calc(var(--spotlight-fullscreen-vertical) * 2),
|
||||
black calc(100% - calc(var(--spotlight-fullscreen-vertical) * 2)),
|
||||
transparent 100%
|
||||
);
|
||||
mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
black calc(var(--spotlight-fullscreen-vertical) * 2),
|
||||
black calc(100% - calc(var(--spotlight-fullscreen-vertical) * 2)),
|
||||
transparent 100%
|
||||
);
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
-webkit-mask-position: 0 0;
|
||||
mask-position: 0 0;
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Border"] .spotlight-banner-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Dark gradient overlays at top and bottom (like left-side overlay): graceful fade and better visibility when content overlaps */
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-banner-container::before,
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-banner-container::after {
|
||||
.spotlight-section .spotlight-item .spotlight-background-single::before,
|
||||
.spotlight-section .spotlight-item .spotlight-background-single::after,
|
||||
.spotlight-section .spotlight-item .spotlight-background-dual::before,
|
||||
.spotlight-section .spotlight-item .spotlight-background-dual::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 15%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-banner-container::before {
|
||||
.spotlight-background-single::before,
|
||||
.spotlight-background-dual::before {
|
||||
width: 45%;
|
||||
background: radial-gradient(farthest-corner at bottom left, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.7) 40%, rgba(0, 0, 0, 0) 70%);
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-background-single::before,
|
||||
.layout-mobile .spotlight-background-dual::before {
|
||||
width: 100%;
|
||||
background: linear-gradient(to bottom, transparent 0%, transparent 40%, rgba(0, 0, 0, 0.45) 60%, rgba(0, 0, 0, 0.85) 100%) !important;
|
||||
}
|
||||
|
||||
.spotlight-background-single::after,
|
||||
.spotlight-background-dual::after {
|
||||
width: 100%;
|
||||
background: linear-gradient( 180deg, black 0%, transparent 35%, transparent 65%, black 100% );
|
||||
}
|
||||
|
||||
/* .spotlight-section[data-layout="Borderless"] .spotlight-item .spotlight-background-single:::before {
|
||||
top: 0;
|
||||
background: linear-gradient(0deg, transparent, black);
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-banner-container::after {
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-item .spotlight-background-single::after {
|
||||
bottom: 0;
|
||||
background: linear-gradient(180deg, transparent, black);
|
||||
}
|
||||
} */
|
||||
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-items-container,
|
||||
.spotlight-section[data-layout="Borderless"] .spotlight-item {
|
||||
@@ -1568,17 +1624,16 @@
|
||||
z-index: 3;
|
||||
grid-template-rows: 1fr auto auto auto;
|
||||
gap: 1.5em;
|
||||
background: linear-gradient(to right, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.7) 70%, transparent 100%);
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"][data-size="large"] .spotlight-overlay {
|
||||
padding: calc(var(--spotlight-fullscreen-vertical) * 1.75) var(--spotlight-fullscreen-horizontal)
|
||||
calc(var(--spotlight-fullscreen-vertical) * 2) var(--spotlight-fullscreen-horizontal);
|
||||
padding: calc(var(--spotlight-fullscreen-vertical) * 5) var(--spotlight-fullscreen-horizontal)
|
||||
calc(var(--spotlight-fullscreen-vertical) * 5) var(--spotlight-fullscreen-horizontal);
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"][data-size="full"] .spotlight-overlay {
|
||||
padding: calc(var(--spotlight-fullscreen-vertical) * 2.25) var(--spotlight-fullscreen-horizontal)
|
||||
calc(var(--spotlight-fullscreen-vertical) * 2.5) var(--spotlight-fullscreen-horizontal);
|
||||
padding: calc(var(--spotlight-fullscreen-vertical) * 5) var(--spotlight-fullscreen-horizontal)
|
||||
calc(var(--spotlight-fullscreen-vertical) * 5) var(--spotlight-fullscreen-horizontal);
|
||||
grid-template-rows: 1fr auto minmax(6rem, auto) minmax(48px, auto);
|
||||
align-content: center;
|
||||
gap: 1.5em;
|
||||
@@ -1733,7 +1788,6 @@
|
||||
|
||||
.layout-mobile .spotlight-overlay {
|
||||
width: calc(100% - 2rem) !important;
|
||||
background: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.4) 40%, rgba(0, 0, 0, 0.85) 100%) !important;
|
||||
padding: 4rem 1rem 1rem 1rem !important;
|
||||
align-items: start;
|
||||
align-content: start;
|
||||
@@ -1795,16 +1849,12 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-section .spotlight-buttons-container.mainDetailButtons .btnPlay {
|
||||
margin: 0.3em !important;
|
||||
}
|
||||
|
||||
.spotlight-section .spotlight-buttons-container.mainDetailButtons .btnPlay {
|
||||
.spotlight-section .spotlight-buttons-container.mainDetailButtons > button {
|
||||
right: 0px !important;
|
||||
margin-top: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
margin-right: 1em !important;
|
||||
margin-right: 0 !important;
|
||||
min-width: unset;
|
||||
flex: unset !important;
|
||||
}
|
||||
@@ -1815,6 +1865,18 @@
|
||||
margin: 0px !important;
|
||||
padding: 0px !important;
|
||||
}
|
||||
.spotlight-section .mainDetailButtons > .btnPlay:is(.emby-button) {
|
||||
padding: 0.25em !important;
|
||||
}
|
||||
.spotlight-section .spotlight-buttons-container.mainDetailButtons {
|
||||
gap: 2em;
|
||||
}
|
||||
.spotlight-section .spotlight-buttons-container.mainDetailButtons > * {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.spotlight-section .spotlight-buttons-container.mainDetailButtons > * span {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.spotlight-section:not(.hide) .headerTabs,
|
||||
.spotlight-section:not(.hide) .sectionTabs {
|
||||
@@ -1831,11 +1893,11 @@
|
||||
}
|
||||
|
||||
.spotlight-section:not(.hide) .emby-tab-button {
|
||||
height: initial !important;
|
||||
padding: 0.5rem 0.5rem !important;
|
||||
padding: 0.5em 1em !important;
|
||||
margin: 0px !important;
|
||||
top: initial !important;
|
||||
transform: initial !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.spotlight-section-title.headerTabs.sectionTabs,
|
||||
@@ -1846,6 +1908,16 @@
|
||||
align-items: start;
|
||||
justify-content: start;
|
||||
width: auto;
|
||||
font-size: revert !important;
|
||||
height: 40px !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:where(.spotlight-section-title.headerTabs.sectionTabs),
|
||||
:where(.spotlight-section .headerTabs.sectionTabs),
|
||||
:where(.spotlight-nav-container.headerTabs.sectionTabs) {
|
||||
background-color: rgba(20, 20, 20, 0.85);
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
.spotlight-section[data-hide-section-name="true"] .spotlight-section-title,
|
||||
@@ -1858,28 +1930,25 @@
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.spotlight-nav-buttons-container {
|
||||
.spotlight-section:not(.hide) .spotlight-nav-buttons-container {
|
||||
display: flex !important;
|
||||
gap: 8px !important;
|
||||
font-size: 1.1rem !important;
|
||||
padding: 0 0.5em !important;
|
||||
}
|
||||
.spotlight-section:not(.hide) .spotlight-nav-buttons-container button {
|
||||
padding: 0.5em;
|
||||
}
|
||||
.spotlight-nav-button span.material-icons {
|
||||
font-size: 24px !important;
|
||||
display: inline-block !important;
|
||||
top: initial !important;
|
||||
}
|
||||
.spotlight-section-title > * {
|
||||
font-size: 18px !important;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
|
||||
.spotlight-metadata-row *:not(a) {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] {
|
||||
margin-top: calc(-1 * calc(var(--spotlight-fullscreen-vertical) * 1.5));
|
||||
margin-bottom: calc(-1 * calc(var(--spotlight-fullscreen-vertical) * 2));
|
||||
}
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] .spotlight-banner-container {
|
||||
height: 55vh;
|
||||
}
|
||||
@@ -1895,18 +1964,13 @@
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] .spotlight-overlay.has-title {
|
||||
padding: calc(var(--spotlight-fullscreen-vertical) * 3) var(--spotlight-fullscreen-horizontal)
|
||||
calc(var(--spotlight-fullscreen-vertical) * 2) var(--spotlight-fullscreen-horizontal);
|
||||
padding: calc(var(--spotlight-fullscreen-vertical) * 5) var(--spotlight-fullscreen-horizontal)
|
||||
calc(var(--spotlight-fullscreen-vertical) * 5) var(--spotlight-fullscreen-horizontal);
|
||||
}
|
||||
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] {
|
||||
--spotlight-fullscreen-vertical: 3em;
|
||||
--spotlight-fullscreen-horizontal: max(env(safe-area-inset-left), env(safe-area-inset-right), 4%);
|
||||
}
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] .spotlight-section-title-container {
|
||||
left: var(--spotlight-fullscreen-horizontal);
|
||||
top: calc(var(--spotlight-fullscreen-vertical) * 2);
|
||||
}
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] .spotlight-tagline {
|
||||
bottom: calc(var(--spotlight-fullscreen-vertical) * 1.5 + 40px);
|
||||
}
|
||||
@@ -1915,7 +1979,7 @@
|
||||
}
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] .spotlight-nav-container {
|
||||
right: var(--spotlight-fullscreen-horizontal);
|
||||
top: calc(var(--spotlight-fullscreen-vertical) * 2);
|
||||
top: calc(var(--spotlight-fullscreen-vertical) * 2.5);
|
||||
}
|
||||
.spotlight-section[data-layout="Borderless"][data-size="normal"] .spotlight-overlay {
|
||||
grid-template-rows: 1fr auto auto auto;
|
||||
@@ -1924,7 +1988,7 @@
|
||||
grid-template-rows: var(--spotlight-logo-height) auto 1fr auto;
|
||||
}
|
||||
.spotlight-section[data-layout="Border"][data-size="full"] .spotlight-overlay {
|
||||
grid-template-rows: 3fr auto minmax(6rem, auto) 1fr;
|
||||
grid-template-rows: 3fr auto minmax(6rem, auto) auto;
|
||||
}
|
||||
.spotlight-section[data-layout="Border"][data-size="full"] .spotlight-logo-section {
|
||||
align-self: end;
|
||||
@@ -1986,9 +2050,6 @@
|
||||
top: 2rem !important;
|
||||
right: 2rem !important;
|
||||
}
|
||||
.spotlight-section[data-layout="Border"][data-size="normal"] .spotlight-section-title a {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
.spotlight-section[data-layout="Border"] .spotlight-banner-container {
|
||||
border: 1px solid rgb(255 255 255 / 10%);
|
||||
}
|
||||
@@ -2004,11 +2065,6 @@
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.spotlight-section[data-size="normal"] .spotlight-background-single img,
|
||||
.spotlight-section[data-size="large"] .spotlight-background-single img {
|
||||
object-position: center 20%;
|
||||
}
|
||||
|
||||
.layout-mobile .sectionTitleContainer-cards .sectionTitle-link > * {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
@@ -2034,10 +2090,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-section[data-layout="Borderless"][data-size="full"] .spotlight-overlay {
|
||||
/* padding-bottom: 5rem !important; */
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-overview-section,
|
||||
.layout-mobile .spotlight-credits-row,
|
||||
.layout-mobile .spotlight-series-info {
|
||||
@@ -2070,25 +2122,14 @@
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* .layout-mobile .spotlight-section[data-layout="Borderless"][data-order="1"] .spotlight-section-title {
|
||||
top: 135px;
|
||||
}
|
||||
.layout-mobile .spotlight-section[data-layout="Borderless"][data-order="1"] {
|
||||
margin-top: calc(-1 * calc(var(--spotlight-fullscreen-vertical) * 10)) !important;
|
||||
} */
|
||||
|
||||
.layout-mobile .spotlight-section-title .emby-tab-button {
|
||||
padding: 0.25rem !important;
|
||||
}
|
||||
.layout-mobile .spotlight-section .emby-tab-button,
|
||||
.layout-mobile .spotlight-metadata-section span a,
|
||||
.layout-mobile .spotlight-metadata-section span {
|
||||
font-size: 1rem !important;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-section .spotlight-item-title {
|
||||
font-size: 2rem !important;
|
||||
font-size: 2em !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -2096,10 +2137,6 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-buttons-container.mainDetailButtons span {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-section .spotlight-metadata-row {
|
||||
justify-content: center;
|
||||
align-self: center;
|
||||
@@ -2192,19 +2229,19 @@ html.sleekfin-main-ui .emby-scroller-container[data-section-id="liveTv-channels"
|
||||
/* .emby-scroller-container[data-card-format="Logo"] .cardImageContainer,
|
||||
.emby-scroller-container[data-card-format="Clear Art"] .cardImageContainer,
|
||||
.emby-scroller-container[data-card-format="Disc"] .cardImageContainer {
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.emby-scroller-container[data-card-format="Logo"] .cardImageContainer.lazy-hidden,
|
||||
.emby-scroller-container[data-card-format="Clear Art"] .cardImageContainer.lazy-hidden,
|
||||
.emby-scroller-container[data-card-format="Disc"] .cardImageContainer.lazy-hidden {
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.emby-scroller-container[data-card-format="Logo"] .cardImageContainer.lazy-loaded,
|
||||
.emby-scroller-container[data-card-format="Clear Art"] .cardImageContainer.lazy-loaded,
|
||||
.emby-scroller-container[data-card-format="Disc"] .cardImageContainer.lazy-loaded {
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
} */
|
||||
|
||||
:not(.layout-mobile) .emby-scroller-container[data-card-format="Logo"]:not([data-border-style]) .itemsContainer,
|
||||
@@ -4064,42 +4101,43 @@ html.sleekfin-main-ui .emby-scroller-container[data-section-id="liveTv-channels"
|
||||
display: none;
|
||||
}
|
||||
|
||||
.spotlight-truncated-list:has(.spotlight-truncated-list-tooltip) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.emby-scroller-container[data-layout="grid"] .emby-scrollbuttons {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* .spotlight-section[data-size="full"] .spotlight-truncated-list.itemDetailsGroup:has(> .detailsGroupItem),
|
||||
/*
|
||||
.spotlight-truncated-list:has(.spotlight-truncated-list-tooltip) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.spotlight-section[data-size="full"] .spotlight-truncated-list.itemDetailsGroup:has(> .detailsGroupItem),
|
||||
.spotlight-section[data-size="full"] .spotlight-truncated-list.sectionTabs:has(> .emby-tab-button) {
|
||||
font-size: large;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: start;
|
||||
font-size: large;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.spotlight-section .itemDetailsGroup:has(.detailsGroupItem:not(.hide)),
|
||||
.spotlight-section .sectionTabs:not(.spotlight-section-title):has(.emby-tab-button:not(.hide)) {
|
||||
margin: 0px !important;
|
||||
padding: 0px !important;
|
||||
width: initial !important;
|
||||
min-width: initial !important;
|
||||
margin: 0px !important;
|
||||
padding: 0px !important;
|
||||
width: initial !important;
|
||||
min-width: initial !important;
|
||||
}
|
||||
|
||||
.spotlight-section:not(.hide) span.emby-tab-button.emby-tab-button-active:not(:has(a)) {
|
||||
cursor: default;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-section .spotlight-section-title.sectionTabs:has(.emby-tab-button:not(.hide)) {
|
||||
justify-self: center;
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
justify-self: center;
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.layout-mobile .spotlight-section .spotlight-section-title.sectionTabs:has(.emby-tab-button:not(.hide)) > * {
|
||||
display: block !important;
|
||||
display: block !important;
|
||||
padding: 0.25em 0.5em !important;
|
||||
}
|
||||
|
||||
@@ -4122,3 +4160,21 @@ html.sleekfin-main-ui .emby-scroller-container[data-section-id="liveTv-channels"
|
||||
.spotlight-section .spotlight-overlay * {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.sectionTitleContainer {
|
||||
display: flex !important;
|
||||
}
|
||||
.cardOverlayContainer > .button-link {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card[data-type="Program"] .cardTextStack .cardText-secondary:nth-child(3) {
|
||||
display: none;
|
||||
}
|
||||
[data-section-id="liveTv-on-now"] .card[data-type="Program"] .cardTextStack .cardText-secondary:nth-child(2) {
|
||||
display: none;
|
||||
}
|
||||
[data-section-id="liveTv-on-now"] .card[data-type="Program"] .cardTextStack .cardText-secondary:nth-child(3) {
|
||||
display: block;
|
||||
}
|
||||
@@ -2525,17 +2525,10 @@
|
||||
footer: footer,
|
||||
closeOnBackdrop: true,
|
||||
closeOnEscape: true,
|
||||
dialogStyle: window.innerWidth >= 900
|
||||
? { maxWidth: '90vw', width: '1400px', maxHeight: '90vh' }
|
||||
: undefined,
|
||||
onOpen: (modalInstance) => {
|
||||
// Check if window is less than 900px
|
||||
const layoutMobile = window.innerWidth < 900;
|
||||
|
||||
// Update modal dialog styling for large size
|
||||
if (modalInstance && modalInstance.dialog && !layoutMobile) {
|
||||
modalInstance.dialog.style.maxWidth = '90vw';
|
||||
modalInstance.dialog.style.width = '1400px';
|
||||
modalInstance.dialog.style.maxHeight = '90vh';
|
||||
}
|
||||
|
||||
// Add event handlers
|
||||
setupConfigModalHandlers(modalInstance, config);
|
||||
}
|
||||
|
||||
+60
-93
@@ -9,6 +9,49 @@ window.ModalSystem = (function() {
|
||||
// Store active modals
|
||||
const activeModals = new Map();
|
||||
|
||||
// Body scroll lock while any kefin modal is open (replaces non-passive wheel trap)
|
||||
let bodyScrollLockCount = 0;
|
||||
let savedBodyOverflow = null;
|
||||
let savedHtmlOverflow = null;
|
||||
|
||||
function lockBodyScroll() {
|
||||
if (bodyScrollLockCount === 0) {
|
||||
savedBodyOverflow = document.body.style.overflow;
|
||||
savedHtmlOverflow = document.documentElement.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.documentElement.style.overflow = 'hidden';
|
||||
}
|
||||
bodyScrollLockCount++;
|
||||
}
|
||||
|
||||
function unlockBodyScroll() {
|
||||
if (bodyScrollLockCount <= 0) return;
|
||||
bodyScrollLockCount--;
|
||||
if (bodyScrollLockCount === 0) {
|
||||
document.body.style.overflow = savedBodyOverflow || '';
|
||||
document.documentElement.style.overflow = savedHtmlOverflow || '';
|
||||
savedBodyOverflow = null;
|
||||
savedHtmlOverflow = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply Jellyfin's scaleup open animation and clear it when finished.
|
||||
* Clearing avoids a stuck compositor layer that leaves large dialogs soft/blurry.
|
||||
* @param {HTMLElement} dialog
|
||||
*/
|
||||
function applyOpenAnimation(dialog) {
|
||||
if (!dialog) return;
|
||||
dialog.style.animation = '160ms ease-out 0s 1 normal both running scaleup';
|
||||
const onEnd = (e) => {
|
||||
if (e.target !== dialog) return;
|
||||
if (e.animationName && e.animationName !== 'scaleup') return;
|
||||
dialog.style.animation = '';
|
||||
dialog.removeEventListener('animationend', onEnd);
|
||||
};
|
||||
dialog.addEventListener('animationend', onEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Jellyfin-style modal dialog
|
||||
* @param {Object} options - Modal configuration
|
||||
@@ -22,6 +65,7 @@ window.ModalSystem = (function() {
|
||||
* @param {boolean} options.closeOnEscape - Whether to close on Escape key (default: true)
|
||||
* @param {boolean} options.showCloseButton - Whether to show close button in header (default: true if title exists)
|
||||
* @param {boolean} [options.fixedSize] - Use dialog-fixedSize. If undefined, enable when window width < 900.
|
||||
* @param {Object} [options.dialogStyle] - CSS styles applied to the dialog before open (e.g. width/height).
|
||||
* @returns {Object} Modal instance
|
||||
*/
|
||||
function createModal(options = {}) {
|
||||
@@ -35,7 +79,8 @@ window.ModalSystem = (function() {
|
||||
closeOnBackdrop = true,
|
||||
closeOnEscape = true,
|
||||
showCloseButton = true,
|
||||
fixedSize
|
||||
fixedSize,
|
||||
dialogStyle
|
||||
} = options;
|
||||
|
||||
if (!id) {
|
||||
@@ -68,12 +113,16 @@ window.ModalSystem = (function() {
|
||||
dialog.setAttribute('data-autofocus', 'true');
|
||||
dialog.setAttribute('data-removeonclose', 'true');
|
||||
dialog.setAttribute('data-name', 'kefin-modal');
|
||||
dialog.style.animation = '160ms ease-out 0s 1 normal both running scaleup';
|
||||
dialog.style.display = 'flex';
|
||||
dialog.style.flexDirection = 'column';
|
||||
if (!useFixedSize) {
|
||||
dialog.style.maxHeight = '90vh';
|
||||
}
|
||||
// Final box size before scaleup so the compositor layer is not soft-scaled after open
|
||||
if (dialogStyle && typeof dialogStyle === 'object') {
|
||||
Object.assign(dialog.style, dialogStyle);
|
||||
}
|
||||
applyOpenAnimation(dialog);
|
||||
|
||||
// Create header if title is provided
|
||||
let dialogHeader = null;
|
||||
@@ -121,89 +170,10 @@ window.ModalSystem = (function() {
|
||||
dialogContent.style.overflowY = 'auto';
|
||||
dialogContent.style.flex = '1';
|
||||
dialogContent.style.minHeight = '0';
|
||||
|
||||
// Helper function to check if an element is scrollable
|
||||
const isScrollable = (element) => {
|
||||
if (!element || element === document.body || element === document.documentElement) {
|
||||
return false;
|
||||
}
|
||||
const style = window.getComputedStyle(element);
|
||||
const overflowY = style.overflowY;
|
||||
const overflow = style.overflow;
|
||||
const hasScrollableContent = element.scrollHeight > element.clientHeight;
|
||||
return (overflowY === 'auto' || overflowY === 'scroll' || overflow === 'auto' || overflow === 'scroll') && hasScrollableContent;
|
||||
};
|
||||
|
||||
// Helper function to find the closest scrollable parent
|
||||
const findClosestScrollable = (element, stopAt = null) => {
|
||||
let current = element;
|
||||
while (current && current !== stopAt && current !== document.body && current !== document.documentElement) {
|
||||
if (isScrollable(current)) {
|
||||
return current;
|
||||
}
|
||||
current = current.parentElement;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Helper function to check if element can scroll in direction
|
||||
const canScrollInDirection = (element, delta) => {
|
||||
if (!element) return false;
|
||||
const scrollTop = element.scrollTop;
|
||||
const scrollHeight = element.scrollHeight;
|
||||
const clientHeight = element.clientHeight;
|
||||
|
||||
// Scrolling down (positive delta)
|
||||
if (delta > 0) {
|
||||
return scrollTop + clientHeight < scrollHeight - 1; // -1 for rounding
|
||||
}
|
||||
// Scrolling up (negative delta)
|
||||
else {
|
||||
return scrollTop > 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Add scroll trap to prevent body scroll when scrolling within modal
|
||||
const wheelHandler = (e) => {
|
||||
const element = dialogContent;
|
||||
const delta = e.deltaY;
|
||||
|
||||
// Find if the event originated from a child scrollable element
|
||||
const childScrollable = findClosestScrollable(e.target, element);
|
||||
|
||||
// If event is from a child scrollable element
|
||||
if (childScrollable && childScrollable !== element) {
|
||||
// Check if the child can scroll in the direction of the wheel
|
||||
if (canScrollInDirection(childScrollable, delta)) {
|
||||
// Let the child handle the scroll, but stop propagation to prevent body scroll
|
||||
e.stopPropagation();
|
||||
return; // Don't prevent default, let child scroll
|
||||
}
|
||||
// Child is at boundary, prevent default to stop body scroll
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// Event is on the modal content itself
|
||||
const scrollTop = element.scrollTop;
|
||||
const scrollHeight = element.scrollHeight;
|
||||
const clientHeight = element.clientHeight;
|
||||
|
||||
// At top and scrolling up
|
||||
if (delta < 0 && scrollTop === 0) {
|
||||
e.preventDefault();
|
||||
}
|
||||
// At bottom and scrolling down
|
||||
else if (delta > 0 && scrollTop + clientHeight >= scrollHeight) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// Stop propagation to prevent body scroll
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
dialogContent.addEventListener('wheel', wheelHandler, { passive: false });
|
||||
// Contain overscroll so nested wheel/touch scroll does not chain to the page
|
||||
// (avoids a non-passive wheel listener that delays input while the main thread is busy)
|
||||
dialogContent.style.overscrollBehavior = 'contain';
|
||||
dialog.style.overscrollBehavior = 'contain';
|
||||
|
||||
// Add content
|
||||
if (content) {
|
||||
@@ -261,12 +231,12 @@ window.ModalSystem = (function() {
|
||||
updateContent: (newContent) => updateModalContent(id, newContent),
|
||||
addEventListener: (event, handler) => {
|
||||
dialog.addEventListener(event, handler);
|
||||
},
|
||||
_wheelHandler: wheelHandler
|
||||
}
|
||||
};
|
||||
|
||||
// Store modal instance
|
||||
activeModals.set(id, modalInstance);
|
||||
//lockBodyScroll();
|
||||
|
||||
// Add event listeners
|
||||
if (closeOnBackdrop) {
|
||||
@@ -308,11 +278,6 @@ window.ModalSystem = (function() {
|
||||
if (modal._escapeHandler) {
|
||||
document.removeEventListener('keydown', modal._escapeHandler);
|
||||
}
|
||||
|
||||
// Remove wheel handler if it exists
|
||||
if (modal._wheelHandler && modal.dialogContent) {
|
||||
modal.dialogContent.removeEventListener('wheel', modal._wheelHandler);
|
||||
}
|
||||
|
||||
// Remove from DOM
|
||||
if (modal.backdrop && modal.backdrop.parentNode) {
|
||||
@@ -324,6 +289,7 @@ window.ModalSystem = (function() {
|
||||
|
||||
// Remove from active modals
|
||||
activeModals.delete(id);
|
||||
//unlockBodyScroll();
|
||||
|
||||
// Call onClose callback if modal instance has it
|
||||
if (modal.onClose && typeof modal.onClose === 'function') {
|
||||
@@ -392,6 +358,7 @@ window.ModalSystem = (function() {
|
||||
updateContent: updateModalContent,
|
||||
isOpen: isModalOpen,
|
||||
getActiveIds: getActiveModalIds,
|
||||
closeAll: closeAllModals
|
||||
closeAll: closeAllModals,
|
||||
applyOpenAnimation
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user