generated from autoblog/Seo
134 lines
6.4 KiB
TypeScript
134 lines
6.4 KiB
TypeScript
|
|
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>
|
||
|
|
);
|
||
|
|
}
|