102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import Image from 'next/image'
|
|
import Link from 'next/link'
|
|
import { Badge } from '@/components/ui/badge'
|
|
import { Card, CardContent } from '@/components/ui/card'
|
|
import { Calendar, Clock, User } from 'lucide-react'
|
|
import { ITopic } from '@/models/topic'
|
|
|
|
interface TopicCardProps {
|
|
topic: ITopic
|
|
showAuthor?: boolean
|
|
showReadingTime?: boolean
|
|
}
|
|
|
|
export function TopicCard({ topic, showAuthor = true, showReadingTime = true }: TopicCardProps) {
|
|
const publishedDate = new Date(topic.publishedAt).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
})
|
|
|
|
return (
|
|
<Link href={`/topics/${topic.slug}`} className="group block">
|
|
<Card className="overflow-hidden transition-all duration-300 hover:shadow-lg hover:scale-[1.02]">
|
|
<div className="aspect-video relative overflow-hidden">
|
|
<Image
|
|
src={topic.coverImage}
|
|
alt={topic.title}
|
|
fill
|
|
className="object-cover transition-transform duration-300 group-hover:scale-105"
|
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
/>
|
|
</div>
|
|
|
|
<CardContent className="p-6">
|
|
{/* Metadata */}
|
|
<div className="flex items-center gap-4 text-sm text-muted-foreground mb-3">
|
|
<div className="flex items-center gap-1">
|
|
<Calendar className="w-3 h-3" />
|
|
<time dateTime={new Date(topic.publishedAt).toISOString()}>
|
|
{publishedDate}
|
|
</time>
|
|
</div>
|
|
|
|
{showReadingTime && topic.readingTime && (
|
|
<div className="flex items-center gap-1">
|
|
<Clock className="w-3 h-3" />
|
|
<span>{topic.readingTime.text}</span>
|
|
</div>
|
|
)}
|
|
|
|
{showAuthor && (
|
|
<div className="flex items-center gap-1">
|
|
<User className="w-3 h-3" />
|
|
<span>{topic.author}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Title */}
|
|
<h2 className="text-xl font-bold mb-3 line-clamp-2 transition-colors group-hover:text-primary">
|
|
{topic.title}
|
|
</h2>
|
|
|
|
{/* Excerpt */}
|
|
<p className="text-muted-foreground mb-4 line-clamp-3 leading-relaxed">
|
|
{topic.excerpt}
|
|
</p>
|
|
|
|
{/* Tags */}
|
|
<div className="flex flex-wrap gap-2">
|
|
{topic.tags.slice(0, 3).map((tag) => (
|
|
<Badge
|
|
key={tag.id || tag.name}
|
|
variant="secondary"
|
|
className="text-xs hover:bg-primary hover:text-primary-foreground transition-colors"
|
|
>
|
|
{tag.name}
|
|
</Badge>
|
|
))}
|
|
{topic.tags.length > 3 && (
|
|
<Badge variant="outline" className="text-xs">
|
|
+{topic.tags.length - 3} more
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
|
|
{/* Featured indicator */}
|
|
{topic.featured && (
|
|
<div className="mt-3">
|
|
<Badge className="text-xs bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600">
|
|
Featured
|
|
</Badge>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
</Link>
|
|
)
|
|
}
|
|
|
|
export default TopicCard
|