generated from autoblog/Seo
142 lines
7.7 KiB
TypeScript
142 lines
7.7 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);
|
|
const sysId = `NODE_IDX_0${article.id.slice(0, 1)}`;
|
|
|
|
if (featured) {
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -20 }}
|
|
whileInView={{ opacity: 1, x: 0 }}
|
|
viewport={{ once: true }}
|
|
className="group relative flex flex-col md:flex-row gap-0 bg-transparent border border-white/5 hover:bg-brand transition-all duration-500 overflow-hidden"
|
|
>
|
|
<div className="md:w-5/12 relative overflow-hidden bg-black grayscale group-hover:grayscale-0 transition-all duration-700 border-r border-white/5">
|
|
<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-1000 group-hover:scale-110 aspect-square md:aspect-auto"
|
|
referrerPolicy="no-referrer"
|
|
/>
|
|
</Link>
|
|
<div className="absolute inset-0 bg-brand/10 group-hover:bg-transparent transition-colors" />
|
|
<div className="absolute top-4 left-4 h-6 w-6 border-l border-t border-brand/50" />
|
|
</div>
|
|
|
|
<div className="md:w-7/12 flex flex-col p-6 lg:p-10 relative">
|
|
<div className="flex items-center justify-between mb-8">
|
|
<div className="flex items-center gap-3 text-[9px] font-mono font-black uppercase tracking-[0.2em] text-brand px-2 py-0.5 bg-brand/5 border-l border-brand w-fit group-hover:bg-black group-hover:text-white transition-colors">
|
|
<span>{article.category}</span>
|
|
</div>
|
|
<span className="text-[8px] font-mono font-black text-slate-800 group-hover:text-black/40 transition-colors uppercase tracking-[0.3em]">{sysId}</span>
|
|
</div>
|
|
|
|
<Link to={`/artigo/${article.slug}`}>
|
|
<h2 className="text-2xl sm:text-3xl lg:text-4xl font-display font-black text-white leading-[0.95] mb-6 group-hover:text-black transition-colors italic uppercase tracking-tighter">
|
|
{article.title}
|
|
</h2>
|
|
</Link>
|
|
|
|
<p className="text-xs font-mono text-slate-500 leading-relaxed mb-10 line-clamp-2 uppercase tracking-tight group-hover:text-black/60 transition-colors">
|
|
{" >> "} {article.excerpt}
|
|
</p>
|
|
|
|
<div className="mt-auto flex items-center justify-between pt-8 border-t border-white/10 group-hover:border-black/10 transition-colors font-mono">
|
|
<div className="flex items-center gap-4">
|
|
<div className="h-12 w-12 border border-white/10 p-0.5 group-hover:border-black/20 transition-colors bg-white/5">
|
|
<img src={article.author.avatar} alt={article.author.name} className="h-full w-full object-cover grayscale opacity-50 group-hover:opacity-100 group-hover:grayscale-0 transition-all" />
|
|
</div>
|
|
<div>
|
|
<p className="text-[10px] font-black text-white leading-none uppercase tracking-wider group-hover:text-black transition-colors">{article.author.name}</p>
|
|
<p className="text-[8px] text-slate-700 uppercase tracking-widest font-black mt-1.5 group-hover:text-black/40 transition-colors italic">ARCHITECT_INFRA_v4</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-brand font-black text-[9px] uppercase tracking-widest bg-brand/5 px-3 py-1 border border-brand/20 group-hover:bg-black group-hover:text-white group-hover:border-black transition-all">
|
|
<Clock size={11} />
|
|
<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-transparent border border-white/5 hover:border-brand/40 transition-all duration-500 overflow-hidden h-full relative"
|
|
>
|
|
<div className="absolute top-0 right-0 w-2 h-2 border-r border-t border-white/10 group-hover:border-brand/50 transition-colors m-4" />
|
|
|
|
<div className="relative aspect-[16/10] overflow-hidden bg-black grayscale group-hover:grayscale-0 transition-all duration-700">
|
|
<Link to={`/artigo/${article.slug}`} className="block h-full">
|
|
<img
|
|
src={article.image}
|
|
alt={article.title}
|
|
className="h-full w-full object-cover group-hover:scale-105 transition-all duration-1000"
|
|
referrerPolicy="no-referrer"
|
|
/>
|
|
</Link>
|
|
<div className="absolute inset-0 bg-brand/5 group-hover:bg-transparent transition-colors" />
|
|
|
|
<button
|
|
onClick={() => toggleBookmark(article.id)}
|
|
className={cn(
|
|
"absolute bottom-4 right-4 h-10 w-10 border border-white/10 backdrop-blur-md flex items-center justify-center transition-all opacity-0 group-hover:opacity-100",
|
|
bookmarked ? "bg-brand border-brand text-black opacity-100" : "bg-black/60 text-brand hover:bg-brand hover:text-black"
|
|
)}
|
|
>
|
|
<Bookmark size={14} fill={bookmarked ? "currentColor" : "none"} />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="p-6 lg:p-8 flex flex-col flex-grow relative">
|
|
<div className="absolute bottom-0 right-0 w-16 h-16 bg-brand/5 blur-3xl -z-10" />
|
|
|
|
<div className="flex items-center justify-between mb-5 font-mono">
|
|
<span className="text-[9px] font-black uppercase tracking-[0.2em] text-brand/60 border-l-2 border-brand pl-3 group-hover:text-brand transition-colors">{article.category}</span>
|
|
<span className="text-[8px] font-mono font-black text-slate-800 uppercase tracking-widest">{sysId}</span>
|
|
</div>
|
|
|
|
<Link to={`/artigo/${article.slug}`} className="flex-grow">
|
|
<h3 className="text-xl font-display font-black text-white leading-[0.95] mb-4 group-hover:text-brand transition-colors italic uppercase tracking-tight">
|
|
{article.title}
|
|
</h3>
|
|
<p className="text-slate-600 text-xs leading-relaxed line-clamp-2 font-mono uppercase tracking-tight mb-10">
|
|
{article.excerpt}
|
|
</p>
|
|
</Link>
|
|
|
|
<div className="mt-auto pt-8 border-t border-white/5 flex items-center justify-between font-mono">
|
|
<div className="flex items-center gap-3">
|
|
<div className="h-9 w-9 border border-white/10 p-0.5 group-hover:border-brand/40 transition-colors bg-white/5">
|
|
<img src={article.author.avatar} alt={article.author.name} className="h-full w-full object-cover grayscale opacity-40 group-hover:opacity-100 group-hover:grayscale-0 transition-all" />
|
|
</div>
|
|
<div className="flex flex-col">
|
|
<span className="text-[9px] font-black text-white uppercase tracking-wider">{article.author.name}</span>
|
|
<span className="text-[7px] text-slate-700 uppercase tracking-widest italic">{article.readTime}</span>
|
|
</div>
|
|
</div>
|
|
<div className="h-10 w-10 border border-white/5 flex items-center justify-center text-slate-700 group-hover:bg-brand group-hover:text-black group-hover:border-brand transition-all">
|
|
<ArrowRight size={16} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
}
|