feat: customizable queue toolbar with drag-and-drop reordering and visibility toggles (#534)

* Add drag-and-drop reordering and visibility toggles for queue toolbar

* docs(changelog): credit PR #534 (queue toolbar customization)

Adds the v1.46.0 CHANGELOG entry and a new bullet on kveld9's
contributors block in Settings → System.

---------

Co-authored-by: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com>
This commit is contained in:
Kveld.
2026-05-11 07:35:38 -03:00
committed by GitHub
parent 02d533e949
commit 64b33e6941
12 changed files with 390 additions and 89 deletions
+70
View File
@@ -0,0 +1,70 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export type QueueToolbarButtonId =
| 'shuffle'
| 'save'
| 'load'
| 'share'
| 'clear'
| 'separator'
| 'gapless'
| 'crossfade'
| 'infinite';
export interface QueueToolbarButtonConfig {
id: QueueToolbarButtonId;
visible: boolean;
}
/**
* Default order and visibility for queue toolbar buttons.
* Matches the historical layout in QueuePanel.tsx.
*/
export const DEFAULT_QUEUE_TOOLBAR_BUTTONS: QueueToolbarButtonConfig[] = [
{ id: 'shuffle', visible: true },
{ id: 'save', visible: true },
{ id: 'load', visible: true },
{ id: 'share', visible: true },
{ id: 'clear', visible: true },
{ id: 'separator', visible: true },
{ id: 'gapless', visible: true },
{ id: 'crossfade', visible: true },
{ id: 'infinite', visible: true },
];
interface QueueToolbarStore {
buttons: QueueToolbarButtonConfig[];
setButtons: (buttons: QueueToolbarButtonConfig[]) => void;
toggleButton: (id: QueueToolbarButtonId) => void;
reset: () => void;
}
export const useQueueToolbarStore = create<QueueToolbarStore>()(
persist(
(set) => ({
buttons: DEFAULT_QUEUE_TOOLBAR_BUTTONS,
setButtons: (buttons) => set({ buttons }),
toggleButton: (id) => set((s) => ({
buttons: s.buttons.map(btn => btn.id === id ? { ...btn, visible: !btn.visible } : btn),
})),
reset: () => set({ buttons: DEFAULT_QUEUE_TOOLBAR_BUTTONS }),
}),
{
name: 'psysonic_queue_toolbar',
onRehydrateStorage: () => (state) => {
if (!state) return;
// Sanitize: remove null/corrupt entries
const knownIds = new Set(DEFAULT_QUEUE_TOOLBAR_BUTTONS.map(b => b.id));
const safe = (state.buttons ?? [])
.filter((b): b is QueueToolbarButtonConfig => b != null && typeof b.id === 'string' && knownIds.has(b.id as QueueToolbarButtonId));
const seen = new Set(safe.map(b => b.id));
const missing = DEFAULT_QUEUE_TOOLBAR_BUTTONS.filter(b => !seen.has(b.id));
state.buttons = missing.length > 0 ? [...safe, ...missing] : safe;
},
}
)
);