`;
});
s = s.replace(/\*\*(.+?)\*\*/g, "$1");
s = s.replace(/\*(.+?)\*/g, "$1");
s = s.replace(/`([^`]+)`/g, "$1");
s = s.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1');
s = s.split(/\n{2,}/).map(block => {
const trimmed = block.trim();
if (!trimmed) return "";
if (/^<(h\d|ul|ol|pre|blockquote)/.test(trimmed) || /\u0000(IMG|BLOCK)\d+\u0000/.test(trimmed)) return trimmed;
return `
${trimmed.replace(/\n/g, " ")}
`;
}).join("\n");
s = s.replace(/\u0000IMG(\d+)\u0000/g, (_, i) => imgs[+i]);
s = s.replace(/\u0000BLOCK(\d+)\u0000/g, (_, i) => blocks[+i]);
return s;
}
/* ============================================================
Cover renderer — image if available, fallback SVG
============================================================ */
function CoverImg({ post, big }) {
const c = post.cover;
// Handle old format (number) and new (object)
if (typeof c === "number") {
return ;
}
if (c && c.image) {
return ;
}
return ;
}
function CoverSVG({ kind }) {
if (kind === 1) {
return (
);
}
if (kind === 2) {
return (
);
}
return (
);
}
/* ============================================================
SEO meta tag injection
============================================================ */
function setMetaTag(attr, key, value) {
let el = document.querySelector(`meta[${attr}="${key}"]`);
if (!value) { if (el) el.remove(); return; }
if (!el) {
el = document.createElement("meta");
el.setAttribute(attr, key);
document.head.appendChild(el);
}
el.setAttribute("content", value);
}
function setLinkCanonical(href) {
let el = document.querySelector('link[rel="canonical"]');
if (!href) { if (el) el.remove(); return; }
if (!el) {
el = document.createElement("link");
el.setAttribute("rel", "canonical");
document.head.appendChild(el);
}
el.setAttribute("href", href);
}
function setJsonLd(data) {
let el = document.getElementById("ms-jsonld");
if (el) el.remove();
if (!data) return;
el = document.createElement("script");
el.type = "application/ld+json";
el.id = "ms-jsonld";
el.textContent = JSON.stringify(data);
document.head.appendChild(el);
}
function applyPostSEO(post, siteUrl) {
if (!post) {
document.title = "Blog · MinerSuite";
setMetaTag("name", "description", "Conteúdo técnico para consultorias em mineração.");
setMetaTag("property", "og:title", "Blog · MinerSuite");
setMetaTag("property", "og:description", "Conteúdo técnico para consultorias em mineração.");
setMetaTag("property", "og:type", "website");
setMetaTag("property", "og:image", "");
setMetaTag("name", "twitter:card", "summary_large_image");
setLinkCanonical(siteUrl + "/blog.html");
setJsonLd(null);
return;
}
const seo = post.seo || {};
const url = siteUrl + "/blog.html#" + post.slug;
const img = (post.cover && post.cover.image) ? (siteUrl + "/" + post.cover.image) : "";
const title = seo.metaTitle || post.title;
const desc = seo.metaDescription || post.excerpt;
document.title = title;
setMetaTag("name", "description", desc);
setMetaTag("name", "keywords", (post.tags || []).join(", "));
setMetaTag("name", "author", post.author);
setMetaTag("property", "og:type", "article");
setMetaTag("property", "og:title", title);
setMetaTag("property", "og:description", desc);
setMetaTag("property", "og:url", url);
setMetaTag("property", "og:image", img);
setMetaTag("property", "article:published_time", post.date);
setMetaTag("property", "article:section", post.category);
setMetaTag("name", "twitter:card", "summary_large_image");
setMetaTag("name", "twitter:title", title);
setMetaTag("name", "twitter:description", desc);
setMetaTag("name", "twitter:image", img);
setLinkCanonical(url);
setJsonLd({
"@context": "https://schema.org",
"@type": "Article",
"headline": post.title,
"description": desc,
"image": img || undefined,
"datePublished": post.date,
"dateModified": post.date,
"author": { "@type": "Organization", "name": post.author },
"publisher": {
"@type": "Organization",
"name": "MinerSuite",
"logo": { "@type": "ImageObject", "url": siteUrl + "/assets/marca/favicon.svg" }
},
"mainEntityOfPage": url,
"keywords": (post.tags || []).join(", ")
});
}
function formatDate(iso) {
const d = new Date(iso + "T00:00:00");
const MES = ["JAN","FEV","MAR","ABR","MAI","JUN","JUL","AGO","SET","OUT","NOV","DEZ"];
return `${String(d.getDate()).padStart(2,"0")} ${MES[d.getMonth()]} · ${d.getFullYear()}`;
}
/* ============================================================
Hero
============================================================ */
function BlogHero({ count }) {
return (
BLOG · MINERSUITE
Conteúdo técnico para consultorias em mineração.
Artigos sobre gestão operacional, propostas, contratos, projetos
técnicos e organização de carteira minerária — escritos a partir
da rotina real do setor.
ARTIGOS{count}Publicados até hoje.
CATEGORIASGestão · Operação · DadosConteúdo técnico do setor mineral.
);
}
/* ============================================================
Post list
============================================================ */
function PostList({ posts }) {
if (!posts.length) {
return (