141 lines
4.9 KiB
TypeScript
141 lines
4.9 KiB
TypeScript
'use client'
|
|
|
|
export interface PlaylistHeaderProps {
|
|
title: string
|
|
description?: string
|
|
coverUrl?: string
|
|
ownerName: string
|
|
isPublic: boolean
|
|
songCount: number
|
|
duration: number
|
|
isOwner?: boolean
|
|
onPlayAll?: () => void
|
|
onEdit?: () => void
|
|
onDelete?: () => void
|
|
}
|
|
|
|
export function PlaylistHeader({
|
|
title,
|
|
description,
|
|
coverUrl,
|
|
ownerName,
|
|
isPublic,
|
|
songCount,
|
|
duration,
|
|
isOwner = false,
|
|
onPlayAll,
|
|
onEdit,
|
|
onDelete
|
|
}: PlaylistHeaderProps) {
|
|
const formatDuration = (seconds: number) => {
|
|
const hours = Math.floor(seconds / 3600)
|
|
const minutes = Math.floor((seconds % 3600) / 60)
|
|
if (hours > 0) return `${hours} hr ${minutes} min`
|
|
return `${minutes} min`
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-end gap-8 mb-8 p-8 bg-gradient-to-b from-zinc-900/80 to-transparent">
|
|
{/* Cover Image */}
|
|
<div className="flex-shrink-0">
|
|
<div className="w-64 h-64 rounded-lg overflow-hidden bg-zinc-800 shadow-2xl relative">
|
|
{coverUrl ? (
|
|
<img
|
|
src={coverUrl}
|
|
alt={title}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full flex items-center justify-center">
|
|
<svg className="w-32 h-32 text-zinc-600" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z" />
|
|
</svg>
|
|
</div>
|
|
)}
|
|
|
|
{/* Privacy Badge */}
|
|
{!isPublic && (
|
|
<div className="absolute top-3 right-3 px-3 py-1 bg-zinc-900/90 backdrop-blur-sm rounded-full text-xs text-zinc-300 flex items-center gap-1">
|
|
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" />
|
|
</svg>
|
|
Private
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Playlist Info */}
|
|
<div className="flex-1 pb-4">
|
|
<p className="text-sm font-semibold text-zinc-400 uppercase mb-2">
|
|
Playlist
|
|
</p>
|
|
|
|
<h1 className="text-6xl font-bold text-white mb-4 line-clamp-2">
|
|
{title}
|
|
</h1>
|
|
|
|
{description && (
|
|
<p className="text-zinc-300 mb-4 line-clamp-2">
|
|
{description}
|
|
</p>
|
|
)}
|
|
|
|
<div className="flex items-center gap-2 text-sm text-zinc-300 mb-6">
|
|
<span className="font-semibold">{ownerName}</span>
|
|
<span>•</span>
|
|
<span>{songCount} {songCount === 1 ? 'song' : 'songs'}</span>
|
|
{duration > 0 && (
|
|
<>
|
|
<span>•</span>
|
|
<span>{formatDuration(duration)}</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className="flex items-center gap-4">
|
|
{onPlayAll && (
|
|
<button
|
|
onClick={onPlayAll}
|
|
className="w-14 h-14 rounded-full bg-purple-500 hover:bg-purple-600 hover:scale-105 flex items-center justify-center transition-all shadow-lg"
|
|
>
|
|
<svg className="w-7 h-7 text-white ml-1" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M6.3 4.1c-.4-.2-.8 0-.8.4v11c0 .4.4.6.8.4l9-5.5c.3-.2.3-.6 0-.8l-9-5.5z" />
|
|
</svg>
|
|
</button>
|
|
)}
|
|
|
|
{isOwner && (
|
|
<>
|
|
{onEdit && (
|
|
<button
|
|
onClick={onEdit}
|
|
className="p-3 rounded-full bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition"
|
|
title="Edit playlist"
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
|
</svg>
|
|
</button>
|
|
)}
|
|
|
|
{onDelete && (
|
|
<button
|
|
onClick={onDelete}
|
|
className="p-3 rounded-full bg-zinc-800 hover:bg-red-500/20 text-zinc-300 hover:text-red-400 transition"
|
|
title="Delete playlist"
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
</svg>
|
|
</button>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|