13 de febrero de 2026•3 min lectura
test2
# Actualizar app/blog/[slug]/page.tsx
$articuloConImagenAdaptativa = @'
import { query } from '@/lib/db'
import { notFound } from 'next/navigation'
import Link from 'next/link'
import { Calendar, User, Eye, ArrowLeft } from 'lucide-react'
import SidebarBlog from '../components/SidebarBlog'
import BlogImage from '../components/BlogImage'
export async function generateMetadata({ params }) {
const { slug } = await params
const articulos = await query(
'SELECT title, excerpt, featured_image FROM posts WHERE slug = ? AND published = 1',
[slug]
) as any[]
if (articulos.length === 0) return { title: 'Artículo no encontrado' }
return {
title: `${articulos[0].title} - CambiCash Blog`,
description: articulos[0].excerpt,
openGraph: {
title: articulos[0].title,
description: articulos[0].excerpt,
images: articulos[0].featured_image ? [{
url: articulos[0].featured_image,
width: 1200,
height: 630,
alt: articulos[0].title
}] : [],
}
}
}
export default async function ArticuloPage({ params }) {
const { slug } = await params
const articulos = await query(`
SELECT
p.*,
u.name as author_name,
GROUP_CONCAT(c.name) as categories,
GROUP_CONCAT(c.slug) as category_slugs
FROM posts p
LEFT JOIN users u ON p.author_id = u.id
LEFT JOIN post_categories pc ON p.id = pc.post_id
LEFT JOIN categories c ON pc.category_id = c.id
WHERE p.slug = ? AND p.published = 1
GROUP BY p.id
`, [slug]) as any[]
if (articulos.length === 0) notFound()
const articulo = articulos[0]
const categorias = articulo.categories ? articulo.categories.split(',') : []
await query('UPDATE posts SET views = views + 1 WHERE id = ?', [articulo.id])
return (
<div className="min-h-screen bg-gray-50">
{/* Barra de navegación */}
<div className="bg-white border-b sticky top-0 z-10">
<div className="container mx-auto px-4 py-3 md:py-4">
<Link
href="/blog"
className="inline-flex items-center gap-1 md:gap-2 text-sm md:text-base text-gray-600 hover:text-blue-600"
>
<ArrowLeft className="w-4 h-4 md:w-5 md:h-5" />
Volver al Blog
</Link>
</div>
</div>
{/* Hero del artículo con imagen adaptativa */}
<div className="relative bg-gray-900">
{/* Imagen de fondo (hero) */}
<div className="relative h-48 sm:h-64 md:h-80 lg:h-96">
<BlogImage
src={articulo.featured_image}
alt={articulo.title}
type="hero"
priority={true}
/>
<div className="absolute inset-0 bg-black/40" />
</div>
{/* Título y metadatos sobre la imagen */}
<div className="absolute bottom-0 left-0 right-0 p-4 md:p-8 text-white">
<div className="container mx-auto">
<div className="max-w-3xl">
{/* Categorías */}
<div className="flex flex-wrap gap-1 md:gap-2 mb-2 md:mb-4">
{categorias.map((cat, idx) => (
<span
key={idx}
className="px-2 md:px-3 py-0.5 md:py-1 bg-blue-600 text-white text-xs md:text-sm rounded-full"
>
{cat}
</span>
))}
</div>
<h1 className="text-xl sm:text-2xl md:text-3xl lg:text-4xl xl:text-5xl font-bold mb-2 md:mb-4 line-clamp-3">
{articulo.title}
</h1>
<div className="flex flex-wrap items-center gap-2 md:gap-4 text-xs md:text-sm text-gray-200">
<span className="flex items-center gap-1">
<User className="w-3 h-3 md:w-4 md:h-4" />
{articulo.author_name || 'CambiCash'}
</span>
<span className="flex items-center gap-1">
<Calendar className="w-3 h-3 md:w-4 md:h-4" />
{new Date(articulo.published_at).toLocaleDateString('es-PE', {
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</span>
<span className="flex items-center gap-1">
<Eye className="w-3 h-3 md:w-4 md:h-4" />
{articulo.views || 0} vistas
</span>
</div>
</div>
</div>
</div>
</div>
{/* Contenido */}
<div className="container mx-auto px-4 py-6 md:py-12">
<div className="grid lg:grid-cols-3 gap-6 md:gap-8">
<div className="lg:col-span-2">
<article className="bg-white rounded-xl md:rounded-2xl shadow-lg p-4 md:p-8">
<div
className="prose prose-sm sm:prose-base md:prose-lg max-w-none"
dangerouslySetInnerHTML={{ __html: articulo.content }}
/>
</article>
</div>
<SidebarBlog />
</div>
</div>
</div>
)
}
'@
# Guardar el archivo
$articuloConImagenAdaptativa | Out-File -LiteralPath "C:\Users\JULIO\Desktop\cambicash-blog-final\app\blog\[slug]\page.tsx" -Encoding UTF8 -Forcevcx