mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-15 18:08:17 -07:00
Merge pull request #6082 from thornbill/mixed-icon
This commit is contained in:
commit
23ee5e62a7
@ -1,4 +1,5 @@
|
||||
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
|
||||
import Movie from '@mui/icons-material/Movie';
|
||||
import MusicNote from '@mui/icons-material/MusicNote';
|
||||
import Photo from '@mui/icons-material/Photo';
|
||||
@ -7,11 +8,11 @@ import Tv from '@mui/icons-material/Tv';
|
||||
import Theaters from '@mui/icons-material/Theaters';
|
||||
import MusicVideo from '@mui/icons-material/MusicVideo';
|
||||
import Book from '@mui/icons-material/Book';
|
||||
import Collections from '@mui/icons-material/Collections';
|
||||
import Queue from '@mui/icons-material/Queue';
|
||||
import Quiz from '@mui/icons-material/Quiz';
|
||||
import VideoLibrary from '@mui/icons-material/VideoLibrary';
|
||||
import Folder from '@mui/icons-material/Folder';
|
||||
import React, { FC } from 'react';
|
||||
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
|
||||
|
||||
interface LibraryIconProps {
|
||||
item: BaseItemDto
|
||||
@ -39,9 +40,11 @@ const LibraryIcon: FC<LibraryIconProps> = ({
|
||||
case CollectionType.Books:
|
||||
return <Book />;
|
||||
case CollectionType.Boxsets:
|
||||
return <Collections />;
|
||||
return <VideoLibrary />;
|
||||
case CollectionType.Playlists:
|
||||
return <Queue />;
|
||||
case undefined:
|
||||
return <Quiz />;
|
||||
default:
|
||||
return <Folder />;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* @module components/cardBuilder/cardBuilder
|
||||
*/
|
||||
|
||||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import { PersonKind } from '@jellyfin/sdk/lib/generated-client/models/person-kind';
|
||||
import escapeHtml from 'escape-html';
|
||||
|
||||
@ -12,7 +13,7 @@ import datetime from 'scripts/datetime';
|
||||
import dom from 'scripts/dom';
|
||||
import globalize from 'lib/globalize';
|
||||
import { getBackdropShape, getPortraitShape, getSquareShape } from 'utils/card';
|
||||
import imageHelper from 'utils/image';
|
||||
import { getItemTypeIcon, getLibraryIcon } from 'utils/image';
|
||||
|
||||
import focusManager from '../focusManager';
|
||||
import imageLoader from '../images/imageLoader';
|
||||
@ -1053,7 +1054,7 @@ function buildCard(index, item, apiClient, options) {
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
}
|
||||
|
||||
if (item.Type === 'CollectionFolder' || item.CollectionType) {
|
||||
if (item.Type === BaseItemKind.CollectionFolder || item.CollectionType) {
|
||||
const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
|
||||
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
|
||||
importRefreshIndicator();
|
||||
@ -1180,41 +1181,18 @@ function getHoverMenuHtml(item, action) {
|
||||
* @returns {string} HTML markup of the card overlay.
|
||||
*/
|
||||
export function getDefaultText(item, options) {
|
||||
if (item.CollectionType) {
|
||||
return '<span class="cardImageIcon material-icons ' + imageHelper.getLibraryIcon(item.CollectionType) + '" aria-hidden="true"></span>';
|
||||
let icon;
|
||||
|
||||
if (item.Type === BaseItemKind.CollectionFolder || item.CollectionType) {
|
||||
icon = getLibraryIcon(item.CollectionType);
|
||||
}
|
||||
|
||||
switch (item.Type) {
|
||||
case 'MusicAlbum':
|
||||
return '<span class="cardImageIcon material-icons album" aria-hidden="true"></span>';
|
||||
case 'MusicArtist':
|
||||
case 'Person':
|
||||
return '<span class="cardImageIcon material-icons person" aria-hidden="true"></span>';
|
||||
case 'Audio':
|
||||
return '<span class="cardImageIcon material-icons audiotrack" aria-hidden="true"></span>';
|
||||
case 'Movie':
|
||||
return '<span class="cardImageIcon material-icons movie" aria-hidden="true"></span>';
|
||||
case 'Episode':
|
||||
case 'Series':
|
||||
return '<span class="cardImageIcon material-icons tv" aria-hidden="true"></span>';
|
||||
case 'Program':
|
||||
return '<span class="cardImageIcon material-icons live_tv" aria-hidden="true"></span>';
|
||||
case 'Book':
|
||||
return '<span class="cardImageIcon material-icons book" aria-hidden="true"></span>';
|
||||
case 'Folder':
|
||||
return '<span class="cardImageIcon material-icons folder" aria-hidden="true"></span>';
|
||||
case 'BoxSet':
|
||||
return '<span class="cardImageIcon material-icons collections" aria-hidden="true"></span>';
|
||||
case 'Playlist':
|
||||
return '<span class="cardImageIcon material-icons view_list" aria-hidden="true"></span>';
|
||||
case 'Photo':
|
||||
return '<span class="cardImageIcon material-icons photo" aria-hidden="true"></span>';
|
||||
case 'PhotoAlbum':
|
||||
return '<span class="cardImageIcon material-icons photo_album" aria-hidden="true"></span>';
|
||||
if (!icon) {
|
||||
icon = getItemTypeIcon(item.Type, options?.defaultCardImageIcon);
|
||||
}
|
||||
|
||||
if (options?.defaultCardImageIcon) {
|
||||
return '<span class="cardImageIcon material-icons ' + options.defaultCardImageIcon + '" aria-hidden="true"></span>';
|
||||
if (icon) {
|
||||
return `<span class="cardImageIcon material-icons ${icon}" aria-hidden="true"></span>`;
|
||||
}
|
||||
|
||||
const defaultName = isUsingLiveTvNaming(item.Type) ? item.Name : itemHelper.getDisplayName(item);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import React, { type FC } from 'react';
|
||||
import Icon from '@mui/material/Icon';
|
||||
import imageHelper from 'utils/image';
|
||||
import { getItemTypeIcon, getLibraryIcon } from 'utils/image';
|
||||
import DefaultName from './DefaultName';
|
||||
import type { ItemDto } from 'types/base/models/item-dto';
|
||||
|
||||
@ -14,38 +14,24 @@ const DefaultIconText: FC<DefaultIconTextProps> = ({
|
||||
item,
|
||||
defaultCardImageIcon
|
||||
}) => {
|
||||
if (item.CollectionType) {
|
||||
return (
|
||||
<Icon
|
||||
className='cardImageIcon'
|
||||
sx={{ color: 'inherit', fontSize: '5em' }}
|
||||
aria-hidden='true'
|
||||
>
|
||||
{imageHelper.getLibraryIcon(item.CollectionType)}
|
||||
</Icon>
|
||||
);
|
||||
let icon;
|
||||
|
||||
if (item.Type === BaseItemKind.CollectionFolder || item.CollectionType) {
|
||||
icon = getLibraryIcon(item.CollectionType);
|
||||
}
|
||||
|
||||
if (item.Type && !(item.Type === BaseItemKind.TvChannel || item.Type === BaseItemKind.Studio )) {
|
||||
return (
|
||||
<Icon
|
||||
className='cardImageIcon'
|
||||
sx={{ color: 'inherit', fontSize: '5em' }}
|
||||
aria-hidden='true'
|
||||
>
|
||||
{imageHelper.getItemTypeIcon(item.Type)}
|
||||
</Icon>
|
||||
);
|
||||
if (!icon) {
|
||||
icon = getItemTypeIcon(item.Type, defaultCardImageIcon);
|
||||
}
|
||||
|
||||
if (defaultCardImageIcon) {
|
||||
if (icon) {
|
||||
return (
|
||||
<Icon
|
||||
className='cardImageIcon'
|
||||
sx={{ color: 'inherit', fontSize: '5em' }}
|
||||
aria-hidden='true'
|
||||
>
|
||||
{defaultCardImageIcon}
|
||||
{icon}
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
101
src/utils/image.test.ts
Normal file
101
src/utils/image.test.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { getItemTypeIcon, getLibraryIcon } from './image';
|
||||
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
|
||||
|
||||
const ITEM_ICON_MAP: Record<string, string | undefined> = {
|
||||
AggregateFolder: undefined,
|
||||
Audio: 'audiotrack',
|
||||
AudioBook: undefined,
|
||||
BasePluginFolder: undefined,
|
||||
Book: 'book',
|
||||
BoxSet: 'video_library',
|
||||
Channel: undefined,
|
||||
ChannelFolderItem: undefined,
|
||||
CollectionFolder: undefined,
|
||||
Episode: 'tv',
|
||||
Folder: 'folder',
|
||||
Genre: undefined,
|
||||
LiveTvChannel: undefined,
|
||||
LiveTvProgram: undefined,
|
||||
ManualPlaylistsFolder: undefined,
|
||||
Movie: 'movie',
|
||||
MusicAlbum: 'album',
|
||||
MusicArtist: 'person',
|
||||
MusicGenre: undefined,
|
||||
MusicVideo: undefined,
|
||||
Person: 'person',
|
||||
Photo: 'photo',
|
||||
PhotoAlbum: 'photo_album',
|
||||
Playlist: 'queue',
|
||||
PlaylistsFolder: undefined,
|
||||
Program: 'live_tv',
|
||||
Recording: undefined,
|
||||
Season: undefined,
|
||||
Series: 'tv',
|
||||
Studio: undefined,
|
||||
Trailer: undefined,
|
||||
TvChannel: undefined,
|
||||
TvProgram: undefined,
|
||||
UserRootFolder: undefined,
|
||||
UserView: undefined,
|
||||
Video: undefined,
|
||||
Year: undefined
|
||||
};
|
||||
|
||||
const LIBRARY_ICON_MAP: Record<string, string | undefined> = {
|
||||
Books: 'book',
|
||||
Boxsets: 'video_library',
|
||||
Folders: 'folder',
|
||||
Homevideos: 'photo',
|
||||
Livetv: 'live_tv',
|
||||
Movies: 'movie',
|
||||
Music: 'music_note',
|
||||
Musicvideos: 'music_video',
|
||||
Photos: 'photo',
|
||||
Playlists: 'queue',
|
||||
Trailers: 'theaters',
|
||||
Tvshows: 'tv',
|
||||
Unknown: 'folder'
|
||||
};
|
||||
|
||||
describe('getItemTypeIcon()', () => {
|
||||
it('Should return the correct icon for item type', () => {
|
||||
Object.entries(BaseItemKind).forEach(([key, value]) => {
|
||||
expect(Object.prototype.hasOwnProperty.call(ITEM_ICON_MAP, key)).toBe(true);
|
||||
expect(`${key}=${getItemTypeIcon(value)}`).toBe(`${key}=${ITEM_ICON_MAP[key]}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should return the default icon for unknown type if provided', () => {
|
||||
expect(getItemTypeIcon('foobar', 'default'))
|
||||
.toBe('default');
|
||||
});
|
||||
|
||||
it('Should return undefined for unknown type', () => {
|
||||
expect(getItemTypeIcon('foobar'))
|
||||
.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLibraryIcon()', () => {
|
||||
it('Should return the correct icon for collection type', () => {
|
||||
Object.entries(CollectionType).forEach(([key, value]) => {
|
||||
expect(Object.prototype.hasOwnProperty.call(LIBRARY_ICON_MAP, key)).toBe(true);
|
||||
expect(`${key}=${getLibraryIcon(value)}`).toBe(`${key}=${LIBRARY_ICON_MAP[key]}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should return the correct icon for nonstandard types', () => {
|
||||
expect(getLibraryIcon(undefined))
|
||||
.toBe('quiz');
|
||||
expect(getLibraryIcon('channels'))
|
||||
.toBe('videocam');
|
||||
});
|
||||
|
||||
it('Should return the default icon for unknown types', () => {
|
||||
expect(getLibraryIcon('foobar'))
|
||||
.toBe('folder');
|
||||
});
|
||||
});
|
@ -1,3 +1,4 @@
|
||||
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
|
||||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import type { DeviceInfo } from '@jellyfin/sdk/lib/generated-client/models/device-info';
|
||||
import type { SessionInfo } from '@jellyfin/sdk/lib/generated-client/models/session-info';
|
||||
@ -75,36 +76,39 @@ export function getDeviceIcon(info: DeviceInfo | SessionInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryIcon(library: string | null | undefined) {
|
||||
export function getLibraryIcon(library: CollectionType | string | null | undefined) {
|
||||
switch (library) {
|
||||
case 'movies':
|
||||
return 'video_library';
|
||||
case 'music':
|
||||
return 'library_music';
|
||||
case 'photos':
|
||||
return 'photo_library';
|
||||
case 'livetv':
|
||||
case CollectionType.Movies:
|
||||
return 'movie';
|
||||
case CollectionType.Music:
|
||||
return 'music_note';
|
||||
case CollectionType.Homevideos:
|
||||
case CollectionType.Photos:
|
||||
return 'photo';
|
||||
case CollectionType.Livetv:
|
||||
return 'live_tv';
|
||||
case 'tvshows':
|
||||
case CollectionType.Tvshows:
|
||||
return 'tv';
|
||||
case 'trailers':
|
||||
return 'local_movies';
|
||||
case 'homevideos':
|
||||
return 'photo_library';
|
||||
case 'musicvideos':
|
||||
case CollectionType.Trailers:
|
||||
return 'theaters';
|
||||
case CollectionType.Musicvideos:
|
||||
return 'music_video';
|
||||
case 'books':
|
||||
return 'library_books';
|
||||
case CollectionType.Books:
|
||||
return 'book';
|
||||
case CollectionType.Boxsets:
|
||||
return 'video_library';
|
||||
case CollectionType.Playlists:
|
||||
return 'queue';
|
||||
case 'channels':
|
||||
return 'videocam';
|
||||
case 'playlists':
|
||||
return 'view_list';
|
||||
case undefined:
|
||||
return 'quiz';
|
||||
default:
|
||||
return 'folder';
|
||||
}
|
||||
}
|
||||
|
||||
export function getItemTypeIcon(itemType: BaseItemKind | string) {
|
||||
export function getItemTypeIcon(itemType: BaseItemKind | string | undefined, defaultIcon?: string) {
|
||||
switch (itemType) {
|
||||
case BaseItemKind.MusicAlbum:
|
||||
return 'album';
|
||||
@ -125,15 +129,15 @@ export function getItemTypeIcon(itemType: BaseItemKind | string) {
|
||||
case BaseItemKind.Folder:
|
||||
return 'folder';
|
||||
case BaseItemKind.BoxSet:
|
||||
return 'collections';
|
||||
return 'video_library';
|
||||
case BaseItemKind.Playlist:
|
||||
return 'view_list';
|
||||
return 'queue';
|
||||
case BaseItemKind.Photo:
|
||||
return 'photo';
|
||||
case BaseItemKind.PhotoAlbum:
|
||||
return 'photo_album';
|
||||
default:
|
||||
return 'folder';
|
||||
return defaultIcon;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user