From 76d8b9c894b5bd6cef50cab6692dd1107a1eccce Mon Sep 17 00:00:00 2001 From: jeffvli Date: Thu, 13 Nov 2025 13:31:57 -0800 Subject: [PATCH] add current song styles to rowIndex and title columns --- .../columns/row-index-column.tsx | 40 +++++++++ .../item-table-list/columns/title-column.tsx | 60 ++++++++++++- .../columns/title-combined-column.tsx | 85 ++++++++++++++++++- .../player/hooks/use-is-current-song.ts | 14 +++ 4 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 src/renderer/features/player/hooks/use-is-current-song.ts diff --git a/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx b/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx index e84fce77b..fb2035438 100644 --- a/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx +++ b/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx @@ -8,10 +8,27 @@ import { TableColumnTextContainer, } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; import { ItemListItem } from '/@/renderer/components/item-list/types'; +import { useIsCurrentSong } from '/@/renderer/features/player/hooks/use-is-current-song'; +import { usePlayerStatus } from '/@/renderer/store'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; +import { Flex } from '/@/shared/components/flex/flex'; +import { Icon } from '/@/shared/components/icon/icon'; import { Text } from '/@/shared/components/text/text'; +import { LibraryItem, QueueSong } from '/@/shared/types/domain-types'; +import { PlayerStatus } from '/@/shared/types/types'; export const RowIndexColumn = (props: ItemTableListInnerColumn) => { + const { itemType } = props; + + switch (itemType) { + case LibraryItem.QUEUE_SONG: + return ; + default: + return ; + } +}; + +const DefaultRowIndexColumn = (props: ItemTableListInnerColumn) => { const { controls, enableExpansion } = props; if (enableExpansion) { @@ -41,3 +58,26 @@ export const RowIndexColumn = (props: ItemTableListInnerColumn) => { return {props.rowIndex}; }; + +const QueueSongRowIndexColumn = (props: ItemTableListInnerColumn) => { + const status = usePlayerStatus(); + const { isActive } = useIsCurrentSong(props.data[props.rowIndex] as QueueSong); + + return ( + + {isActive ? ( + status === PlayerStatus.PLAYING ? ( + + + + ) : ( + + + + ) + ) : ( + props.rowIndex + )} + + ); +}; diff --git a/src/renderer/components/item-list/item-table-list/columns/title-column.tsx b/src/renderer/components/item-list/item-table-list/columns/title-column.tsx index 96b3835ee..2537aa4a6 100644 --- a/src/renderer/components/item-list/item-table-list/columns/title-column.tsx +++ b/src/renderer/components/item-list/item-table-list/columns/title-column.tsx @@ -10,9 +10,22 @@ import { ItemTableListInnerColumn, TableColumnContainer, } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { useIsCurrentSong } from '/@/renderer/features/player/hooks/use-is-current-song'; import { Text } from '/@/shared/components/text/text'; +import { LibraryItem, QueueSong } from '/@/shared/types/domain-types'; export const TitleColumn = (props: ItemTableListInnerColumn) => { + const { itemType } = props; + + switch (itemType) { + case LibraryItem.QUEUE_SONG: + return ; + default: + return ; + } +}; + +function DefaultTitleColumn(props: ItemTableListInnerColumn) { const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[ props.columns[props.columnIndex].id ]; @@ -50,4 +63,49 @@ export const TitleColumn = (props: ItemTableListInnerColumn) => { } return ; -}; +} + +function QueueSongTitleColumn(props: ItemTableListInnerColumn) { + const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[ + props.columns[props.columnIndex].id + ]; + + const { isActive } = useIsCurrentSong(props.data[props.rowIndex] as QueueSong); + + if (typeof row === 'string') { + const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string); + + const textStyles = isActive ? { color: 'var(--theme-colors-primary)' } : {}; + + const titleLinkProps = path + ? { + component: Link, + isLink: true, + to: path, + } + : {}; + + return ( + + + {row} + + + ); + } + + if (row === null) { + return ; + } + + return ; +} diff --git a/src/renderer/components/item-list/item-table-list/columns/title-combined-column.tsx b/src/renderer/components/item-list/item-table-list/columns/title-combined-column.tsx index cbcbc456f..3d7e9ec33 100644 --- a/src/renderer/components/item-list/item-table-list/columns/title-combined-column.tsx +++ b/src/renderer/components/item-list/item-table-list/columns/title-combined-column.tsx @@ -10,12 +10,13 @@ import { ItemTableListInnerColumn, TableColumnContainer, } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { useIsCurrentSong } from '/@/renderer/features/player/hooks/use-is-current-song'; import { AppRoute } from '/@/renderer/router/routes'; import { Image } from '/@/shared/components/image/image'; import { Text } from '/@/shared/components/text/text'; -import { RelatedAlbumArtist } from '/@/shared/types/domain-types'; +import { LibraryItem, QueueSong, RelatedAlbumArtist } from '/@/shared/types/domain-types'; -export const TitleCombinedColumn = (props: ItemTableListInnerColumn) => { +export const DefaultTitleCombinedColumn = (props: ItemTableListInnerColumn) => { const row: object | undefined = (props.data as (any | undefined)[])[props.rowIndex]; const artists = useMemo(() => { @@ -74,3 +75,83 @@ export const TitleCombinedColumn = (props: ItemTableListInnerColumn) => { return ; }; + +export const QueueSongTitleCombinedColumn = (props: ItemTableListInnerColumn) => { + const row: object | undefined = (props.data as (any | undefined)[])[props.rowIndex]; + + const { isActive } = useIsCurrentSong(props.data[props.rowIndex] as QueueSong); + + const artists = useMemo(() => { + if (row && 'artists' in row && Array.isArray(row.artists)) { + return (row.artists as RelatedAlbumArtist[]).map((artist) => { + const path = generatePath(AppRoute.LIBRARY_ARTISTS_DETAIL, { + artistId: artist.id, + }); + return { ...artist, path }; + }); + } + return []; + }, [row]); + + if (row && 'name' in row && 'imageUrl' in row && 'artists' in row) { + const rowHeight = props.getRowHeight(props.rowIndex, props); + const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string); + + const textStyles = isActive ? { color: 'var(--theme-colors-primary)' } : {}; + + const titleLinkProps = path + ? { + component: Link, + isLink: true, + to: path, + } + : {}; + + return ( + + +
+ + {row.name as string} + +
+ {artists.map((artist, index) => ( + + + {artist.name} + + {index < artists.length - 1 && ', '} + + ))} +
+
+
+ ); + } + + if (row === null) { + return ; + } + + return ; +}; + +export const TitleCombinedColumn = (props: ItemTableListInnerColumn) => { + const { itemType } = props; + + switch (itemType) { + case LibraryItem.QUEUE_SONG: + return ; + default: + return ; + } +}; diff --git a/src/renderer/features/player/hooks/use-is-current-song.ts b/src/renderer/features/player/hooks/use-is-current-song.ts new file mode 100644 index 000000000..ae44297ee --- /dev/null +++ b/src/renderer/features/player/hooks/use-is-current-song.ts @@ -0,0 +1,14 @@ +import { useMemo } from 'react'; + +import { usePlayerSong } from '/@/renderer/store'; +import { QueueSong } from '/@/shared/types/domain-types'; + +export const useIsCurrentSong = (song: QueueSong) => { + const currentSong = usePlayerSong(); + + const isActive = useMemo(() => { + return song._uniqueId === currentSong?._uniqueId; + }, [song._uniqueId, currentSong?._uniqueId]); + + return { isActive }; +};