Skip to content

Commit

Permalink
Merge pull request #68 from zhanglun/feature/podcast
Browse files Browse the repository at this point in the history
Feature/podcast
  • Loading branch information
zhanglun authored Nov 20, 2024
2 parents ec86cb6 + 4e01ded commit 1e0fa5e
Show file tree
Hide file tree
Showing 12 changed files with 654 additions and 585 deletions.
136 changes: 96 additions & 40 deletions src/components/LPodcast/MiniPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,38 @@
import React from 'react';
import { Box, Flex, IconButton, Text } from '@radix-ui/themes';
import { PlayIcon, PauseIcon, ArrowUpIcon } from '@radix-ui/react-icons';
import { AudioTrack } from './index';
import React from "react";
import { Box, Flex, IconButton, Text, Avatar } from "@radix-ui/themes";
import { PlayIcon, ChevronUpIcon } from "@radix-ui/react-icons";
import { AudioTrack } from "./index";
import { motion } from "framer-motion";
import "./shared.css";
import { PlayListPopover } from "./PlayListPopover";

const AudioWaveform = () => {
const bars = [
{ height: [8, 16, 8], delay: 0 },
{ height: [10, 20, 10], delay: 0.2 },
{ height: [6, 14, 6], delay: 0.4 },
{ height: [12, 18, 12], delay: 0.6 },
];

return (
<Flex className="h-6 items-center justify-center gap-1">
{bars.map((bar, index) => (
<motion.div
key={index}
initial={{ height: bar.height[0] }}
animate={{ height: bar.height }}
transition={{
duration: 0.8,
repeat: Infinity,
ease: "easeInOut",
delay: bar.delay,
}}
className="w-0.5 bg-white rounded-[1px]"
/>
))}
</Flex>
);
};

interface MiniPlayerProps {
currentTrack: AudioTrack | null;
Expand All @@ -10,44 +41,69 @@ interface MiniPlayerProps {
onExpand: () => void;
}

export const MiniPlayer: React.FC<MiniPlayerProps> = ({
currentTrack,
isPlaying,
togglePlay,
onExpand,
}) => {
export const MiniPlayer: React.FC<MiniPlayerProps> = ({ currentTrack, isPlaying, togglePlay, onExpand }) => {
return (
<Box
className="mini-player"
style={{
position: 'fixed',
bottom: '20px',
right: '20px',
background: 'var(--color-panel-solid)',
padding: '8px',
width: '240px',
borderRadius: '8px',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
zIndex: 1000,
}}
>
<Flex align="center" gap="2">
<IconButton
size="1"
variant="soft"
onClick={togglePlay}
>
{isPlaying ? <PauseIcon /> : <PlayIcon />}
</IconButton>
<Text size="1" style={{ flex: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
{currentTrack?.title || 'No track selected'}
<Box className="bg-[var(--gray-1)] rounded-lg shadow-lg overflow-hidden w-[380px] border">
<Flex align="center" className="p-2 gap-3">
{/* Cover with play/pause overlay */}
<div className="mini-player-cover">
<Avatar
size="3"
radius="medium"
src={currentTrack?.thumbnail}
fallback={
<div className="w-full h-full flex items-center justify-center bg-[var(--gray-3)]">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="4" />
<path d="M12 8v8" />
<path d="M8 12h8" />
</svg>
</div>
}
className="cursor-pointer"
/>

{/* Always visible overlay */}
<div className="play-button-overlay !opacity-100" onClick={togglePlay}>
{isPlaying ? (
<AudioWaveform />
) : (
<motion.div
animate={{
scale: [1, 1.1, 1],
opacity: [0.8, 1, 0.8],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut",
}}
>
<PlayIcon className="text-white w-5 h-5" />
</motion.div>
)}
</div>
</div>

{/* Track Info */}
<Text size="1" className="flex-1 truncate">
{currentTrack?.title || "No track selected"}
</Text>
<IconButton
size="1"
variant="ghost"
onClick={onExpand}
>
<ArrowUpIcon />

<PlayListPopover currentTrack={currentTrack} isPlaying={isPlaying} />
{/* Expand Button */}
<IconButton size="1" variant="ghost" onClick={onExpand}>
<ChevronUpIcon />
</IconButton>
</Flex>
</Box>
Expand Down
61 changes: 20 additions & 41 deletions src/components/LPodcast/PlayList.css
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
.playlist-scroll-area [data-radix-scroll-area-scrollbar] {
width: 10px;
padding: 4px;
transform: translateX(8px);
transition: transform 150ms ease-in-out;
.playlist-scroll {
scrollbar-width: thin;
scrollbar-color: var(--gray-7) transparent;
}

.playlist-scroll-area:hover [data-radix-scroll-area-scrollbar] {
transform: translateX(0);
.playlist-scroll::-webkit-scrollbar {
width: 6px;
}

.playlist-scroll-area [data-radix-scroll-area-thumb] {
background-color: var(--gray-8);
border-radius: 3px;
.playlist-scroll::-webkit-scrollbar-track {
background: transparent;
}

.playlist-scroll-area [data-radix-scroll-area-thumb]:hover {
background-color: var(--gray-9);
}

.playlist-item {
transition: background-color 200ms ease-in-out;
}

.playlist-item:hover .playlist-text {
color: var(--gray-12);
.playlist-scroll::-webkit-scrollbar-thumb {
background-color: var(--gray-7);
border-radius: 3px;
}

.playlist-item:hover .playlist-subtext {
color: var(--gray-11);
.playlist-scroll::-webkit-scrollbar-thumb:hover {
background-color: var(--gray-8);
}

.playlist-cover-wrapper {
Expand All @@ -41,36 +31,25 @@
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(1px);
border-radius: 3px;
opacity: 0;
transition: opacity 200ms ease-in-out;
transition: opacity 0.2s ease;
border-radius: 4px;
backdrop-filter: blur(1px);
}

.playlist-item:hover .play-button-overlay {
opacity: 1;
}

.play-button {
color: white;
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
color: white;
cursor: pointer;
transition: transform 100ms ease-in-out;
}

.play-button:hover {
transform: scale(1.1);
}

.play-button:active {
transform: scale(0.95);
transform: scale(0.9);
transition: transform 0.2s ease;
}

.play-button svg {
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
.playlist-item:hover .play-button {
transform: scale(1);
}
Loading

0 comments on commit 1e0fa5e

Please sign in to comment.