owl-stream/app/components/StreamCard.tsx

63 lines
2.5 KiB
TypeScript

import React from 'react';
import Link from 'next/link';
import { Radio, Users, MapPin } from 'lucide-react';
import type { Stream } from '@/lib/api';
export default function StreamCard({ stream }: { stream: Stream }) {
return (
<Link href={`/streams/${stream.id}`} className="group block">
<div className="bg-surfaceGreen border border-white/5 rounded-2xl overflow-hidden hover:border-teal/30 transition-all hover:shadow-xl hover:shadow-teal/5">
{/* Thumbnail area */}
<div className="relative aspect-video bg-black/40 overflow-hidden">
{stream.thumbnailUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={stream.thumbnailUrl}
alt={stream.name}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
/>
) : (
<div className="w-full h-full flex items-center justify-center">
<Radio size={48} className="text-stone-600" />
</div>
)}
{/* Status badge */}
<div className={`absolute top-3 left-3 flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider ${
stream.status === 'live'
? 'bg-red-500/90 text-white'
: 'bg-black/60 text-stone-300'
}`}>
{stream.status === 'live' && <span className="w-1.5 h-1.5 rounded-full bg-white animate-pulse" />}
{stream.status === 'live' ? 'Live' : 'Offline'}
</div>
{/* Viewer count */}
{stream.viewerCount > 0 && (
<div className="absolute top-3 right-3 flex items-center gap-1 bg-black/60 px-2 py-1 rounded-full text-xs text-stone-200 font-semibold">
<Users size={12} />
{stream.viewerCount.toLocaleString()}
</div>
)}
</div>
{/* Info */}
<div className="p-5 space-y-2">
<h3 className="font-bold text-white group-hover:text-teal transition-colors text-base leading-snug">
{stream.name}
</h3>
{stream.location && (
<div className="flex items-center gap-1.5 text-xs text-stone-400 font-medium">
<MapPin size={12} />
{stream.location}
</div>
)}
{stream.description && (
<p className="text-sm text-stone-400 line-clamp-2 leading-relaxed">{stream.description}</p>
)}
</div>
</div>
</Link>
);
}