mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-21 22:15:40 +00:00
feat(player-bar): album context menu on song title right-click (#512)
* feat(player-bar): album context menu on song title right-click Right-clicking the track title in the player bar now opens the same album context menu that album cards use (open, play next, enqueue, go to artist, favorite, rate, share, download, add to playlist). Mirrors the existing left-click behavior on the title, which already navigates to the album. Suppressed for radio and preview, matching the click handler. MarqueeText gains an optional onContextMenu prop; PlayerBar builds a SubsonicAlbum shape from currentTrack on demand. * docs(changelog): add entry for PR #512 (player-bar title context menu)
This commit is contained in:
committed by
GitHub
parent
dc2068303d
commit
6f50fb6a19
@@ -18,6 +18,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Added
|
||||
|
||||
### Player Bar — album context menu on song title right-click
|
||||
|
||||
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#512](https://github.com/Psychotoxical/psysonic/pull/512)**
|
||||
|
||||
* Right-clicking the **track title** in the player bar now opens the same album context menu that album cards expose — open, play next, enqueue, go to artist, favorite, rate, share, download, add to playlist.
|
||||
* Mirrors the existing left-click on the title (which already navigates to the album) and is suppressed during radio playback and previews.
|
||||
|
||||
### Settings — OpenDyslexic font option for dyslexic readers
|
||||
|
||||
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#507](https://github.com/Psychotoxical/psysonic/pull/507)**
|
||||
|
||||
@@ -6,9 +6,10 @@ interface Props {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
onClick?: () => void;
|
||||
onContextMenu?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
}
|
||||
|
||||
export default function MarqueeText({ text, className, style, onClick }: Props) {
|
||||
export default function MarqueeText({ text, className, style, onClick, onContextMenu }: Props) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const textRef = useRef<HTMLSpanElement>(null);
|
||||
const [scrollAmount, setScrollAmount] = useState(0);
|
||||
@@ -40,6 +41,7 @@ export default function MarqueeText({ text, className, style, onClick }: Props)
|
||||
className={`marquee-wrap${className ? ` ${className}` : ''}`}
|
||||
style={style}
|
||||
onClick={onClick}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
<span
|
||||
ref={textRef}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { usePlayerStore, getPlaybackProgressSnapshot, subscribePlaybackProgress
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { useThemeStore } from '../store/themeStore';
|
||||
import { buildCoverArtUrl, coverArtCacheKey, star, unstar, setRating } from '../api/subsonic';
|
||||
import { buildCoverArtUrl, coverArtCacheKey, star, unstar, setRating, SubsonicAlbum } from '../api/subsonic';
|
||||
import CachedImage from './CachedImage';
|
||||
import WaveformSeek from './WaveformSeek';
|
||||
import Equalizer from './Equalizer';
|
||||
@@ -84,6 +84,7 @@ export default function PlayerBar() {
|
||||
isQueueVisible, toggleQueue,
|
||||
starredOverrides, setStarredOverride,
|
||||
userRatingOverrides, setUserRatingOverride,
|
||||
openContextMenu,
|
||||
} = usePlayerStore(useShallow(s => ({
|
||||
currentTrack: s.currentTrack,
|
||||
currentRadio: s.currentRadio,
|
||||
@@ -105,6 +106,7 @@ export default function PlayerBar() {
|
||||
setStarredOverride: s.setStarredOverride,
|
||||
userRatingOverrides: s.userRatingOverrides,
|
||||
setUserRatingOverride: s.setUserRatingOverride,
|
||||
openContextMenu: s.openContextMenu,
|
||||
})));
|
||||
const { lastfmSessionKey } = useAuthStore();
|
||||
const floatingPlayerBar = useThemeStore(s => s.floatingPlayerBar);
|
||||
@@ -382,6 +384,21 @@ export default function PlayerBar() {
|
||||
className="player-track-name"
|
||||
style={{ cursor: !isRadio && !showPreviewMeta && currentTrack?.albumId ? 'pointer' : 'default' }}
|
||||
onClick={() => !isRadio && !showPreviewMeta && currentTrack?.albumId && navigate(`/album/${currentTrack.albumId}`)}
|
||||
onContextMenu={!isRadio && !showPreviewMeta && currentTrack?.albumId
|
||||
? (e) => {
|
||||
e.preventDefault();
|
||||
const album: SubsonicAlbum = {
|
||||
id: currentTrack.albumId,
|
||||
name: currentTrack.album,
|
||||
artist: currentTrack.artist,
|
||||
artistId: currentTrack.artistId ?? '',
|
||||
coverArt: currentTrack.coverArt,
|
||||
songCount: 0,
|
||||
duration: 0,
|
||||
};
|
||||
openContextMenu(e.clientX, e.clientY, album, 'album');
|
||||
}
|
||||
: undefined}
|
||||
/>
|
||||
<MarqueeText
|
||||
text={isRadio
|
||||
|
||||
Reference in New Issue
Block a user