From 3be8c367dd6a2de6168a3cdea8134706d37b1d83 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Thu, 4 Jun 2026 01:36:24 +0200 Subject: [PATCH] Fix queue handle cursor and Favorites column sorting (#974) * fix(ui): pointer cursor on the queue collapse handle The round handle is a click-to-collapse button but showed the col-resize cursor like the seam strip. Use a pointer on the handle; the seam keeps col-resize and a real drag still switches the body cursor to col-resize. * fix(favorites): make Plays, Last Played and BPM columns sortable The header marked these columns sortable (pointer cursor) but handleSortClick gated on a separate, narrower column set, so clicks did nothing. Both the comparator and the header now share one SORTABLE_COLUMNS source, so the affordance and the behaviour can't drift apart again. * docs(changelog): queue handle cursor + favorites column sorting (#974) --- CHANGELOG.md | 7 +++++++ src/components/favorites/FavoritesSongsTracklist.tsx | 3 +-- src/hooks/useFavoritesSongFiltering.tsx | 7 +++++-- src/styles/layout/resizer-handles.css | 5 ++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59897908..79cda700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -833,6 +833,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * "Exclude audiobooks & radio plays" no longer treats **Thriller** and **Fantasy** as audiobook keywords. They matched regular music (Trance/Metal genre tags, a track titled "Thriller") because the filter scans genre, title, album and artist, so a handful of legitimate songs were dropped from each mix. * The exclusion's toggle area is tightened so only the checkbox and its title respond to a click — the description text and surrounding empty space no longer toggle it. +### Cursors and Favorites sorting + +**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#974](https://github.com/Psychotoxical/psysonic/pull/974) — reported by zunoz on Discord** + +* The queue collapse handle now shows a hand cursor like every other button; the thin resize line beside it keeps the resize cursor. +* On Favorites, the **Plays**, **Last Played** and **BPM** columns are now actually sortable — they showed a clickable cursor but clicking did nothing. + ## [1.46.0] - 2026-05-18 > **🙏 Special thanks to [@zz5zz](https://github.com/zz5zz)** for his tireless quirk-spotting and bug reports on the [Psysonic Discord](https://discord.gg/AMnDRErm4u) — several of the polish fixes in this release landed directly off the back of his messages. diff --git a/src/components/favorites/FavoritesSongsTracklist.tsx b/src/components/favorites/FavoritesSongsTracklist.tsx index 55f576eb..7cb0beb1 100644 --- a/src/components/favorites/FavoritesSongsTracklist.tsx +++ b/src/components/favorites/FavoritesSongsTracklist.tsx @@ -15,8 +15,7 @@ import { useOrbitSongRowBehavior } from '../../hooks/useOrbitSongRowBehavior'; import { songToTrack } from '../../utils/playback/songToTrack'; import { APP_MAIN_SCROLL_VIEWPORT_ID } from '../../constants/appScroll'; import { useElementClientHeightById } from '../../hooks/useResizeClientHeight'; - -const SORTABLE_COLUMNS = new Set(['title', 'artist', 'album', 'rating', 'duration', 'playCount', 'lastPlayed', 'bpm']); +import { SORTABLE_COLUMNS } from '../../hooks/useFavoritesSongFiltering'; interface Props { visibleSongs: SubsonicSong[]; diff --git a/src/hooks/useFavoritesSongFiltering.tsx b/src/hooks/useFavoritesSongFiltering.tsx index 9a4f7a0e..8101a196 100644 --- a/src/hooks/useFavoritesSongFiltering.tsx +++ b/src/hooks/useFavoritesSongFiltering.tsx @@ -6,8 +6,11 @@ import { usePlayerStore } from '../store/playerStore'; const CURRENT_YEAR = new Date().getFullYear(); const MIN_YEAR = 1950; -// Columns that support 3-state sorting (asc → desc → reset) -const SORTABLE_COLUMNS = new Set(['title', 'artist', 'album', 'rating', 'duration']); +// Columns that support 3-state sorting (asc → desc → reset). +// Single source of truth — the tracklist header imports this to decide which +// headers show the sortable affordance, so the cursor and the click behaviour +// can never drift apart. Every key here is handled in the comparator below. +export const SORTABLE_COLUMNS = new Set(['title', 'artist', 'album', 'rating', 'duration', 'playCount', 'lastPlayed', 'bpm']); export type SortDir = 'asc' | 'desc'; diff --git a/src/styles/layout/resizer-handles.css b/src/styles/layout/resizer-handles.css index 8e7ec13a..830b0855 100644 --- a/src/styles/layout/resizer-handles.css +++ b/src/styles/layout/resizer-handles.css @@ -27,7 +27,10 @@ border: 1px solid var(--border-subtle); background: var(--bg-card); color: var(--text-muted); - cursor: col-resize; + /* The round handle is primarily a click-to-collapse button; the seam strip + (.resizer) keeps col-resize, and an actual drag sets the body cursor to + col-resize via useQueueResizer. */ + cursor: pointer; display: flex; align-items: center; justify-content: center;