feat(now-playing): draggable widget cards with per-user layout (#267)

Each dashboard card (Album, Top Songs, Credits, Artist, Discography,
On Tour) is now a widget the user grabs and drops anywhere — reorder
within a column or move across columns. Layout persists per-install
via the new nowPlayingLayoutStore (Zustand + localStorage, same shape
as sidebarStore with an onRehydrateStorage guard for unknown IDs).

Drag uses psyDnD (useDragSource / psy-drop event, the mouse-event
based system from DragDropContext) — HTML5 native DnD is a no-go on
WebKitGTK Linux where it always shows a forbidden cursor. The whole
card is the drag handle; the column listens via a document-level
mousemove for the drop indicator and via a global psy-drop listener
that reads the latest hovered column from a ref, so drops below the
last card still land correctly regardless of column height.

Visibility is toggled from a layout menu in the top-right of the
dashboard — two sections (visible / hidden) plus a reset-to-defaults
button. No hide buttons on the cards themselves (keeps the card UI
uncluttered). An equal-height grid (align-items: stretch + min-height
on columns) keeps the drop zone active for the full vertical span of
either column.

Co-authored-by: Psychotoxical <dev@psysonic.app>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Frank Stellmacher
2026-04-22 21:14:13 +02:00
committed by GitHub
parent b4f31e0954
commit db72ed9e5a
11 changed files with 574 additions and 45 deletions
+7
View File
@@ -117,6 +117,13 @@ export const zhTranslation = {
rgAutoTooltip: 'ReplayGain (自动)',
showMoreTracks: '显示另外 {{count}} 首',
showLessTracks: '收起',
hideCard: '隐藏卡片',
layoutMenu: '布局',
visibleCards: '可见卡片',
hiddenCards: '已隐藏的卡片',
noHiddenCards: '没有已隐藏的卡片',
resetLayout: '重置布局',
emptyColumn: '将卡片拖到此处',
},
contextMenu: {
playNow: '立即播放',