mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
refactor(queue): co-locate QueuePanel UI into features/queue
Extract the queue UI (QueuePanel + queuePanel/* components + useQueue* hooks)
into features/queue/ with a barrel. This is the chosen playback/queue boundary:
queue = the QueuePanel UI that CONSUMES the playback store; queue STATE and the
audio engine stay in store/ (playback-core, moved separately). Verified
one-way: no playback-core file imports the queue UI back (only doc comments
mention it).
Excluded as NOT queue-UI: useIdlePlayQueuePull (AppShell) and
usePlayQueueSyncLedState (ConnectionIndicator) are queue-SYNC orchestration,
not panel UI — left in hooks/ to move with playback.
Pure move. One test fix: QueuePanel.test.tsx reads its subject via a hardcoded
readFileSync('src/components/QueuePanel.tsx') path (architecture-pin grep for
forbidden HTML5 DnD) — repointed to the new location (the move tool can't
rewrite non-import string paths). tsc 0, lint 0/0, suite 319/2353 green.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import React, { useLayoutEffect } from 'react';
|
||||
import { registerQueueListScrollTopReader, consumePendingQueueListScrollTop } from '@/store/queueUndo';
|
||||
import type { QueueItemRef, Track } from '@/store/playerStoreTypes';
|
||||
|
||||
interface Args {
|
||||
queue: QueueItemRef[];
|
||||
queueIndex: number;
|
||||
currentTrack: Track | null;
|
||||
queueListRef: React.RefObject<HTMLDivElement | null>;
|
||||
suppressNextAutoScrollRef: React.MutableRefObject<boolean>;
|
||||
}
|
||||
|
||||
/** Queue scroll-position bridge for undo: publishes the list's scrollTop to the
|
||||
* undo store and restores any pending scrollTop snapshot (set when an undo
|
||||
* restores a prior queue state). The "scroll the next track into view" path
|
||||
* lives in `QueueList` now that the list is virtualized (scrollToIndex). */
|
||||
export function useQueueAutoScroll({
|
||||
queue, queueIndex, currentTrack, queueListRef, suppressNextAutoScrollRef,
|
||||
}: Args) {
|
||||
useLayoutEffect(() => {
|
||||
registerQueueListScrollTopReader(() => queueListRef.current?.scrollTop);
|
||||
return () => registerQueueListScrollTopReader(null);
|
||||
}, [queueListRef]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const top = consumePendingQueueListScrollTop();
|
||||
if (top === undefined) return;
|
||||
const el = queueListRef.current;
|
||||
if (!el) return;
|
||||
suppressNextAutoScrollRef.current = true;
|
||||
el.scrollTop = top;
|
||||
el.dispatchEvent(new Event('scroll', { bubbles: false }));
|
||||
}, [queue, queueIndex, currentTrack?.id, queueListRef, suppressNextAutoScrollRef]);
|
||||
}
|
||||
Reference in New Issue
Block a user