diff --git a/packages/frontend/src/components/PaginatedSongList.tsx b/packages/frontend/src/components/PaginatedSongList.tsx
index 958c93e..5b7a1d1 100644
--- a/packages/frontend/src/components/PaginatedSongList.tsx
+++ b/packages/frontend/src/components/PaginatedSongList.tsx
@@ -12,8 +12,13 @@ import {
Input,
InputGroup,
InputLeftElement,
+ Menu,
+ MenuButton,
+ MenuList,
+ MenuItem,
+ MenuDivider,
} from '@chakra-ui/react';
-import { Search2Icon } from '@chakra-ui/icons';
+import { Search2Icon, ChevronDownIcon } from '@chakra-ui/icons';
import { FiPlay } from 'react-icons/fi';
import type { Song, PlaylistNode } from '../types/interfaces';
import { api } from '../services/api';
@@ -131,7 +136,7 @@ const SongItem = memo<{
- {formattedDuration}
+ {formattedDuration}{song.tonality ? ` - ${song.tonality}` : ''}
{song.averageBpm} BPM
@@ -202,6 +207,13 @@ export const PaginatedSongList: React.FC = memo(({
loadingRef_state.current = loading;
onLoadMoreRef.current = onLoadMore;
}, [hasMore, loading, onLoadMore]);
+
+ // Clear selection when switching playlists
+ useEffect(() => {
+ if (isSwitchingPlaylist) {
+ setSelectedSongs(new Set());
+ }
+ }, [isSwitchingPlaylist]);
// Debounce search to prevent excessive API calls
const debouncedSearchQuery = useDebounce(localSearchQuery, 300);
@@ -522,27 +534,32 @@ export const PaginatedSongList: React.FC = memo(({
{selectedSongs.size > 0 && (
-
-
- {currentPlaylist !== "All Songs" && onRemoveFromPlaylist && (
-
- )}
-
+ Actions
+
+
+
+ {currentPlaylist !== "All Songs" && onRemoveFromPlaylist && (
+ <>
+
+
+ >
+ )}
+
+
)}
diff --git a/packages/frontend/src/components/SongList.tsx b/packages/frontend/src/components/SongList.tsx
index 0b8171f..e18a710 100644
--- a/packages/frontend/src/components/SongList.tsx
+++ b/packages/frontend/src/components/SongList.tsx
@@ -19,7 +19,7 @@ import { Input, InputGroup, InputLeftElement } from "@chakra-ui/input";
import { Search2Icon, ChevronDownIcon } from "@chakra-ui/icons";
import { FiPlay, FiMusic } from 'react-icons/fi';
import type { Song, PlaylistNode } from "../types/interfaces";
-import { useState, useCallback, useMemo } from "react";
+import { useState, useCallback, useMemo, useEffect } from "react";
import { formatDuration, formatTotalDuration } from '../utils/formatters';
@@ -33,6 +33,7 @@ interface SongListProps {
currentPlaylist: string | null;
depth?: number;
onPlaySong?: (song: Song) => void;
+ isSwitchingPlaylist?: boolean;
}
export const SongList: React.FC = ({
@@ -44,11 +45,19 @@ export const SongList: React.FC = ({
selectedSongId,
currentPlaylist,
depth = 0,
- onPlaySong
+ onPlaySong,
+ isSwitchingPlaylist = false
}) => {
const [selectedSongs, setSelectedSongs] = useState>(new Set());
const [searchQuery, setSearchQuery] = useState("");
+ // Clear selection when switching playlists
+ useEffect(() => {
+ if (isSwitchingPlaylist) {
+ setSelectedSongs(new Set());
+ }
+ }, [isSwitchingPlaylist]);
+
// Helper function to get all playlists (excluding folders) from the playlist tree
const getAllPlaylists = useCallback((nodes: PlaylistNode[]): PlaylistNode[] => {
let result: PlaylistNode[] = [];
@@ -270,7 +279,7 @@ export const SongList: React.FC = ({
fontSize={depth > 0 ? "xs" : "sm"}
color={selectedSongId === song.id ? "gray.300" : "gray.500"}
>
- {song.artist} • {formatDuration(song.totalTime)}
+ {song.artist} • {formatDuration(song.totalTime)}{song.tonality ? ` - ${song.tonality}` : ''}
{song.location && (
- Sync and Matching
+ Sync and Matching ({storageProvider})
}
@@ -274,7 +274,7 @@ export function Configuration() {
variant="solid"
onClick={() => api.startStorageSync()}
>
- Sync {storageProvider} (incremental)
+ Sync (incremental)
}
@@ -282,7 +282,7 @@ export function Configuration() {
variant="outline"
onClick={() => api.startStorageSync({ force: true })}
>
- Force {storageProvider} Sync (rescan all)
+ Force Sync (rescan all)
}
@@ -290,7 +290,7 @@ export function Configuration() {
variant="outline"
onClick={() => api.startStorageSync({ clearLinks: true, force: true })}
>
- Clear Links + Force {storageProvider} Sync
+ Clear Links + Force Sync