Test-Generate-123/Template-02/src/components/ArticleCard.tsx

134 lines
6.4 KiB
TypeScript
Raw Normal View History

2026-05-13 22:38:24 +00:00
import { Link } from 'react-router-dom';
import { Article } from '../types';
import { motion } from 'motion/react';
import { Bookmark, Clock, User, ArrowRight } from 'lucide-react';
import { useBookmarks } from '../contexts/BookmarksContext';
import { cn } from '../lib/utils';
interface ArticleCardProps {
article: Article;
featured?: boolean;
}
export default function ArticleCard({ article, featured = false }: ArticleCardProps) {
const { toggleBookmark, isBookmarked } = useBookmarks();
const bookmarked = isBookmarked(article.id);
if (featured) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="group relative flex flex-col md:flex-row gap-8 lg:gap-12 bg-white p-6 rounded-[2.5rem] border border-slate-100 shadow-sm hover:shadow-xl hover:shadow-slate-200/50 transition-all duration-500"
>
<div className="md:w-1/2 relative overflow-hidden rounded-[2rem] bg-slate-100">
<Link to={`/artigo/${article.slug}`} className="block h-full">
<img
src={article.image}
alt={article.title}
className="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105 aspect-square md:aspect-video lg:aspect-[4/3]"
referrerPolicy="no-referrer"
/>
</Link>
<button
onClick={() => toggleBookmark(article.id)}
className={cn(
"absolute top-6 right-6 h-12 w-12 rounded-full border border-white/20 backdrop-blur-md flex items-center justify-center transition-all shadow-lg",
bookmarked ? "bg-brand border-brand text-white" : "bg-black/10 text-white hover:bg-white hover:text-brand"
)}
>
<Bookmark size={20} fill={bookmarked ? "currentColor" : "none"} />
</button>
</div>
<div className="md:w-1/2 flex flex-col justify-center">
<div className="flex items-center gap-4 text-[10px] font-bold uppercase tracking-widest text-brand mb-6 bg-brand/5 w-fit px-3 py-1 rounded-full border border-brand/10">
<span>{article.category}</span>
</div>
<Link to={`/artigo/${article.slug}`}>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-display font-extrabold text-slate-950 leading-[1.1] mb-6 hover:text-brand transition-colors">
{article.title}
</h2>
</Link>
<p className="text-lg text-slate-500 leading-relaxed mb-8 line-clamp-3 font-medium">
{article.excerpt}
</p>
<div className="mt-auto flex items-center justify-between pt-8 border-t border-slate-50">
<div className="flex items-center gap-3">
<img src={article.author.avatar} alt={article.author.name} className="h-10 w-10 rounded-full border border-slate-100" />
<div>
<p className="text-sm font-bold text-slate-900 leading-none">{article.author.name}</p>
<p className="text-[10px] text-slate-400 uppercase tracking-widest font-bold mt-1.5">Autor</p>
</div>
</div>
<div className="flex items-center gap-1.5 text-slate-400 font-bold text-[10px] uppercase tracking-widest bg-slate-50 px-3 py-1.5 rounded-lg border border-slate-100">
<Clock size={12} className="text-brand" />
<span>{article.readTime}</span>
</div>
</div>
</div>
</motion.div>
);
}
return (
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="group flex flex-col bg-white rounded-3xl border border-slate-100 overflow-hidden hover:shadow-xl hover:shadow-slate-200/50 transition-all duration-500"
>
<div className="relative aspect-[16/10] overflow-hidden bg-slate-100 rounded-t-[2.5rem]">
<Link to={`/artigo/${article.slug}`} className="block h-full">
<img
src={article.image}
alt={article.title}
className="h-full w-full object-cover grayscale-[0.5] group-hover:grayscale-0 transition-all duration-700 group-hover:scale-105"
referrerPolicy="no-referrer"
/>
</Link>
<button
onClick={() => toggleBookmark(article.id)}
className={cn(
"absolute top-6 right-6 h-11 w-11 rounded-full border border-white/20 backdrop-blur-md flex items-center justify-center transition-all opacity-0 group-hover:opacity-100 translate-y-2 group-hover:translate-y-0",
bookmarked ? "bg-brand border-brand text-white opacity-100 translate-y-0" : "bg-black/20 text-white hover:bg-white hover:text-brand shadow-xl"
)}
>
<Bookmark size={18} fill={bookmarked ? "currentColor" : "none"} />
</button>
</div>
<div className="p-10 flex flex-col flex-grow">
<div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-3">
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-brand">{article.category}</span>
</div>
<span className="text-[10px] font-bold text-slate-300 uppercase tracking-widest">{article.readTime}</span>
</div>
<Link to={`/artigo/${article.slug}`}>
<h3 className="text-2xl lg:text-3xl font-display font-black text-slate-950 leading-[1.15] mb-6 group-hover:text-brand transition-colors">
{article.title}
</h3>
</Link>
<p className="text-slate-500 text-sm leading-relaxed line-clamp-3 font-medium mb-10">
{article.excerpt}
</p>
<div className="mt-auto pt-8 border-t border-slate-50 flex items-center justify-between">
<div className="flex items-center gap-3">
<img src={article.author.avatar} alt={article.author.name} className="h-8 w-8 rounded-full grayscale hover:grayscale-0 transition-all border border-slate-100" />
<span className="text-[10px] font-black text-slate-950 uppercase tracking-widest">{article.author.name}</span>
</div>
<div className="h-8 w-8 rounded-full bg-slate-50 flex items-center justify-center text-slate-400 group-hover:bg-brand group-hover:text-white transition-all">
<ArrowRight size={14} />
</div>
</div>
</div>
</motion.div>
);
}