generated from autoblog/Advogados
213 lines
9 KiB
TypeScript
213 lines
9 KiB
TypeScript
|
|
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>
|
||
|
|
);
|
||
|
|
}
|