all
This commit is contained in:
1 parent
d7f584059e
commit
409d9455f6
17 files changed
+412
-171
No files matched your search
@@ -0,0 +1,141 @@
|
||||
'use client';
|
||||
import { useEffect } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useBlogPost } from '../../../services/blog';
|
||||
import { assetUrl } from '../../../services/api';
|
||||
import Loader from '../../../components/Loader';
|
||||
|
||||
function renderContent(content: string) {
|
||||
return content.split('\n').map((line, i) => {
|
||||
if (line.startsWith('# '))
|
||||
return <h2 key={i} style={{ fontSize: '1.5rem', fontWeight: 700, color: '#0a0a0a', marginTop: '2rem', marginBottom: '0.5rem', lineHeight: 1.3 }}>{line.slice(2)}</h2>;
|
||||
if (line.startsWith('## '))
|
||||
return <h3 key={i} style={{ fontSize: '1.15rem', fontWeight: 600, color: '#1a1a1a', marginTop: '1.5rem', marginBottom: '0.4rem' }}>{line.slice(3)}</h3>;
|
||||
if (line.startsWith('- '))
|
||||
return <li key={i} style={{ color: '#4a4744', lineHeight: 1.8, marginLeft: '1.2rem', listStyleType: 'disc' }}>{line.slice(2)}</li>;
|
||||
if (line.trim() === '')
|
||||
return <br key={i} />;
|
||||
return <p key={i} style={{ color: '#4a4744', lineHeight: 1.85, marginBottom: '0.25rem' }}>{line}</p>;
|
||||
});
|
||||
}
|
||||
|
||||
export default function ArticlePage() {
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
const slug = typeof params.slug === 'string' ? params.slug : params.slug?.[0] ?? '';
|
||||
|
||||
const { data: post, isLoading, isError } = useBlogPost(slug);
|
||||
|
||||
useEffect(() => {
|
||||
if (post) document.title = `${post.title} | Blog`;
|
||||
}, [post]);
|
||||
|
||||
if (isLoading) return <Loader className="py-40" />;
|
||||
if (isError || !post) {
|
||||
return (
|
||||
<main style={{ minHeight: '80vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 16 }}>
|
||||
<p style={{ color: '#aaa8a4', fontSize: 14, fontFamily: 'monospace', letterSpacing: '0.1em' }}>ARTÍCULO NO ENCONTRADO</p>
|
||||
<button onClick={() => router.push('/blog')}
|
||||
style={{ color: '#3b82f6', fontSize: 14, textDecoration: 'underline', background: 'none', border: 'none', cursor: 'pointer' }}>
|
||||
Volver al blog
|
||||
</button>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
const imageUrl = assetUrl(post.imageUrl);
|
||||
const publishDate = post.publishedAt
|
||||
? new Date(post.publishedAt).toLocaleDateString('es-MX', { day: '2-digit', month: 'long', year: 'numeric' })
|
||||
: null;
|
||||
|
||||
return (
|
||||
<main id="main-content">
|
||||
{/* Hero */}
|
||||
<section style={{ background: '#ffffff', borderBottom: '1px solid #dddbd5', paddingTop: '140px', paddingBottom: '60px' }}
|
||||
className="px-8 md:px-14">
|
||||
<div className="mx-auto" style={{ maxWidth: '780px' }}>
|
||||
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5 }}>
|
||||
{/* Breadcrumb */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 28, fontFamily: 'monospace', fontSize: 11, letterSpacing: '0.14em', color: '#aaa8a4' }}>
|
||||
<Link href="/blog" style={{ color: '#3b82f6', textDecoration: 'none' }}>BLOG</Link>
|
||||
<span>/</span>
|
||||
<span style={{ color: '#aaa8a4', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '40ch' }}>
|
||||
{post.category.toUpperCase()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Categoría */}
|
||||
<span style={{ display: 'inline-block', background: '#3b82f6', color: '#fff', fontFamily: 'monospace', fontSize: 10, letterSpacing: '0.14em', padding: '3px 10px', borderRadius: 2, marginBottom: 20 }}>
|
||||
{post.category.toUpperCase()}
|
||||
</span>
|
||||
|
||||
{/* Título */}
|
||||
<h1 style={{ fontSize: 'clamp(1.8rem, 4vw, 2.8rem)', fontWeight: 700, color: '#0a0a0a', lineHeight: 1.2, marginBottom: 20 }}>
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
{/* Resumen */}
|
||||
{post.summary && (
|
||||
<p style={{ fontSize: '1.1rem', color: '#6a6866', lineHeight: 1.7, marginBottom: 28, borderLeft: '3px solid #dddbd5', paddingLeft: 16 }}>
|
||||
{post.summary}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Meta */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 16, paddingTop: 20, borderTop: '1px solid #dddbd5' }}>
|
||||
{post.authorName && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<div style={{ width: 32, height: 32, borderRadius: '50%', background: 'linear-gradient(135deg,#3b82f6,#6366f1)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 13, fontWeight: 700 }}>
|
||||
{post.authorName.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: '#2a2a2a' }}>{post.authorName}</span>
|
||||
</div>
|
||||
)}
|
||||
{publishDate && (
|
||||
<>
|
||||
{post.authorName && <span style={{ color: '#dddbd5' }}>·</span>}
|
||||
<span style={{ fontFamily: 'monospace', fontSize: 11, color: '#aaa8a4', letterSpacing: '0.1em' }}>
|
||||
{publishDate.toUpperCase()}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Imagen de portada */}
|
||||
{imageUrl && (
|
||||
<div style={{ background: '#f0efec', borderBottom: '1px solid #dddbd5' }}>
|
||||
<div className="mx-auto" style={{ maxWidth: '1100px', padding: '0 2rem' }}>
|
||||
<motion.div initial={{ opacity: 0, scale: 0.98 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.6, delay: 0.15 }}
|
||||
style={{ overflow: 'hidden', borderRadius: 4, aspectRatio: '16/7', marginTop: -1 }}>
|
||||
<img src={imageUrl} alt={post.title} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Contenido */}
|
||||
<section style={{ background: '#f5f5f3', borderBottom: '1px solid #dddbd5', padding: '80px 0' }}
|
||||
className="px-8 md:px-14">
|
||||
<motion.div className="mx-auto" style={{ maxWidth: '780px' }}
|
||||
initial={{ opacity: 0, y: 24 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.6, delay: 0.2 }}>
|
||||
<div style={{ background: '#ffffff', border: '1px solid #dddbd5', borderRadius: 4, padding: '48px 52px', fontSize: '1rem', lineHeight: 1.85 }}>
|
||||
{renderContent(post.content)}
|
||||
</div>
|
||||
|
||||
{/* Volver */}
|
||||
<div style={{ marginTop: 48, paddingTop: 32, borderTop: '1px solid #dddbd5' }}>
|
||||
<Link href="/blog"
|
||||
style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontFamily: 'monospace', fontSize: 11, letterSpacing: '0.14em', color: '#3b82f6', textDecoration: 'none' }}>
|
||||
← VOLVER AL BLOG
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user