1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

clean up GenresView & GenresItemsContainer

This commit is contained in:
grafixeyehero 2022-10-29 02:07:24 +03:00
parent 1c6b1fc478
commit 071e7d15d9
4 changed files with 101 additions and 142 deletions

View file

@ -10,14 +10,31 @@ import cardBuilder from '../cardbuilder/cardBuilder';
import layoutManager from '../layoutManager'; import layoutManager from '../layoutManager';
import lazyLoader from '../lazyLoader/lazyLoaderIntersectionObserver'; import lazyLoader from '../lazyLoader/lazyLoaderIntersectionObserver';
import globalize from '../../scripts/globalize'; import globalize from '../../scripts/globalize';
import ItemsScrollerContainerElement from '../../elements/ItemsScrollerContainerElement';
import ItemsContainerElement from '../../elements/ItemsContainerElement';
const createLinkElement = ({ className, title, href }: { className?: string, title?: string | null, href?: string }) => ({
__html: `<a
is="emby-linkbutton"
class="${className}"
href="${href}"
>
<h2 class='sectionTitle sectionTitle-cards'>
${title}
</h2>
<span class='material-icons chevron_right' aria-hidden='true'></span>
</a>`
});
interface GenresItemsContainerProps { interface GenresItemsContainerProps {
topParentId?: string | null; topParentId?: string | null;
getCurrentViewStyle: () => string; itemsResult: BaseItemDtoQueryResult;
itemsResult?: BaseItemDtoQueryResult;
} }
const GenresItemsContainer: FC<GenresItemsContainerProps> = ({ topParentId, getCurrentViewStyle, itemsResult = {} }) => { const GenresItemsContainer: FC<GenresItemsContainerProps> = ({
topParentId,
itemsResult = {}
}) => {
const element = useRef<HTMLDivElement>(null); const element = useRef<HTMLDivElement>(null);
const enableScrollX = useCallback(() => { const enableScrollX = useCallback(() => {
@ -28,21 +45,10 @@ const GenresItemsContainer: FC<GenresItemsContainerProps> = ({ topParentId, getC
return enableScrollX() ? 'overflowPortrait' : 'portrait'; return enableScrollX() ? 'overflowPortrait' : 'portrait';
}, [enableScrollX]); }, [enableScrollX]);
const getThumbShape = useCallback(() => {
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
}, [enableScrollX]);
const fillItemsContainer = useCallback((entry) => { const fillItemsContainer = useCallback((entry) => {
const elem = entry.target; const elem = entry.target;
const id = elem.getAttribute('data-id'); const id = elem.getAttribute('data-id');
const viewStyle = getCurrentViewStyle();
let limit = viewStyle == 'Thumb' || viewStyle == 'ThumbCard' ? 5 : 9;
if (enableScrollX()) {
limit = 10;
}
const enableImageTypes = viewStyle == 'Thumb' || viewStyle == 'ThumbCard' ? 'Primary,Backdrop,Thumb' : 'Primary';
const query = { const query = {
SortBy: 'Random', SortBy: 'Random',
SortOrder: 'Ascending', SortOrder: 'Ascending',
@ -50,108 +56,69 @@ const GenresItemsContainer: FC<GenresItemsContainerProps> = ({ topParentId, getC
Recursive: true, Recursive: true,
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
ImageTypeLimit: 1, ImageTypeLimit: 1,
EnableImageTypes: enableImageTypes, EnableImageTypes: 'Primary',
Limit: limit, Limit: 12,
GenreIds: id, GenreIds: id,
EnableTotalRecordCount: false, EnableTotalRecordCount: false,
ParentId: topParentId ParentId: topParentId
}; };
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => { window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
const items = result.Items || []; cardBuilder.buildCards(result.Items || [], {
if (viewStyle == 'Thumb') { itemsContainer: elem,
cardBuilder.buildCards(items, { shape: getPortraitShape(),
itemsContainer: elem, scalable: true,
shape: getThumbShape(), overlayMoreButton: true,
preferThumb: true, allowBottomPadding: true,
showTitle: true, showTitle: true,
scalable: true, centerText: true,
centerText: true, showYear: true
overlayMoreButton: true, });
allowBottomPadding: false
});
} else if (viewStyle == 'ThumbCard') {
cardBuilder.buildCards(items, {
itemsContainer: elem,
shape: getThumbShape(),
preferThumb: true,
showTitle: true,
scalable: true,
centerText: false,
cardLayout: true,
showYear: true
});
} else if (viewStyle == 'PosterCard') {
cardBuilder.buildCards(items, {
itemsContainer: elem,
shape: getPortraitShape(),
showTitle: true,
scalable: true,
centerText: false,
cardLayout: true,
showYear: true
});
} else if (viewStyle == 'Poster') {
cardBuilder.buildCards(items, {
itemsContainer: elem,
shape: getPortraitShape(),
scalable: true,
overlayMoreButton: true,
allowBottomPadding: true,
showTitle: true,
centerText: true,
showYear: true
});
}
}); });
}, [enableScrollX, getCurrentViewStyle, getPortraitShape, getThumbShape, topParentId]); }, [getPortraitShape, topParentId]);
useEffect(() => { useEffect(() => {
const elem = element.current?.querySelector('#items') as HTMLDivElement; const elem = element.current;
let html = '';
const items = itemsResult.Items || [];
for (let i = 0, length = items.length; i < length; i++) {
const item = items[i];
html += '<div class="verticalSection">';
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl(item, {
context: 'movies',
parentId: topParentId
}) + '" class="more button-flat button-flat-mini sectionTitleTextButton btnMoreFromGenre' + item.Id + '">';
html += '<h2 class="sectionTitle sectionTitle-cards">';
html += escapeHTML(item.Name);
html += '</h2>';
html += '<span class="material-icons chevron_right" aria-hidden="true"></span>';
html += '</a>';
html += '</div>';
if (enableScrollX()) {
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x lazy" data-id="' + item.Id + '">';
} else {
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap lazy padded-left padded-right" data-id="' + item.Id + '">';
}
html += '</div>';
html += '</div>';
}
if (!itemsResult.Items?.length) {
html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoGenresAvailable') + '</p>';
html += '</div>';
}
elem.innerHTML = html;
lazyLoader.lazyChildren(elem, fillItemsContainer); lazyLoader.lazyChildren(elem, fillItemsContainer);
}, [getCurrentViewStyle, itemsResult.Items, fillItemsContainer, topParentId, enableScrollX]); }, [itemsResult.Items, fillItemsContainer]);
const items = itemsResult.Items || [];
return ( return (
<div ref={element}> <div ref={element}>
<div id='items'/> {
!items.length ? (
<div className='noItemsMessage centerMessage'>
<h1>{globalize.translate('MessageNothingHere')}</h1>
<p>{globalize.translate('MessageNoGenresAvailable')}</p>
</div>
) : items.map((item, index) => (
<div key={index} className='verticalSection'>
<div
className='sectionTitleContainer sectionTitleContainer-cards padded-left'
dangerouslySetInnerHTML={createLinkElement({
className: 'more button-flat button-flat-mini sectionTitleTextButton btnMoreFromGenre',
title: escapeHTML(item.Name),
href: appRouter.getRouteUrl(item, {
context: 'movies',
parentId: topParentId
})
})}
/>
{enableScrollX() ?
<ItemsScrollerContainerElement
scrollerclassName='padded-top-focusscale padded-bottom-focusscale'
dataMousewheel='false'
dataCenterfocus='true'
className='itemsContainer scrollSlider focuscontainer-x lazy'
dataId={item.Id}
/> : <ItemsContainerElement
className='itemsContainer vertical-wrap lazy padded-left padded-right'
dataId={item.Id}
/>
}
</div>
))
}
</div> </div>
); );
}; };

View file

@ -1,22 +1,25 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
const createElement = ({ className }: IProps) => ({ const createElement = ({ className, dataId }: IProps) => ({
__html: `<div __html: `<div
is="emby-itemscontainer" is="emby-itemscontainer"
class="${className}" class="${className}"
${dataId}
> >
</div>` </div>`
}); });
interface IProps { interface IProps {
className?: string; className?: string;
dataId?: string;
} }
const ItemsContainerElement: FC<IProps> = ({ className }) => { const ItemsContainerElement: FC<IProps> = ({ className, dataId }) => {
return ( return (
<div <div
dangerouslySetInnerHTML={createElement({ dangerouslySetInnerHTML={createElement({
className: className className: className,
dataId: dataId ? `data-id="${dataId}"` : ''
})} })}
/> />
); );

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
const createScroller = ({ scrollerclassName, dataHorizontal, dataMousewheel, dataCenterfocus, className }: IProps) => ({ const createScroller = ({ scrollerclassName, dataHorizontal, dataMousewheel, dataCenterfocus, dataId, className }: IProps) => ({
__html: `<div is="emby-scroller" __html: `<div is="emby-scroller"
class="${scrollerclassName}" class="${scrollerclassName}"
${dataHorizontal} ${dataHorizontal}
@ -10,6 +10,7 @@ const createScroller = ({ scrollerclassName, dataHorizontal, dataMousewheel, dat
<div <div
is="emby-itemscontainer" is="emby-itemscontainer"
class="${className}" class="${className}"
${dataId}
> >
</div> </div>
</div>` </div>`
@ -20,10 +21,11 @@ interface IProps {
dataHorizontal?: string; dataHorizontal?: string;
dataMousewheel?: string; dataMousewheel?: string;
dataCenterfocus?: string; dataCenterfocus?: string;
dataId?: string;
className?: string; className?: string;
} }
const ItemsScrollerContainerElement: FC<IProps> = ({ scrollerclassName, dataHorizontal, dataMousewheel, dataCenterfocus, className }) => { const ItemsScrollerContainerElement: FC<IProps> = ({ scrollerclassName, dataHorizontal, dataMousewheel, dataCenterfocus, dataId, className }) => {
return ( return (
<div <div
dangerouslySetInnerHTML={createScroller({ dangerouslySetInnerHTML={createScroller({
@ -31,6 +33,7 @@ const ItemsScrollerContainerElement: FC<IProps> = ({ scrollerclassName, dataHori
dataHorizontal: dataHorizontal ? `data-horizontal="${dataHorizontal}"` : '', dataHorizontal: dataHorizontal ? `data-horizontal="${dataHorizontal}"` : '',
dataMousewheel: dataMousewheel ? `data-mousewheel="${dataMousewheel}"` : '', dataMousewheel: dataMousewheel ? `data-mousewheel="${dataMousewheel}"` : '',
dataCenterfocus: dataCenterfocus ? `data-centerfocus="${dataCenterfocus}"` : '', dataCenterfocus: dataCenterfocus ? `data-centerfocus="${dataCenterfocus}"` : '',
dataId: dataId ? `data-id="${dataId}"` : '',
className: className className: className
})} })}
/> />

View file

@ -1,54 +1,40 @@
import type { BaseItemDtoQueryResult } from '@jellyfin/sdk/lib/generated-client'; import type { BaseItemDtoQueryResult } from '@jellyfin/sdk/lib/generated-client';
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import React, { FC, useCallback, useEffect, useState } from 'react';
import loading from '../../components/loading/loading'; import loading from '../../components/loading/loading';
import * as userSettings from '../../scripts/settings/userSettings';
import GenresItemsContainer from '../../components/common/GenresItemsContainer'; import GenresItemsContainer from '../../components/common/GenresItemsContainer';
import { LibraryViewProps, Query } from '../../types/interface'; import { LibraryViewProps } from '../../types/interface';
const GenresView: FC<LibraryViewProps> = ({ topParentId }) => { const GenresView: FC<LibraryViewProps> = ({ topParentId }) => {
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({}); const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
const element = useRef<HTMLDivElement>(null);
const getSettingsKey = useCallback(() => {
return topParentId + '-genres';
}, [topParentId]);
const getViewSettings = useCallback(() => {
return getSettingsKey() + '-view';
}, [getSettingsKey]);
let query = useMemo<Query>(() => ({
SortBy: 'SortName',
SortOrder: 'Ascending',
IncludeItemTypes: 'Movie',
Recursive: true,
EnableTotalRecordCount: false,
Limit: userSettings.libraryPageSize(undefined),
StartIndex: 0,
ParentId: topParentId }), [topParentId]);
query = userSettings.loadQuerySettings(getSettingsKey(), query);
const getCurrentViewStyle = useCallback(() => {
return userSettings.get(getViewSettings(), false) || 'Poster';
}, [getViewSettings]);
const reloadItems = useCallback(() => { const reloadItems = useCallback(() => {
loading.show(); loading.show();
window.ApiClient.getGenres(window.ApiClient.getCurrentUserId(), query).then((result) => { window.ApiClient.getGenres(
window.ApiClient.getCurrentUserId(),
{
SortBy: 'SortName',
SortOrder: 'Ascending',
IncludeItemTypes: 'Movie',
Recursive: true,
EnableTotalRecordCount: false,
ParentId: topParentId
}
).then((result) => {
setItemsResult(result); setItemsResult(result);
loading.hide(); loading.hide();
}); });
}, [query]); }, [topParentId]);
useEffect(() => { useEffect(() => {
reloadItems(); reloadItems();
}, [reloadItems]); }, [reloadItems]);
return ( return (
<div ref={element}> <GenresItemsContainer
<GenresItemsContainer topParentId={topParentId} getCurrentViewStyle={getCurrentViewStyle} itemsResult={itemsResult} /> topParentId={topParentId}
</div> itemsResult={itemsResult}
/>
); );
}; };