2026-02-05 21:40:06 +00:00
|
|
|
import { Slider } from '@/components/ui/slider';
|
|
|
|
|
import { formatTime } from './types';
|
|
|
|
|
|
|
|
|
|
interface AudioPlayerProgressProps {
|
|
|
|
|
currentTime: number;
|
|
|
|
|
duration: number;
|
|
|
|
|
onSeek: (value: number[]) => void;
|
feat(ui): hover cards, Spotify player layout, scrollbar tokens, context menu integration
HoverCard component (new):
- Rich preview cards on hover with framer-motion animation
- Viewport-aware positioning, portal rendering, open/close delays
- UserHoverContent: Discord-style user preview (avatar, bio, stats, follow)
- TrackHoverContent: Spotify-style track preview (cover, stats, play)
Audio player — Spotify-like 3-column layout:
- grid-cols-3 layout: track info | controls | volume+queue
- Progress bar moved to top edge (minimal variant)
- Glassmorphism (bg-background/95 backdrop-blur-md)
- Prominent centered play button (h-10 w-10 rounded-full, active:scale-95)
- Title marquee animation for long track names
- Reduced padding for tighter premium feel
Scrollbar styling:
- Migrated hardcoded rgba() to semantic tokens via color-mix(in oklch)
- Added transition on thumb hover for smooth visual feedback
ContextMenu integration:
- TrackListRow wrapped with ContextMenu (play, like, more actions)
- Dynamic items based on available callbacks
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 22:18:46 +00:00
|
|
|
/** "default" shows time labels on sides; "minimal" renders a thin full-width bar (for top-of-player placement). */
|
|
|
|
|
variant?: 'default' | 'minimal';
|
2026-02-05 21:40:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function AudioPlayerProgress({
|
|
|
|
|
currentTime,
|
|
|
|
|
duration,
|
|
|
|
|
onSeek,
|
feat(ui): hover cards, Spotify player layout, scrollbar tokens, context menu integration
HoverCard component (new):
- Rich preview cards on hover with framer-motion animation
- Viewport-aware positioning, portal rendering, open/close delays
- UserHoverContent: Discord-style user preview (avatar, bio, stats, follow)
- TrackHoverContent: Spotify-style track preview (cover, stats, play)
Audio player — Spotify-like 3-column layout:
- grid-cols-3 layout: track info | controls | volume+queue
- Progress bar moved to top edge (minimal variant)
- Glassmorphism (bg-background/95 backdrop-blur-md)
- Prominent centered play button (h-10 w-10 rounded-full, active:scale-95)
- Title marquee animation for long track names
- Reduced padding for tighter premium feel
Scrollbar styling:
- Migrated hardcoded rgba() to semantic tokens via color-mix(in oklch)
- Added transition on thumb hover for smooth visual feedback
ContextMenu integration:
- TrackListRow wrapped with ContextMenu (play, like, more actions)
- Dynamic items based on available callbacks
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 22:18:46 +00:00
|
|
|
variant = 'default',
|
2026-02-05 21:40:06 +00:00
|
|
|
}: AudioPlayerProgressProps) {
|
feat(ui): hover cards, Spotify player layout, scrollbar tokens, context menu integration
HoverCard component (new):
- Rich preview cards on hover with framer-motion animation
- Viewport-aware positioning, portal rendering, open/close delays
- UserHoverContent: Discord-style user preview (avatar, bio, stats, follow)
- TrackHoverContent: Spotify-style track preview (cover, stats, play)
Audio player — Spotify-like 3-column layout:
- grid-cols-3 layout: track info | controls | volume+queue
- Progress bar moved to top edge (minimal variant)
- Glassmorphism (bg-background/95 backdrop-blur-md)
- Prominent centered play button (h-10 w-10 rounded-full, active:scale-95)
- Title marquee animation for long track names
- Reduced padding for tighter premium feel
Scrollbar styling:
- Migrated hardcoded rgba() to semantic tokens via color-mix(in oklch)
- Added transition on thumb hover for smooth visual feedback
ContextMenu integration:
- TrackListRow wrapped with ContextMenu (play, like, more actions)
- Dynamic items based on available callbacks
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 22:18:46 +00:00
|
|
|
if (variant === 'minimal') {
|
|
|
|
|
return (
|
|
|
|
|
<div className="w-full group">
|
|
|
|
|
<Slider
|
|
|
|
|
value={[currentTime]}
|
|
|
|
|
max={duration || 1}
|
|
|
|
|
step={0.1}
|
|
|
|
|
onValueChange={onSeek}
|
|
|
|
|
className="w-full"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-05 21:40:06 +00:00
|
|
|
return (
|
|
|
|
|
<div className="flex items-center gap-2 flex-1">
|
|
|
|
|
<span className="text-xs text-muted-foreground w-12 text-right">
|
|
|
|
|
{formatTime(currentTime)}
|
|
|
|
|
</span>
|
|
|
|
|
<Slider
|
|
|
|
|
value={[currentTime]}
|
|
|
|
|
max={duration || 1}
|
|
|
|
|
step={0.1}
|
|
|
|
|
onValueChange={onSeek}
|
|
|
|
|
className="flex-1"
|
|
|
|
|
/>
|
|
|
|
|
<span className="text-xs text-muted-foreground w-12">
|
|
|
|
|
{formatTime(duration)}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|