From 6f50fb6a1949973bffd54e61491b355b2bb61c8d Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Thu, 7 May 2026 23:33:25 +0200 Subject: [PATCH] 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) --- CHANGELOG.md | 7 +++++++ src/components/MarqueeText.tsx | 4 +++- src/components/PlayerBar.tsx | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c71874a0..adafc563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)** diff --git a/src/components/MarqueeText.tsx b/src/components/MarqueeText.tsx index 8ea87507..d199d7d3 100644 --- a/src/components/MarqueeText.tsx +++ b/src/components/MarqueeText.tsx @@ -6,9 +6,10 @@ interface Props { className?: string; style?: React.CSSProperties; onClick?: () => void; + onContextMenu?: (e: React.MouseEvent) => void; } -export default function MarqueeText({ text, className, style, onClick }: Props) { +export default function MarqueeText({ text, className, style, onClick, onContextMenu }: Props) { const containerRef = useRef(null); const textRef = useRef(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} > ({ 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} />