add current song styles to rowIndex and title columns

This commit is contained in:
jeffvli
2025-11-13 13:31:57 -08:00
parent 8e6beeed98
commit 76d8b9c894
4 changed files with 196 additions and 3 deletions
@@ -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 <QueueSongRowIndexColumn {...props} />;
default:
return <DefaultRowIndexColumn {...props} />;
}
};
const DefaultRowIndexColumn = (props: ItemTableListInnerColumn) => {
const { controls, enableExpansion } = props;
if (enableExpansion) {
@@ -41,3 +58,26 @@ export const RowIndexColumn = (props: ItemTableListInnerColumn) => {
return <TableColumnTextContainer {...props}>{props.rowIndex}</TableColumnTextContainer>;
};
const QueueSongRowIndexColumn = (props: ItemTableListInnerColumn) => {
const status = usePlayerStatus();
const { isActive } = useIsCurrentSong(props.data[props.rowIndex] as QueueSong);
return (
<TableColumnTextContainer {...props}>
{isActive ? (
status === PlayerStatus.PLAYING ? (
<Flex>
<Icon fill="primary" icon="mediaPlay" />
</Flex>
) : (
<Flex>
<Icon fill="primary" icon="mediaPause" />
</Flex>
)
) : (
props.rowIndex
)}
</TableColumnTextContainer>
);
};
@@ -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 <QueueSongTitleColumn {...props} />;
default:
return <DefaultTitleColumn {...props} />;
}
};
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 <ColumnSkeletonVariable {...props} />;
};
}
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 (
<TableColumnContainer {...props}>
<Text
className={clsx({
[styles.compact]: props.size === 'compact',
[styles.large]: props.size === 'large',
[styles.nameContainer]: true,
})}
isNoSelect
{...titleLinkProps}
style={textStyles}
>
{row}
</Text>
</TableColumnContainer>
);
}
if (row === null) {
return <ColumnNullFallback {...props} />;
}
return <ColumnSkeletonVariable {...props} />;
}
@@ -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 <ColumnSkeletonVariable {...props} />;
};
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 (
<TableColumnContainer
className={styles['title-combined']}
containerStyle={{ '--row-height': `${rowHeight}px` } as CSSProperties}
{...props}
>
<Image containerClassName={styles.image} src={row.imageUrl as string} />
<div className={styles['text-container']}>
<Text
className={styles.title}
isNoSelect
{...titleLinkProps}
style={textStyles}
>
{row.name as string}
</Text>
<div className={styles.artists}>
{artists.map((artist, index) => (
<span key={artist.id}>
<Text component={Link} isLink isMuted isNoSelect to={artist.path}>
{artist.name}
</Text>
{index < artists.length - 1 && ', '}
</span>
))}
</div>
</div>
</TableColumnContainer>
);
}
if (row === null) {
return <ColumnNullFallback {...props} />;
}
return <ColumnSkeletonVariable {...props} />;
};
export const TitleCombinedColumn = (props: ItemTableListInnerColumn) => {
const { itemType } = props;
switch (itemType) {
case LibraryItem.QUEUE_SONG:
return <QueueSongTitleCombinedColumn {...props} />;
default:
return <DefaultTitleCombinedColumn {...props} />;
}
};
@@ -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 };
};