diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index ac60ebc58..15c2eaf1c 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1086,6 +1086,7 @@ "bpm": "$t(common.bpm)", "channels": "$t(common.channel_other)", "codec": "$t(common.codec)", + "composer": "composer", "dateAdded": "date added", "discNumber": "disc number", "duration": "$t(common.duration)", diff --git a/src/renderer/components/item-list/item-table-list/columns/composer-column.module.css b/src/renderer/components/item-list/item-table-list/columns/composer-column.module.css new file mode 100644 index 000000000..0fcce5237 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/composer-column.module.css @@ -0,0 +1,16 @@ +.composers-container { + display: -webkit-box; + overflow: hidden; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + color: var(--theme-colors-foreground-muted); + user-select: none; +} + +.composers-container.compact { + -webkit-line-clamp: 1; +} + +.composers-container.large { + -webkit-line-clamp: 3; +} diff --git a/src/renderer/components/item-list/item-table-list/columns/composer-column.tsx b/src/renderer/components/item-list/item-table-list/columns/composer-column.tsx new file mode 100644 index 000000000..c655bb1e2 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/composer-column.tsx @@ -0,0 +1,50 @@ +import clsx from 'clsx'; +import { memo } from 'react'; + +import styles from './composer-column.module.css'; + +import { + ColumnNullFallback, + ColumnSkeletonVariable, + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { JoinedArtists } from '/@/renderer/features/albums/components/joined-artists'; +import { Album, RelatedArtist, Song } from '/@/shared/types/domain-types'; + +const ComposerColumn = (props: ItemTableListInnerColumn) => { + const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex]; + const item = rowItem as Album | Song | undefined; + + const composers = item?.participants?.composer || []; + + if (composers && Array.isArray(composers) && composers.length > 0) { + return ( + +
+ +
+
+ ); + } + + if (composers?.length === 0 || item === null || item === undefined) { + return ; + } + + return ; +}; + +export const ComposerColumnMemo = memo(ComposerColumn); + +export { ComposerColumnMemo as ComposerColumn }; diff --git a/src/renderer/components/item-list/item-table-list/default-columns.ts b/src/renderer/components/item-list/item-table-list/default-columns.ts index e35a0dd40..fdba40291 100644 --- a/src/renderer/components/item-list/item-table-list/default-columns.ts +++ b/src/renderer/components/item-list/item-table-list/default-columns.ts @@ -94,6 +94,15 @@ export const SONG_TABLE_COLUMNS: DefaultTableColumn[] = [ value: TableColumn.ARTIST, width: 300, }, + { + align: 'start', + autoSize: false, + isEnabled: false, + label: i18n.t('table.config.label.composer', { postProcess: 'titleCase' }), + pinned: null, + value: TableColumn.COMPOSER, + width: 300, + }, { align: 'start', autoSize: false, @@ -360,6 +369,15 @@ export const ALBUM_TABLE_COLUMNS: DefaultTableColumn[] = [ value: TableColumn.ARTIST, width: 300, }, + { + align: 'start', + autoSize: false, + isEnabled: false, + label: i18n.t('table.config.label.composer', { postProcess: 'titleCase' }), + pinned: null, + value: TableColumn.COMPOSER, + width: 300, + }, { align: 'center', autoSize: false, 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 43a3a062a..4985577c1 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 @@ -26,6 +26,7 @@ import { ActionsColumn } from '/@/renderer/components/item-list/item-table-list/ import { AlbumArtistsColumn } from '/@/renderer/components/item-list/item-table-list/columns/album-artists-column'; import { AlbumColumn } from '/@/renderer/components/item-list/item-table-list/columns/album-column'; import { ArtistsColumn } from '/@/renderer/components/item-list/item-table-list/columns/artists-column'; +import { ComposerColumn } from '/@/renderer/components/item-list/item-table-list/columns/composer-column'; import { CountColumn } from '/@/renderer/components/item-list/item-table-list/columns/count-column'; import { AbsoluteDateColumn, @@ -482,6 +483,9 @@ export const ItemTableListColumn = (props: ItemTableListColumn) => { case TableColumn.TRACK_NUMBER: return ; + case TableColumn.COMPOSER: + return ; + case TableColumn.DATE_ADDED: return ; @@ -1126,6 +1130,9 @@ const columnLabelMap: Record = { [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.COMPOSER]: i18n.t('table.config.label.composer', { + postProcess: 'upperCase', + }) as string, [TableColumn.DATE_ADDED]: i18n.t('table.column.dateAdded', { postProcess: 'upperCase', }) as string, diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts index b66fe3daa..e7463c0e0 100644 --- a/src/renderer/store/settings.store.ts +++ b/src/renderer/store/settings.store.ts @@ -1941,10 +1941,52 @@ export const useSettingsStore = createWithEqualityFn()( }); } + if (version <= 21) { + // Add COMPOSER column to SONG and ALBUM table configs + const composerColumn: ItemTableListColumnConfig = { + align: 'start', + autoSize: false, + id: TableColumn.COMPOSER, + isEnabled: false, + pinned: null, + width: 300, + }; + + const listKeysToUpdate: (LibraryItem | string)[] = [ + LibraryItem.SONG, + LibraryItem.ALBUM, + LibraryItem.PLAYLIST_SONG, + LibraryItem.QUEUE_SONG, + ItemListKey.ALBUM_DETAIL, + ItemListKey.FULL_SCREEN, + ItemListKey.SIDE_QUEUE, + ]; + + listKeysToUpdate.forEach((listKey) => { + const listConfig = state.lists[listKey]; + if (listConfig?.table?.columns) { + const columns = listConfig.table.columns; + const hasComposer = columns.some( + (col) => col.id === TableColumn.COMPOSER, + ); + if (!hasComposer) { + const artistIndex = columns.findIndex( + (col) => col.id === TableColumn.ARTIST, + ); + if (artistIndex >= 0) { + columns.splice(artistIndex + 1, 0, composerColumn); + } else { + columns.push(composerColumn); + } + } + } + }); + } + return persistedState; }, name: 'store_settings', - version: 21, + version: 22, }, ), ); diff --git a/src/shared/types/types.ts b/src/shared/types/types.ts index 0aa56b385..9a46079a7 100644 --- a/src/shared/types/types.ts +++ b/src/shared/types/types.ts @@ -168,6 +168,7 @@ export enum TableColumn { CHANNELS = 'channels', CODEC = 'container', COMMENT = 'comment', + COMPOSER = 'composer', DATE_ADDED = 'createdAt', DISC_NUMBER = 'discNumber', DURATION = 'duration',