Redesign playlist cards to match VideoCard list style
Replace 2-col grid of small cards with a full-width list layout: thumbnail on the left, title + status on the right — same proportions and hover behaviour as VideoCard variant="list". Index/Re-index button appears on hover, video count shown as a pill overlay on the thumbnail. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -412,30 +412,43 @@ export default function ChannelPage() {
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
{playlists.map(pl => (
|
||||
<button key={pl.id} onClick={() => { setOpenPlaylistId(pl.id); setPlaylistOffset(0); }}
|
||||
className="text-left flex flex-col gap-1.5 rounded-lg overflow-hidden hover:bg-zinc-800/50 transition-colors p-1.5">
|
||||
<div className="relative aspect-video w-full rounded overflow-hidden bg-zinc-800">
|
||||
<div key={pl.id}
|
||||
onClick={() => { setOpenPlaylistId(pl.id); setPlaylistOffset(0); }}
|
||||
className="group flex gap-3 sm:gap-4 px-2 sm:px-3 py-2 sm:py-3 rounded-lg cursor-pointer hover:bg-zinc-900/70 transition-colors">
|
||||
{/* Thumbnail */}
|
||||
<div className="relative w-32 sm:w-60 md:w-72 aspect-video rounded-lg overflow-hidden bg-zinc-800 shrink-0">
|
||||
{pl.thumbnail_url ? (
|
||||
<img src={pl.thumbnail_url} alt="" className="w-full h-full object-cover" />
|
||||
<img src={pl.thumbnail_url} alt="" className="w-full h-full object-cover group-hover:scale-[1.03] transition-transform duration-300" />
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center text-zinc-600">
|
||||
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5}
|
||||
d="M4 6h16M4 10h16M4 14h8M4 18h8" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 6h16M4 10h16M4 14h8M4 18h8" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
<div className="absolute bottom-1 right-1 bg-black/70 text-white text-xs px-1 rounded">
|
||||
{pl.video_count}
|
||||
<span className="absolute bottom-1.5 right-1.5 bg-black/80 text-white text-[10px] font-medium px-1.5 py-0.5 rounded font-mono">
|
||||
{pl.video_count} videos
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs font-medium text-zinc-200 line-clamp-2 leading-snug px-0.5">{pl.title}</p>
|
||||
{pl.indexed_at && (
|
||||
<p className="text-xs text-zinc-600 px-0.5">Indexed</p>
|
||||
{/* Info */}
|
||||
<div className="flex flex-col gap-1 min-w-0 flex-1 py-px sm:py-0.5">
|
||||
<h3 className="font-semibold text-[12px] sm:text-[14px] leading-snug text-zinc-50 line-clamp-2">{pl.title}</h3>
|
||||
<span className="text-[10px] sm:text-[11px] text-zinc-500">
|
||||
{pl.indexed_at ? "Indexed" : "Not indexed"}
|
||||
</span>
|
||||
{pl.description && (
|
||||
<p className="hidden sm:block text-[11px] leading-relaxed text-zinc-500 line-clamp-1">{pl.description}</p>
|
||||
)}
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); indexPlaylistMut.mutate(pl.id); }}
|
||||
disabled={indexPlaylistMut.isPending}
|
||||
className="mt-auto self-start text-[10px] text-zinc-600 hover:text-zinc-300 transition-colors disabled:opacity-40 opacity-0 group-hover:opacity-100">
|
||||
{indexPlaylistMut.isPending ? "Indexing…" : pl.indexed_at ? "Re-index" : "Index"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user