287 lines
8.1 KiB
JavaScript
287 lines
8.1 KiB
JavaScript
/**
|
|
* Fonte única das informações de SEO do ESPDocs.
|
|
*
|
|
* Centralizar aqui evita o problema clássico de metadata espalhado: a URL do
|
|
* site aparecendo com valores diferentes em cada arquivo, ou uma página nova
|
|
* nascendo sem título próprio.
|
|
*/
|
|
|
|
export const SITE = {
|
|
url: "https://espdocs.cienciaembarcada.com.br",
|
|
nome: "ESPDocs",
|
|
autor: "Lucas Rayan Guerra",
|
|
autorUrl: "https://lucasrguerra.dev.br",
|
|
autorLinkedin: "https://linkedin.com/in/lucasrguerra",
|
|
autorEmail: "contato@lucasrguerra.dev.br",
|
|
repositorio: "https://github.com/lucasrguerra/ESPDocs",
|
|
blog: "https://cienciaembarcada.com.br",
|
|
};
|
|
|
|
/**
|
|
* Monta o objeto `metadata` de uma página, já com canonical e Open Graph.
|
|
* Usar isto em vez de escrever o objeto à mão garante que nenhuma página fique
|
|
* sem canonical ou sem og:title.
|
|
*/
|
|
export function paginaMeta({ titulo, descricao, caminho, keywords = [], tipo = "website" }) {
|
|
const url = `${SITE.url}${caminho}`;
|
|
return {
|
|
title: titulo,
|
|
description: descricao,
|
|
keywords,
|
|
alternates: { canonical: caminho },
|
|
openGraph: {
|
|
type: tipo,
|
|
locale: "pt_BR",
|
|
url,
|
|
siteName: SITE.nome,
|
|
title: `${titulo} · ${SITE.nome}`,
|
|
description: descricao,
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: `${titulo} · ${SITE.nome}`,
|
|
description: descricao,
|
|
},
|
|
};
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
Dados estruturados (JSON-LD). São eles que rendem os resultados ricos:
|
|
trilha de navegação, box de busca e reconhecimento de autoria.
|
|
------------------------------------------------------------------------ */
|
|
|
|
export const jsonLd = {
|
|
siteESociedade() {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@graph": [
|
|
{
|
|
"@type": "WebSite",
|
|
"@id": `${SITE.url}/#site`,
|
|
url: SITE.url,
|
|
name: SITE.nome,
|
|
inLanguage: "pt-BR",
|
|
description:
|
|
"Documentação do ecossistema ESP32 em português brasileiro: especificações, pinagem, comparação e seleção de séries.",
|
|
publisher: { "@id": `${SITE.url}/#autor` },
|
|
},
|
|
{
|
|
"@type": "Person",
|
|
"@id": `${SITE.url}/#autor`,
|
|
name: SITE.autor,
|
|
url: SITE.autorUrl,
|
|
email: SITE.autorEmail,
|
|
sameAs: [SITE.autorLinkedin, SITE.repositorio, SITE.blog],
|
|
},
|
|
],
|
|
};
|
|
},
|
|
|
|
/** Trilha de navegação: aparece acima do título no resultado de busca. */
|
|
trilha(itens) {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "BreadcrumbList",
|
|
itemListElement: itens.map((it, i) => ({
|
|
"@type": "ListItem",
|
|
position: i + 1,
|
|
name: it.nome,
|
|
item: `${SITE.url}${it.caminho}`,
|
|
})),
|
|
};
|
|
},
|
|
|
|
/** Documentação e ficha técnica da série como TechArticle para o Google. */
|
|
serie(chave, serie) {
|
|
const prop = (nome, valor) =>
|
|
valor ? { "@type": "PropertyValue", name: nome, value: String(valor) } : null;
|
|
|
|
const propriedades = [
|
|
prop("Fabricante", "Espressif Systems"),
|
|
prop("Arquitetura", serie.arquitetura),
|
|
prop("Núcleos", serie.nucleos),
|
|
prop("Frequência máxima", serie.frequencia),
|
|
prop("SRAM", serie.memoria_sram),
|
|
prop("RTC SRAM", serie.memoria_sram_rtc),
|
|
prop("Flash suportada", serie.flash_suportada),
|
|
prop("PSRAM suportada", serie.psram_suportada),
|
|
prop("GPIO", serie.gpio),
|
|
prop("Wi-Fi", serie.wifi),
|
|
prop("Bluetooth", serie.bluetooth),
|
|
prop("Zigbee / Thread / 802.15.4", serie.zigbee_thread),
|
|
prop("Encapsulamento", serie.encapsulamento),
|
|
prop("ESP-IDF mínimo", serie.esp_idf_minimo),
|
|
].filter(Boolean);
|
|
|
|
const imagem = serie.placa
|
|
? `${SITE.url}${serie.placa}`
|
|
: `${SITE.url}/opengraph-image.png`;
|
|
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "TechArticle",
|
|
"@id": `${SITE.url}/series/${chave}#artigo`,
|
|
headline: `${serie.nome_completo || chave}: especificações e pinagem`,
|
|
name: `${serie.nome_completo || chave} - Documentação Técnica e Especificações`,
|
|
description: serie.descricao,
|
|
image: [imagem],
|
|
inLanguage: "pt-BR",
|
|
datePublished: "2026-08-25T00:00:00.000Z",
|
|
dateModified: new Date().toISOString(),
|
|
mainEntityOfPage: `${SITE.url}/series/${chave}`,
|
|
url: `${SITE.url}/series/${chave}`,
|
|
author: {
|
|
"@type": "Person",
|
|
name: SITE.autor,
|
|
url: SITE.autorUrl,
|
|
},
|
|
publisher: {
|
|
"@type": "Organization",
|
|
name: "Ciência Embarcada",
|
|
url: SITE.blog,
|
|
logo: {
|
|
"@type": "ImageObject",
|
|
url: `${SITE.url}/marca/espdocs-marca.svg`,
|
|
},
|
|
},
|
|
about: {
|
|
"@type": "Thing",
|
|
name: serie.nome_completo || chave,
|
|
description: serie.descricao,
|
|
additionalProperty: propriedades,
|
|
},
|
|
};
|
|
},
|
|
|
|
/** Documentação técnica de framework. */
|
|
framework(chave, framework) {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "TechArticle",
|
|
"@id": `${SITE.url}/frameworks/${encodeURIComponent(chave)}#artigo`,
|
|
headline: `${framework.nome} para ESP32: Guia e Documentação`,
|
|
name: `${framework.nome_completo || framework.nome} para ESP32`,
|
|
description: framework.descricao,
|
|
image: [`${SITE.url}/opengraph-image.png`],
|
|
inLanguage: "pt-BR",
|
|
datePublished: "2026-08-25T00:00:00.000Z",
|
|
dateModified: new Date().toISOString(),
|
|
mainEntityOfPage: `${SITE.url}/frameworks/${encodeURIComponent(chave)}`,
|
|
url: `${SITE.url}/frameworks/${encodeURIComponent(chave)}`,
|
|
author: {
|
|
"@type": "Person",
|
|
name: SITE.autor,
|
|
url: SITE.autorUrl,
|
|
},
|
|
publisher: {
|
|
"@type": "Organization",
|
|
name: "Ciência Embarcada",
|
|
url: SITE.blog,
|
|
logo: {
|
|
"@type": "ImageObject",
|
|
url: `${SITE.url}/marca/espdocs-marca.svg`,
|
|
},
|
|
},
|
|
about: {
|
|
"@type": "SoftwareApplication",
|
|
name: framework.nome_completo || framework.nome,
|
|
applicationCategory: "DeveloperApplication",
|
|
operatingSystem: "Embedded",
|
|
description: framework.descricao,
|
|
url: framework.documentacao || `${SITE.url}/frameworks/${encodeURIComponent(chave)}`,
|
|
},
|
|
};
|
|
},
|
|
|
|
/** Glossário: marca cada verbete como termo definido. */
|
|
glossario(categorias) {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "DefinedTermSet",
|
|
"@id": `${SITE.url}/glossario#glossario`,
|
|
name: "Glossário Técnico do ESP32",
|
|
inLanguage: "pt-BR",
|
|
hasDefinedTerm: categorias.flatMap((cat) =>
|
|
cat.termos.map((t) => ({
|
|
"@type": "DefinedTerm",
|
|
name: t.termo,
|
|
description: t.definicao,
|
|
inDefinedTermSet: `${SITE.url}/glossario#glossario`,
|
|
}))
|
|
),
|
|
};
|
|
},
|
|
|
|
/** Perguntas frequentes: pode render o bloco expansível no Google. */
|
|
perguntas(pares) {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "FAQPage",
|
|
mainEntity: pares.map(({ pergunta, resposta }) => ({
|
|
"@type": "Question",
|
|
name: pergunta,
|
|
acceptedAnswer: { "@type": "Answer", text: resposta },
|
|
})),
|
|
};
|
|
},
|
|
|
|
/** Aplicação web / ferramenta interativa (Seletor, Comparador, Catálogo). */
|
|
aplicacaoWeb({ nome, descricao, caminho }) {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "WebApplication",
|
|
"@id": `${SITE.url}${caminho}#app`,
|
|
name: nome,
|
|
description: descricao,
|
|
url: `${SITE.url}${caminho}`,
|
|
applicationCategory: "DeveloperApplication",
|
|
operatingSystem: "All",
|
|
browserRequirements: "Requires JavaScript",
|
|
inLanguage: "pt-BR",
|
|
author: {
|
|
"@type": "Person",
|
|
name: SITE.autor,
|
|
url: SITE.autorUrl,
|
|
},
|
|
publisher: {
|
|
"@type": "Organization",
|
|
name: "Ciência Embarcada",
|
|
url: SITE.blog,
|
|
logo: {
|
|
"@type": "ImageObject",
|
|
url: `${SITE.url}/marca/espdocs-marca.svg`,
|
|
},
|
|
},
|
|
offers: {
|
|
"@type": "Offer",
|
|
price: "0",
|
|
priceCurrency: "BRL",
|
|
},
|
|
};
|
|
},
|
|
|
|
/** Página Sobre com metadados E-E-A-T de autoria e reputação. */
|
|
paginaSobre() {
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "AboutPage",
|
|
"@id": `${SITE.url}/sobre#sobre`,
|
|
name: "Sobre o ESPDocs",
|
|
description: "O ESPDocs é uma plataforma independente que reúne a documentação do ecossistema ESP32 em português brasileiro.",
|
|
url: `${SITE.url}/sobre`,
|
|
inLanguage: "pt-BR",
|
|
mainEntity: {
|
|
"@type": "Person",
|
|
name: SITE.autor,
|
|
url: SITE.autorUrl,
|
|
email: SITE.autorEmail,
|
|
sameAs: [
|
|
SITE.autorLinkedin,
|
|
SITE.repositorio,
|
|
SITE.blog,
|
|
],
|
|
},
|
|
};
|
|
},
|
|
};
|