refactor: improve layout and styling of Playlist component for better readability

This commit is contained in:
JSC
2025-08-09 21:13:50 +02:00
parent 5ca8c8bf15
commit f65ed660ef

View File

@@ -22,9 +22,10 @@ export function Playlist({
const maxHeight = variant === 'maximized' ? 'h-[calc(100vh-200px)]' : 'h-60' const maxHeight = variant === 'maximized' ? 'h-[calc(100vh-200px)]' : 'h-60'
return ( return (
<div className="space-y-2"> <div className="w-full">
<div className="flex items-center justify-between"> {/* Header */}
<h4 className="font-medium text-sm"> <div className="flex items-center justify-between mb-2">
<h4 className="font-medium text-sm truncate">
{playlist.name} {playlist.name}
</h4> </h4>
<Badge variant="secondary" className="text-xs"> <Badge variant="secondary" className="text-xs">
@@ -32,98 +33,69 @@ export function Playlist({
</Badge> </Badge>
</div> </div>
<ScrollArea className={cn('w-full', maxHeight)}> {/* Track List */}
<div className="space-y-1"> <ScrollArea className={maxHeight}>
<div className="w-full">
{playlist.sounds.map((sound, index) => ( {playlist.sounds.map((sound, index) => (
<div <div
key={sound.id} key={sound.id}
className={cn( className={cn(
'flex items-center gap-3 p-2 rounded-lg cursor-pointer transition-colors', 'grid grid-cols-10 gap-2 items-center py-1.5 px-2 rounded hover:bg-muted/50 cursor-pointer text-xs',
'hover:bg-muted/50', currentIndex === index && 'bg-primary/10 text-primary'
currentIndex === index && 'bg-primary/10 border border-primary/20'
)} )}
onClick={() => onTrackSelect(index)} onClick={() => onTrackSelect(index)}
> >
{/* Track Number or Play Icon */} {/* Track number/play icon - 1 column */}
<div className="w-6 h-6 flex items-center justify-center flex-shrink-0"> <div className="col-span-1 flex justify-center">
{currentIndex === index ? ( {currentIndex === index ? (
<Play className="h-3 w-3 text-primary" /> <Play className="h-3 w-3" />
) : ( ) : (
<span className="text-xs text-muted-foreground"> <span className="text-muted-foreground">{index + 1}</span>
{index + 1}
</span>
)} )}
</div> </div>
{/* Thumbnail */} {/* Thumbnail - 1 column */}
<div className={cn( <div className="col-span-1">
'flex-shrink-0 bg-muted rounded flex items-center justify-center overflow-hidden', <div className={cn(
variant === 'maximized' ? 'w-10 h-10' : 'w-8 h-8' 'bg-muted rounded flex items-center justify-center overflow-hidden',
)}> variant === 'maximized' ? 'w-6 h-6' : 'w-5 h-5'
{sound.thumbnail ? ( )}>
<img {sound.thumbnail ? (
src={filesService.getThumbnailUrl(sound.id)} <img
alt={sound.name} src={filesService.getThumbnailUrl(sound.id)}
className="w-full h-full object-cover" alt=""
onError={(e) => { className="w-full h-full object-cover"
// Hide image and show music icon if thumbnail fails to load />
const target = e.target as HTMLImageElement ) : (
target.style.display = 'none' <Music className="h-3 w-3 text-muted-foreground" />
const musicIcon = target.nextElementSibling as HTMLElement
if (musicIcon) musicIcon.style.display = 'block'
}}
/>
) : null}
<Music
className={cn(
'text-muted-foreground',
variant === 'maximized' ? 'h-5 w-5' : 'h-4 w-4',
sound.thumbnail ? 'hidden' : 'block'
)} )}
/> </div>
</div> </div>
{/* Track Info */} {/* Track name - 6 columns (takes most space) */}
<div className="flex-1 min-w-0"> <div className="col-span-6">
<p className={cn( <span className={cn(
'font-medium truncate', 'font-medium truncate block',
variant === 'maximized' ? 'text-sm' : 'text-xs', variant === 'maximized' ? 'text-sm' : 'text-xs',
currentIndex === index && 'text-primary' currentIndex === index ? 'text-primary' : 'text-foreground'
)}> )}>
{sound.name} {sound.name}
</p> </span>
{/* <p className={cn(
'text-muted-foreground truncate',
variant === 'maximized' ? 'text-xs' : 'text-[10px]'
)}>
{sound.filename}
</p> */}
</div> </div>
{/* Duration and Type */} {/* Duration - 2 columns */}
{/* <div className="flex flex-col items-end gap-1 flex-shrink-0"> <div className="col-span-2 text-right">
<span className={cn( <span className="text-muted-foreground text-[10px] whitespace-nowrap">
'text-muted-foreground',
variant === 'maximized' ? 'text-xs' : 'text-[10px]'
)}>
{formatDuration(sound.duration)} {formatDuration(sound.duration)}
</span> </span>
<Badge </div>
variant="outline"
className={cn(
variant === 'maximized' ? 'text-[10px] px-1' : 'text-[8px] px-1 py-0'
)}
>
{sound.type}
</Badge>
</div> */}
</div> </div>
))} ))}
</div> </div>
</ScrollArea> </ScrollArea>
{/* Playlist Stats */} {/* Footer Stats */}
<div className="pt-2 border-t"> <div className="pt-2 mt-2 border-t">
<div className="flex justify-between text-xs text-muted-foreground"> <div className="flex justify-between text-xs text-muted-foreground">
<span>{playlist.sounds.length} tracks</span> <span>{playlist.sounds.length} tracks</span>
<span>{formatDuration(playlist.duration)}</span> <span>{formatDuration(playlist.duration)}</span>