From 92ed674e7e038b673dd2eb77a8afec1bec2a913f Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Sun, 15 Oct 2023 02:02:51 -0400 Subject: [PATCH 1/3] Remove click action from item details primary image --- src/components/cardbuilder/cardBuilder.js | 4 +- src/components/cardbuilder/cardImage.ts | 61 +++++++++++++++++++++++ src/controllers/itemDetails/index.js | 33 ++++-------- src/utils/card.ts | 3 +- 4 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 src/components/cardbuilder/cardImage.ts diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index 8c746554d..811bac185 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -261,7 +261,7 @@ function buildCardsHtmlInternal(items, options) { * @param {string} shape - Shape of the desired image. * @returns {CardImageUrl} Object representing the URL of the card's image. */ -function getCardImageUrl(item, apiClient, options, shape) { +export function getCardImageUrl(item, apiClient, options, shape) { item = item.ProgramInfo || item; const width = options.width; @@ -1049,7 +1049,7 @@ function buildCard(index, item, apiClient, options) { cardImageContainerOpen += getDefaultText(item, options); } - const tagName = (layoutManager.tv) && !overlayButtons ? 'button' : 'div'; + const tagName = layoutManager.tv && !overlayButtons ? 'button' : 'div'; const nameWithPrefix = (item.SortName || item.Name || ''); let prefix = nameWithPrefix.substring(0, Math.min(3, nameWithPrefix.length)); diff --git a/src/components/cardbuilder/cardImage.ts b/src/components/cardbuilder/cardImage.ts new file mode 100644 index 000000000..087c8fc18 --- /dev/null +++ b/src/components/cardbuilder/cardImage.ts @@ -0,0 +1,61 @@ +import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; +import type { ApiClient } from 'jellyfin-apiclient'; +import type { CardOptions } from 'types/cardOptions'; +import { CardShape } from 'utils/card'; + +import { getCardImageUrl } from './cardBuilder'; + +/** + * Builds an html string for a basic image only card. + */ +export function buildCardImage( + apiClient: ApiClient, + item: BaseItemDto, + options: CardOptions +): string { + let shape: CardShape = CardShape.Square; + if (item.PrimaryImageAspectRatio) { + if (item.PrimaryImageAspectRatio >= 3) { + shape = CardShape.Banner; + } else if (item.PrimaryImageAspectRatio >= 1.33) { + shape = CardShape.Backdrop; + } else if (item.PrimaryImageAspectRatio > 0.71) { + shape = CardShape.Square; + } else { + shape = CardShape.Portrait; + } + } + + const image = getCardImageUrl( + item, + apiClient, + options, + shape + ); + + if (!image) return ''; + + const className = ` ${shape}Card`; + + const { blurhash, imgUrl } = image; + let blurhashAttrib = ''; + if (blurhash && blurhash.length > 0) { + blurhashAttrib = `data-blurhash="${blurhash}"`; + } + + return ( + `
+
+
+
+
+
+
+
` + ); +} diff --git a/src/controllers/itemDetails/index.js b/src/controllers/itemDetails/index.js index d8adec3ad..9f214856f 100644 --- a/src/controllers/itemDetails/index.js +++ b/src/controllers/itemDetails/index.js @@ -7,6 +7,7 @@ import isEqual from 'lodash-es/isEqual'; import { appHost } from 'components/apphost'; import { clearBackdrop, setBackdrops } from 'components/backdrop/backdrop'; import cardBuilder from 'components/cardbuilder/cardBuilder'; +import { buildCardImage } from 'components/cardbuilder/cardImage'; import confirm from 'components/confirm/confirm'; import imageLoader from 'components/images/imageLoader'; import itemContextMenu from 'components/itemContextMenu'; @@ -526,7 +527,7 @@ function reloadFromItem(instance, page, params, item, user) { libraryMenu.setTitle(''); // Start rendering the artwork first - renderImage(page, item); + renderImage(page, item, apiClient); // Save some screen real estate in TV mode if (!layoutManager.tv) { renderLogo(page, item, apiClient); @@ -717,31 +718,20 @@ function renderLinks(page, item) { } } -function renderDetailImage(elem, item, loader) { - const itemArray = []; - itemArray.push(item); - const cardHtml = cardBuilder.getCardsHtml(itemArray, { - shape: 'auto', - showTitle: false, - centerText: true, - overlayText: false, - transition: false, - disableHoverMenu: true, - disableIndicators: true, - overlayPlayButton: layoutManager.desktop, - action: layoutManager.desktop ? 'resume' : 'none', - width: dom.getWindowSize().innerWidth * 0.25 - }); +function renderDetailImage(apiClient, elem, item, loader) { + const html = buildCardImage( + apiClient, + item, + { width: dom.getWindowSize().innerWidth * 0.25 } + ); - elem.innerHTML = cardHtml; + elem.innerHTML = html; loader.lazyChildren(elem); - - // Avoid breaking the design by preventing focus of the poster using the keyboard. - elem.querySelector('a, button').tabIndex = -1; } -function renderImage(page, item) { +function renderImage(page, item, apiClient) { renderDetailImage( + apiClient, page.querySelector('.detailImageContainer'), item, imageLoader @@ -2016,7 +2006,6 @@ export default function (view, params) { bindAll(view, '.btnCancelSeriesTimer', 'click', onCancelSeriesTimerClick); bindAll(view, '.btnCancelTimer', 'click', onCancelTimerClick); bindAll(view, '.btnDownload', 'click', onDownloadClick); - view.querySelector('.detailImageContainer').addEventListener('click', onPlayClick); view.querySelector('.trackSelections').addEventListener('submit', onTrackSelectionsSubmit); view.querySelector('.btnSplitVersions').addEventListener('click', function () { splitVersions(self, view, apiClient, params); diff --git a/src/utils/card.ts b/src/utils/card.ts index c3f047a79..bdb68e724 100644 --- a/src/utils/card.ts +++ b/src/utils/card.ts @@ -1,6 +1,7 @@ -enum CardShape { +export enum CardShape { Backdrop = 'backdrop', BackdropOverflow = 'overflowBackdrop', + Banner = 'banner', Portrait = 'portrait', PortraitOverflow = 'overflowPortrait', Square = 'square', From 680b6c9f339d5b99b4e1af79b6bcad529bb7c4da Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 30 Nov 2023 13:09:29 -0500 Subject: [PATCH 2/3] Add icon support to cardImage --- src/components/cardbuilder/cardImage.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/components/cardbuilder/cardImage.ts b/src/components/cardbuilder/cardImage.ts index 087c8fc18..05379ae68 100644 --- a/src/components/cardbuilder/cardImage.ts +++ b/src/components/cardbuilder/cardImage.ts @@ -1,9 +1,10 @@ import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; +import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind'; import type { ApiClient } from 'jellyfin-apiclient'; import type { CardOptions } from 'types/cardOptions'; import { CardShape } from 'utils/card'; -import { getCardImageUrl } from './cardBuilder'; +import { getCardImageUrl, getDefaultText } from './cardBuilder'; /** * Builds an html string for a basic image only card. @@ -38,6 +39,17 @@ export function buildCardImage( const className = ` ${shape}Card`; const { blurhash, imgUrl } = image; + + let cardPadderIcon = ''; + // TV Channel logos are transparent so skip the placeholder to avoid overlapping + if (imgUrl && item.Type !== BaseItemKind.TvChannel) { + cardPadderIcon = getDefaultText(item, { + // Always use an icon + defaultCardImageIcon: 'folder', + ...options + }); + } + let blurhashAttrib = ''; if (blurhash && blurhash.length > 0) { blurhashAttrib = `data-blurhash="${blurhash}"`; @@ -47,7 +59,9 @@ export function buildCardImage( `
-
+
+ ${cardPadderIcon} +
Date: Thu, 4 Jan 2024 11:11:21 -0500 Subject: [PATCH 3/3] Remove unnecessary class name variable --- src/components/cardbuilder/cardImage.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/cardbuilder/cardImage.ts b/src/components/cardbuilder/cardImage.ts index 05379ae68..b6d73744d 100644 --- a/src/components/cardbuilder/cardImage.ts +++ b/src/components/cardbuilder/cardImage.ts @@ -1,6 +1,7 @@ import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind'; import type { ApiClient } from 'jellyfin-apiclient'; + import type { CardOptions } from 'types/cardOptions'; import { CardShape } from 'utils/card'; @@ -36,8 +37,6 @@ export function buildCardImage( if (!image) return ''; - const className = ` ${shape}Card`; - const { blurhash, imgUrl } = image; let cardPadderIcon = ''; @@ -56,7 +55,7 @@ export function buildCardImage( } return ( - `
+ `