feat(queue): add per-track overflow menu in queue panel
Replace the bare "remove" cross on each queue row with a ghost three-dot menu offering Play now, Move next (reposition right after the current track), Track info, and Remove — consolidating the previously separate info button into the same menu.
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
import { Slider, Badge } from '@olly/modern-sk';
|
||||
import {
|
||||
Slider,
|
||||
Badge,
|
||||
Menu,
|
||||
MenuTrigger,
|
||||
MenuContent,
|
||||
MenuItem,
|
||||
IconButton,
|
||||
} from '@olly/modern-sk';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon } from '../common/Icon';
|
||||
import { ArtTile } from '../common/ArtTile';
|
||||
@@ -7,6 +15,7 @@ import { useAppDispatch, useAppSelector } from '../../hooks/useAppDispatch';
|
||||
import {
|
||||
goToIndex,
|
||||
removeFromQueue,
|
||||
moveInQueue,
|
||||
clearQueue,
|
||||
type QueueEntry,
|
||||
} from '../../store/slices/queue';
|
||||
@@ -112,6 +121,11 @@ export function QueuePanel() {
|
||||
isCurrent={index === queue.currentIndex}
|
||||
isPlaying={isPlaying}
|
||||
onPlay={() => dispatch(goToIndex(index))}
|
||||
onMoveNext={() =>
|
||||
dispatch(
|
||||
moveInQueue({ from: index, to: queue.currentIndex + 1 }),
|
||||
)
|
||||
}
|
||||
onRemove={() => dispatch(removeFromQueue(index))}
|
||||
/>
|
||||
))}
|
||||
@@ -137,12 +151,14 @@ function QueueRow({
|
||||
isCurrent,
|
||||
isPlaying,
|
||||
onPlay,
|
||||
onMoveNext,
|
||||
onRemove,
|
||||
}: {
|
||||
entry: QueueEntry;
|
||||
isCurrent: boolean;
|
||||
isPlaying: boolean;
|
||||
onPlay: () => void;
|
||||
onMoveNext: () => void;
|
||||
onRemove: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
@@ -174,24 +190,29 @@ function QueueRow({
|
||||
<div className="t">{resolved?.title ?? entry.title}</div>
|
||||
<div className="r">{resolved?.artistName ?? entry.artistName}</div>
|
||||
</div>
|
||||
{isCurrent && (
|
||||
<button
|
||||
type="button"
|
||||
className="iconbtn sm"
|
||||
onClick={() => dispatch(openTrackInfo(entry.trackId))}
|
||||
title={t('trackInfo.open')}
|
||||
>
|
||||
<Icon name="info" />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="iconbtn sm"
|
||||
onClick={onRemove}
|
||||
title={t('queue.removeFromQueue')}
|
||||
>
|
||||
<Icon name="x" />
|
||||
</button>
|
||||
<Menu>
|
||||
<MenuTrigger asChild>
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
aria-label={t('queue.menu.options')}
|
||||
>
|
||||
⋯
|
||||
</IconButton>
|
||||
</MenuTrigger>
|
||||
<MenuContent>
|
||||
<MenuItem onSelect={onPlay}>{t('queue.menu.playNow')}</MenuItem>
|
||||
{!isCurrent && (
|
||||
<MenuItem onSelect={onMoveNext}>
|
||||
{t('queue.menu.moveNext')}
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem onSelect={() => dispatch(openTrackInfo(entry.trackId))}>
|
||||
{t('queue.menu.info')}
|
||||
</MenuItem>
|
||||
<MenuItem onSelect={onRemove}>{t('queue.menu.remove')}</MenuItem>
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user