mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
refactor(components): co-locate remaining UI/feature components (TracklistColumnPicker+LosslessModeBanner->ui, fixedThemes->utils/themes, ThemeUpdateBanner/WindowButtonPreview/AboutPsysonicLol->settings, BottomNav/MobileMoreOverlay->sidebar, MobilePlayerView->nowPlaying, WhatsNewBanner->whatsNew)
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
+6
-6
@@ -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,
|
||||
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 } {
|
||||
|
||||
@@ -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';
|
||||
|
||||
+2
-2
@@ -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;
|
||||
@@ -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';
|
||||
|
||||
+1
-1
@@ -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;
|
||||
@@ -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' },
|
||||
+2
-2
@@ -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';
|
||||
@@ -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';
|
||||
|
||||
+2
-2
@@ -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;
|
||||
+1
-1
@@ -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[] = [
|
||||
+1
-1
@@ -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). */
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user