diff --git a/src/app/AppShell.tsx b/src/app/AppShell.tsx index a3532298..6d181a0e 100644 --- a/src/app/AppShell.tsx +++ b/src/app/AppShell.tsx @@ -70,7 +70,7 @@ import { usePerfProbeFlags } from '@/lib/perf/perfFlags'; import { persistSidebarCollapsed, readInitialSidebarCollapsed, -} from '../utils/componentHelpers/appShellHelpers'; +} from '@/app/appShellHelpers'; /** * The main webview's persistent layout: titlebar (Linux + macOS) + sidebar + diff --git a/src/app/AppShellQueueResizerSeam.tsx b/src/app/AppShellQueueResizerSeam.tsx index 6bc82fa4..ad1f1b69 100644 --- a/src/app/AppShellQueueResizerSeam.tsx +++ b/src/app/AppShellQueueResizerSeam.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { TFunction } from 'i18next'; import { PanelRight, PanelRightClose } from 'lucide-react'; -import { shouldSuppressQueueResizerMouseDown } from '@/utils/componentHelpers/appShellHelpers'; +import { shouldSuppressQueueResizerMouseDown } from '@/app/appShellHelpers'; interface Props { isQueueVisible: boolean; diff --git a/src/utils/componentHelpers/appShellHelpers.ts b/src/app/appShellHelpers.ts similarity index 97% rename from src/utils/componentHelpers/appShellHelpers.ts rename to src/app/appShellHelpers.ts index 521e8c46..e7cb9a4d 100644 --- a/src/utils/componentHelpers/appShellHelpers.ts +++ b/src/app/appShellHelpers.ts @@ -1,4 +1,4 @@ -import { APP_MAIN_SCROLL_VIEWPORT_ID } from '../../constants/appScroll'; +import { APP_MAIN_SCROLL_VIEWPORT_ID } from '@/constants/appScroll'; export const SIDEBAR_COLLAPSED_STORAGE_KEY = 'psysonic_sidebar_collapsed'; diff --git a/src/config/settingsCredits.test.ts b/src/config/settingsCredits.test.ts index cf88b5d0..de1099a7 100644 --- a/src/config/settingsCredits.test.ts +++ b/src/config/settingsCredits.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest'; import { CONTRIBUTORS } from './settingsCredits'; -import { isNewer } from '../utils/componentHelpers/appUpdaterHelpers'; +import { isNewer } from '@/lib/util/appUpdaterHelpers'; describe('CONTRIBUTORS ordering', () => { it('is sorted ascending by the `since` app version', () => { diff --git a/src/config/settingsCredits.ts b/src/config/settingsCredits.ts index 4926ca6d..85395366 100644 --- a/src/config/settingsCredits.ts +++ b/src/config/settingsCredits.ts @@ -1,4 +1,4 @@ -import { isNewer } from '../utils/componentHelpers/appUpdaterHelpers'; +import { isNewer } from '@/lib/util/appUpdaterHelpers'; // Credits list rendered on the Settings → System tab. Update via PR when adding a contributor. const CONTRIBUTOR_ENTRIES = [ diff --git a/src/cover/artistHero.tsx b/src/cover/artistHero.tsx index 56a0cdc0..73ac64e8 100644 --- a/src/cover/artistHero.tsx +++ b/src/cover/artistHero.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useState, type CSSProperties, type ImgHTMLAttributes } from 'react'; import type { SubsonicArtistInfo } from '@/lib/api/subsonicTypes'; -import { isRealArtistImage } from '../utils/componentHelpers/nowPlayingHelpers'; +import { isRealArtistImage } from './isRealArtistImage'; import { CoverArtImage } from './CoverArtImage'; import type { CoverArtRef, CoverSurfaceKind } from './types'; diff --git a/src/cover/isRealArtistImage.ts b/src/cover/isRealArtistImage.ts new file mode 100644 index 00000000..6c85c666 --- /dev/null +++ b/src/cover/isRealArtistImage.ts @@ -0,0 +1,10 @@ +/** + * Filter out the well-known Last.fm "no image" placeholder that Subsonic + * backends aggregate into `largeImageUrl`/`mediumImageUrl` when no real + * artist image exists. The placeholder MD5 is fixed and documented. + */ +export function isRealArtistImage(url?: string): boolean { + if (!url) return false; + if (url.includes('2a96cbd8b46e442fc41c2b86b821562f')) return false; + return true; +} diff --git a/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx b/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx index 9627e79e..b88ca2ee 100644 --- a/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx @@ -8,7 +8,7 @@ import { showToast } from '@/lib/dom/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '@/utils/componentHelpers/contextMenuHelpers'; +} from '@/features/contextMenu/utils/contextMenuHelpers'; interface Props { songIds: string[]; diff --git a/src/features/contextMenu/components/ContextMenu.tsx b/src/features/contextMenu/components/ContextMenu.tsx index 6df22925..9cabb5dd 100644 --- a/src/features/contextMenu/components/ContextMenu.tsx +++ b/src/features/contextMenu/components/ContextMenu.tsx @@ -12,7 +12,7 @@ import { downloadAlbum as downloadAlbumAction, startInstantMix as startInstantMixAction, startRadio as startRadioAction, -} from '@/utils/componentHelpers/contextMenuActions'; +} from '@/features/contextMenu/utils/contextMenuActions'; import { useContextMenuKeyboardNav } from '@/features/contextMenu/hooks/useContextMenuKeyboardNav'; import { useContextMenuRating } from '@/features/contextMenu/hooks/useContextMenuRating'; import { usePlaybackLibraryNavigate } from '@/features/playback/hooks/usePlaybackLibraryNavigate'; diff --git a/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx b/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx index f402cf36..6266168e 100644 --- a/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx @@ -8,7 +8,7 @@ import { showToast } from '@/lib/dom/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '@/utils/componentHelpers/contextMenuHelpers'; +} from '@/features/contextMenu/utils/contextMenuHelpers'; interface Props { albumIds: string[]; diff --git a/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx b/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx index 1a5e4fa9..bf37e6af 100644 --- a/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx @@ -9,7 +9,7 @@ import { showToast } from '@/lib/dom/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '@/utils/componentHelpers/contextMenuHelpers'; +} from '@/features/contextMenu/utils/contextMenuHelpers'; interface Props { artistIds: string[]; diff --git a/src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx b/src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx index a99bd068..5a2c58fb 100644 --- a/src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx +++ b/src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { ListMusic, Plus } from 'lucide-react'; import { usePlaylistStore } from '@/features/playlist'; import { showToast } from '@/lib/dom/toast'; -import { isSmartPlaylistName } from '@/utils/componentHelpers/contextMenuHelpers'; +import { isSmartPlaylistName } from '@/features/contextMenu/utils/contextMenuHelpers'; interface SingleProps { playlist: { id: string; name: string }; diff --git a/src/utils/componentHelpers/contextMenuActions.ts b/src/features/contextMenu/utils/contextMenuActions.ts similarity index 94% rename from src/utils/componentHelpers/contextMenuActions.ts rename to src/features/contextMenu/utils/contextMenuActions.ts index d1ce9cf9..0ddcdfe6 100644 --- a/src/utils/componentHelpers/contextMenuActions.ts +++ b/src/features/contextMenu/utils/contextMenuActions.ts @@ -1,17 +1,17 @@ import { join } from '@tauri-apps/api/path'; import { invoke } from '@tauri-apps/api/core'; import { getSimilarSongs2, fetchSimilarTracksRouted, getTopSongs } from '@/lib/api/subsonicArtists'; -import { filterSongsForLuckyMixRatings, getMixMinRatingsConfigFromAuth } from '../mix/mixRatingFilter'; +import { filterSongsForLuckyMixRatings, getMixMinRatingsConfigFromAuth } from '@/utils/mix/mixRatingFilter'; import { buildDownloadUrl } from '@/lib/api/subsonicStreamUrl'; -import { useAuthStore } from '../../store/authStore'; +import { useAuthStore } from '@/store/authStore'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import type { Track } from '@/lib/media/trackTypes'; import { resolveQueueTrack } from '@/features/playback/store/queueTrackView'; import { useZipDownloadStore } from '@/features/offline'; import { useDownloadModalStore } from '@/features/offline'; -import type { EntityShareKind } from '../share/shareLink'; -import { copyEntityShareLink } from '../share/copyEntityShareLink'; -import { sanitizeFilename, shuffleArray } from './contextMenuHelpers'; +import type { EntityShareKind } from '@/utils/share/shareLink'; +import { copyEntityShareLink } from '@/utils/share/copyEntityShareLink'; +import { sanitizeFilename, shuffleArray } from '@/features/contextMenu/utils/contextMenuHelpers'; import { songToTrack } from '@/lib/media/songToTrack'; import { showToast } from '@/lib/dom/toast'; diff --git a/src/utils/componentHelpers/contextMenuHelpers.ts b/src/features/contextMenu/utils/contextMenuHelpers.ts similarity index 95% rename from src/utils/componentHelpers/contextMenuHelpers.ts rename to src/features/contextMenu/utils/contextMenuHelpers.ts index 1951cab9..8397260a 100644 --- a/src/utils/componentHelpers/contextMenuHelpers.ts +++ b/src/features/contextMenu/utils/contextMenuHelpers.ts @@ -1,4 +1,4 @@ -import { useConfirmModalStore } from '../../store/confirmModalStore'; +import { useConfirmModalStore } from '@/store/confirmModalStore'; /** Psysonic smart playlists (Navidrome); not valid targets for manual add-to-playlist. */ export const SMART_PLAYLIST_PREFIX = 'psy-smart-'; diff --git a/src/features/favorites/components/FavoriteSongRow.tsx b/src/features/favorites/components/FavoriteSongRow.tsx index d5513626..424494a4 100644 --- a/src/features/favorites/components/FavoriteSongRow.tsx +++ b/src/features/favorites/components/FavoriteSongRow.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { AudioLines, ChevronRight, Play, Square, X } from 'lucide-react'; import type { ColDef } from '@/hooks/useTracklistColumns'; import type { SubsonicSong } from '@/lib/api/subsonicTypes'; -import { codecLabel } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { codecLabel } from '@/lib/format/playlistDetailHelpers'; import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers'; import i18n from '@/lib/i18n'; import { formatTrackTime } from '@/lib/format/formatDuration'; diff --git a/src/features/nowPlaying/components/AlbumCard.tsx b/src/features/nowPlaying/components/AlbumCard.tsx index 6136ae37..66be0fe0 100644 --- a/src/features/nowPlaying/components/AlbumCard.tsx +++ b/src/features/nowPlaying/components/AlbumCard.tsx @@ -2,7 +2,7 @@ import React, { memo, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Disc3, ExternalLink, Star } from 'lucide-react'; import type { SubsonicAlbum, SubsonicSong } from '@/lib/api/subsonicTypes'; -import { formatTotalDuration } from '@/utils/componentHelpers/nowPlayingHelpers'; +import { formatTotalDuration } from '@/features/nowPlaying/utils/nowPlayingHelpers'; import { formatTrackTime } from '@/lib/format/formatDuration'; interface AlbumCardProps { diff --git a/src/features/nowPlaying/components/ArtistCard.tsx b/src/features/nowPlaying/components/ArtistCard.tsx index 48fd0662..3492f5a3 100644 --- a/src/features/nowPlaying/components/ArtistCard.tsx +++ b/src/features/nowPlaying/components/ArtistCard.tsx @@ -2,7 +2,8 @@ import React, { memo, useEffect, useLayoutEffect, useMemo, useRef, useState } fr import { useTranslation } from 'react-i18next'; import { ExternalLink } from 'lucide-react'; import type { SubsonicArtistInfo } from '@/lib/api/subsonicTypes'; -import { isRealArtistImage, sanitizeHtml } from '@/utils/componentHelpers/nowPlayingHelpers'; +import { isRealArtistImage } from '@/cover/isRealArtistImage'; +import { sanitizeHtml } from '@/features/nowPlaying/utils/nowPlayingHelpers'; import CachedImage from '@/ui/CachedImage'; export interface ArtistCardTab { diff --git a/src/features/nowPlaying/components/CreditsCard.tsx b/src/features/nowPlaying/components/CreditsCard.tsx index 082b4555..a4616695 100644 --- a/src/features/nowPlaying/components/CreditsCard.tsx +++ b/src/features/nowPlaying/components/CreditsCard.tsx @@ -1,6 +1,6 @@ import React, { memo } from 'react'; import { useTranslation } from 'react-i18next'; -import type { ContributorRow } from '@/utils/componentHelpers/nowPlayingHelpers'; +import type { ContributorRow } from '@/features/nowPlaying/utils/nowPlayingHelpers'; interface CreditsCardProps { rows: ContributorRow[]; } diff --git a/src/features/nowPlaying/components/TourCard.tsx b/src/features/nowPlaying/components/TourCard.tsx index bdfa5630..36377afa 100644 --- a/src/features/nowPlaying/components/TourCard.tsx +++ b/src/features/nowPlaying/components/TourCard.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Calendar, Info } from 'lucide-react'; import { open as shellOpen } from '@tauri-apps/plugin-shell'; import type { BandsintownEvent } from '@/api/bandsintown'; -import { isoToParts } from '@/utils/componentHelpers/nowPlayingHelpers'; +import { isoToParts } from '@/features/nowPlaying/utils/nowPlayingHelpers'; interface TourCardProps { artistName: string; diff --git a/src/features/nowPlaying/pages/NowPlaying.tsx b/src/features/nowPlaying/pages/NowPlaying.tsx index dff22708..b5e183b7 100644 --- a/src/features/nowPlaying/pages/NowPlaying.tsx +++ b/src/features/nowPlaying/pages/NowPlaying.tsx @@ -24,7 +24,7 @@ import { import { buildContributorRows, -} from '@/utils/componentHelpers/nowPlayingHelpers'; +} from '@/features/nowPlaying/utils/nowPlayingHelpers'; import NpCardWrap from '@/features/nowPlaying/components/NpCardWrap'; import NpColumnEl from '@/features/nowPlaying/components/NpColumnEl'; import RadioView from '@/features/nowPlaying/components/RadioView'; diff --git a/src/utils/componentHelpers/nowPlayingHelpers.ts b/src/features/nowPlaying/utils/nowPlayingHelpers.ts similarity index 86% rename from src/utils/componentHelpers/nowPlayingHelpers.ts rename to src/features/nowPlaying/utils/nowPlayingHelpers.ts index 62a91833..a4837454 100644 --- a/src/utils/componentHelpers/nowPlayingHelpers.ts +++ b/src/features/nowPlaying/utils/nowPlayingHelpers.ts @@ -64,14 +64,3 @@ export function buildContributorRows(song: SubsonicSong | null | undefined, main } return out; } - -/** - * Filter out the well-known Last.fm "no image" placeholder that Subsonic - * backends aggregate into `largeImageUrl`/`mediumImageUrl` when no real - * artist image exists. The placeholder MD5 is fixed and documented. - */ -export function isRealArtistImage(url?: string): boolean { - if (!url) return false; - if (url.includes('2a96cbd8b46e442fc41c2b86b821562f')) return false; - return true; -} diff --git a/src/features/offline/store/offlineStore.ts b/src/features/offline/store/offlineStore.ts index 83d09353..84154d56 100644 --- a/src/features/offline/store/offlineStore.ts +++ b/src/features/offline/store/offlineStore.ts @@ -18,7 +18,7 @@ import { } from '@/features/offline/utils/offlineLibraryHelpers'; import { librarySqlServerId } from '@/api/coverCache'; import { resolveIndexKey, serverIndexKeyForProfile } from '@/lib/server/serverIndexKey'; -import { isSmartPlaylistName } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { isSmartPlaylistName } from '@/lib/format/playlistDetailHelpers'; import { enqueueOfflinePin, registerOfflinePinExecutor, diff --git a/src/features/offline/utils/pinnedOfflineSync.test.ts b/src/features/offline/utils/pinnedOfflineSync.test.ts index 3db73221..530ee58d 100644 --- a/src/features/offline/utils/pinnedOfflineSync.test.ts +++ b/src/features/offline/utils/pinnedOfflineSync.test.ts @@ -14,7 +14,7 @@ import { syncAllPinnedPlaylists, syncPinnedArtistIfNeeded, } from '@/features/offline/utils/pinnedOfflineSync'; -import { SMART_PREFIX } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { SMART_PREFIX } from '@/lib/format/playlistDetailHelpers'; const getPlaylistMock = vi.fn(); const getAlbumForServerMock = vi.fn(); diff --git a/src/features/offline/utils/pinnedOfflineSync.ts b/src/features/offline/utils/pinnedOfflineSync.ts index f99b31da..1635c226 100644 --- a/src/features/offline/utils/pinnedOfflineSync.ts +++ b/src/features/offline/utils/pinnedOfflineSync.ts @@ -9,7 +9,7 @@ import type { PinSource } from '@/store/localPlaybackStore'; import { useLocalPlaybackStore } from '@/store/localPlaybackStore'; import { useOfflineStore } from '@/features/offline/store/offlineStore'; import { usePlaylistStore } from '@/features/playlist'; -import { isSmartPlaylistName } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { isSmartPlaylistName } from '@/lib/format/playlistDetailHelpers'; import { getMediaDir } from '@/lib/media/mediaDir'; import { isActiveServerReachable, diff --git a/src/features/playlist/components/PlaylistHero.tsx b/src/features/playlist/components/PlaylistHero.tsx index 697ed448..49b99c30 100644 --- a/src/features/playlist/components/PlaylistHero.tsx +++ b/src/features/playlist/components/PlaylistHero.tsx @@ -13,7 +13,7 @@ import { useThemeStore } from '@/store/themeStore'; import { usePlaylistLayoutStore, type PlaylistLayoutItemId } from '@/features/playlist/store/playlistLayoutStore'; import { displayPlaylistName, formatSize, isSmartPlaylistName, totalDurationLabel, -} from '@/utils/componentHelpers/playlistDetailHelpers'; +} from '@/lib/format/playlistDetailHelpers'; import type { CoverArtId } from '@/cover/types'; import { AlbumCoverArtImage } from '@/cover/AlbumCoverArtImage'; import { PLAYLIST_MAIN_COVER_CSS_PX } from '@/features/playlist/hooks/usePlaylistCovers'; diff --git a/src/features/playlist/components/PlaylistRow.tsx b/src/features/playlist/components/PlaylistRow.tsx index 60f57570..e42d366f 100644 --- a/src/features/playlist/components/PlaylistRow.tsx +++ b/src/features/playlist/components/PlaylistRow.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { AudioLines, ChevronRight, Heart, Play, Square, Trash2 } from 'lucide-react'; import type { ColDef } from '@/hooks/useTracklistColumns'; import type { SubsonicSong } from '@/lib/api/subsonicTypes'; -import { codecLabel } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { codecLabel } from '@/lib/format/playlistDetailHelpers'; import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers'; import i18n from '@/lib/i18n'; import { formatTrackTime } from '@/lib/format/formatDuration'; diff --git a/src/features/playlist/components/PlaylistSuggestions.tsx b/src/features/playlist/components/PlaylistSuggestions.tsx index c20bded9..313d379c 100644 --- a/src/features/playlist/components/PlaylistSuggestions.tsx +++ b/src/features/playlist/components/PlaylistSuggestions.tsx @@ -12,7 +12,7 @@ import { useThemeStore } from '@/store/themeStore'; import { usePlaylistLayoutStore } from '@/features/playlist/store/playlistLayoutStore'; import { songToTrack } from '@/lib/media/songToTrack'; import { getQueueTracksView } from '@/features/playback/store/queueTrackView'; -import { codecLabel } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { codecLabel } from '@/lib/format/playlistDetailHelpers'; import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers'; import { formatTrackTime } from '@/lib/format/formatDuration'; import i18n from '@/lib/i18n'; diff --git a/src/features/playlist/utils/runPlaylistZipDownload.ts b/src/features/playlist/utils/runPlaylistZipDownload.ts index 5b6930a1..731f844c 100644 --- a/src/features/playlist/utils/runPlaylistZipDownload.ts +++ b/src/features/playlist/utils/runPlaylistZipDownload.ts @@ -3,7 +3,7 @@ import { join } from '@tauri-apps/api/path'; import { buildDownloadUrl } from '@/lib/api/subsonicStreamUrl'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { useZipDownloadStore } from '@/features/offline'; -import { sanitizeFilename } from '@/utils/componentHelpers/playlistDetailHelpers'; +import { sanitizeFilename } from '@/lib/format/playlistDetailHelpers'; export interface RunPlaylistZipDownloadDeps { playlist: SubsonicPlaylist; diff --git a/src/features/queue/components/QueueCurrentTrack.tsx b/src/features/queue/components/QueueCurrentTrack.tsx index a3750701..788907f5 100644 --- a/src/features/queue/components/QueueCurrentTrack.tsx +++ b/src/features/queue/components/QueueCurrentTrack.tsx @@ -7,7 +7,7 @@ import type { PlaybackSourceKind } from '@/features/playback/utils/playback/reso import { formatQueueReplayGainParts, renderStars, -} from '@/utils/componentHelpers/queuePanelHelpers'; +} from '@/features/queue/utils/queuePanelHelpers'; import { loudnessGainPlaceholderUntilCacheDb } from '@/features/playback/utils/audio/loudnessPlaceholder'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider'; import { formatQueueBpmTech, formatQueueMoodLabels } from '@/lib/library/trackEnrichment'; diff --git a/src/features/queue/components/QueueHeader.tsx b/src/features/queue/components/QueueHeader.tsx index 7f2bae03..a8d90a7d 100644 --- a/src/features/queue/components/QueueHeader.tsx +++ b/src/features/queue/components/QueueHeader.tsx @@ -6,7 +6,7 @@ import { usePlayerStore } from '@/features/playback/store/playerStore'; import { useAuthStore } from '@/store/authStore'; import type { QueueItemRef } from '@/lib/media/trackTypes'; import type { QueueDisplayMode } from '@/store/authStoreTypes'; -import type { DurationMode } from '@/utils/componentHelpers/queuePanelHelpers'; +import type { DurationMode } from '@/features/queue/utils/queuePanelHelpers'; import { formatLongDuration } from '@/lib/format/formatDuration'; import { formatClockTime } from '@/lib/format/formatClockTime'; import { resolveQueueTrack } from '@/features/playback/store/queueTrackView'; diff --git a/src/utils/componentHelpers/queuePanelHelpers.tsx b/src/features/queue/utils/queuePanelHelpers.tsx similarity index 94% rename from src/utils/componentHelpers/queuePanelHelpers.tsx rename to src/features/queue/utils/queuePanelHelpers.tsx index f8571fba..9414d8d7 100644 --- a/src/utils/componentHelpers/queuePanelHelpers.tsx +++ b/src/features/queue/utils/queuePanelHelpers.tsx @@ -2,7 +2,7 @@ import { Star } from 'lucide-react'; import type { TFunction } from 'i18next'; import type { Track } from '@/lib/media/trackTypes'; -export type { DurationMode } from '../../store/authStoreTypes'; +export type { DurationMode } from '@/store/authStoreTypes'; export function formatQueueReplayGainParts(track: Track, t: TFunction): string[] { const parts: string[] = []; diff --git a/src/features/settings/components/ArtistLayoutCustomizer.tsx b/src/features/settings/components/ArtistLayoutCustomizer.tsx index 1a40ab12..ce77ce82 100644 --- a/src/features/settings/components/ArtistLayoutCustomizer.tsx +++ b/src/features/settings/components/ArtistLayoutCustomizer.tsx @@ -2,7 +2,7 @@ import { useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useArtistLayoutStore, type ArtistSectionConfig, type ArtistSectionId } from '@/features/artist'; import { useListReorderDnd } from '@/lib/hooks/useListReorderDnd'; -import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import { applyListReorderById, type ListReorderDropTarget } from '@/lib/util/listReorder'; import { ReorderGripHandle } from '@/features/settings/components/ReorderGripHandle'; const ARTIST_SECTION_LABEL_KEYS: Record = { diff --git a/src/features/settings/components/LyricsSourcesCustomizer.tsx b/src/features/settings/components/LyricsSourcesCustomizer.tsx index dcdfe10a..9ec2eb2f 100644 --- a/src/features/settings/components/LyricsSourcesCustomizer.tsx +++ b/src/features/settings/components/LyricsSourcesCustomizer.tsx @@ -4,7 +4,7 @@ import { useShallow } from 'zustand/react/shallow'; import { useAuthStore } from '@/store/authStore'; import type { LyricsSourceId } from '@/store/authStoreTypes'; import { useListReorderDnd } from '@/lib/hooks/useListReorderDnd'; -import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import { applyListReorderById, type ListReorderDropTarget } from '@/lib/util/listReorder'; import { ReorderGripHandle } from '@/features/settings/components/ReorderGripHandle'; import { SettingsToggle } from '@/features/settings/components/SettingsToggle'; diff --git a/src/features/settings/components/QueueToolbarCustomizer.tsx b/src/features/settings/components/QueueToolbarCustomizer.tsx index e1a104f2..1e44a4fd 100644 --- a/src/features/settings/components/QueueToolbarCustomizer.tsx +++ b/src/features/settings/components/QueueToolbarCustomizer.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Blend, Infinity as InfinityIcon, ListMusic, MoveRight, Share2, Shuffle, Trash2, Waves } from 'lucide-react'; import { useQueueToolbarStore, QueueToolbarButtonId } from '@/store/queueToolbarStore'; import { useListReorderDnd } from '@/lib/hooks/useListReorderDnd'; -import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import { applyListReorderById, type ListReorderDropTarget } from '@/lib/util/listReorder'; import { ReorderGripHandle } from '@/features/settings/components/ReorderGripHandle'; const QUEUE_TOOLBAR_BUTTON_ICONS: Record = { diff --git a/src/features/settings/components/ServersTab.tsx b/src/features/settings/components/ServersTab.tsx index ae5890f9..64babefd 100644 --- a/src/features/settings/components/ServersTab.tsx +++ b/src/features/settings/components/ServersTab.tsx @@ -38,7 +38,7 @@ import { switchActiveServer } from '@/utils/server/switchActiveServer'; import { AddServerForm } from '@/features/settings/components/AddServerForm'; import { ServerCapabilityHeaderBadge } from '@/features/settings/components/ServerCapabilityHeaderBadge'; import { useListReorderDnd } from '@/lib/hooks/useListReorderDnd'; -import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import { applyListReorderById, type ListReorderDropTarget } from '@/lib/util/listReorder'; import { ReorderGripHandle } from '@/features/settings/components/ReorderGripHandle'; import { tooltipAttrs } from '@/ui/tooltipAttrs'; diff --git a/src/features/settings/components/SidebarCustomizer.tsx b/src/features/settings/components/SidebarCustomizer.tsx index 97e10f96..be4e8672 100644 --- a/src/features/settings/components/SidebarCustomizer.tsx +++ b/src/features/settings/components/SidebarCustomizer.tsx @@ -6,7 +6,7 @@ import { useLuckyMixAvailable } from '@/features/randomMix'; import { ALL_NAV_ITEMS } from '@/config/navItems'; import { applySidebarReorderById } from '@/features/sidebar'; import { useListReorderDnd } from '@/lib/hooks/useListReorderDnd'; -import type { ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import type { ListReorderDropTarget } from '@/lib/util/listReorder'; import { ReorderGripHandle } from '@/features/settings/components/ReorderGripHandle'; import { SettingsGroup } from '@/features/settings/components/SettingsGroup'; import { SettingsToggle } from '@/features/settings/components/SettingsToggle'; diff --git a/src/features/settings/components/ThemeStoreSection.tsx b/src/features/settings/components/ThemeStoreSection.tsx index c21b6db4..059ac06f 100644 --- a/src/features/settings/components/ThemeStoreSection.tsx +++ b/src/features/settings/components/ThemeStoreSection.tsx @@ -16,7 +16,7 @@ import { } from '@/lib/themes/themeRegistry'; import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry'; import { uninstallTheme } from '@/lib/themes/uninstallTheme'; -import { isNewer } from '@/utils/componentHelpers/appUpdaterHelpers'; +import { isNewer } from '@/lib/util/appUpdaterHelpers'; type ModeFilter = 'all' | 'dark' | 'light'; type SortMode = 'newest' | 'name'; diff --git a/src/features/settings/hooks/useThemeUpdates.ts b/src/features/settings/hooks/useThemeUpdates.ts index 69771669..2eba7d97 100644 --- a/src/features/settings/hooks/useThemeUpdates.ts +++ b/src/features/settings/hooks/useThemeUpdates.ts @@ -1,5 +1,5 @@ import { useEffect, useMemo, useState } from 'react'; -import { isNewer } from '@/utils/componentHelpers/appUpdaterHelpers'; +import { isNewer } from '@/lib/util/appUpdaterHelpers'; import { fetchRegistry, getCachedRegistry, type Registry, type RegistryTheme } from '@/lib/themes/themeRegistry'; import { useInstalledThemesStore } from '@/store/installedThemesStore'; diff --git a/src/features/sidebar/utils/sidebarNavReorder.ts b/src/features/sidebar/utils/sidebarNavReorder.ts index c0041fc9..2fa179cb 100644 --- a/src/features/sidebar/utils/sidebarNavReorder.ts +++ b/src/features/sidebar/utils/sidebarNavReorder.ts @@ -1,6 +1,6 @@ import { ALL_NAV_ITEMS } from '@/config/navItems'; import { CONSERVED_SIDEBAR_NAV_IDS, type SidebarItemConfig } from '@/features/sidebar/store/sidebarStore'; -import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import { applyListReorderById, type ListReorderDropTarget } from '@/lib/util/listReorder'; export type SidebarNavSection = 'library' | 'system'; diff --git a/src/features/updater/hooks/useAppUpdater.ts b/src/features/updater/hooks/useAppUpdater.ts index 2b99aac5..97e10153 100644 --- a/src/features/updater/hooks/useAppUpdater.ts +++ b/src/features/updater/hooks/useAppUpdater.ts @@ -5,7 +5,7 @@ import { invoke } from '@tauri-apps/api/core'; import { useTranslation } from 'react-i18next'; import { version as currentVersion } from '../../../../package.json'; import { IS_LINUX, IS_MACOS, IS_WINDOWS } from '@/lib/util/platform'; -import { SKIP_KEY, isNewer, isWithinModerationWindow, pickAsset, type ReleaseData, type DlState } from '@/utils/componentHelpers/appUpdaterHelpers'; +import { SKIP_KEY, isNewer, isWithinModerationWindow, pickAsset, type ReleaseData, type DlState } from '@/lib/util/appUpdaterHelpers'; /** All update-modal state, the GitHub release probe and the download/relaunch * handlers. The component owns only the early-return guard and the JSX. */ diff --git a/src/utils/componentHelpers/playlistDetailHelpers.ts b/src/lib/format/playlistDetailHelpers.ts similarity index 100% rename from src/utils/componentHelpers/playlistDetailHelpers.ts rename to src/lib/format/playlistDetailHelpers.ts diff --git a/src/lib/hooks/useListReorderDnd.ts b/src/lib/hooks/useListReorderDnd.ts index 90f77403..608dca23 100644 --- a/src/lib/hooks/useListReorderDnd.ts +++ b/src/lib/hooks/useListReorderDnd.ts @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useDragDrop } from '@/lib/dnd/DragDropContext'; -import type { ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; +import type { ListReorderDropTarget } from '@/lib/util/listReorder'; interface Options { /** Payload discriminator the drag source emits, e.g. `'lyrics_source_reorder'`. */ diff --git a/src/utils/componentHelpers/appUpdaterHelpers.test.ts b/src/lib/util/appUpdaterHelpers.test.ts similarity index 97% rename from src/utils/componentHelpers/appUpdaterHelpers.test.ts rename to src/lib/util/appUpdaterHelpers.test.ts index 94c87a5e..3ea9176c 100644 --- a/src/utils/componentHelpers/appUpdaterHelpers.test.ts +++ b/src/lib/util/appUpdaterHelpers.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { isWithinModerationWindow, WINGET_MODERATION_DELAY_MS } from './appUpdaterHelpers'; +import { isWithinModerationWindow, WINGET_MODERATION_DELAY_MS } from '@/lib/util/appUpdaterHelpers'; describe('isWithinModerationWindow', () => { const published = '2026-06-27T00:00:00Z'; diff --git a/src/utils/componentHelpers/appUpdaterHelpers.ts b/src/lib/util/appUpdaterHelpers.ts similarity index 100% rename from src/utils/componentHelpers/appUpdaterHelpers.ts rename to src/lib/util/appUpdaterHelpers.ts diff --git a/src/utils/componentHelpers/listReorder.test.ts b/src/lib/util/listReorder.test.ts similarity index 97% rename from src/utils/componentHelpers/listReorder.test.ts rename to src/lib/util/listReorder.test.ts index 9aa32140..38069f2b 100644 --- a/src/utils/componentHelpers/listReorder.test.ts +++ b/src/lib/util/listReorder.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { applyListReorderById } from './listReorder'; +import { applyListReorderById } from '@/lib/util/listReorder'; type Item = { id: string; visible?: boolean }; diff --git a/src/utils/componentHelpers/listReorder.ts b/src/lib/util/listReorder.ts similarity index 100% rename from src/utils/componentHelpers/listReorder.ts rename to src/lib/util/listReorder.ts