From 15a6590e77f2a1f8dfa08a9504d0cc6ca2cead68 Mon Sep 17 00:00:00 2001 From: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com> Date: Tue, 30 Jun 2026 19:12:26 +0200 Subject: [PATCH] refactor(updater+contextMenu): co-locate updater feature (AppUpdater+Changelog) and the context-menu subsystem into features/ --- src/app/AppShell.tsx | 4 ++-- .../album/components/AlbumDetailToolbar.tsx | 2 +- .../components}/AddToPlaylistSubmenu.tsx | 4 ++-- .../components}/AlbumArtistToPlaylistSubmenu.tsx | 2 +- .../components}/AlbumContextItems.tsx | 6 +++--- .../components}/ArtistContextItems.tsx | 6 +++--- .../contextMenu}/components/ContextMenu.test.tsx | 2 +- .../contextMenu}/components/ContextMenu.tsx | 16 ++++++++-------- .../contextMenu/components}/ContextMenuItems.tsx | 12 ++++++------ .../components}/MoveToFolderSubmenu.tsx | 2 +- .../components}/MultiAlbumToPlaylistSubmenu.tsx | 4 ++-- .../components}/MultiArtistToPlaylistSubmenu.tsx | 4 ++-- .../components}/PlaylistContextItems.tsx | 10 +++++----- .../components}/PlaylistToPlaylistSubmenus.tsx | 4 ++-- .../components}/QueueItemContextItems.tsx | 10 +++++----- .../contextMenu/components}/SongContextItems.tsx | 14 +++++++------- .../components}/contextMenuItemTypes.ts | 2 +- src/features/contextMenu/index.ts | 8 ++++++++ .../components/FavoritesSongsSectionHeader.tsx | 2 +- .../components/PlaylistSongSearchPanel.tsx | 2 +- .../playlist/components/PlaylistTracklist.tsx | 2 +- .../updater}/components/AppUpdater.tsx | 8 ++++---- .../updater/components}/Changelog.tsx | 0 src/features/updater/index.ts | 5 +++++ 24 files changed, 72 insertions(+), 59 deletions(-) rename src/{components/contextMenu => features/contextMenu/components}/AddToPlaylistSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/AlbumArtistToPlaylistSubmenu.tsx (96%) rename src/{components/contextMenu => features/contextMenu/components}/AlbumContextItems.tsx (97%) rename src/{components/contextMenu => features/contextMenu/components}/ArtistContextItems.tsx (96%) rename src/{ => features/contextMenu}/components/ContextMenu.test.tsx (99%) rename src/{ => features/contextMenu}/components/ContextMenu.tsx (94%) rename src/{components/contextMenu => features/contextMenu/components}/ContextMenuItems.tsx (54%) rename src/{components/contextMenu => features/contextMenu/components}/MoveToFolderSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/MultiAlbumToPlaylistSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/MultiArtistToPlaylistSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/PlaylistContextItems.tsx (94%) rename src/{components/contextMenu => features/contextMenu/components}/PlaylistToPlaylistSubmenus.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/QueueItemContextItems.tsx (93%) rename src/{components/contextMenu => features/contextMenu/components}/SongContextItems.tsx (97%) rename src/{components/contextMenu => features/contextMenu/components}/contextMenuItemTypes.ts (97%) create mode 100644 src/features/contextMenu/index.ts rename src/{ => features/updater}/components/AppUpdater.tsx (97%) rename src/{components/appUpdater => features/updater/components}/Changelog.tsx (100%) create mode 100644 src/features/updater/index.ts diff --git a/src/app/AppShell.tsx b/src/app/AppShell.tsx index 8adc99f3..bfb90fd4 100644 --- a/src/app/AppShell.tsx +++ b/src/app/AppShell.tsx @@ -15,7 +15,7 @@ import { NowPlayingDropdown } from '@/features/nowPlaying'; import QueuePanel from '@/features/queue'; import AppRoutes from './AppRoutes'; import FullscreenPlayer from '@/features/fullscreenPlayer'; -import ContextMenu from '../components/ContextMenu'; +import ContextMenu from '@/features/contextMenu/components/ContextMenu'; import SongInfoModal from '../components/SongInfoModal'; import { DownloadFolderModal } from '@/features/offline'; import GlobalConfirmModal from '../components/GlobalConfirmModal'; @@ -30,7 +30,7 @@ import { import ConnectionIndicator from '@/app/ConnectionIndicator'; import MusicNetworkIndicator from '../components/MusicNetworkIndicator'; import { OfflineBanner } from '@/features/offline'; -import AppUpdater from '../components/AppUpdater'; +import AppUpdater from '@/features/updater/components/AppUpdater'; import TitleBar from '@/app/TitleBar'; import { OrbitSessionBar, OrbitStartTrigger } from '@/features/orbit'; import { useOrbitHost } from '@/features/orbit'; diff --git a/src/features/album/components/AlbumDetailToolbar.tsx b/src/features/album/components/AlbumDetailToolbar.tsx index 15fe4e8b..6eab478b 100644 --- a/src/features/album/components/AlbumDetailToolbar.tsx +++ b/src/features/album/components/AlbumDetailToolbar.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { ListPlus, Search, X } from 'lucide-react'; import type { TFunction } from 'i18next'; import { useSelectionStore } from '@/store/selectionStore'; -import { AddToPlaylistSubmenu } from '@/components/ContextMenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/ContextMenu'; import { offlineActionPolicy, type OfflineActionPolicy } from '@/features/offline'; interface Props { diff --git a/src/components/contextMenu/AddToPlaylistSubmenu.tsx b/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx similarity index 98% rename from src/components/contextMenu/AddToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/AddToPlaylistSubmenu.tsx index 98e0d216..d22f899d 100644 --- a/src/components/contextMenu/AddToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx @@ -4,11 +4,11 @@ import { ListMusic, Plus } from 'lucide-react'; import { getPlaylist, updatePlaylist } from '@/lib/api/subsonicPlaylists'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '../../utils/componentHelpers/contextMenuHelpers'; +} from '@/utils/componentHelpers/contextMenuHelpers'; interface Props { songIds: string[]; diff --git a/src/components/contextMenu/AlbumArtistToPlaylistSubmenu.tsx b/src/features/contextMenu/components/AlbumArtistToPlaylistSubmenu.tsx similarity index 96% rename from src/components/contextMenu/AlbumArtistToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/AlbumArtistToPlaylistSubmenu.tsx index 9f962fc9..3b3bc3f4 100644 --- a/src/components/contextMenu/AlbumArtistToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/AlbumArtistToPlaylistSubmenu.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { resolveAlbum, resolveArtist, resolveMediaServerId } from '@/features/offline'; -import { AddToPlaylistSubmenu } from './AddToPlaylistSubmenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/AddToPlaylistSubmenu'; interface AlbumProps { albumId: string; diff --git a/src/components/contextMenu/AlbumContextItems.tsx b/src/features/contextMenu/components/AlbumContextItems.tsx similarity index 97% rename from src/components/contextMenu/AlbumContextItems.tsx rename to src/features/contextMenu/components/AlbumContextItems.tsx index 3a7f8a03..e673c78e 100644 --- a/src/components/contextMenu/AlbumContextItems.tsx +++ b/src/features/contextMenu/components/AlbumContextItems.tsx @@ -6,9 +6,9 @@ import { star, unstar } from '@/lib/api/subsonicStarRating'; import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; import { songToTrack } from '@/lib/media/songToTrack'; import StarRating from '@/ui/StarRating'; -import { AlbumToPlaylistSubmenu } from './AlbumArtistToPlaylistSubmenu'; -import { MultiAlbumToPlaylistSubmenu } from './MultiAlbumToPlaylistSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { AlbumToPlaylistSubmenu } from '@/features/contextMenu/components/AlbumArtistToPlaylistSubmenu'; +import { MultiAlbumToPlaylistSubmenu } from '@/features/contextMenu/components/MultiAlbumToPlaylistSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function AlbumContextItems(props: ContextMenuItemsProps) { const { diff --git a/src/components/contextMenu/ArtistContextItems.tsx b/src/features/contextMenu/components/ArtistContextItems.tsx similarity index 96% rename from src/components/contextMenu/ArtistContextItems.tsx rename to src/features/contextMenu/components/ArtistContextItems.tsx index da423e8d..5ef70a80 100644 --- a/src/components/contextMenu/ArtistContextItems.tsx +++ b/src/features/contextMenu/components/ArtistContextItems.tsx @@ -3,9 +3,9 @@ import { Radio, Heart, ChevronRight, ListMusic, Star, Share2 } from 'lucide-reac import { star, unstar } from '@/lib/api/subsonicStarRating'; import type { SubsonicArtist } from '@/lib/api/subsonicTypes'; import StarRating from '@/ui/StarRating'; -import { ArtistToPlaylistSubmenu } from './AlbumArtistToPlaylistSubmenu'; -import { MultiArtistToPlaylistSubmenu } from './MultiArtistToPlaylistSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { ArtistToPlaylistSubmenu } from '@/features/contextMenu/components/AlbumArtistToPlaylistSubmenu'; +import { MultiArtistToPlaylistSubmenu } from '@/features/contextMenu/components/MultiArtistToPlaylistSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function ArtistContextItems(props: ContextMenuItemsProps) { const { diff --git a/src/components/ContextMenu.test.tsx b/src/features/contextMenu/components/ContextMenu.test.tsx similarity index 99% rename from src/components/ContextMenu.test.tsx rename to src/features/contextMenu/components/ContextMenu.test.tsx index 9577590c..29e1601b 100644 --- a/src/components/ContextMenu.test.tsx +++ b/src/features/contextMenu/components/ContextMenu.test.tsx @@ -51,7 +51,7 @@ vi.mock('@/features/offline/hooks/useOfflineBrowseContext', () => ({ }), })); -import ContextMenu from './ContextMenu'; +import ContextMenu from '@/features/contextMenu/components/ContextMenu'; import { renderWithProviders } from '@/test/helpers/renderWithProviders'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import { useAuthStore } from '@/store/authStore'; diff --git a/src/components/ContextMenu.tsx b/src/features/contextMenu/components/ContextMenu.tsx similarity index 94% rename from src/components/ContextMenu.tsx rename to src/features/contextMenu/components/ContextMenu.tsx index a0b91dd1..ccf780d4 100644 --- a/src/components/ContextMenu.tsx +++ b/src/features/contextMenu/components/ContextMenu.tsx @@ -3,26 +3,26 @@ import type { Track } from '@/lib/media/trackTypes'; import { useOrbitStore } from '@/features/orbit'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import { useShallow } from 'zustand/react/shallow'; -import { useAuthStore } from '../store/authStore'; +import { useAuthStore } from '@/store/authStore'; import { useTranslation } from 'react-i18next'; -import type { EntityShareKind } from '../utils/share/shareLink'; -import { AddToPlaylistSubmenu } from './contextMenu/AddToPlaylistSubmenu'; +import type { EntityShareKind } from '@/utils/share/shareLink'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/AddToPlaylistSubmenu'; import { copyShareLink as copyShareLinkAction, downloadAlbum as downloadAlbumAction, startInstantMix as startInstantMixAction, startRadio as startRadioAction, -} from '../utils/componentHelpers/contextMenuActions'; -import { useContextMenuKeyboardNav } from '../hooks/useContextMenuKeyboardNav'; -import { useContextMenuRating } from '../hooks/useContextMenuRating'; -import { usePlaybackLibraryNavigate } from '../hooks/usePlaybackLibraryNavigate'; +} from '@/utils/componentHelpers/contextMenuActions'; +import { useContextMenuKeyboardNav } from '@/hooks/useContextMenuKeyboardNav'; +import { useContextMenuRating } from '@/hooks/useContextMenuRating'; +import { usePlaybackLibraryNavigate } from '@/hooks/usePlaybackLibraryNavigate'; import { useNavigate } from 'react-router-dom'; import { useOfflineBrowseContext } from '@/features/offline'; import { offlineActionPolicy, type OfflineSurface, } from '@/features/offline'; -import ContextMenuItems from './contextMenu/ContextMenuItems'; +import ContextMenuItems from '@/features/contextMenu/components/ContextMenuItems'; function contextMenuSurfaceForType(type: string | null): OfflineSurface { switch (type) { diff --git a/src/components/contextMenu/ContextMenuItems.tsx b/src/features/contextMenu/components/ContextMenuItems.tsx similarity index 54% rename from src/components/contextMenu/ContextMenuItems.tsx rename to src/features/contextMenu/components/ContextMenuItems.tsx index 524b5456..e5b7e13b 100644 --- a/src/components/contextMenu/ContextMenuItems.tsx +++ b/src/features/contextMenu/components/ContextMenuItems.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; -import SongContextItems from './SongContextItems'; -import QueueItemContextItems from './QueueItemContextItems'; -import AlbumContextItems from './AlbumContextItems'; -import ArtistContextItems from './ArtistContextItems'; -import PlaylistContextItems from './PlaylistContextItems'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; +import SongContextItems from '@/features/contextMenu/components/SongContextItems'; +import QueueItemContextItems from '@/features/contextMenu/components/QueueItemContextItems'; +import AlbumContextItems from '@/features/contextMenu/components/AlbumContextItems'; +import ArtistContextItems from '@/features/contextMenu/components/ArtistContextItems'; +import PlaylistContextItems from '@/features/contextMenu/components/PlaylistContextItems'; export default function ContextMenuItems(props: ContextMenuItemsProps) { const { type } = props; diff --git a/src/components/contextMenu/MoveToFolderSubmenu.tsx b/src/features/contextMenu/components/MoveToFolderSubmenu.tsx similarity index 98% rename from src/components/contextMenu/MoveToFolderSubmenu.tsx rename to src/features/contextMenu/components/MoveToFolderSubmenu.tsx index bfaa2e66..85103424 100644 --- a/src/components/contextMenu/MoveToFolderSubmenu.tsx +++ b/src/features/contextMenu/components/MoveToFolderSubmenu.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Check, Folder, FolderMinus, Plus } from 'lucide-react'; -import { useAuthStore } from '../../store/authStore'; +import { useAuthStore } from '@/store/authStore'; import { EMPTY_SERVER_FOLDERS, usePlaylistFolderStore } from '@/features/playlist'; interface Props { diff --git a/src/components/contextMenu/MultiAlbumToPlaylistSubmenu.tsx b/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx similarity index 98% rename from src/components/contextMenu/MultiAlbumToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx index 9c2272f0..14a22ca0 100644 --- a/src/components/contextMenu/MultiAlbumToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx @@ -4,11 +4,11 @@ import { ListMusic, Plus } from 'lucide-react'; import { resolveAlbum, resolveMediaServerId, resolvePlaylist } from '@/features/offline'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '../../utils/componentHelpers/contextMenuHelpers'; +} from '@/utils/componentHelpers/contextMenuHelpers'; interface Props { albumIds: string[]; diff --git a/src/components/contextMenu/MultiArtistToPlaylistSubmenu.tsx b/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx similarity index 98% rename from src/components/contextMenu/MultiArtistToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx index 096c8f32..b1e7cdf5 100644 --- a/src/components/contextMenu/MultiArtistToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx @@ -5,11 +5,11 @@ import { resolveAlbum, resolveArtist, resolveMediaServerId, resolvePlaylist } fr import { getPlaylists } from '@/lib/api/subsonicPlaylists'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '../../utils/componentHelpers/contextMenuHelpers'; +} from '@/utils/componentHelpers/contextMenuHelpers'; interface Props { artistIds: string[]; diff --git a/src/components/contextMenu/PlaylistContextItems.tsx b/src/features/contextMenu/components/PlaylistContextItems.tsx similarity index 94% rename from src/components/contextMenu/PlaylistContextItems.tsx rename to src/features/contextMenu/components/PlaylistContextItems.tsx index efb345f0..a8252d3c 100644 --- a/src/components/contextMenu/PlaylistContextItems.tsx +++ b/src/features/contextMenu/components/PlaylistContextItems.tsx @@ -2,9 +2,9 @@ import { useTranslation } from 'react-i18next'; import { Play, ChevronRight, FolderTree, ListMusic, Trash2 } from 'lucide-react'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { MultiPlaylistToPlaylistSubmenu, SinglePlaylistToPlaylistSubmenu } from './PlaylistToPlaylistSubmenus'; -import MoveToFolderSubmenu from './MoveToFolderSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { MultiPlaylistToPlaylistSubmenu, SinglePlaylistToPlaylistSubmenu } from '@/features/contextMenu/components/PlaylistToPlaylistSubmenus'; +import MoveToFolderSubmenu from '@/features/contextMenu/components/MoveToFolderSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function PlaylistContextItems(props: ContextMenuItemsProps) { const { @@ -64,7 +64,7 @@ export default function PlaylistContextItems(props: ContextMenuItemsProps) { <>
handleAction(async () => { - const { showToast } = await import('../../utils/ui/toast'); + const { showToast } = await import('@/utils/ui/toast'); const { deletePlaylist } = await import('@/lib/api/subsonicPlaylists'); const { removeId } = usePlaylistStore.getState(); try { @@ -112,7 +112,7 @@ export default function PlaylistContextItems(props: ContextMenuItemsProps) { )} {offlinePolicy.canEditPlaylist && (
handleAction(async () => { - const { showToast } = await import('../../utils/ui/toast'); + const { showToast } = await import('@/utils/ui/toast'); const { deletePlaylist } = await import('@/lib/api/subsonicPlaylists'); const { removeId } = usePlaylistStore.getState(); const deletedIds: string[] = []; diff --git a/src/components/contextMenu/PlaylistToPlaylistSubmenus.tsx b/src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx similarity index 98% rename from src/components/contextMenu/PlaylistToPlaylistSubmenus.tsx rename to src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx index f090aa3e..573a2f46 100644 --- a/src/components/contextMenu/PlaylistToPlaylistSubmenus.tsx +++ b/src/features/contextMenu/components/PlaylistToPlaylistSubmenus.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 're import { useTranslation } from 'react-i18next'; import { ListMusic, Plus } from 'lucide-react'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; -import { isSmartPlaylistName } from '../../utils/componentHelpers/contextMenuHelpers'; +import { showToast } from '@/utils/ui/toast'; +import { isSmartPlaylistName } from '@/utils/componentHelpers/contextMenuHelpers'; interface SingleProps { playlist: { id: string; name: string }; diff --git a/src/components/contextMenu/QueueItemContextItems.tsx b/src/features/contextMenu/components/QueueItemContextItems.tsx similarity index 93% rename from src/components/contextMenu/QueueItemContextItems.tsx rename to src/features/contextMenu/components/QueueItemContextItems.tsx index 4786a421..c1de9e4f 100644 --- a/src/components/contextMenu/QueueItemContextItems.tsx +++ b/src/features/contextMenu/components/QueueItemContextItems.tsx @@ -1,13 +1,13 @@ import { useTranslation } from 'react-i18next'; import { Play, Radio, Heart, ChevronRight, User, Disc3, ListMusic, Info, Sparkles, Star, Trash2, Share2 } from 'lucide-react'; import { queueSongStar } from '@/features/playback/store/pendingStarSync'; -import { getMusicNetworkRuntime, useEnrichmentPrimary } from '../../music-network'; +import { getMusicNetworkRuntime, useEnrichmentPrimary } from '@/music-network'; import type { Track } from '@/lib/media/trackTypes'; -import { useAuthStore } from '../../store/authStore'; -import { renderPresetIcon } from '../settings/musicNetwork/presetIcon'; +import { useAuthStore } from '@/store/authStore'; +import { renderPresetIcon } from '@/components/settings/musicNetwork/presetIcon'; import StarRating from '@/ui/StarRating'; -import { AddToPlaylistSubmenu } from './AddToPlaylistSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/AddToPlaylistSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function QueueItemContextItems(props: ContextMenuItemsProps) { const { diff --git a/src/components/contextMenu/SongContextItems.tsx b/src/features/contextMenu/components/SongContextItems.tsx similarity index 97% rename from src/components/contextMenu/SongContextItems.tsx rename to src/features/contextMenu/components/SongContextItems.tsx index cdb30463..55aa46b5 100644 --- a/src/components/contextMenu/SongContextItems.tsx +++ b/src/features/contextMenu/components/SongContextItems.tsx @@ -4,17 +4,17 @@ import { useNavigateToAlbum } from '@/features/album'; import { useNavigateToArtist } from '@/features/artist'; import { resolveAlbum, resolveMediaServerId, resolvePlaylist } from '@/features/offline'; import { queueSongStar } from '@/features/playback/store/pendingStarSync'; -import { getMusicNetworkRuntime, useEnrichmentPrimary } from '../../music-network'; +import { getMusicNetworkRuntime, useEnrichmentPrimary } from '@/music-network'; import type { Track } from '@/lib/media/trackTypes'; -import { useAuthStore } from '../../store/authStore'; +import { useAuthStore } from '@/store/authStore'; import { usePlaylistStore } from '@/features/playlist'; import { songToTrack } from '@/lib/media/songToTrack'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { suggestOrbitTrack, hostEnqueueToOrbit, evaluateOrbitSuggestGate, OrbitSuggestBlockedError } from '@/features/orbit'; -import { renderPresetIcon } from '../settings/musicNetwork/presetIcon'; +import { renderPresetIcon } from '@/components/settings/musicNetwork/presetIcon'; import StarRating from '@/ui/StarRating'; -import { AddToPlaylistSubmenu } from './AddToPlaylistSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/AddToPlaylistSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function SongContextItems(props: ContextMenuItemsProps) { const { @@ -179,7 +179,7 @@ export default function SongContextItems(props: ContextMenuItemsProps) { {offlinePolicy.canEditPlaylist && playlistId && playlistSongIndex !== undefined && (
handleAction(async () => { const { updatePlaylist } = await import('@/lib/api/subsonicPlaylists'); - const { showToast } = await import('../../utils/ui/toast'); + const { showToast } = await import('@/utils/ui/toast'); const touchPlaylist = usePlaylistStore.getState().touchPlaylist; try { const serverId = resolveMediaServerId(); diff --git a/src/components/contextMenu/contextMenuItemTypes.ts b/src/features/contextMenu/components/contextMenuItemTypes.ts similarity index 97% rename from src/components/contextMenu/contextMenuItemTypes.ts rename to src/features/contextMenu/components/contextMenuItemTypes.ts index 12412c0e..c25e1cf1 100644 --- a/src/components/contextMenu/contextMenuItemTypes.ts +++ b/src/features/contextMenu/components/contextMenuItemTypes.ts @@ -1,7 +1,7 @@ import type React from 'react'; import type { SubsonicAlbum, SubsonicArtist } from '@/lib/api/subsonicTypes'; import type { QueueItemRef, Track } from '@/lib/media/trackTypes'; -import type { EntityShareKind } from '../../utils/share/shareLink'; +import type { EntityShareKind } from '@/utils/share/shareLink'; import type { OfflineActionPolicy } from '@/features/offline'; export type RatingKind = 'song' | 'album' | 'artist'; diff --git a/src/features/contextMenu/index.ts b/src/features/contextMenu/index.ts new file mode 100644 index 00000000..997c0a38 --- /dev/null +++ b/src/features/contextMenu/index.ts @@ -0,0 +1,8 @@ +/** + * Context-menu feature — the rendered ContextMenu plus the per-entity menu-item + * builders (album/artist/playlist/song/queue items + add-to-playlist / + * move-to-folder submenus). ContextMenu is deep-imported by its consumers + * (app shell + favorites/album/playlist surfaces); the item builders are + * internal to the subsystem, so nothing is re-exported here. + */ +export {}; diff --git a/src/features/favorites/components/FavoritesSongsSectionHeader.tsx b/src/features/favorites/components/FavoritesSongsSectionHeader.tsx index 9b0a1a05..e2ed51fd 100644 --- a/src/features/favorites/components/FavoritesSongsSectionHeader.tsx +++ b/src/features/favorites/components/FavoritesSongsSectionHeader.tsx @@ -5,7 +5,7 @@ import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import { useSelectionStore } from '@/store/selectionStore'; import { songToTrack } from '@/lib/media/songToTrack'; -import { AddToPlaylistSubmenu } from '@/components/ContextMenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/ContextMenu'; import GenreFilterBar from '@/ui/GenreFilterBar'; interface Props { diff --git a/src/features/playlist/components/PlaylistSongSearchPanel.tsx b/src/features/playlist/components/PlaylistSongSearchPanel.tsx index 70a2b33d..e4255872 100644 --- a/src/features/playlist/components/PlaylistSongSearchPanel.tsx +++ b/src/features/playlist/components/PlaylistSongSearchPanel.tsx @@ -7,7 +7,7 @@ import { songToTrack } from '@/lib/media/songToTrack'; import { formatTrackTime } from '@/lib/format/formatDuration'; import { AlbumCoverArtImage } from '@/cover/AlbumCoverArtImage'; import { COVER_DENSE_SEARCH_CSS_PX } from '@/cover/layoutSizes'; -import { AddToPlaylistSubmenu } from '@/components/ContextMenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/ContextMenu'; function PlaylistSearchResultThumb({ albumId, coverArt }: { albumId: string; coverArt: string }) { return ( diff --git a/src/features/playlist/components/PlaylistTracklist.tsx b/src/features/playlist/components/PlaylistTracklist.tsx index 05d2262b..e2c9d472 100644 --- a/src/features/playlist/components/PlaylistTracklist.tsx +++ b/src/features/playlist/components/PlaylistTracklist.tsx @@ -19,7 +19,7 @@ import { useDragDrop } from '@/lib/dnd/DragDropContext'; import { useOrbitSongRowBehavior } from '@/features/orbit'; import { songToTrack } from '@/lib/media/songToTrack'; import type { PlaylistSortKey, PlaylistSortDir } from '@/features/playlist/utils/playlistDisplayedSongs'; -import { AddToPlaylistSubmenu } from '@/components/ContextMenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/ContextMenu'; const PL_CENTERED = new Set(['favorite', 'rating', 'duration', 'playCount', 'bpm']); diff --git a/src/components/AppUpdater.tsx b/src/features/updater/components/AppUpdater.tsx similarity index 97% rename from src/components/AppUpdater.tsx rename to src/features/updater/components/AppUpdater.tsx index 0b107a5b..1e6ef549 100644 --- a/src/components/AppUpdater.tsx +++ b/src/features/updater/components/AppUpdater.tsx @@ -2,11 +2,11 @@ import { type ReactNode } from 'react'; import { open } from '@tauri-apps/plugin-shell'; import { ArrowUpCircle, CheckCircle2, ChevronDown, Download, FolderOpen, RefreshCw, ShieldCheck } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { version as currentVersion } from '../../package.json'; +import { version as currentVersion } from '@/../package.json'; import { formatBytes } from '@/lib/format/formatBytes'; -import { useAppUpdater } from '../hooks/useAppUpdater'; -import Modal from './Modal'; -import Changelog from './appUpdater/Changelog'; +import { useAppUpdater } from '@/hooks/useAppUpdater'; +import Modal from '@/components/Modal'; +import Changelog from '@/features/updater/components/Changelog'; export default function AppUpdater() { const { t } = useTranslation(); diff --git a/src/components/appUpdater/Changelog.tsx b/src/features/updater/components/Changelog.tsx similarity index 100% rename from src/components/appUpdater/Changelog.tsx rename to src/features/updater/components/Changelog.tsx diff --git a/src/features/updater/index.ts b/src/features/updater/index.ts new file mode 100644 index 00000000..d43e1f3c --- /dev/null +++ b/src/features/updater/index.ts @@ -0,0 +1,5 @@ +/** + * Updater feature — the in-app update checker/notification (AppUpdater) and its + * changelog display. Mounted by the app shell; deep-imported, not re-exported. + */ +export {};