diff --git a/src/renderer/components/item-list/item-detail-list/columns/actions-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/actions-column.tsx new file mode 100644 index 000000000..2e90299ce --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/actions-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const ActionsColumn = (_props: ItemDetailListCellProps) => null; diff --git a/src/renderer/components/item-list/item-detail-list/columns/album-artist-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/album-artist-column.tsx new file mode 100644 index 000000000..350414769 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/album-artist-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const AlbumArtistColumn = ({ song }: ItemDetailListCellProps) => + song.albumArtistName ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/album-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/album-column.tsx new file mode 100644 index 000000000..902edecd5 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/album-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const AlbumColumn = ({ song }: ItemDetailListCellProps) => song.album ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/artist-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/artist-column.tsx new file mode 100644 index 000000000..ffc8d1a02 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/artist-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const ArtistColumn = ({ song }: ItemDetailListCellProps) => song.artistName ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/bit-depth-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/bit-depth-column.tsx new file mode 100644 index 000000000..b268652dd --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/bit-depth-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const BitDepthColumn = ({ song }: ItemDetailListCellProps) => + song.bitDepth != null ? String(song.bitDepth) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/bit-rate-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/bit-rate-column.tsx new file mode 100644 index 000000000..a4584bac4 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/bit-rate-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const BitRateColumn = ({ song }: ItemDetailListCellProps) => + song.bitRate != null ? `${song.bitRate} kbps` : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/bpm-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/bpm-column.tsx new file mode 100644 index 000000000..b8cfffc4f --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/bpm-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const BpmColumn = ({ song }: ItemDetailListCellProps) => + song.bpm != null ? String(song.bpm) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/channels-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/channels-column.tsx new file mode 100644 index 000000000..d15eac622 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/channels-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const ChannelsColumn = ({ song }: ItemDetailListCellProps) => + song.channels != null ? String(song.channels) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/codec-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/codec-column.tsx new file mode 100644 index 000000000..8878a4a04 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/codec-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const CodecColumn = ({ song }: ItemDetailListCellProps) => song.container ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/comment-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/comment-column.tsx new file mode 100644 index 000000000..890aedf4d --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/comment-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const CommentColumn = ({ song }: ItemDetailListCellProps) => song.comment ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/composer-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/composer-column.tsx new file mode 100644 index 000000000..57bd2e7f1 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/composer-column.tsx @@ -0,0 +1,7 @@ +import { ItemDetailListCellProps } from './types'; + +export const ComposerColumn = ({ song }: ItemDetailListCellProps) => { + const composers = song.participants?.composer; + if (!composers?.length) return '—'; + return composers.map((a) => a.name).join(', '); +}; diff --git a/src/renderer/components/item-list/item-detail-list/columns/date-added-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/date-added-column.tsx new file mode 100644 index 000000000..4252bb667 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/date-added-column.tsx @@ -0,0 +1,5 @@ +import { ItemDetailListCellProps } from './types'; +import { formatDateAbsolute } from '/@/renderer/utils/format'; + +export const DateAddedColumn = ({ song }: ItemDetailListCellProps) => + song.createdAt ? formatDateAbsolute(song.createdAt) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/default-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/default-column.tsx new file mode 100644 index 000000000..88a980746 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/default-column.tsx @@ -0,0 +1,12 @@ +import { ItemDetailListCellProps } from './types'; +import { TableColumn } from '/@/shared/types/types'; + +interface DefaultColumnProps extends ItemDetailListCellProps { + columnId: string; +} + +export const DefaultColumn = ({ columnId, song }: DefaultColumnProps) => { + const raw = (song as Record)[columnId]; + if (raw === undefined || raw === null || typeof raw === 'object') return '—'; + return String(raw); +}; diff --git a/src/renderer/components/item-list/item-detail-list/columns/disc-number-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/disc-number-column.tsx new file mode 100644 index 000000000..9edbd78b1 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/disc-number-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const DiscNumberColumn = ({ song }: ItemDetailListCellProps) => + String(song.discNumber ?? 1); diff --git a/src/renderer/components/item-list/item-detail-list/columns/duration-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/duration-column.tsx new file mode 100644 index 000000000..45d280aa6 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/duration-column.tsx @@ -0,0 +1,5 @@ +import formatDuration from 'format-duration'; + +import { ItemDetailListCellProps } from './types'; + +export const DurationColumn = ({ song }: ItemDetailListCellProps) => formatDuration(song.duration); diff --git a/src/renderer/components/item-list/item-detail-list/columns/favorite-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/favorite-column.tsx new file mode 100644 index 000000000..75bfa2eff --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/favorite-column.tsx @@ -0,0 +1,24 @@ +import { ItemDetailListCellProps } from './types'; +import { Icon } from '/@/shared/components/icon/icon'; + +export const FavoriteColumn = ({ + isMutatingFavorite, + onFavoriteClick, + song, +}: ItemDetailListCellProps) => ( +
{ + event.stopPropagation(); + event.preventDefault(); + onFavoriteClick?.(song); + }} + onDoubleClick={(event) => { + event.stopPropagation(); + event.preventDefault(); + }} + role="button" + > + +
+); diff --git a/src/renderer/components/item-list/item-detail-list/columns/genre-badge-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/genre-badge-column.tsx new file mode 100644 index 000000000..d88a93000 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/genre-badge-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const GenreBadgeColumn = ({ song }: ItemDetailListCellProps) => + song.genres?.length ? song.genres.map((g) => g.name).join(', ') : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/genre-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/genre-column.tsx new file mode 100644 index 000000000..ad73b97d5 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/genre-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const GenreColumn = ({ song }: ItemDetailListCellProps) => + song.genres?.length ? song.genres.map((g) => g.name).join(', ') : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/image-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/image-column.tsx new file mode 100644 index 000000000..8e3a11483 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/image-column.tsx @@ -0,0 +1,10 @@ +import { ItemDetailListCellProps } from './types'; +import { ItemImage } from '/@/renderer/components/item-image/item-image'; +import { LibraryItem } from '/@/shared/types/domain-types'; + +export const ImageColumn = ({ song }: ItemDetailListCellProps) => + song.imageId ? ( + + ) : ( + '—' + ); diff --git a/src/renderer/components/item-list/item-detail-list/columns/index.ts b/src/renderer/components/item-list/item-detail-list/columns/index.ts new file mode 100644 index 000000000..db5bb5285 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/index.ts @@ -0,0 +1,127 @@ +import React, { type ReactNode } from 'react'; + +import type { ItemDetailListCellProps } from './types'; + +import { ActionsColumn } from './actions-column'; +import { AlbumArtistColumn } from './album-artist-column'; +import { AlbumColumn } from './album-column'; +import { ArtistColumn } from './artist-column'; +import { BitDepthColumn } from './bit-depth-column'; +import { BitRateColumn } from './bit-rate-column'; +import { BpmColumn } from './bpm-column'; +import { ChannelsColumn } from './channels-column'; +import { CodecColumn } from './codec-column'; +import { CommentColumn } from './comment-column'; +import { ComposerColumn } from './composer-column'; +import { DateAddedColumn } from './date-added-column'; +import { DefaultColumn } from './default-column'; +import { DiscNumberColumn } from './disc-number-column'; +import { DurationColumn } from './duration-column'; +import { FavoriteColumn } from './favorite-column'; +import { GenreBadgeColumn } from './genre-badge-column'; +import { GenreColumn } from './genre-column'; +import { ImageColumn } from './image-column'; +import { LastPlayedColumn } from './last-played-column'; +import { PathColumn } from './path-column'; +import { PlayCountColumn } from './play-count-column'; +import { RatingColumn } from './rating-column'; +import { ReleaseDateColumn } from './release-date-column'; +import { RowIndexColumn } from './row-index-column'; +import { SampleRateColumn } from './sample-rate-column'; +import { SizeColumn } from './size-column'; +import { TitleArtistColumn } from './title-artist-column'; +import { TitleColumn } from './title-column'; +import { TitleCombinedColumn } from './title-combined-column'; +import { TrackNumberColumn } from './track-number-column'; +import { YearColumn } from './year-column'; + +import { TableColumn } from '/@/shared/types/types'; + +type CellComponent = (props: ItemDetailListCellProps) => ReactNode; + +const COLUMN_MAP: Partial> = { + [TableColumn.ACTIONS]: ActionsColumn, + [TableColumn.ALBUM]: AlbumColumn, + [TableColumn.ALBUM_ARTIST]: AlbumArtistColumn, + [TableColumn.ARTIST]: ArtistColumn, + [TableColumn.BIT_DEPTH]: BitDepthColumn, + [TableColumn.BIT_RATE]: BitRateColumn, + [TableColumn.BPM]: BpmColumn, + [TableColumn.CHANNELS]: ChannelsColumn, + [TableColumn.CODEC]: CodecColumn, + [TableColumn.COMMENT]: CommentColumn, + [TableColumn.COMPOSER]: ComposerColumn, + [TableColumn.DATE_ADDED]: DateAddedColumn, + [TableColumn.DISC_NUMBER]: DiscNumberColumn, + [TableColumn.DURATION]: DurationColumn, + [TableColumn.GENRE]: GenreColumn, + [TableColumn.GENRE_BADGE]: GenreBadgeColumn, + [TableColumn.IMAGE]: ImageColumn, + [TableColumn.LAST_PLAYED]: LastPlayedColumn, + [TableColumn.PATH]: PathColumn, + [TableColumn.PLAY_COUNT]: PlayCountColumn, + [TableColumn.RELEASE_DATE]: ReleaseDateColumn, + [TableColumn.ROW_INDEX]: RowIndexColumn, + [TableColumn.SAMPLE_RATE]: SampleRateColumn, + [TableColumn.SIZE]: SizeColumn, + [TableColumn.TITLE]: TitleColumn, + [TableColumn.TITLE_ARTIST]: TitleArtistColumn, + [TableColumn.TITLE_COMBINED]: TitleCombinedColumn, + [TableColumn.TRACK_NUMBER]: TrackNumberColumn, + [TableColumn.USER_FAVORITE]: FavoriteColumn, + [TableColumn.USER_RATING]: RatingColumn, + [TableColumn.YEAR]: YearColumn, +}; + +export type DetailListCellComponentProps = ItemDetailListCellProps & { columnId?: string }; + +export function getDetailListCellComponent( + columnId: string | TableColumn, +): (props: DetailListCellComponentProps) => ReactNode { + const Component = COLUMN_MAP[columnId as TableColumn]; + if (Component) { + return Component as (props: DetailListCellComponentProps) => ReactNode; + } + return (props: DetailListCellComponentProps) => + React.createElement(DefaultColumn, { + columnId: props.columnId ?? (columnId as string), + song: props.song, + }); +} + +export type { ItemDetailListCellProps } from './types'; + +export { + ActionsColumn, + AlbumArtistColumn, + AlbumColumn, + ArtistColumn, + BitDepthColumn, + BitRateColumn, + BpmColumn, + ChannelsColumn, + CodecColumn, + CommentColumn, + ComposerColumn, + DateAddedColumn, + DefaultColumn, + DiscNumberColumn, + DurationColumn, + FavoriteColumn, + GenreBadgeColumn, + GenreColumn, + ImageColumn, + LastPlayedColumn, + PathColumn, + PlayCountColumn, + RatingColumn, + ReleaseDateColumn, + RowIndexColumn, + SampleRateColumn, + SizeColumn, + TitleArtistColumn, + TitleColumn, + TitleCombinedColumn, + TrackNumberColumn, + YearColumn, +}; diff --git a/src/renderer/components/item-list/item-detail-list/columns/last-played-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/last-played-column.tsx new file mode 100644 index 000000000..8c6c3aa63 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/last-played-column.tsx @@ -0,0 +1,5 @@ +import { ItemDetailListCellProps } from './types'; +import { formatDateRelative } from '/@/renderer/utils/format'; + +export const LastPlayedColumn = ({ song }: ItemDetailListCellProps) => + song.lastPlayedAt ? formatDateRelative(song.lastPlayedAt) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx new file mode 100644 index 000000000..54c605203 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const PathColumn = ({ song }: ItemDetailListCellProps) => song.path ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/play-count-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/play-count-column.tsx new file mode 100644 index 000000000..28a307d1a --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/play-count-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const PlayCountColumn = ({ song }: ItemDetailListCellProps) => + String(song.playCount ?? 0); diff --git a/src/renderer/components/item-list/item-detail-list/columns/rating-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/rating-column.tsx new file mode 100644 index 000000000..300a6e63c --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/rating-column.tsx @@ -0,0 +1,6 @@ +import { ItemDetailListCellProps } from './types'; +import { ReadOnlyRating } from '/@/shared/components/read-only-rating/read-only-rating'; + +export const RatingColumn = ({ song }: ItemDetailListCellProps) => ( + +); diff --git a/src/renderer/components/item-list/item-detail-list/columns/release-date-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/release-date-column.tsx new file mode 100644 index 000000000..f2ef18179 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/release-date-column.tsx @@ -0,0 +1,5 @@ +import { ItemDetailListCellProps } from './types'; +import { formatDateAbsoluteUTC } from '/@/renderer/utils/format'; + +export const ReleaseDateColumn = ({ song }: ItemDetailListCellProps) => + song.releaseDate ? formatDateAbsoluteUTC(song.releaseDate) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/row-index-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/row-index-column.tsx new file mode 100644 index 000000000..b96e40116 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/row-index-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const RowIndexColumn = ({ rowIndex }: ItemDetailListCellProps) => + String((rowIndex ?? 0) + 1); diff --git a/src/renderer/components/item-list/item-detail-list/columns/sample-rate-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/sample-rate-column.tsx new file mode 100644 index 000000000..58f9e125b --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/sample-rate-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const SampleRateColumn = ({ song }: ItemDetailListCellProps) => + song.sampleRate != null ? `${song.sampleRate} Hz` : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/size-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/size-column.tsx new file mode 100644 index 000000000..9b8b45287 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/size-column.tsx @@ -0,0 +1,5 @@ +import { ItemDetailListCellProps } from './types'; +import { formatSizeString } from '/@/renderer/utils/format'; + +export const SizeColumn = ({ song }: ItemDetailListCellProps) => + song.size != null ? formatSizeString(song.size) : '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/title-artist-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/title-artist-column.tsx new file mode 100644 index 000000000..8f7c46dfa --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/title-artist-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const TitleArtistColumn = ({ song }: ItemDetailListCellProps) => + [song.name, song.artistName].filter(Boolean).join(' — ') || '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/title-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/title-column.tsx new file mode 100644 index 000000000..d56ff562c --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/title-column.tsx @@ -0,0 +1,3 @@ +import { ItemDetailListCellProps } from './types'; + +export const TitleColumn = ({ song }: ItemDetailListCellProps) => song.name ?? '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/title-combined-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/title-combined-column.tsx new file mode 100644 index 000000000..42afb081e --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/title-combined-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const TitleCombinedColumn = ({ song }: ItemDetailListCellProps) => + [song.name, song.artistName].filter(Boolean).join(' — ') || '—'; diff --git a/src/renderer/components/item-list/item-detail-list/columns/track-number-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/track-number-column.tsx new file mode 100644 index 000000000..c234225c0 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/track-number-column.tsx @@ -0,0 +1,7 @@ +import { ItemDetailListCellProps } from './types'; + +export const TrackNumberColumn = ({ song }: ItemDetailListCellProps) => { + const disc = song.discNumber ?? 1; + const track = song.trackNumber.toString().padStart(2, '0'); + return `${disc} - ${track}`; +}; diff --git a/src/renderer/components/item-list/item-detail-list/columns/types.ts b/src/renderer/components/item-list/item-detail-list/columns/types.ts new file mode 100644 index 000000000..b61dbe849 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/types.ts @@ -0,0 +1,8 @@ +import { Song } from '/@/shared/types/domain-types'; + +export interface ItemDetailListCellProps { + isMutatingFavorite?: boolean; + onFavoriteClick?: (song: Song) => void; + rowIndex?: number; + song: Song; +} diff --git a/src/renderer/components/item-list/item-detail-list/columns/year-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/year-column.tsx new file mode 100644 index 000000000..a736d7834 --- /dev/null +++ b/src/renderer/components/item-list/item-detail-list/columns/year-column.tsx @@ -0,0 +1,4 @@ +import { ItemDetailListCellProps } from './types'; + +export const YearColumn = ({ song }: ItemDetailListCellProps) => + song.releaseYear != null ? String(song.releaseYear) : '—'; diff --git a/src/renderer/components/item-detail/item-detail.module.css b/src/renderer/components/item-list/item-detail-list/item-detail.module.css similarity index 100% rename from src/renderer/components/item-detail/item-detail.module.css rename to src/renderer/components/item-list/item-detail-list/item-detail.module.css diff --git a/src/renderer/components/item-detail/item-detail.tsx b/src/renderer/components/item-list/item-detail-list/item-detail.tsx similarity index 88% rename from src/renderer/components/item-detail/item-detail.tsx rename to src/renderer/components/item-list/item-detail-list/item-detail.tsx index ea4c931ac..2b7e339a9 100644 --- a/src/renderer/components/item-detail/item-detail.tsx +++ b/src/renderer/components/item-list/item-detail-list/item-detail.tsx @@ -1,5 +1,4 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; -import formatDuration from 'format-duration'; import throttle from 'lodash/throttle'; import { AnimatePresence } from 'motion/react'; import { useOverlayScrollbars } from 'overlayscrollbars-react'; @@ -19,6 +18,7 @@ import { useItemSelectionState, } from '/@/renderer/components/item-list/helpers/item-list-state'; import { parseTableColumns } from '/@/renderer/components/item-list/helpers/parse-table-columns'; +import { getDetailListCellComponent } from '/@/renderer/components/item-list/item-detail-list/columns'; import { pickTableColumns, SONG_TABLE_COLUMNS, @@ -31,8 +31,6 @@ import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutatio import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation'; import { AppRoute } from '/@/renderer/router/routes'; import { useSettingsStore } from '/@/renderer/store'; -import { Icon } from '/@/shared/components/icon/icon'; -import { ReadOnlyRating } from '/@/shared/components/read-only-rating/read-only-rating'; import { Skeleton } from '/@/shared/components/skeleton/skeleton'; import { Album, LibraryItem, Song } from '/@/shared/types/domain-types'; import { ItemListKey, TableColumn } from '/@/shared/types/types'; @@ -66,6 +64,7 @@ interface TrackRowProps { internalState: ItemListStateActions; isMutatingFavorite: boolean; onFavoriteClick: (song: Song) => void; + rowIndex: number; song: Song; } @@ -73,7 +72,14 @@ const textAlignFromAlign = (align: ItemTableListColumnConfig['align']) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; const TrackRow = memo( - ({ columns, internalState, isMutatingFavorite, onFavoriteClick, song }: TrackRowProps) => { + ({ + columns, + internalState, + isMutatingFavorite, + onFavoriteClick, + rowIndex, + song, + }: TrackRowProps) => { const playerContext = usePlayer(); const { dragRef, isDragging } = useItemDragDropState({ enableDrag: true, @@ -83,8 +89,6 @@ const TrackRow = memo( itemType: LibraryItem.SONG, playerContext, }); - const discAndCol = - `${song.discNumber ?? 1}` + ' - ' + song.trackNumber.toString().padStart(2, '0'); const isSelected = useItemSelectionState(internalState, song.id); const handleRowClick = useCallback( @@ -195,52 +199,16 @@ const TrackRow = memo( textAlign: textAlignFromAlign(col.align), ...widthStyle, }; - - let content: React.ReactNode; - switch (col.id) { - case TableColumn.DISC_NUMBER: - case TableColumn.TRACK_NUMBER: - content = discAndCol; - break; - case TableColumn.DURATION: - content = formatDuration(song.duration); - break; - case TableColumn.TITLE: - content = song.name; - break; - case TableColumn.USER_FAVORITE: - content = ( -
{ - event.stopPropagation(); - event.preventDefault(); - onFavoriteClick(song); - }} - onDoubleClick={(event) => { - event.stopPropagation(); - event.preventDefault(); - }} - role="button" - > - -
- ); - break; - case TableColumn.USER_RATING: - content = ( - - ); - break; - default: { - const raw = (song as Record)[col.id]; - content = - raw !== undefined && raw !== null && typeof raw !== 'object' - ? String(raw) - : '—'; - break; - } - } + const CellComponent = getDetailListCellComponent(col.id); + const content = ( + + ); return ( @@ -378,13 +346,14 @@ const RowContent = memo(
- {songs.map((song) => ( + {songs.map((song, rowIndex) => ( ))} diff --git a/src/renderer/features/albums/components/album-list-infinite-detail.tsx b/src/renderer/features/albums/components/album-list-infinite-detail.tsx index ec02aff3b..503824ae2 100644 --- a/src/renderer/features/albums/components/album-list-infinite-detail.tsx +++ b/src/renderer/features/albums/components/album-list-infinite-detail.tsx @@ -1,9 +1,9 @@ import { UseSuspenseQueryOptions } from '@tanstack/react-query'; import { api } from '/@/renderer/api'; -import { ItemDetailList } from '/@/renderer/components/item-detail/item-detail'; import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; +import { ItemDetailList } from '/@/renderer/components/item-list/item-detail-list/item-detail'; import { ItemListComponentProps } from '/@/renderer/components/item-list/types'; import { albumQueries } from '/@/renderer/features/albums/api/album-api'; import {