diff --git a/src/app/AppRoutes.tsx b/src/app/AppRoutes.tsx index ccfc5611..8d44ff4b 100644 --- a/src/app/AppRoutes.tsx +++ b/src/app/AppRoutes.tsx @@ -1,6 +1,6 @@ import { lazy } from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; -import MobilePlayerView from '../components/MobilePlayerView'; +import MobilePlayerView from '@/features/nowPlaying/components/MobilePlayerView'; import { useIsMobile } from '@/lib/hooks/useIsMobile'; import { useSidebarStore } from '@/features/sidebar'; import { useAuthStore } from '../store/authStore'; diff --git a/src/app/AppShell.tsx b/src/app/AppShell.tsx index c02ac25e..8adc99f3 100644 --- a/src/app/AppShell.tsx +++ b/src/app/AppShell.tsx @@ -7,7 +7,7 @@ import { PanelRight } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import Sidebar from '@/features/sidebar'; import PlayerBar from '@/features/playback/components/PlayerBar'; -import BottomNav from '../components/BottomNav'; +import BottomNav from '@/features/sidebar/components/BottomNav'; import { useIsMobile } from '@/lib/hooks/useIsMobile'; import { LiveSearch } from '@/features/search'; import DevNetworkModeToggle from '@/app/DevNetworkModeToggle'; diff --git a/src/features/album/components/AlbumTrackList.tsx b/src/features/album/components/AlbumTrackList.tsx index ad129736..943e01fa 100644 --- a/src/features/album/components/AlbumTrackList.tsx +++ b/src/features/album/components/AlbumTrackList.tsx @@ -13,7 +13,7 @@ import { import { useAlbumTrackListSelection } from '@/features/album/hooks/useAlbumTrackListSelection'; import { TrackRow } from '@/features/album/components/TrackRow'; import { AlbumTrackListMobile } from '@/features/album/components/AlbumTrackListMobile'; -import { TracklistColumnPicker } from '@/components/albumTrackList/TracklistColumnPicker'; +import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker'; import { TracklistHeaderRow } from '@/features/album/components/TracklistHeaderRow'; import { offlineActionPolicy, type OfflineActionPolicy } from '@/features/offline'; diff --git a/src/features/album/pages/AlbumDetail.tsx b/src/features/album/pages/AlbumDetail.tsx index 730be3cf..383dc022 100644 --- a/src/features/album/pages/AlbumDetail.tsx +++ b/src/features/album/pages/AlbumDetail.tsx @@ -42,7 +42,7 @@ import { albumArtistDisplayName, deriveAlbumHeaderArtistRefs } from '@/features/ import { usePerfProbeFlags } from '@/utils/perf/perfFlags'; import { albumGridWarmCovers } from '@/cover/layoutSizes'; import { VirtualCardGrid } from '@/ui/VirtualCardGrid'; -import LosslessModeBanner from '@/components/LosslessModeBanner'; +import LosslessModeBanner from '@/ui/LosslessModeBanner'; import { isLosslessSuffix } from '@/lib/library/losslessFormats'; import { isLosslessMode } from '@/lib/library/losslessMode'; import { readDetailServerId } from '@/utils/navigation/detailServerScope'; diff --git a/src/features/artist/pages/ArtistDetail.tsx b/src/features/artist/pages/ArtistDetail.tsx index bae9d483..77d1866b 100644 --- a/src/features/artist/pages/ArtistDetail.tsx +++ b/src/features/artist/pages/ArtistDetail.tsx @@ -29,7 +29,7 @@ import ArtistDetailHero from '@/features/artist/components/ArtistDetailHero'; import ArtistDetailTopTracks from '@/features/artist/components/ArtistDetailTopTracks'; import ArtistDetailSimilarArtists from '@/features/artist/components/ArtistDetailSimilarArtists'; import { ArtistCard } from '@/features/nowPlaying'; -import LosslessModeBanner from '@/components/LosslessModeBanner'; +import LosslessModeBanner from '@/ui/LosslessModeBanner'; import { usePerfProbeFlags } from '@/utils/perf/perfFlags'; import { albumGridWarmCovers, COVER_DENSE_GRID_MIN_CELL_CSS_PX, GRID_COVER_WARM_LIMIT } from '@/cover/layoutSizes'; import { artistDetailCoverWarmAlbums } from '@/features/artist/components/topSongAlbumForCover'; diff --git a/src/features/favorites/components/FavoritesSongsTracklist.tsx b/src/features/favorites/components/FavoritesSongsTracklist.tsx index c444c3be..c8fbf6f9 100644 --- a/src/features/favorites/components/FavoritesSongsTracklist.tsx +++ b/src/features/favorites/components/FavoritesSongsTracklist.tsx @@ -1,7 +1,7 @@ import React, { useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useVirtualizer } from '@tanstack/react-virtual'; import FavoriteSongRow, { type FavoriteSongRowCallbacks } from '@/features/favorites/components/FavoriteSongRow'; -import { TracklistColumnPicker } from '@/components/albumTrackList/TracklistColumnPicker'; +import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import type { ColDef } from '@/utils/useTracklistColumns'; diff --git a/src/components/MobilePlayerView.tsx b/src/features/nowPlaying/components/MobilePlayerView.tsx similarity index 97% rename from src/components/MobilePlayerView.tsx rename to src/features/nowPlaying/components/MobilePlayerView.tsx index 340564b7..53ff3e44 100644 --- a/src/components/MobilePlayerView.tsx +++ b/src/features/nowPlaying/components/MobilePlayerView.tsx @@ -1,11 +1,11 @@ import { queueSongStar } from '@/features/playback/store/pendingStarSync'; -import { usePlaybackCoverArt } from '../hooks/usePlaybackCoverArt'; -import { usePlaybackTrackCoverRef } from '../cover/useLibraryCoverRef'; +import { usePlaybackCoverArt } from '@/hooks/usePlaybackCoverArt'; +import { usePlaybackTrackCoverRef } from '@/cover/useLibraryCoverRef'; import type { Track } from '@/lib/media/trackTypes'; import { getPlaybackProgressSnapshot, subscribePlaybackProgress } from '@/features/playback/store/playbackProgress'; import React, { useState, useCallback, useRef, useEffect, useSyncExternalStore, CSSProperties } from 'react'; import { useNavigate } from 'react-router-dom'; -import { usePlaybackLibraryNavigate } from '../hooks/usePlaybackLibraryNavigate'; +import { usePlaybackLibraryNavigate } from '@/hooks/usePlaybackLibraryNavigate'; import { useTranslation } from 'react-i18next'; import { useVirtualizer } from '@tanstack/react-virtual'; import { @@ -22,11 +22,11 @@ import { getQueueResolverVersion, subscribeQueueResolver, } from '@/features/playback/store/queueTrackResolver'; -import LyricsPane from './LyricsPane'; -import { usePlaybackDelayPress } from '../hooks/usePlaybackDelayPress'; +import LyricsPane from '@/components/LyricsPane'; +import { usePlaybackDelayPress } from '@/hooks/usePlaybackDelayPress'; import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal'; import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge'; -import { usePlaybackScheduleRemaining } from '../utils/format/playbackScheduleFormat'; +import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat'; // ── Color extraction ────────────────────────────────────────────────────────── // Samples a 16×16 canvas to find the most vibrant (highest-saturation, diff --git a/src/features/playlist/components/PlaylistTracklist.tsx b/src/features/playlist/components/PlaylistTracklist.tsx index adff5f58..05d2262b 100644 --- a/src/features/playlist/components/PlaylistTracklist.tsx +++ b/src/features/playlist/components/PlaylistTracklist.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useVirtualizer } from '@tanstack/react-virtual'; import PlaylistRow, { type PlaylistRowCallbacks } from '@/features/playlist/components/PlaylistRow'; -import { TracklistColumnPicker } from '@/components/albumTrackList/TracklistColumnPicker'; +import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker'; import { useTranslation } from 'react-i18next'; import { APP_MAIN_SCROLL_VIEWPORT_ID } from '@/constants/appScroll'; import { useElementClientHeightById } from '@/lib/hooks/useResizeClientHeight'; diff --git a/src/components/AboutPsysonicLol.tsx b/src/features/settings/components/AboutPsysonicLol.tsx similarity index 100% rename from src/components/AboutPsysonicLol.tsx rename to src/features/settings/components/AboutPsysonicLol.tsx diff --git a/src/features/settings/components/AppearanceTab.tsx b/src/features/settings/components/AppearanceTab.tsx index d701bd03..c41b24af 100644 --- a/src/features/settings/components/AppearanceTab.tsx +++ b/src/features/settings/components/AppearanceTab.tsx @@ -17,7 +17,7 @@ import { SettingsToggle } from '@/features/settings/components/SettingsToggle'; import { SettingsSubCard, SettingsField, SettingsValue } from '@/features/settings/components/SettingsSubCard'; import { SettingsSegmented, type SegmentedOption } from '@/features/settings/components/SettingsSegmented'; import { SeekbarPreview } from '@/features/waveform'; -import WindowButtonPreview from '@/components/WindowButtonPreview'; +import WindowButtonPreview from '@/features/settings/components/WindowButtonPreview'; export function AppearanceTab() { const { t } = useTranslation(); diff --git a/src/features/settings/components/InstalledThemes.tsx b/src/features/settings/components/InstalledThemes.tsx index 15be6891..8e396c6f 100644 --- a/src/features/settings/components/InstalledThemes.tsx +++ b/src/features/settings/components/InstalledThemes.tsx @@ -9,7 +9,7 @@ import { useThemeUpdates } from '@/hooks/useThemeUpdates'; import { useThemeAnimationRisk } from '@/hooks/useThemeAnimationRisk'; import { showToast } from '@/utils/ui/toast'; import { AnimatedThemeBadge } from '@/features/settings/components/AnimatedThemeBadge'; -import { FIXED_THEMES } from '@/components/settings/fixedThemes'; +import { FIXED_THEMES } from '@/utils/themes/fixedThemes'; /** Pull a 3-band swatch (bg / card / accent) out of an installed theme's CSS. */ function swatch(css: string): { bg: string; card: string; accent: string } { diff --git a/src/features/settings/components/SystemTab.tsx b/src/features/settings/components/SystemTab.tsx index f06d4a9d..962530a5 100644 --- a/src/features/settings/components/SystemTab.tsx +++ b/src/features/settings/components/SystemTab.tsx @@ -11,7 +11,7 @@ import { useAuthStore } from '@/store/authStore'; import type { ClockFormat, LinuxWaylandTextRenderProfile, LoggingMode } from '@/store/authStoreTypes'; import { IS_LINUX } from '@/lib/util/platform'; import { showToast } from '@/utils/ui/toast'; -import { AboutPsysonicBrandHeader } from '@/components/AboutPsysonicLol'; +import { AboutPsysonicBrandHeader } from '@/features/settings/components/AboutPsysonicLol'; import CustomSelect from '@/ui/CustomSelect'; import LicensesPanel from '@/features/settings/components/LicensesPanel'; import SettingsSubSection from '@/features/settings/components/SettingsSubSection'; diff --git a/src/components/ThemeUpdateBanner.tsx b/src/features/settings/components/ThemeUpdateBanner.tsx similarity index 94% rename from src/components/ThemeUpdateBanner.tsx rename to src/features/settings/components/ThemeUpdateBanner.tsx index 2f09adbf..a9184ce5 100644 --- a/src/components/ThemeUpdateBanner.tsx +++ b/src/features/settings/components/ThemeUpdateBanner.tsx @@ -2,8 +2,8 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; import { Paintbrush, X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { useAuthStore } from '../store/authStore'; -import { useThemeUpdates, themeUpdateSignature } from '../hooks/useThemeUpdates'; +import { useAuthStore } from '@/store/authStore'; +import { useThemeUpdates, themeUpdateSignature } from '@/hooks/useThemeUpdates'; interface Props { collapsed?: boolean; diff --git a/src/features/settings/components/ThemesTab.tsx b/src/features/settings/components/ThemesTab.tsx index 8c8a728f..70b6cc9d 100644 --- a/src/features/settings/components/ThemesTab.tsx +++ b/src/features/settings/components/ThemesTab.tsx @@ -5,7 +5,7 @@ import { useThemeStore } from '@/store/themeStore'; import { useInstalledThemesStore } from '@/store/installedThemesStore'; import CustomSelect from '@/ui/CustomSelect'; import BackToTopButton from '@/ui/BackToTopButton'; -import { FIXED_THEMES } from '@/components/settings/fixedThemes'; +import { FIXED_THEMES } from '@/utils/themes/fixedThemes'; import { InstalledThemes } from '@/features/settings/components/InstalledThemes'; import { ThemeImportSection } from '@/features/settings/components/ThemeImportSection'; import { ThemeStoreSection } from '@/features/settings/components/ThemeStoreSection'; diff --git a/src/components/WindowButtonPreview.tsx b/src/features/settings/components/WindowButtonPreview.tsx similarity index 97% rename from src/components/WindowButtonPreview.tsx rename to src/features/settings/components/WindowButtonPreview.tsx index ee992398..e820c6e7 100644 --- a/src/components/WindowButtonPreview.tsx +++ b/src/features/settings/components/WindowButtonPreview.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Minus, Square, X } from 'lucide-react'; -import type { WindowButtonStyle } from '../store/authStoreTypes'; +import type { WindowButtonStyle } from '@/store/authStoreTypes'; interface Props { style: WindowButtonStyle; diff --git a/src/components/BottomNav.tsx b/src/features/sidebar/components/BottomNav.tsx similarity index 96% rename from src/components/BottomNav.tsx rename to src/features/sidebar/components/BottomNav.tsx index 0be480e2..ece92e0f 100644 --- a/src/components/BottomNav.tsx +++ b/src/features/sidebar/components/BottomNav.tsx @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'; import { Disc3, Search, Music4, AudioLines, MoreHorizontal } from 'lucide-react'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import { MobileSearchOverlay } from '@/features/search'; -import MobileMoreOverlay from './MobileMoreOverlay'; +import MobileMoreOverlay from '@/features/sidebar/components/MobileMoreOverlay'; const NAV_ITEMS = [ { to: '/', end: true, icon: Disc3, labelKey: 'sidebar.mainstage' }, diff --git a/src/components/MobileMoreOverlay.tsx b/src/features/sidebar/components/MobileMoreOverlay.tsx similarity index 97% rename from src/components/MobileMoreOverlay.tsx rename to src/features/sidebar/components/MobileMoreOverlay.tsx index 50fcb711..e26b78f5 100644 --- a/src/components/MobileMoreOverlay.tsx +++ b/src/features/sidebar/components/MobileMoreOverlay.tsx @@ -3,8 +3,8 @@ import { NavLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Settings, HardDriveDownload } from 'lucide-react'; import { useSidebarStore } from '@/features/sidebar'; -import { useAuthStore } from '../store/authStore'; -import { ALL_NAV_ITEMS } from '../config/navItems'; +import { useAuthStore } from '@/store/authStore'; +import { ALL_NAV_ITEMS } from '@/config/navItems'; import { useLuckyMixAvailable } from '@/features/randomMix'; import { isOfflineSidebarNavAllowed } from '@/features/offline'; import { useOfflineBrowseContext } from '@/features/offline'; diff --git a/src/features/sidebar/components/SidebarNavBody.tsx b/src/features/sidebar/components/SidebarNavBody.tsx index c69f8b66..b064bb1a 100644 --- a/src/features/sidebar/components/SidebarNavBody.tsx +++ b/src/features/sidebar/components/SidebarNavBody.tsx @@ -4,8 +4,8 @@ import { useTranslation } from 'react-i18next'; import { AudioLines, ChevronRight, HardDriveDownload, Settings } from 'lucide-react'; import type { SidebarItemConfig } from '@/features/sidebar/store/sidebarStore'; import { ALL_NAV_ITEMS } from '@/config/navItems'; -import WhatsNewBanner from '@/components/WhatsNewBanner'; -import ThemeUpdateBanner from '@/components/ThemeUpdateBanner'; +import WhatsNewBanner from '@/features/whatsNew/components/WhatsNewBanner'; +import ThemeUpdateBanner from '@/features/settings/components/ThemeUpdateBanner'; import SidebarLibraryPicker from '@/features/sidebar/components/SidebarLibraryPicker'; import SidebarPlaylistsSection from '@/features/sidebar/components/SidebarPlaylistsSection'; import SidebarActiveJobs from '@/features/sidebar/components/SidebarActiveJobs'; diff --git a/src/components/WhatsNewBanner.tsx b/src/features/whatsNew/components/WhatsNewBanner.tsx similarity index 95% rename from src/components/WhatsNewBanner.tsx rename to src/features/whatsNew/components/WhatsNewBanner.tsx index 88a09e14..bd90d845 100644 --- a/src/components/WhatsNewBanner.tsx +++ b/src/features/whatsNew/components/WhatsNewBanner.tsx @@ -2,8 +2,8 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; import { Sparkles, X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { version } from '../../package.json'; -import { useAuthStore } from '../store/authStore'; +import { version } from '@/../package.json'; +import { useAuthStore } from '@/store/authStore'; interface Props { collapsed?: boolean; diff --git a/src/components/LosslessModeBanner.tsx b/src/ui/LosslessModeBanner.tsx similarity index 100% rename from src/components/LosslessModeBanner.tsx rename to src/ui/LosslessModeBanner.tsx diff --git a/src/components/albumTrackList/TracklistColumnPicker.test.tsx b/src/ui/TracklistColumnPicker.test.tsx similarity index 98% rename from src/components/albumTrackList/TracklistColumnPicker.test.tsx rename to src/ui/TracklistColumnPicker.test.tsx index 540c8455..3c4098ac 100644 --- a/src/components/albumTrackList/TracklistColumnPicker.test.tsx +++ b/src/ui/TracklistColumnPicker.test.tsx @@ -4,7 +4,7 @@ import { screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import type { TFunction } from 'i18next'; import { renderWithProviders } from '@/test/helpers/renderWithProviders'; -import { TracklistColumnPicker } from './TracklistColumnPicker'; +import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker'; import type { ColDef } from '@/utils/useTracklistColumns'; const COLUMNS: readonly ColDef[] = [ diff --git a/src/components/albumTrackList/TracklistColumnPicker.tsx b/src/ui/TracklistColumnPicker.tsx similarity index 98% rename from src/components/albumTrackList/TracklistColumnPicker.tsx rename to src/ui/TracklistColumnPicker.tsx index f2da54ad..c96a2464 100644 --- a/src/components/albumTrackList/TracklistColumnPicker.tsx +++ b/src/ui/TracklistColumnPicker.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { Check, ChevronDown, RotateCcw } from 'lucide-react'; import type { TFunction } from 'i18next'; -import type { ColDef } from '../../utils/useTracklistColumns'; +import type { ColDef } from '@/utils/useTracklistColumns'; interface Props { /** Every column (required ones are filtered out of the menu). */ diff --git a/src/components/settings/fixedThemes.ts b/src/utils/themes/fixedThemes.ts similarity index 100% rename from src/components/settings/fixedThemes.ts rename to src/utils/themes/fixedThemes.ts diff --git a/src/utils/themes/themeMigration.test.ts b/src/utils/themes/themeMigration.test.ts index 55fd4cd1..6cfd0238 100644 --- a/src/utils/themes/themeMigration.test.ts +++ b/src/utils/themes/themeMigration.test.ts @@ -13,7 +13,7 @@ import { readThemeMigrationNotice, clearThemeMigrationNotice, } from './themeMigration'; -import { FIXED_THEMES } from '../../components/settings/fixedThemes'; +import { FIXED_THEMES } from '@/utils/themes/fixedThemes'; const THEME_KEY = 'psysonic_theme'; const INSTALLED_KEY = 'psysonic_installed_themes'; diff --git a/src/utils/themes/themeMigration.ts b/src/utils/themes/themeMigration.ts index e315135c..6d405e3f 100644 --- a/src/utils/themes/themeMigration.ts +++ b/src/utils/themes/themeMigration.ts @@ -1,4 +1,4 @@ -import { FIXED_THEMES } from '../../components/settings/fixedThemes'; +import { FIXED_THEMES } from '@/utils/themes/fixedThemes'; /** * Slim-bundle theme migration (C5). Older builds bundled ~80 palettes that now diff --git a/src/utils/themes/validateThemePackage.ts b/src/utils/themes/validateThemePackage.ts index 9379c81d..5b0661e4 100644 --- a/src/utils/themes/validateThemePackage.ts +++ b/src/utils/themes/validateThemePackage.ts @@ -1,5 +1,5 @@ import { validateThemeCss } from './themeInjection'; -import { FIXED_THEMES } from '../../components/settings/fixedThemes'; +import { FIXED_THEMES } from '@/utils/themes/fixedThemes'; /** * Validation for a locally imported theme package (a .zip holding manifest.json