diff --git a/src/app/AppShell.tsx b/src/app/AppShell.tsx index 420e5bde..bacc180e 100644 --- a/src/app/AppShell.tsx +++ b/src/app/AppShell.tsx @@ -12,7 +12,7 @@ import { useIsMobile } from '@/lib/hooks/useIsMobile'; import { LiveSearch } from '@/features/search'; import DevNetworkModeToggle from '../components/DevNetworkModeToggle'; import { NowPlayingDropdown } from '@/features/nowPlaying'; -import QueuePanel from '../components/QueuePanel'; +import QueuePanel from '@/features/queue'; import AppRoutes from './AppRoutes'; import FullscreenPlayer from '@/features/fullscreenPlayer'; import ContextMenu from '../components/ContextMenu'; @@ -44,7 +44,7 @@ import { useNowPlayingTrayTitle } from '../hooks/useNowPlayingTrayTitle'; import { usePrefetchReleaseNotes } from '../hooks/usePrefetchReleaseNotes'; import { useTrayMenuI18n } from '../hooks/useTrayMenuI18n'; import { useServerCapabilitiesProbe } from '../hooks/useServerCapabilitiesProbe'; -import { useQueueResizer } from '../hooks/useQueueResizer'; +import { useQueueResizer } from '@/features/queue'; import { useGlobalDndAndSelectionBlockers } from '../hooks/useGlobalDndAndSelectionBlockers'; import { useAppActivityTracking } from '../hooks/useAppActivityTracking'; import { useMainScrollingIndicator } from '../hooks/useMainScrollingIndicator'; diff --git a/src/features/fullscreenPlayer/components/FullscreenPlayerStatic.tsx b/src/features/fullscreenPlayer/components/FullscreenPlayerStatic.tsx index 618cde39..a283c007 100644 --- a/src/features/fullscreenPlayer/components/FullscreenPlayerStatic.tsx +++ b/src/features/fullscreenPlayer/components/FullscreenPlayerStatic.tsx @@ -13,7 +13,7 @@ import { useArtistFanart } from '@/cover/useArtistFanart'; import { backdropFromConfig } from '@/cover/artistBackdrop'; import { useThemeStore } from '@/store/themeStore'; import { useFsIdleFade } from '@/hooks/useFsIdleFade'; -import { useQueueTrackAt } from '@/hooks/useQueueTracks'; +import { useQueueTrackAt } from '@/features/queue'; import { WaveformSeek } from '@/features/waveform'; import { FsQueueModal } from '@/features/fullscreenPlayer/components/FsQueueModal'; import { FsLyricsApple } from '@/features/fullscreenPlayer/components/FsLyricsApple'; diff --git a/src/components/queuePanel/LoadPlaylistModal.tsx b/src/features/queue/components/LoadPlaylistModal.tsx similarity index 100% rename from src/components/queuePanel/LoadPlaylistModal.tsx rename to src/features/queue/components/LoadPlaylistModal.tsx diff --git a/src/components/queuePanel/QueueCurrentTrack.tsx b/src/features/queue/components/QueueCurrentTrack.tsx similarity index 90% rename from src/components/queuePanel/QueueCurrentTrack.tsx rename to src/features/queue/components/QueueCurrentTrack.tsx index 578b2d3b..8ad073cd 100644 --- a/src/components/queuePanel/QueueCurrentTrack.tsx +++ b/src/features/queue/components/QueueCurrentTrack.tsx @@ -1,24 +1,24 @@ import React from 'react'; import { ChevronDown, FolderOpen, HardDrive, Music, Waves } from 'lucide-react'; import type { TFunction } from 'i18next'; -import type { Track } from '../../store/playerStoreTypes'; -import type { LoudnessLufsPreset, NormalizationEngine } from '../../store/authStoreTypes'; -import type { PlaybackSourceKind } from '../../utils/playback/resolvePlaybackUrl'; +import type { Track } from '@/store/playerStoreTypes'; +import type { LoudnessLufsPreset, NormalizationEngine } from '@/store/authStoreTypes'; +import type { PlaybackSourceKind } from '@/utils/playback/resolvePlaybackUrl'; import { formatQueueReplayGainParts, renderStars, -} from '../../utils/componentHelpers/queuePanelHelpers'; -import { loudnessGainPlaceholderUntilCacheDb } from '../../utils/audio/loudnessPlaceholder'; -import { effectiveLoudnessPreAnalysisAttenuationDb } from '../../utils/audio/loudnessPreAnalysisSlider'; -import { formatQueueBpmTech, formatQueueMoodLabels } from '../../utils/library/trackEnrichment'; -import { useQueueTrackEnrichment } from '../../hooks/useQueueTrackEnrichment'; -import { QueueLufsTargetMenu } from './QueueLufsTargetMenu'; -import { PlaybackBufferingOverlay } from '../playback/PlaybackBufferingOverlay'; -import { CoverArtImage } from '../../cover/CoverArtImage'; +} from '@/utils/componentHelpers/queuePanelHelpers'; +import { loudnessGainPlaceholderUntilCacheDb } from '@/utils/audio/loudnessPlaceholder'; +import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; +import { formatQueueBpmTech, formatQueueMoodLabels } from '@/utils/library/trackEnrichment'; +import { useQueueTrackEnrichment } from '@/features/queue/hooks/useQueueTrackEnrichment'; +import { QueueLufsTargetMenu } from '@/features/queue/components/QueueLufsTargetMenu'; +import { PlaybackBufferingOverlay } from '@/components/playback/PlaybackBufferingOverlay'; +import { CoverArtImage } from '@/cover/CoverArtImage'; import { OpenArtistRefInline } from '@/features/artist'; -import { usePlaybackTrackCoverRef } from '../../cover/useLibraryCoverRef'; -import { usePlayerStore } from '../../store/playerStore'; -import { resolveTrackArtistRefs } from '../../utils/playback/trackArtistRefs'; +import { usePlaybackTrackCoverRef } from '@/cover/useLibraryCoverRef'; +import { usePlayerStore } from '@/store/playerStore'; +import { resolveTrackArtistRefs } from '@/utils/playback/trackArtistRefs'; interface Props { currentTrack: Track; diff --git a/src/components/queuePanel/QueueHeader.tsx b/src/features/queue/components/QueueHeader.tsx similarity index 94% rename from src/components/queuePanel/QueueHeader.tsx rename to src/features/queue/components/QueueHeader.tsx index 7f33ea13..3033a1e3 100644 --- a/src/components/queuePanel/QueueHeader.tsx +++ b/src/features/queue/components/QueueHeader.tsx @@ -2,18 +2,18 @@ import { useDeferredValue, useMemo, useSyncExternalStore } from 'react'; import { AlignCenterVertical, ChevronDown, ListMusic, ListOrdered } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; -import { usePlayerStore } from '../../store/playerStore'; -import { useAuthStore } from '../../store/authStore'; -import type { QueueItemRef } from '../../store/playerStoreTypes'; -import type { QueueDisplayMode } from '../../store/authStoreTypes'; -import type { DurationMode } from '../../utils/componentHelpers/queuePanelHelpers'; +import { usePlayerStore } from '@/store/playerStore'; +import { useAuthStore } from '@/store/authStore'; +import type { QueueItemRef } from '@/store/playerStoreTypes'; +import type { QueueDisplayMode } from '@/store/authStoreTypes'; +import type { DurationMode } from '@/utils/componentHelpers/queuePanelHelpers'; import { formatLongDuration } from '@/lib/format/formatDuration'; import { formatClockTime } from '@/lib/format/formatClockTime'; -import { resolveQueueTrack } from '../../utils/library/queueTrackView'; +import { resolveQueueTrack } from '@/utils/library/queueTrackView'; import { getQueueResolverVersion, subscribeQueueResolver, -} from '../../utils/library/queueTrackResolver'; +} from '@/utils/library/queueTrackResolver'; interface Props { queue: QueueItemRef[]; diff --git a/src/components/queuePanel/QueueList.tsx b/src/features/queue/components/QueueList.tsx similarity index 96% rename from src/components/queuePanel/QueueList.tsx rename to src/features/queue/components/QueueList.tsx index d8242a50..7ae5dcc6 100644 --- a/src/components/queuePanel/QueueList.tsx +++ b/src/features/queue/components/QueueList.tsx @@ -3,20 +3,20 @@ import { useVirtualizer } from '@tanstack/react-virtual'; import { Play } from 'lucide-react'; import type { TFunction } from 'i18next'; import OverlayScrollArea from '@/ui/OverlayScrollArea'; -import { usePlayerStore } from '../../store/playerStore'; -import { useLuckyMixStore } from '../../store/luckyMixStore'; -import type { QueueItemRef, PlayerState } from '../../store/playerStoreTypes'; -import type { QueueDisplayMode } from '../../store/authStoreTypes'; +import { usePlayerStore } from '@/store/playerStore'; +import { useLuckyMixStore } from '@/store/luckyMixStore'; +import type { QueueItemRef, PlayerState } from '@/store/playerStoreTypes'; +import type { QueueDisplayMode } from '@/store/authStoreTypes'; import { formatTrackTime } from '@/lib/format/formatDuration'; -import { resolveQueueTrack } from '../../utils/library/queueTrackView'; +import { resolveQueueTrack } from '@/utils/library/queueTrackView'; import { getQueueResolverVersion, subscribeQueueResolver, -} from '../../utils/library/queueTrackResolver'; -import { findQueueItemRefIndex } from '../../utils/playback/queueIdentity'; -import type { TimelineDisplayRow } from '../../utils/queue/buildTimelineDisplayRows'; -import { findTimelineScrollLocalIndex } from '../../utils/queue/buildTimelineDisplayRows'; -import { playTimelineHistoryTrack } from '../../utils/queue/playTimelineHistoryTrack'; +} from '@/utils/library/queueTrackResolver'; +import { findQueueItemRefIndex } from '@/utils/playback/queueIdentity'; +import type { TimelineDisplayRow } from '@/utils/queue/buildTimelineDisplayRows'; +import { findTimelineScrollLocalIndex } from '@/utils/queue/buildTimelineDisplayRows'; +import { playTimelineHistoryTrack } from '@/utils/queue/playTimelineHistoryTrack'; type StartDrag = ( payload: { data: string; label: string }, diff --git a/src/components/queuePanel/QueueLufsTargetMenu.tsx b/src/features/queue/components/QueueLufsTargetMenu.tsx similarity index 96% rename from src/components/queuePanel/QueueLufsTargetMenu.tsx rename to src/features/queue/components/QueueLufsTargetMenu.tsx index ba8edf19..e5ccd067 100644 --- a/src/components/queuePanel/QueueLufsTargetMenu.tsx +++ b/src/features/queue/components/QueueLufsTargetMenu.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { createPortal } from 'react-dom'; -import type { LoudnessLufsPreset } from '../../store/authStoreTypes'; +import type { LoudnessLufsPreset } from '@/store/authStoreTypes'; interface Props { menuRef: React.RefObject; diff --git a/src/components/QueuePanel.test.tsx b/src/features/queue/components/QueuePanel.test.tsx similarity index 97% rename from src/components/QueuePanel.test.tsx rename to src/features/queue/components/QueuePanel.test.tsx index 2d7badda..2c0595ac 100644 --- a/src/components/QueuePanel.test.tsx +++ b/src/features/queue/components/QueuePanel.test.tsx @@ -30,7 +30,7 @@ vi.mock('@/features/orbit/utils/orbitBulkGuard', () => ({ orbitBulkGuard: vi.fn(async () => true), })); -import QueuePanel from './QueuePanel'; +import QueuePanel from '@/features/queue/components/QueuePanel'; import { fireEvent } from '@testing-library/react'; import { renderWithProviders } from '@/test/helpers/renderWithProviders'; import { usePlayerStore } from '@/store/playerStore'; @@ -224,7 +224,7 @@ describe('QueuePanel — DnD architecture pin (§4.4 of v2 plan)', () => { // `dragenter` / `dragover` props are allowed because the document // listens for them to render the drop indicator without acting as // a sink for HTML5 payloads. - const source = readFileSync(join(process.cwd(), 'src/components/QueuePanel.tsx'), 'utf8'); + const source = readFileSync(join(process.cwd(), 'src/features/queue/components/QueuePanel.tsx'), 'utf8'); expect(source).not.toMatch(/dataTransfer\.setData/); expect(source).not.toMatch(/dataTransfer\.getData/); expect(source).not.toMatch(/\bonDragStart\s*=/); @@ -232,7 +232,7 @@ describe('QueuePanel — DnD architecture pin (§4.4 of v2 plan)', () => { }); it('the source file does not use `application/json` MIME anywhere (WebView2 restriction)', () => { - const source = readFileSync(join(process.cwd(), 'src/components/QueuePanel.tsx'), 'utf8'); + const source = readFileSync(join(process.cwd(), 'src/features/queue/components/QueuePanel.tsx'), 'utf8'); expect(source).not.toMatch(/application\/json/); }); }); diff --git a/src/components/QueuePanel.tsx b/src/features/queue/components/QueuePanel.tsx similarity index 89% rename from src/components/QueuePanel.tsx rename to src/features/queue/components/QueuePanel.tsx index fa71130b..931daf57 100644 --- a/src/components/QueuePanel.tsx +++ b/src/features/queue/components/QueuePanel.tsx @@ -1,40 +1,40 @@ import { Play } from 'lucide-react'; import { updatePlaylist } from '@/lib/api/subsonicPlaylists'; import { resolvePlaylist, resolveMediaServerId } from '@/features/offline'; -import { songToTrack } from '../utils/playback/songToTrack'; -import type { Track } from '../store/playerStoreTypes'; +import { songToTrack } from '@/utils/playback/songToTrack'; +import type { Track } from '@/store/playerStoreTypes'; import { useState, useRef, useMemo } from 'react'; -import { usePlayerStore } from '../store/playerStore'; +import { usePlayerStore } from '@/store/playerStore'; import { useOrbitStore } from '@/features/orbit'; import { OrbitGuestQueue, OrbitQueueHead } from '@/features/orbit'; -import HostApprovalQueue from './HostApprovalQueue'; +import HostApprovalQueue from '@/components/HostApprovalQueue'; import { usePlaylistStore } from '@/features/playlist'; import { useTranslation } from 'react-i18next'; -import { usePlaybackLibraryNavigate } from '../hooks/usePlaybackLibraryNavigate'; -import { useAuthStore } from '../store/authStore'; -import { encodeSharePayload } from '../utils/share/shareLink'; -import { serverShareBaseUrl } from '../utils/server/serverEndpoint'; -import { copyTextToClipboard } from '../utils/server/serverMagicString'; -import { showToast } from '../utils/ui/toast'; -import { useThemeStore } from '../store/themeStore'; -import { useLyricsStore } from '../store/lyricsStore'; -import LyricsPane from './LyricsPane'; +import { usePlaybackLibraryNavigate } from '@/hooks/usePlaybackLibraryNavigate'; +import { useAuthStore } from '@/store/authStore'; +import { encodeSharePayload } from '@/utils/share/shareLink'; +import { serverShareBaseUrl } from '@/utils/server/serverEndpoint'; +import { copyTextToClipboard } from '@/utils/server/serverMagicString'; +import { showToast } from '@/utils/ui/toast'; +import { useThemeStore } from '@/store/themeStore'; +import { useLyricsStore } from '@/store/lyricsStore'; +import LyricsPane from '@/components/LyricsPane'; import { NowPlayingInfo } from '@/features/nowPlaying'; -import { useLuckyMixStore } from '../store/luckyMixStore'; -import { useQueueToolbarStore } from '../store/queueToolbarStore'; -import { SavePlaylistModal } from './queuePanel/SavePlaylistModal'; -import { LoadPlaylistModal } from './queuePanel/LoadPlaylistModal'; -import { QueueHeader } from './queuePanel/QueueHeader'; -import { QueueCurrentTrack } from './queuePanel/QueueCurrentTrack'; -import { useQueuePanelDrag } from '../hooks/useQueuePanelDrag'; -import { useQueueLufsTgtPopover } from '../hooks/useQueueLufsTgtPopover'; -import { QueueToolbar } from './queuePanel/QueueToolbar'; -import { QueueList } from './queuePanel/QueueList'; -import { QueueTabBar } from './queuePanel/QueueTabBar'; -import { useQueueAutoScroll } from '../hooks/useQueueAutoScroll'; -import { useTimelineBootstrapOnMode, useTimelineHistoryResolver, useTimelinePlayHistory } from '../hooks/useTimelinePlayHistory'; -import { buildTimelineDisplayRows } from '../utils/queue/buildTimelineDisplayRows'; -import { activeServerQueueTrackIds } from '../utils/playback/trackServerScope'; +import { useLuckyMixStore } from '@/store/luckyMixStore'; +import { useQueueToolbarStore } from '@/store/queueToolbarStore'; +import { SavePlaylistModal } from '@/features/queue/components/SavePlaylistModal'; +import { LoadPlaylistModal } from '@/features/queue/components/LoadPlaylistModal'; +import { QueueHeader } from '@/features/queue/components/QueueHeader'; +import { QueueCurrentTrack } from '@/features/queue/components/QueueCurrentTrack'; +import { useQueuePanelDrag } from '@/features/queue/hooks/useQueuePanelDrag'; +import { useQueueLufsTgtPopover } from '@/features/queue/hooks/useQueueLufsTgtPopover'; +import { QueueToolbar } from '@/features/queue/components/QueueToolbar'; +import { QueueList } from '@/features/queue/components/QueueList'; +import { QueueTabBar } from '@/features/queue/components/QueueTabBar'; +import { useQueueAutoScroll } from '@/features/queue/hooks/useQueueAutoScroll'; +import { useTimelineBootstrapOnMode, useTimelineHistoryResolver, useTimelinePlayHistory } from '@/hooks/useTimelinePlayHistory'; +import { buildTimelineDisplayRows } from '@/utils/queue/buildTimelineDisplayRows'; +import { activeServerQueueTrackIds } from '@/utils/playback/trackServerScope'; export default function QueuePanel() { const orbitRole = useOrbitStore(s => s.role); diff --git a/src/components/queuePanel/QueueTabBar.tsx b/src/features/queue/components/QueueTabBar.tsx similarity index 100% rename from src/components/queuePanel/QueueTabBar.tsx rename to src/features/queue/components/QueueTabBar.tsx diff --git a/src/components/queuePanel/QueueToolbar.tsx b/src/features/queue/components/QueueToolbar.tsx similarity index 97% rename from src/components/queuePanel/QueueToolbar.tsx rename to src/features/queue/components/QueueToolbar.tsx index 5126d5b5..477a772a 100644 --- a/src/components/queuePanel/QueueToolbar.tsx +++ b/src/features/queue/components/QueueToolbar.tsx @@ -3,12 +3,12 @@ import { Blend, Check, FolderOpen, Infinity as InfinityIcon, ListMusic, MoveRight, Save, Share2, Shuffle, Trash2, Waves, } from 'lucide-react'; import type { TFunction } from 'i18next'; -import type { QueueItemRef } from '../../store/playerStoreTypes'; +import type { QueueItemRef } from '@/store/playerStoreTypes'; import type { QueueToolbarButtonConfig, QueueToolbarButtonId, -} from '../../store/queueToolbarStore'; -import { getTransitionMode, setTransitionMode } from '../../utils/playback/playbackTransition'; +} from '@/store/queueToolbarStore'; +import { getTransitionMode, setTransitionMode } from '@/utils/playback/playbackTransition'; import { useOrbitStore } from '@/features/orbit'; interface Props { diff --git a/src/components/queuePanel/SavePlaylistModal.tsx b/src/features/queue/components/SavePlaylistModal.tsx similarity index 100% rename from src/components/queuePanel/SavePlaylistModal.tsx rename to src/features/queue/components/SavePlaylistModal.tsx diff --git a/src/hooks/useQueueAutoScroll.ts b/src/features/queue/hooks/useQueueAutoScroll.ts similarity index 92% rename from src/hooks/useQueueAutoScroll.ts rename to src/features/queue/hooks/useQueueAutoScroll.ts index 1bf844f4..dbb25615 100644 --- a/src/hooks/useQueueAutoScroll.ts +++ b/src/features/queue/hooks/useQueueAutoScroll.ts @@ -1,6 +1,6 @@ import React, { useLayoutEffect } from 'react'; -import { registerQueueListScrollTopReader, consumePendingQueueListScrollTop } from '../store/queueUndo'; -import type { QueueItemRef, Track } from '../store/playerStoreTypes'; +import { registerQueueListScrollTopReader, consumePendingQueueListScrollTop } from '@/store/queueUndo'; +import type { QueueItemRef, Track } from '@/store/playerStoreTypes'; interface Args { queue: QueueItemRef[]; diff --git a/src/hooks/useQueueLufsTgtPopover.ts b/src/features/queue/hooks/useQueueLufsTgtPopover.ts similarity index 100% rename from src/hooks/useQueueLufsTgtPopover.ts rename to src/features/queue/hooks/useQueueLufsTgtPopover.ts diff --git a/src/hooks/useQueuePanelDrag.ts b/src/features/queue/hooks/useQueuePanelDrag.ts similarity index 96% rename from src/hooks/useQueuePanelDrag.ts rename to src/features/queue/hooks/useQueuePanelDrag.ts index f4665d83..d35931c2 100644 --- a/src/hooks/useQueuePanelDrag.ts +++ b/src/features/queue/hooks/useQueuePanelDrag.ts @@ -1,9 +1,9 @@ import React, { useEffect, useRef, useState } from 'react'; import { resolveAlbum, resolveMediaServerId } from '@/features/offline'; -import { songToTrack } from '../utils/playback/songToTrack'; +import { songToTrack } from '@/utils/playback/songToTrack'; import { useDragDrop, registerQueueDragHitTest } from '@/lib/dnd/DragDropContext'; -import { usePlayerStore } from '../store/playerStore'; -import type { Track } from '../store/playerStoreTypes'; +import { usePlayerStore } from '@/store/playerStore'; +import type { Track } from '@/store/playerStoreTypes'; /** Drag types that may be dropped into the queue panel. */ const QUEUE_DROP_TYPES = new Set(['song', 'album', 'queue_reorder']); diff --git a/src/hooks/useQueueResizer.ts b/src/features/queue/hooks/useQueueResizer.ts similarity index 100% rename from src/hooks/useQueueResizer.ts rename to src/features/queue/hooks/useQueueResizer.ts diff --git a/src/hooks/useQueueTrackEnrichment.ts b/src/features/queue/hooks/useQueueTrackEnrichment.ts similarity index 91% rename from src/hooks/useQueueTrackEnrichment.ts rename to src/features/queue/hooks/useQueueTrackEnrichment.ts index 48cf02c2..a08fb768 100644 --- a/src/hooks/useQueueTrackEnrichment.ts +++ b/src/features/queue/hooks/useQueueTrackEnrichment.ts @@ -1,16 +1,16 @@ import { useEffect, useState } from 'react'; import { listen } from '@tauri-apps/api/event'; import { libraryGetFacts, libraryGetTrack } from '@/lib/api/library'; -import { usePlaybackServerId } from './usePlaybackServerId'; -import { useLibraryIndexStore } from '../store/libraryIndexStore'; +import { usePlaybackServerId } from '@/hooks/usePlaybackServerId'; +import { useLibraryIndexStore } from '@/store/libraryIndexStore'; import { enrichmentDisplayComplete, OXIMEDIA_MOOD_UI_ENABLED, parseTrackEnrichmentFacts, type ParsedTrackEnrichment, -} from '../utils/library/trackEnrichment'; -import { libraryIsReady } from '../utils/library/libraryReady'; -import { normalizeAnalysisTrackId } from '../utils/playback/queueIdentity'; +} from '@/utils/library/trackEnrichment'; +import { libraryIsReady } from '@/utils/library/libraryReady'; +import { normalizeAnalysisTrackId } from '@/utils/playback/queueIdentity'; const EMPTY: ParsedTrackEnrichment = { serverBpm: null, diff --git a/src/hooks/useQueueTracks.test.ts b/src/features/queue/hooks/useQueueTracks.test.ts similarity index 98% rename from src/hooks/useQueueTracks.test.ts rename to src/features/queue/hooks/useQueueTracks.test.ts index f84ee224..2d85b9b9 100644 --- a/src/hooks/useQueueTracks.test.ts +++ b/src/features/queue/hooks/useQueueTracks.test.ts @@ -4,7 +4,7 @@ import { usePlayerStore } from '@/store/playerStore'; import type { Track } from '@/store/playerStoreTypes'; import { getCachedTrack, _resetQueueResolverForTest } from '@/utils/library/queueTrackResolver'; import { seedQueue } from '@/test/helpers/factories'; -import { useQueueTrackAt, useCurrentTrack, useQueueItems } from './useQueueTracks'; +import { useQueueTrackAt, useCurrentTrack, useQueueItems } from '@/features/queue/hooks/useQueueTracks'; const track = (id: string, over: Partial = {}): Track => ({ id, title: id, artist: '', album: 'A', albumId: 'A', duration: 1, ...over }); diff --git a/src/hooks/useQueueTracks.ts b/src/features/queue/hooks/useQueueTracks.ts similarity index 84% rename from src/hooks/useQueueTracks.ts rename to src/features/queue/hooks/useQueueTracks.ts index 92f9ee49..d842c098 100644 --- a/src/hooks/useQueueTracks.ts +++ b/src/features/queue/hooks/useQueueTracks.ts @@ -1,11 +1,11 @@ import { useMemo, useSyncExternalStore } from 'react'; -import { usePlayerStore } from '../store/playerStore'; -import type { QueueItemRef, Track } from '../store/playerStoreTypes'; -import { resolveQueueTrack } from '../utils/library/queueTrackView'; +import { usePlayerStore } from '@/store/playerStore'; +import type { QueueItemRef, Track } from '@/store/playerStoreTypes'; +import { resolveQueueTrack } from '@/utils/library/queueTrackView'; import { getQueueResolverVersion, subscribeQueueResolver, -} from '../utils/library/queueTrackResolver'; +} from '@/utils/library/queueTrackResolver'; /** * Stable queue selectors (queue thin-state). The store is refs-canonical now: diff --git a/src/features/queue/index.ts b/src/features/queue/index.ts new file mode 100644 index 00000000..503bea0a --- /dev/null +++ b/src/features/queue/index.ts @@ -0,0 +1,5 @@ +// Public API of the queue feature (QueuePanel UI + its hooks). Consumes the +// playback store; holds no audio-engine state itself. +export { default } from './components/QueuePanel'; +export { useQueueResizer } from './hooks/useQueueResizer'; +export { useQueueTrackAt } from './hooks/useQueueTracks';