/* Blog InfectoLab — cuatro plantillas navegables * 1) Índice /blog/ 2) Artículo /blog// * 3) Autor /dr-samuel-navarro-alvarez/ 4) Archivo temático /category// * Datos: window.BLOG_DATA (src/blog-data.js). Sustituir por API/CMS. */ /* Hoja de estilo del blog. * Vive DENTRO del componente, como en pages-sucursales.jsx: viaja con el JSX, * no puede quedar desfasada respecto al marcado ni depender del caché de * styles.css. Mismo lenguaje visual que el bloque Blog del Home. */ function BlogStyles() { return ; } const BD = () => window.BLOG_DATA; const findAuthor = (id) => BD().authors.find(a => a.id === id) || null; const findTopic = (id) => BD().topics.find(t => t.id === id) || null; const topicBySlug = (slug) => BD().topics.find(t => t.slug === slug) || null; const hasBody = (a) => Array.isArray(a.body) && a.body.length > 0; const MESES = ["enero","febrero","marzo","abril","mayo","junio", "julio","agosto","septiembre","octubre","noviembre","diciembre"]; /* Fecha real de publicación. null = sin dato: no se inventa. */ function fmtFecha(iso) { if (!iso) return null; const d = new Date(iso); if (isNaN(d)) return null; return d.getUTCDate() + " de " + MESES[d.getUTCMonth()] + " de " + d.getUTCFullYear(); } const esVideo = (a) => a.content_type === "video" || a.content_type === "entrevista"; const ctaDe = (a) => a.content_type === "entrevista" ? "Ver entrevista" : a.content_type === "video" ? "Ver video" : "Leer artículo"; /* Etiqueta de autoría honesta: null = no verificada */ function autoriaLabel(a) { const au = findAuthor(a.author_id); if (!au) return "InfectoLab"; if (a.contributor_role === "entrevistado") return "Entrevista con " + au.name; if (a.contributor_role === "presentador") return "Presentado por " + au.name; return au.name; } /* Portada editorial de marca para los artículos sin imagen publicable. * No es un placeholder genérico ni una foto inventada: es una cubierta * tipográfica compuesta con la paleta y el motivo de puntos de InfectoLab. */ const COVER_TONOS = { infectologia: ["#30477F", "#3953A4"], examenes: ["#3953A4", "#7EB9C7"], vacunas: ["#1D2A4D", "#30477F"], "covid-19": ["#30477F", "#4D4D4D"], t2dx: ["#3953A4", "#30477F"], salud: ["#30477F", "#7EB9C7"], nutricion: ["#4D4D4D", "#30477F"], }; function EditorialCover({ article, alto }) { const t = findTopic(article.topic_ids[0]); const [a, b] = COVER_TONOS[t ? t.id : "infectologia"] || COVER_TONOS.infectologia; const inicial = article.title.replace(/^[¿¡]/, "").trim().charAt(0).toUpperCase(); return ( ); } /* Miniatura: imagen real cuando existe; si no, portada editorial. * Nunca una caja vacía. */ function Thumb({ article, alto }) { const conVideo = !!article.video; return (
{article.image ? {article.image.alt} : } {conVideo && ( )}
); } /* ───────────────────────── Tarjeta de artículo ───────────────────────── */ function BlogCard({ article, openArticle, openTopic, destacado }) { const t = findTopic(article.topic_ids[0]); const fecha = fmtFecha(article.published_at); return (
{t && ( )} {article.content_type === "entrevista" && Entrevista} {article.content_type === "video" && Video}

{article.title}

{article.excerpt &&

{article.excerpt}

}
{autoriaLabel(article)} {fecha && <>·}
); } /* ───────────────────────── Paginación ───────────────────────── */ function BlogPager({ page, total, onPage }) { if (total <= 1) return null; return ( ); } /* ───────────────────────── 1. ÍNDICE /blog/ ───────────────────────── */ function BlogIndexPage({ navigate, openArticle, openTopic, openAuthor, blogState, setBlogState }) { const { articles, pageSize } = BD(); const { q, topic, author, page } = blogState; const set = (patch) => setBlogState({ ...blogState, page: 1, ...patch }); const filtrando = q.trim() !== "" || topic !== "all" || author !== "all"; const filtrados = articles.filter(a => { if (topic !== "all" && !a.topic_ids.includes(topic)) return false; if (author !== "all" && a.author_id !== author) return false; if (q.trim()) { const s = (a.title + " " + (a.excerpt || "")).toLowerCase(); if (!s.includes(q.trim().toLowerCase())) return false; } return true; }); const destacado = filtrando ? null : articles.find(a => hasBody(a)) || null; const lista = destacado ? filtrados.filter(a => a.id !== destacado.id) : filtrados; const totalPag = Math.max(1, Math.ceil(lista.length / pageSize)); const pagina = Math.min(page, totalPag); const visibles = lista.slice((pagina - 1) * pageSize, pagina * pageSize); const autoresConArticulos = BD().authors.filter(au => articles.some(a => a.author_id === au.id)); return (
Blog

Blog InfectoLab

Información sobre pruebas de laboratorio, enfermedades infecciosas y prevención.

{/* Filtros */}
set({ q: e.target.value })} />
{filtrando && ( )}
{BD().topics.filter(t => articles.some(a => a.topic_ids.includes(t.id))).map(t => ( ))}
{/* Destacado */} {destacado && (
Destacado
)} {/* Resultados */} {filtrando && (

{lista.length === 0 ? "Sin resultados" : lista.length + (lista.length === 1 ? " artículo" : " artículos")}

)} {lista.length === 0 ? (

No encontramos artículos con esos filtros

Prueba con otro término o revisa el archivo completo del blog.

) : ( <>
{visibles.map(a => ( ))}
setBlogState({ ...blogState, page: n })} /> )} {/* Archivos temáticos */}

Explora por tema

{BD().topics.filter(t => articles.some(a => a.topic_ids.includes(t.id))).map(t => ( ))}
); } /* ───────────────────────── 2. ARTÍCULO /blog// ───────────────────────── */ function ShareLink({ url }) { const [ok, setOk] = React.useState(false); const copiar = () => { const done = () => { setOk(true); setTimeout(() => setOk(false), 2200); }; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(url).then(done).catch(() => {}); } else { const ta = document.createElement("textarea"); ta.value = url; document.body.appendChild(ta); ta.select(); try { document.execCommand("copy"); done(); } catch (e) {} document.body.removeChild(ta); } }; return ( ); } function ArticleBody({ blocks }) { return (
{blocks.map((b, i) => { if (b.type === "h2") return

{b.text}

; if (b.type === "p") return

{b.text}

; if (b.type === "quote") return
{b.text}
; if (b.type === "nota") return ; if (b.type === "list") return
    {b.items.map((x, j) =>
  • {x}
  • )}
; if (b.type === "figure") return (
{b.alt} {(b.caption || b.credit) && (
{b.caption}{b.credit ? (b.caption ? " · " : "") + b.credit : ""}
)}
); if (b.type === "deflist") return (
{b.items.map(([k, v], j) =>
{k}
{v}
)}
); return null; })}
); } function BlogArticlePage({ slug, navigate, openArticle, openTopic, openAuthor, openStudy }) { const article = BD().articles.find(a => a.slug === slug); if (!article) { return (

No encontramos ese artículo

); } const autor = findAuthor(article.author_id); const temas = article.topic_ids.map(findTopic).filter(Boolean); const cuerpo = hasBody(article) ? article.body : []; const secciones = cuerpo.map((b, i) => ({ ...b, i })).filter(b => b.type === "h2"); const fecha = fmtFecha(article.published_at); const relacionados = BD().articles.filter(a => a.id !== article.id && a.topic_ids.some(t => article.topic_ids.includes(t))).slice(0, 3); const estudios = (article.related_study_ids || []) .map(id => (window.STUDIES || []).find(s => s.id === id)).filter(Boolean); const shareUrl = window.location.origin + window.location.pathname + "#/blog/" + article.slug + "/"; return (
{temas.map(t => )}

{article.title}

{article.excerpt}

{article.video ? (