mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Use Card component as poster on details page
This commit is contained in:
parent
d54e30cfda
commit
de0e45c0c0
3 changed files with 57 additions and 189 deletions
|
@ -608,7 +608,7 @@
|
||||||
margin: 1.25em 0;
|
margin: 1.25em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detailImageContainer {
|
.detailImageContainer .card {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -617,11 +617,11 @@
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbDetailImageContainer {
|
.detailImageContainer .card.backdropCard {
|
||||||
top: 35%;
|
top: 35%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.squareDetailImageContainer {
|
.detailImageContainer .card.squareCard {
|
||||||
top: 40%;
|
top: 40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1380,7 +1380,6 @@ import 'programStyles';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
if (layoutManager.tv) {
|
||||||
|
|
||||||
// Don't use the IMG tag with safari because it puts a white border around it
|
// Don't use the IMG tag with safari because it puts a white border around it
|
||||||
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">');
|
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">');
|
||||||
|
|
||||||
|
@ -1398,6 +1397,7 @@ import 'programStyles';
|
||||||
cardBoxClose = '</div>';
|
cardBoxClose = '</div>';
|
||||||
cardScalableClose = '</div>';
|
cardScalableClose = '</div>';
|
||||||
|
|
||||||
|
if (!options.disableIndicators || options.disableIndicators === false) {
|
||||||
let indicatorsHtml = '';
|
let indicatorsHtml = '';
|
||||||
|
|
||||||
if (options.missingIndicator !== false) {
|
if (options.missingIndicator !== false) {
|
||||||
|
@ -1427,6 +1427,7 @@ import 'programStyles';
|
||||||
if (indicatorsHtml) {
|
if (indicatorsHtml) {
|
||||||
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
|
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!imgUrl) {
|
if (!imgUrl) {
|
||||||
cardImageContainerOpen += getDefaultText(item, options);
|
cardImageContainerOpen += getDefaultText(item, options);
|
||||||
|
@ -1474,7 +1475,7 @@ import 'programStyles';
|
||||||
let additionalCardContent = '';
|
let additionalCardContent = '';
|
||||||
|
|
||||||
if (layoutManager.desktop) {
|
if (layoutManager.desktop) {
|
||||||
additionalCardContent += getHoverMenuHtml(item, action);
|
additionalCardContent += getHoverMenuHtml(item, action, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
|
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
|
||||||
|
@ -1484,9 +1485,10 @@ import 'programStyles';
|
||||||
* Generates HTML markup for the card overlay.
|
* Generates HTML markup for the card overlay.
|
||||||
* @param {object} item - Item used to generate the card overlay.
|
* @param {object} item - Item used to generate the card overlay.
|
||||||
* @param {string} action - Action assigned to the overlay.
|
* @param {string} action - Action assigned to the overlay.
|
||||||
|
* @param {Array} options - Card builder options.
|
||||||
* @returns {string} HTML markup of the card overlay.
|
* @returns {string} HTML markup of the card overlay.
|
||||||
*/
|
*/
|
||||||
function getHoverMenuHtml(item, action) {
|
function getHoverMenuHtml(item, action, options) {
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|
||||||
html += '<div class="cardOverlayContainer itemAction" data-action="' + action + '">';
|
html += '<div class="cardOverlayContainer itemAction" data-action="' + action + '">';
|
||||||
|
@ -1501,12 +1503,12 @@ import 'programStyles';
|
||||||
|
|
||||||
const userData = item.UserData || {};
|
const userData = item.UserData || {};
|
||||||
|
|
||||||
if (itemHelper.canMarkPlayed(item)) {
|
if (itemHelper.canMarkPlayed(item) && !options.disableHoverMenu) {
|
||||||
require(['emby-playstatebutton']);
|
require(['emby-playstatebutton']);
|
||||||
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
|
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemHelper.canRate(item)) {
|
if (itemHelper.canRate(item) && !options.disableHoverMenu) {
|
||||||
|
|
||||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||||
|
|
||||||
|
@ -1514,7 +1516,9 @@ import 'programStyles';
|
||||||
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
|
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.disableHoverMenu) {
|
||||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_vert"></span></button>';
|
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_vert"></span></button>';
|
||||||
|
}
|
||||||
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
|
@ -470,34 +470,12 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||||
var imgUrl;
|
var imgUrl;
|
||||||
var hasbackdrop = false;
|
var hasbackdrop = false;
|
||||||
var itemBackdropElement = page.querySelector('#itemBackdrop');
|
var itemBackdropElement = page.querySelector('#itemBackdrop');
|
||||||
var usePrimaryImage = item.MediaType === 'Video' && item.Type !== 'Movie' && item.Type !== 'Trailer' ||
|
|
||||||
item.MediaType && item.MediaType !== 'Video' ||
|
|
||||||
item.Type === 'MusicAlbum' ||
|
|
||||||
item.Type === 'Person';
|
|
||||||
|
|
||||||
if (!layoutManager.mobile && !userSettings.detailsBanner()) {
|
if (!layoutManager.mobile && !userSettings.enableBackdrops()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('Program' === item.Type && item.ImageTags && item.ImageTags.Thumb) {
|
if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Thumb',
|
|
||||||
maxWidth: dom.getScreenWidth(),
|
|
||||||
index: 0,
|
|
||||||
tag: item.ImageTags.Thumb
|
|
||||||
});
|
|
||||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
|
||||||
hasbackdrop = true;
|
|
||||||
} else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) {
|
|
||||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Primary',
|
|
||||||
maxWidth: dom.getScreenWidth(),
|
|
||||||
index: 0,
|
|
||||||
tag: item.ImageTags.Primary
|
|
||||||
});
|
|
||||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
|
||||||
hasbackdrop = true;
|
|
||||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
|
||||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||||
type: 'Backdrop',
|
type: 'Backdrop',
|
||||||
maxWidth: dom.getScreenWidth(),
|
maxWidth: dom.getScreenWidth(),
|
||||||
|
@ -515,15 +493,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||||
});
|
});
|
||||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||||
hasbackdrop = true;
|
hasbackdrop = true;
|
||||||
} else if (item.ImageTags && item.ImageTags.Thumb) {
|
|
||||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Thumb',
|
|
||||||
maxWidth: dom.getScreenWidth(),
|
|
||||||
index: 0,
|
|
||||||
tag: item.ImageTags.Thumb
|
|
||||||
});
|
|
||||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
|
||||||
hasbackdrop = true;
|
|
||||||
} else {
|
} else {
|
||||||
itemBackdropElement.style.backgroundImage = '';
|
itemBackdropElement.style.backgroundImage = '';
|
||||||
}
|
}
|
||||||
|
@ -714,132 +683,25 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDetailImage(page, elem, item, apiClient, editable, imageLoader, indicators) {
|
function renderDetailImage(page, elem, item, apiClient, editable, imageLoader, indicators) {
|
||||||
if ('SeriesTimer' === item.Type || 'Program' === item.Type) {
|
|
||||||
editable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.classList.add('detailimg-hidemobile');
|
elem.classList.add('detailimg-hidemobile');
|
||||||
|
|
||||||
var imageTags = item.ImageTags || {};
|
const itemArray = [];
|
||||||
|
itemArray.push(item);
|
||||||
if (item.PrimaryImageTag) {
|
const cardHtml = cardBuilder.getCardsHtml(itemArray, {
|
||||||
imageTags.Primary = item.PrimaryImageTag;
|
shape: 'auto',
|
||||||
}
|
showTitle: false,
|
||||||
|
centerText: true,
|
||||||
var url;
|
overlayText: false,
|
||||||
var html = '';
|
transition: false,
|
||||||
var shape = 'portrait';
|
disableIndicators: true,
|
||||||
var detectRatio = false;
|
disableHoverMenu: true,
|
||||||
|
overlayPlayButton: true,
|
||||||
/* In the following section, getScreenWidth() is multiplied by 0.5 as the posters
|
width: dom.getWindowSize().innerWidth * 0.25
|
||||||
are 25vw and we need double the resolution to counter Skia's scaling. */
|
|
||||||
// TODO: Find a reliable way to get the poster width
|
|
||||||
if (imageTags.Primary) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Primary',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.ImageTags.Primary
|
|
||||||
});
|
});
|
||||||
detectRatio = true;
|
|
||||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Backdrop',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.BackdropImageTags[0]
|
|
||||||
});
|
|
||||||
shape = 'thumb';
|
|
||||||
} else if (imageTags.Thumb) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Thumb',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.ImageTags.Thumb
|
|
||||||
});
|
|
||||||
shape = 'thumb';
|
|
||||||
} else if (imageTags.Disc) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.Id, {
|
|
||||||
type: 'Disc',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.ImageTags.Disc
|
|
||||||
});
|
|
||||||
shape = 'square';
|
|
||||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.AlbumId, {
|
|
||||||
type: 'Primary',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.AlbumPrimaryImageTag
|
|
||||||
});
|
|
||||||
shape = 'square';
|
|
||||||
} else if (item.SeriesId && item.SeriesPrimaryImageTag) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.SeriesId, {
|
|
||||||
type: 'Primary',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.SeriesPrimaryImageTag
|
|
||||||
});
|
|
||||||
} else if (item.ParentPrimaryImageItemId && item.ParentPrimaryImageTag) {
|
|
||||||
url = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, {
|
|
||||||
type: 'Primary',
|
|
||||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
|
||||||
tag: item.ParentPrimaryImageTag
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editable && url === undefined) {
|
elem.innerHTML = cardHtml;
|
||||||
html += "<a class='itemDetailGalleryLink itemDetailImage defaultCardBackground defaultCardBackground" + cardBuilder.getDefaultBackgroundClass(item.Name) + "' is='emby-linkbutton' style='display:block;margin:0;padding:0;' href='#'>";
|
|
||||||
} else if (!editable && url === undefined) {
|
|
||||||
html += "<div class='itemDetailGalleryLink itemDetailImage defaultCardBackground defaultCardBackground" + cardBuilder.getDefaultBackgroundClass(item.Name) + "' is='emby-linkbutton' style='display:block;margin:0;padding:0;' href='#'>";
|
|
||||||
} else if (editable) {
|
|
||||||
html += "<a class='itemDetailGalleryLink' is='emby-linkbutton' style='display:block;margin:0;padding:0;' href='#'>";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url) {
|
imageLoader.lazyChildren(elem);
|
||||||
html += "<img class='itemDetailImage lazy' src='data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' />";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url === undefined) {
|
|
||||||
html += cardBuilder.getDefaultText(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editable) {
|
|
||||||
html += '</a>';
|
|
||||||
} else if (!editable && url === undefined) {
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var progressHtml = item.IsFolder || !item.UserData ? '' : indicators.getProgressBarHtml(item);
|
|
||||||
html += '<div class="detailImageProgressContainer">';
|
|
||||||
|
|
||||||
if (progressHtml) {
|
|
||||||
html += progressHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
elem.innerHTML = html;
|
|
||||||
|
|
||||||
if (detectRatio && item.PrimaryImageAspectRatio) {
|
|
||||||
if (item.PrimaryImageAspectRatio >= 1.48) {
|
|
||||||
shape = 'thumb';
|
|
||||||
} else if (item.PrimaryImageAspectRatio >= 0.85 && item.PrimaryImageAspectRatio <= 1.34) {
|
|
||||||
shape = 'square';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('thumb' == shape) {
|
|
||||||
elem.classList.add('thumbDetailImageContainer');
|
|
||||||
elem.classList.remove('portraitDetailImageContainer');
|
|
||||||
elem.classList.remove('squareDetailImageContainer');
|
|
||||||
} else if ('square' == shape) {
|
|
||||||
elem.classList.remove('thumbDetailImageContainer');
|
|
||||||
elem.classList.remove('portraitDetailImageContainer');
|
|
||||||
elem.classList.add('squareDetailImageContainer');
|
|
||||||
} else {
|
|
||||||
elem.classList.remove('thumbDetailImageContainer');
|
|
||||||
elem.classList.add('portraitDetailImageContainer');
|
|
||||||
elem.classList.remove('squareDetailImageContainer');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url) {
|
|
||||||
imageLoader.lazyImage(elem.querySelector('img'), url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderImage(page, item, apiClient, user) {
|
function renderImage(page, item, apiClient, user) {
|
||||||
|
@ -1887,12 +1749,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindAll(view, selector, eventName, fn) {
|
function bindAll(view, selector, eventName, fn) {
|
||||||
var i;
|
|
||||||
var length;
|
|
||||||
var elems = view.querySelectorAll(selector);
|
var elems = view.querySelectorAll(selector);
|
||||||
|
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (let elem of elems) {
|
||||||
elems[i].addEventListener(eventName, fn);
|
elem.addEventListener(eventName, fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1912,6 +1772,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||||
var user = responses[1];
|
var user = responses[1];
|
||||||
currentItem = item;
|
currentItem = item;
|
||||||
reloadFromItem(instance, page, params, item, user);
|
reloadFromItem(instance, page, params, item, user);
|
||||||
|
|
||||||
|
let detailImageContainer = page.querySelector('.detailImageContainer');
|
||||||
|
const overlayPlayButton = detailImageContainer.querySelector('.cardOverlayFab-primary');
|
||||||
|
overlayPlayButton.addEventListener('click', onPlayClick);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue