advogados01/Template-01/src/pages/BlogPost.tsx

213 lines
9 KiB
TypeScript
Raw Normal View History

2026-05-15 14:18:07 +00:00
import React, { useEffect, useState } from 'react';
import { ArrowLeft, User, Calendar, Share2, Copy, Check, MessageCircle, Linkedin, Facebook, Twitter, X } from 'lucide-react';
import { Link, useParams } from 'react-router-dom';
import { motion, AnimatePresence } from 'motion/react';
import { MOCK_POSTS, MOCK_POSTSList } from '../data/posts';
export function BlogPost() {
const { id } = useParams();
const post = id ? MOCK_POSTS[id] : null;
const [showShareMenu, setShowShareMenu] = useState(false);
const [copied, setCopied] = useState(false);
useEffect(() => {
window.scrollTo({ top: 0, behavior: 'instant' });
}, [id]);
if (!post) {
return (
<div className="flex min-h-screen items-center justify-center bg-gray-50 pt-20">
<div className="text-center">
<h2 className="mb-4 text-2xl font-bold text-brand-blue">Artigo não encontrado</h2>
<Link to="/blog" className="text-brand-gold hover:underline">
Voltar para o Blog
</Link>
</div>
</div>
);
}
const url = window.location.href;
const encodedUrl = encodeURIComponent(url);
const encodedTitle = encodeURIComponent(post.title);
const copyToClipboard = () => {
navigator.clipboard.writeText(url);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const shareLinks = [
{
name: 'WhatsApp',
icon: MessageCircle,
href: `https://api.whatsapp.com/send?text=${encodedTitle}%20${encodedUrl}`,
color: 'hover:text-green-500 hover:bg-green-50'
},
{
name: 'LinkedIn',
icon: Linkedin,
href: `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
color: 'hover:text-blue-600 hover:bg-blue-50'
},
{
name: 'Facebook',
icon: Facebook,
href: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
color: 'hover:text-blue-500 hover:bg-blue-50'
},
{
name: 'X (Twitter)',
icon: Twitter,
href: `https://twitter.com/intent/tweet?url=${encodedUrl}&text=${encodedTitle}`,
color: 'hover:text-gray-900 hover:bg-gray-100'
}
];
const relatedPosts = MOCK_POSTSList.filter(p => p.category === post.category && p.id !== post.id).slice(0, 3);
if (relatedPosts.length < 3) {
const morePosts = MOCK_POSTSList.filter(p => !relatedPosts.includes(p) && p.id !== post.id);
relatedPosts.push(...morePosts.slice(0, 3 - relatedPosts.length));
}
return (
<main className="w-full bg-[#fcfcfc] pb-24 pt-32">
<article className="mx-auto max-w-4xl px-6 lg:px-8">
{/* ... (rest of the content is unchanged) */}
<Link to="/blog" className="mb-10 inline-flex items-center gap-2 text-sm text-gray-500 transition-colors hover:text-brand-gold">
<ArrowLeft className="h-4 w-4" /> Todos os artigos
</Link>
{/* Header */}
<header className="mb-12 text-center">
<span className="mb-4 inline-block bg-brand-blue px-3 py-1 text-xs font-bold uppercase tracking-widest text-brand-gold">
{post.category}
</span>
<h1 className="mb-6 font-serif text-3xl font-bold leading-tight text-brand-blue md:text-5xl">
{post.title}
</h1>
<div className="flex flex-wrap items-center justify-center gap-6 border-b border-gray-200 pb-8 text-sm text-gray-500">
<div className="flex items-center gap-2">
<User className="h-4 w-4" /> Dr. João Silva
</div>
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4" /> {post.date}
</div>
<button
onClick={copyToClipboard}
className={`flex items-center gap-2 transition-colors ${copied ? 'text-green-600' : 'hover:text-brand-blue'}`}
>
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
{copied ? 'Copiado!' : 'Copiar Link'}
</button>
<div className="relative">
<button
onClick={() => setShowShareMenu(!showShareMenu)}
className="flex items-center gap-2 hover:text-brand-blue transition-colors"
>
{showShareMenu ? <X className="h-4 w-4" /> : <Share2 className="h-4 w-4" />}
Compartilhar
</button>
<AnimatePresence>
{showShareMenu && (
<motion.div
initial={{ opacity: 0, y: 10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 10, scale: 0.95 }}
transition={{ duration: 0.15 }}
className="absolute right-1/2 top-full mt-2 w-48 translate-x-1/2 sm:translate-x-0 sm:right-0 sm:left-auto rounded-lg border border-gray-100 bg-white p-2 shadow-xl z-10"
>
<div className="flex flex-col text-left">
{shareLinks.map((link) => (
<a
key={link.name}
href={link.href}
target="_blank"
rel="noopener noreferrer"
className={`flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-gray-700 transition-colors ${link.color}`}
onClick={() => setShowShareMenu(false)}
>
<link.icon className="h-4 w-4" /> {link.name}
</a>
))}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
</div>
</header>
{/* Featured Image */}
<motion.div
initial={{ opacity: 0, scale: 0.98 }}
animate={{ opacity: 1, scale: 1 }}
className="mb-14 overflow-hidden rounded-sm"
>
<img
src={post.imageUrl}
alt={post.title}
className="aspect-[2/1] w-full object-cover"
/>
</motion.div>
{/* Article Body */}
<div className="mx-auto max-w-3xl prose prose-blue prose-lg prose-headings:font-serif prose-headings:text-brand-blue prose-a:text-brand-gold prose-a:no-underline hover:prose-a:underline">
{/* Render HTML content safely since it's hardcoded mock, but natively prefer Markdown if CMS */}
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</div>
{/* CTA Section */}
<div className="mx-auto mt-20 max-w-3xl bg-brand-blue p-8 text-center sm:p-12 mb-20">
<h3 className="mb-4 font-serif text-2xl font-bold text-white">Este conteúdo ajudou em sua situação?</h3>
<p className="mb-8 text-gray-300">Cada caso demanda uma análise específica. Caso esteja passando por esta situação, avaliarei o seu cenário de forma técnica e sigilosa.</p>
<Link to="/contato" className="inline-block bg-brand-gold px-8 py-3 font-semibold text-white transition-colors hover:bg-white hover:text-brand-blue">
Solicitar Análise de Caso
</Link>
</div>
{/* Artigos Relacionados */}
{relatedPosts.length > 0 && (
<div className="mx-auto max-w-5xl border-t border-gray-100 pt-16">
<h3 className="mb-8 font-serif text-2xl font-bold text-brand-blue text-center">
Você também pode se interessar por:
</h3>
<div className="grid grid-cols-1 gap-8 md:grid-cols-3">
{relatedPosts.map((relatedPost, index) => (
<motion.article
key={relatedPost.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1 }}
className="group flex flex-col overflow-hidden bg-white shadow-sm border border-gray-100 transition-all hover:-translate-y-1 hover:shadow-xl hover:border-brand-gold/30"
>
<Link to={`/blog/${relatedPost.id}`} className="aspect-[16/10] w-full overflow-hidden block">
<img
src={relatedPost.imageUrl}
alt={relatedPost.title}
className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
/>
</Link>
<div className="flex flex-1 flex-col p-6">
<span className="mb-3 text-xs font-bold uppercase tracking-wider text-brand-gold">
{relatedPost.category}
</span>
<Link to={`/blog/${relatedPost.id}`} className="font-serif text-lg font-bold leading-snug text-brand-blue group-hover:text-brand-gold-hover">
{relatedPost.title}
</Link>
</div>
</motion.article>
))}
</div>
</div>
)}
</article>
</main>
);
}