diff --git a/src/renderer/components/item-list/item-table-list/columns/album-artists-column.module.css b/src/renderer/components/item-list/item-table-list/columns/album-artists-column.module.css new file mode 100644 index 000000000..bcdaacda8 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/album-artists-column.module.css @@ -0,0 +1,8 @@ +.group { + gap: var(--theme-spacing-sm) var(--theme-spacing-xs); + overflow: hidden; +} + +.group a { + cursor: pointer; +} diff --git a/src/renderer/components/item-list/item-table-list/columns/album-artists-column.tsx b/src/renderer/components/item-list/item-table-list/columns/album-artists-column.tsx new file mode 100644 index 000000000..353394d23 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/album-artists-column.tsx @@ -0,0 +1,62 @@ +import { memo, useMemo } from 'react'; +import { generatePath, Link } from 'react-router-dom'; + +import styles from './album-artists-column.module.css'; + +import { + ItemTableListInnerColumn, + TableColumnContainer, + TableColumnTextContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { AppRoute } from '/@/renderer/router/routes'; +import { Group } from '/@/shared/components/group/group'; +import { Skeleton } from '/@/shared/components/skeleton/skeleton'; +import { Text } from '/@/shared/components/text/text'; +import { RelatedAlbumArtist } from '/@/shared/types/domain-types'; + +const AlbumArtistsColumn = (props: ItemTableListInnerColumn) => { + const row: RelatedAlbumArtist[] | undefined = ( + props.data as (RelatedAlbumArtist[] | undefined)[] + )[props.rowIndex]?.[props.columns[props.columnIndex].id]; + + const albumArtists = useMemo(() => { + if (!row) return []; + return row.map((albumArtist) => { + const path = generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, { + albumArtistId: albumArtist.id, + }); + return { ...albumArtist, path }; + }); + }, [row]); + + if (Array.isArray(row)) { + return ( + + + {albumArtists.map((albumArtist, index) => ( + + {albumArtist.name} + {index < albumArtists.length - 1 && ','} + + ))} + + + ); + } + + return ( + + + + ); +}; + +export const AlbumArtistsColumnMemo = memo(AlbumArtistsColumn); + +export { AlbumArtistsColumnMemo as AlbumArtistsColumn }; diff --git a/src/renderer/components/item-list/item-table-list/columns/genre-column.module.css b/src/renderer/components/item-list/item-table-list/columns/genre-column.module.css new file mode 100644 index 000000000..bcdaacda8 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/genre-column.module.css @@ -0,0 +1,8 @@ +.group { + gap: var(--theme-spacing-sm) var(--theme-spacing-xs); + overflow: hidden; +} + +.group a { + cursor: pointer; +} diff --git a/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx b/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx index 3c8e65c49..bd244d6b9 100644 --- a/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx +++ b/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx @@ -1,35 +1,47 @@ +import { memo, useMemo } from 'react'; +import { generatePath, Link } from 'react-router-dom'; + +import styles from './genre-column.module.css'; + import { ItemTableListInnerColumn, TableColumnContainer, TableColumnTextContainer, } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { AppRoute } from '/@/renderer/router/routes'; import { Badge } from '/@/shared/components/badge/badge'; import { Group } from '/@/shared/components/group/group'; import { Skeleton } from '/@/shared/components/skeleton/skeleton'; import { Genre } from '/@/shared/types/domain-types'; import { stringToColor } from '/@/shared/utils/string-to-color'; -export const GenreColumn = (props: ItemTableListInnerColumn) => { +const GenreColumn = (props: ItemTableListInnerColumn) => { const row: Genre[] | undefined = (props.data as (Genre[] | undefined)[])[props.rowIndex]?.[ props.columns[props.columnIndex].id ]; - const genres = (row || []).map((genre) => { - const { color, isLight } = stringToColor(genre.name); - return { ...genre, color, isLight }; - }); + const genres = useMemo(() => { + if (!row) return []; + return row.map((genre) => { + const { color, isLight } = stringToColor(genre.name); + const path = generatePath(AppRoute.LIBRARY_GENRES_ALBUMS, { genreId: genre.id }); + return { ...genre, color, isLight, path }; + }); + }, [row]); if (Array.isArray(row)) { return ( - + {genres.map((genre) => ( {genre.name} @@ -45,3 +57,7 @@ export const GenreColumn = (props: ItemTableListInnerColumn) => { ); }; + +export const GenreColumnMemo = memo(GenreColumn); + +export { GenreColumnMemo as GenreColumn }; diff --git a/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx b/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx index 927b08628..ab0bcc06b 100644 --- a/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx +++ b/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx @@ -6,6 +6,7 @@ import styles from './item-table-list-column.module.css'; import i18n from '/@/i18n/i18n'; import { ActionsColumn } from '/@/renderer/components/item-list/item-table-list/columns/actions-column'; +import { AlbumArtistsColumn } from '/@/renderer/components/item-list/item-table-list/columns/album-artists-column'; import { CountColumn } from '/@/renderer/components/item-list/item-table-list/columns/count-column'; import { DateColumn, @@ -47,6 +48,9 @@ export const ItemTableListColumn = (props: ItemTableListColumn) => { case TableColumn.SKIP: return ; + case TableColumn.ALBUM_ARTIST: + return ; + case TableColumn.ALBUM_COUNT: case TableColumn.PLAY_COUNT: case TableColumn.SONG_COUNT: @@ -184,61 +188,61 @@ export const TableColumnHeaderContainer = ( const columnLabelMap: Record = { [TableColumn.ACTIONS]: '', - [TableColumn.ALBUM]: i18n.t('table.column.album', { postProcess: 'titleCase' }) as string, + [TableColumn.ALBUM]: i18n.t('table.column.album', { postProcess: 'upperCase' }) as string, [TableColumn.ALBUM_ARTIST]: i18n.t('table.column.albumArtist', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.ALBUM_COUNT]: i18n.t('table.column.albumCount', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, - [TableColumn.ARTIST]: i18n.t('table.column.artist', { postProcess: 'titleCase' }) as string, + [TableColumn.ARTIST]: i18n.t('table.column.artist', { postProcess: 'upperCase' }) as string, [TableColumn.BIOGRAPHY]: i18n.t('table.column.biography', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, - [TableColumn.BIT_RATE]: i18n.t('table.column.bitrate', { postProcess: 'titleCase' }) as string, - [TableColumn.BPM]: i18n.t('table.column.bpm', { postProcess: 'titleCase' }) as string, - [TableColumn.CHANNELS]: i18n.t('table.column.channels', { postProcess: 'titleCase' }) as string, - [TableColumn.CODEC]: i18n.t('table.column.codec', { postProcess: 'titleCase' }) as string, - [TableColumn.COMMENT]: i18n.t('table.column.comment', { postProcess: 'titleCase' }) as string, + [TableColumn.BIT_RATE]: i18n.t('table.column.bitrate', { postProcess: 'upperCase' }) as string, + [TableColumn.BPM]: i18n.t('table.column.bpm', { postProcess: 'upperCase' }) as string, + [TableColumn.CHANNELS]: i18n.t('table.column.channels', { postProcess: 'upperCase' }) as string, + [TableColumn.CODEC]: i18n.t('table.column.codec', { postProcess: 'upperCase' }) as string, + [TableColumn.COMMENT]: i18n.t('table.column.comment', { postProcess: 'upperCase' }) as string, [TableColumn.DATE_ADDED]: i18n.t('table.column.dateAdded', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.DISC_NUMBER]: i18n.t('table.column.discNumber', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.DURATION]: , - [TableColumn.GENRE]: i18n.t('table.column.genre', { postProcess: 'titleCase' }) as string, + [TableColumn.GENRE]: i18n.t('table.column.genre', { postProcess: 'upperCase' }) as string, [TableColumn.ID]: 'ID', [TableColumn.IMAGE]: '', [TableColumn.LAST_PLAYED]: i18n.t('table.column.lastPlayed', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, - [TableColumn.OWNER]: i18n.t('table.column.owner', { postProcess: 'titleCase' }) as string, - [TableColumn.PATH]: i18n.t('table.column.path', { postProcess: 'titleCase' }) as string, + [TableColumn.OWNER]: i18n.t('table.column.owner', { postProcess: 'upperCase' }) as string, + [TableColumn.PATH]: i18n.t('table.column.path', { postProcess: 'upperCase' }) as string, [TableColumn.PLAY_COUNT]: i18n.t('table.column.playCount', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.RELEASE_DATE]: i18n.t('table.column.releaseDate', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, - [TableColumn.ROW_INDEX]: '#', - [TableColumn.SIZE]: i18n.t('table.column.size', { postProcess: 'titleCase' }) as string, + [TableColumn.ROW_INDEX]: , + [TableColumn.SIZE]: i18n.t('table.column.size', { postProcess: 'upperCase' }) as string, [TableColumn.SKIP]: '', [TableColumn.SONG_COUNT]: i18n.t('table.column.songCount', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, - [TableColumn.TITLE]: i18n.t('table.column.title', { postProcess: 'titleCase' }) as string, + [TableColumn.TITLE]: i18n.t('table.column.title', { postProcess: 'upperCase' }) as string, [TableColumn.TITLE_COMBINED]: i18n.t('table.column.titleCombined', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.TRACK_NUMBER]: i18n.t('table.column.trackNumber', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.USER_FAVORITE]: i18n.t('table.column.favorite', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, [TableColumn.USER_RATING]: i18n.t('table.column.rating', { - postProcess: 'titleCase', + postProcess: 'upperCase', }) as string, - [TableColumn.YEAR]: i18n.t('table.column.releaseYear', { postProcess: 'titleCase' }) as string, + [TableColumn.YEAR]: i18n.t('table.column.releaseYear', { postProcess: 'upperCase' }) as string, }; diff --git a/src/shared/types/types.ts b/src/shared/types/types.ts index e0d68b877..b682f5894 100644 --- a/src/shared/types/types.ts +++ b/src/shared/types/types.ts @@ -144,7 +144,7 @@ export enum PlayerType { export enum TableColumn { ACTIONS = 'actions', ALBUM = 'album', - ALBUM_ARTIST = 'albumArtist', + ALBUM_ARTIST = 'albumArtists', ALBUM_COUNT = 'albumCount', ARTIST = 'artist', BIOGRAPHY = 'biography', @@ -153,7 +153,7 @@ export enum TableColumn { CHANNELS = 'channels', CODEC = 'container', COMMENT = 'comment', - DATE_ADDED = 'dateAdded', + DATE_ADDED = 'createdAt', DISC_NUMBER = 'discNumber', DURATION = 'duration', GENRE = 'genres',