feat(music-player): add minimize feature with floating icon and centered controls

Layout Changes:
- Center all control buttons (shuffle, prev, play/pause, next, repeat)
- Center progress bar alongside controls
- Keep volume control + close button on the right
- Song info remains on the left

New Feature - Minimize Player:
- Add isMinimized state to track player visibility
- Replace close button with minimize functionality
- Show floating music icon when minimized (bottom-right corner)
- Click floating icon to restore player bar
- Floating icon has hover scale animation for better UX

UI/UX Improvements:
- Better visual hierarchy with centered controls
- Floating icon uses blue bg with white music icon
- Smooth transitions between states
- Icon scales on hover for interactive feedback
- Persistent player state (song continues playing when minimized)

Files changed:
- src/app/darmasaba/_com/FixedPlayerBar.tsx: Complete redesign

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-05 14:14:46 +08:00
parent ce46d3b5f7
commit ee39b88b00

View File

@@ -12,6 +12,7 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { import {
IconArrowsShuffle, IconArrowsShuffle,
IconMusic,
IconPlayerPauseFilled, IconPlayerPauseFilled,
IconPlayerPlayFilled, IconPlayerPlayFilled,
IconPlayerSkipBackFilled, IconPlayerSkipBackFilled,
@@ -45,7 +46,7 @@ export default function FixedPlayerBar() {
} = useMusic(); } = useMusic();
const [showVolume, setShowVolume] = useState(false); const [showVolume, setShowVolume] = useState(false);
const [isPlayerVisible, setIsPlayerVisible] = useState(true); const [isMinimized, setIsMinimized] = useState(false);
// Format time // Format time
const formatTime = (seconds: number) => { const formatTime = (seconds: number) => {
@@ -69,12 +70,52 @@ export default function FixedPlayerBar() {
toggleShuffle(); toggleShuffle();
}; };
// Handle close player // Handle minimize player (show floating icon)
const handleClosePlayer = () => { const handleMinimizePlayer = () => {
setIsPlayerVisible(false); setIsMinimized(true);
}; };
if (!currentSong || !isPlayerVisible) { // Handle restore player from floating icon
const handleRestorePlayer = () => {
setIsMinimized(false);
};
// If minimized, show floating icon instead of player bar
if (isMinimized) {
return (
<>
{/* Floating Music Icon - Shows when player is minimized */}
<Paper
pos="fixed"
bottom={20}
right={20}
p="md"
shadow="xl"
radius="xl"
bg="blue"
style={{
zIndex: 1001,
cursor: 'pointer',
transition: 'transform 0.2s',
}}
onClick={handleRestorePlayer}
onMouseEnter={(e) => {
e.currentTarget.style.transform = 'scale(1.1)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = 'scale(1)';
}}
>
<IconMusic size={28} color="white" />
</Paper>
{/* Spacer to prevent content from being hidden behind player */}
<Box h={20} />
</>
);
}
if (!currentSong) {
return null; return null;
} }
@@ -94,7 +135,7 @@ export default function FixedPlayerBar() {
}} }}
> >
<Flex align="center" gap="md" justify="space-between"> <Flex align="center" gap="md" justify="space-between">
{/* Song Info */} {/* Song Info - Left */}
<Group gap="sm" flex={1} style={{ minWidth: 0 }}> <Group gap="sm" flex={1} style={{ minWidth: 0 }}>
<Avatar <Avatar
src={currentSong.coverImage?.link || ''} src={currentSong.coverImage?.link || ''}
@@ -113,7 +154,9 @@ export default function FixedPlayerBar() {
</Box> </Box>
</Group> </Group>
{/* Controls */} {/* Controls + Progress - Center */}
<Group gap="xs" flex={2} justify="center">
{/* Control Buttons */}
<Group gap="xs"> <Group gap="xs">
<ActionIcon <ActionIcon
variant={isShuffle ? 'filled' : 'subtle'} variant={isShuffle ? 'filled' : 'subtle'}
@@ -182,9 +225,10 @@ export default function FixedPlayerBar() {
label={(value) => formatTime(value)} label={(value) => formatTime(value)}
/> />
</Box> </Box>
</Group>
{/* Right Controls */} {/* Right Controls - Volume + Close */}
<Group gap="xs"> <Group gap="xs" flex={1} justify="flex-end">
<Box <Box
onMouseEnter={() => setShowVolume(true)} onMouseEnter={() => setShowVolume(true)}
onMouseLeave={() => setShowVolume(false)} onMouseLeave={() => setShowVolume(false)}
@@ -241,8 +285,8 @@ export default function FixedPlayerBar() {
variant="subtle" variant="subtle"
color="gray" color="gray"
size="lg" size="lg"
onClick={handleClosePlayer} onClick={handleMinimizePlayer}
title="Close player" title="Minimize player"
> >
<IconX size={18} /> <IconX size={18} />
</ActionIcon> </ActionIcon>