feat(ux): improve song details panel UX - hide panel by default, show only when song selected, add close button with X icon
This commit is contained in:
parent
96fdf64060
commit
dc8254772c
@ -83,6 +83,11 @@ const RekordboxReader: React.FC = () => {
|
|||||||
setSelectedSong(song);
|
setSelectedSong(song);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Handle closing the song details panel
|
||||||
|
const handleCloseSongDetails = useCallback(() => {
|
||||||
|
setSelectedSong(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Handle playing a song from the main view
|
// Handle playing a song from the main view
|
||||||
const handlePlaySong = useCallback((song: Song) => {
|
const handlePlaySong = useCallback((song: Song) => {
|
||||||
// Check if song has S3 file
|
// Check if song has S3 file
|
||||||
@ -685,7 +690,7 @@ const RekordboxReader: React.FC = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Details Panel */}
|
{/* Details Panel */}
|
||||||
{!isMobile && (
|
{!isMobile && selectedSong && (
|
||||||
<Box
|
<Box
|
||||||
w="350px"
|
w="350px"
|
||||||
minW="350px"
|
minW="350px"
|
||||||
@ -706,7 +711,7 @@ const RekordboxReader: React.FC = () => {
|
|||||||
'&::-webkit-scrollbar-track': { backgroundColor: 'var(--chakra-colors-gray-900)' },
|
'&::-webkit-scrollbar-track': { backgroundColor: 'var(--chakra-colors-gray-900)' },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SongDetails song={selectedSong} />
|
<SongDetails song={selectedSong} onClose={handleCloseSongDetails} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import React, { useMemo, memo } from "react";
|
import React, { useMemo, memo } from "react";
|
||||||
import { Box, VStack, Text, Divider } from "@chakra-ui/react";
|
import { Box, VStack, Text, Divider, IconButton, HStack } from "@chakra-ui/react";
|
||||||
|
import { CloseIcon } from "@chakra-ui/icons";
|
||||||
import { Song } from "../types/interfaces";
|
import { Song } from "../types/interfaces";
|
||||||
import { formatDuration } from '../utils/formatters';
|
import { formatDuration } from '../utils/formatters';
|
||||||
|
|
||||||
interface SongDetailsProps {
|
interface SongDetailsProps {
|
||||||
song: Song | null;
|
song: Song | null;
|
||||||
|
onClose?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculateBitrate = (size: string, totalTime: string): number | null => {
|
const calculateBitrate = (size: string, totalTime: string): number | null => {
|
||||||
@ -22,7 +24,7 @@ const calculateBitrate = (size: string, totalTime: string): number | null => {
|
|||||||
return Math.round(bits / seconds / 1000);
|
return Math.round(bits / seconds / 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SongDetails: React.FC<SongDetailsProps> = memo(({ song }) => {
|
export const SongDetails: React.FC<SongDetailsProps> = memo(({ song, onClose }) => {
|
||||||
// Memoize expensive calculations
|
// Memoize expensive calculations
|
||||||
const songDetails = useMemo(() => {
|
const songDetails = useMemo(() => {
|
||||||
if (!song) return null;
|
if (!song) return null;
|
||||||
@ -72,14 +74,27 @@ export const SongDetails: React.FC<SongDetailsProps> = memo(({ song }) => {
|
|||||||
return (
|
return (
|
||||||
<Box p={4} bg="gray.800" borderRadius="md">
|
<Box p={4} bg="gray.800" borderRadius="md">
|
||||||
<VStack align="stretch" spacing={4}>
|
<VStack align="stretch" spacing={4}>
|
||||||
<Box>
|
<HStack justify="space-between" align="flex-start">
|
||||||
<Text fontSize="lg" fontWeight="bold" color="white">
|
<Box flex={1}>
|
||||||
{song.title}
|
<Text fontSize="lg" fontWeight="bold" color="white">
|
||||||
</Text>
|
{song.title}
|
||||||
<Text fontSize="md" color="gray.400">
|
</Text>
|
||||||
{song.artist}
|
<Text fontSize="md" color="gray.400">
|
||||||
</Text>
|
{song.artist}
|
||||||
</Box>
|
</Text>
|
||||||
|
</Box>
|
||||||
|
{onClose && (
|
||||||
|
<IconButton
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
icon={<CloseIcon />}
|
||||||
|
onClick={onClose}
|
||||||
|
aria-label="Close details"
|
||||||
|
color="gray.400"
|
||||||
|
_hover={{ bg: "gray.700", color: "white" }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</HStack>
|
||||||
<Divider borderColor="gray.700" />
|
<Divider borderColor="gray.700" />
|
||||||
<VStack align="stretch" spacing={3}>
|
<VStack align="stretch" spacing={3}>
|
||||||
{songDetails.details.map(({ label, value }) => (
|
{songDetails.details.map(({ label, value }) => (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user