Files
ESPDocs/app/[locale]/page.jsx
T
Lucas RayanandClaude Sonnet 5.5 5a9fe676fc
CI / Lint e auditorias (push) Successful in 1m10s
CI / Trivy (dependências e segredos) (push) Successful in 12s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m39s
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 18s
Release / Cria a release no Gitea (push) Successful in 5s
feat(i18n): Simplified Chinese (zh-CN), search answers per locale, fr/de/es data fixes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 23:28:39 -03:00

802 lines
35 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import BookCover from "@/components/BookCover";
import Link from "next/link";
import seriesDataPt from "@/public/series.json";
import frameworksDataPt from "@/public/frameworks.json";
import seriesDataEn from "@/data/en/series.json";
import frameworksDataEn from "@/data/en/frameworks.json";
import seriesDataEs from "@/data/es/series.json";
import frameworksDataEs from "@/data/es/frameworks.json";
import seriesDataFr from "@/data/fr/series.json";
import frameworksDataFr from "@/data/fr/frameworks.json";
import seriesDataDe from "@/data/de/series.json";
import seriesDataZh from "@/data/zh-CN/series.json";
import frameworksDataDe from "@/data/de/frameworks.json";
import frameworksDataZh from "@/data/zh-CN/frameworks.json";
import { SITE } from "@/lib/seo";
import { getLocalizedHref } from "@/i18n/links";
import {
AlertTriangle,
ArrowRight,
ArrowUpRight,
BookOpen,
Box,
Cpu,
Scale,
SlidersHorizontal,
Terminal,
} from "lucide-react";
const FEATURED = ["ESP32", "ESP32-S3", "ESP32-C6", "ESP32-C3", "ESP32-P4", "ESP32-H2"];
const TOOLS_PT = [
{
href: "/seletor",
title: "Seletor inteligente",
desc: "Responda oito perguntas sobre o projeto e receba os chips mais compatíveis, com justificativa técnica.",
icon: SlidersHorizontal,
action: "Encontrar meu chip",
},
{
href: "/comparacao",
title: "Comparador de séries",
desc: "Coloque até quatro modelos lado a lado e compare núcleos, rádio, memória, periféricos e segurança.",
icon: Scale,
action: "Comparar agora",
},
{
href: "/diagnostico",
title: "Diagnóstico de falhas",
desc: "Causas e correções para brownout, bootloop, Guru Meditation, watchdog e falhas de flash.",
icon: AlertTriangle,
action: "Abrir diagnóstico",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, bibliotecas e BSPs do registro oficial da Espressif, com manifesto pronto para o projeto.",
icon: Box,
action: "Explorar componentes",
},
{
href: "/frameworks",
title: "Frameworks e SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython e as ferramentas que ficam em volta do chip.",
icon: Terminal,
action: "Ver frameworks",
},
{
href: "/catalogo",
title: "Catálogo de placas",
desc: "DevKits e módulos reais, com interface USB, sensores integrados e link para a loja oficial.",
icon: Cpu,
action: "Ver placas",
},
];
const TOOLS_EN = [
{
href: "/seletor",
title: "Smart Selector",
desc: "Answer eight questions about your project and find recommended chips, backed by technical rationale.",
icon: SlidersHorizontal,
action: "Find my chip",
},
{
href: "/comparacao",
title: "Series Comparator",
desc: "Place up to four models side by side and compare cores, radio, memory, peripherals, and security.",
icon: Scale,
action: "Compare now",
},
{
href: "/diagnostico",
title: "Fault Diagnostics",
desc: "Root causes and fixes for brownout, bootloop, Guru Meditation, watchdog, and flash errors.",
icon: AlertTriangle,
action: "Open diagnostics",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, libraries and BSPs from the official Espressif registry, with ready-to-use manifests.",
icon: Box,
action: "Explore components",
},
{
href: "/frameworks",
title: "Frameworks & SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython and the tools built around the silicon.",
icon: Terminal,
action: "View frameworks",
},
{
href: "/catalogo",
title: "Board Catalog",
desc: "Real DevKits and modules, with USB interfaces, integrated sensors and direct store links.",
icon: Cpu,
action: "View boards",
},
];
const TOOLS_ES = [
{
href: "/seletor",
title: "Selector inteligente",
desc: "Responda a ocho preguntas sobre su proyecto y reciba los chips más compatibles, con justificación técnica.",
icon: SlidersHorizontal,
action: "Encontrar mi chip",
},
{
href: "/comparacao",
title: "Comparador de series",
desc: "Compare hasta cuatro modelos frente a frente: núcleos, radio, memoria, periféricos y seguridad.",
icon: Scale,
action: "Comparar ahora",
},
{
href: "/diagnostico",
title: "Diagnóstico de fallos",
desc: "Causas y soluciones para brownout, bootloop, Guru Meditation, watchdog y fallos de flash.",
icon: AlertTriangle,
action: "Abrir diagnóstico",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Drivers, bibliotecas y BSPs del registro oficial de Espressif, con manifiesto listo para su proyecto.",
icon: Box,
action: "Explorar componentes",
},
{
href: "/frameworks",
title: "Frameworks y SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython y las herramientas que rodean al silicio.",
icon: Terminal,
action: "Ver frameworks",
},
{
href: "/catalogo",
title: "Catálogo de placas",
desc: "DevKits y módulos reales, con interfaz USB, sensores integrados y enlace directo a la tienda oficial.",
icon: Cpu,
action: "Ver placas",
},
];
const TOOLS_FR = [
{
href: "/seletor",
title: "Sélecteur intelligent",
desc: "Répondez à huit questions sur votre projet et découvrez les puces recommandées, avec justification technique.",
icon: SlidersHorizontal,
action: "Trouver ma puce",
},
{
href: "/comparacao",
title: "Comparateur de séries",
desc: "Comparez jusqu'à quatre modèles côte à côte : cœurs, radio, mémoire, périphériques et sécurité.",
icon: Scale,
action: "Comparer maintenant",
},
{
href: "/diagnostico",
title: "Diagnostic de pannes",
desc: "Causes et solutions pour brownout, bootloop, Guru Meditation, watchdog et erreurs de flash.",
icon: AlertTriangle,
action: "Ouvrir le diagnostic",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Pilotes, bibliothèques et BSP du registre officiel Espressif, avec manifeste prêt pour votre projet.",
icon: Box,
action: "Explorer les composants",
},
{
href: "/frameworks",
title: "Frameworks et SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython et les outils gravitant autour de la puce.",
icon: Terminal,
action: "Voir les frameworks",
},
{
href: "/catalogo",
title: "Catalogue de cartes",
desc: "DevKits et modules réels, avec interface USB, capteurs intégrés et lien vers la boutique officielle.",
icon: Cpu,
action: "Voir les cartes",
},
];
const TOOLS_DE = [
{
href: "/seletor",
title: "Intelligente Auswahl",
desc: "Beantworten Sie acht Fragen zu Ihrem Projekt und erhalten Sie passende Chip-Empfehlungen mit technischer Begründung.",
icon: SlidersHorizontal,
action: "Meinen Chip finden",
},
{
href: "/comparacao",
title: "Serienvergleich",
desc: "Vergleichen Sie bis zu vier Modelle nebeneinander: Kerne, Funk, Speicher, Peripherie und Sicherheit.",
icon: Scale,
action: "Jetzt vergleichen",
},
{
href: "/diagnostico",
title: "Fehlerdiagnose",
desc: "Ursachen und Lösungen für Brownout, Bootloops, Guru Meditation, Watchdog und Flash-Fehler.",
icon: AlertTriangle,
action: "Diagnose öffnen",
},
{
href: "/componentes",
title: "Component Registry",
desc: "Treiber, Bibliotheken und BSPs aus der offiziellen Espressif-Registry, mit fertigem Manifest für Ihr Projekt.",
icon: Box,
action: "Komponenten erkunden",
},
{
href: "/frameworks",
title: "Frameworks & SDKs",
desc: "ESP-IDF, Arduino, Rust, Matter, MicroPython und die Werkzeuge rund um den Chip.",
icon: Terminal,
action: "Frameworks ansehen",
},
{
href: "/catalogo",
title: "Board-Katalog",
desc: "Reale DevKits und Module, mit USB-Schnittstelle, integrierten Sensoren und Link zum offiziellen Shop.",
icon: Cpu,
action: "Boards ansehen",
},
];
const TOOLS_ZH = [
{
href: "/seletor",
title: "智能选型",
desc: "回答八个关于项目的问题,获得推荐芯片及其技术依据。",
icon: SlidersHorizontal,
action: "找到我的芯片",
},
{
href: "/comparacao",
title: "系列对比",
desc: "最多把四个型号并排放在一起,对比内核、无线、内存、外设和安全。",
icon: Scale,
action: "立即对比",
},
{
href: "/diagnostico",
title: "故障诊断",
desc: "针对欠压、启动循环、Guru Meditation、看门狗和闪存错误的根因与解决办法。",
icon: AlertTriangle,
action: "打开诊断",
},
{
href: "/componentes",
title: "Component Registry",
desc: "来自乐鑫官方注册中心的驱动、库和 BSP,附带可直接使用的清单。",
icon: Box,
action: "探索组件",
},
{
href: "/frameworks",
title: "框架与 SDK",
desc: "ESP-IDF、Arduino、Rust、Matter、MicroPython,以及围绕芯片构建的工具。",
icon: Terminal,
action: "查看框架",
},
{
href: "/catalogo",
title: "开发板目录",
desc: "真实的 DevKit 与模组,含 USB 接口、板载传感器和直达商店的链接。",
icon: Cpu,
action: "查看开发板",
},
];
const ERRORS_PT = [
{
code: "Brownout detector was triggered",
cause: "Queda de tensão na inicialização do rádio.",
fix: "Capacitor de 10–100 µF junto ao chip e fonte de 5 V com corrente suficiente.",
},
{
code: "Guru Meditation Error",
cause: "Ponteiro inválido, stack overflow ou uso incorreto de interrupção.",
fix: "Leia o backtrace com addr2line e dimensione a stack da task no FreeRTOS.",
},
{
code: "ADC2 indisponível com Wi-Fi",
cause: "O controlador de rádio reserva o ADC2 enquanto está ativo.",
fix: "Use os pinos do ADC1 para sensores analógicos que convivem com o Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tensão ou modo de flash incorretos, ou pino de strapping preso no boot.",
fix: "Confira 3,3 V, pull-ups de boot e a configuração de flash no esptool.",
},
];
const ERRORS_EN = [
{
code: "Brownout detector was triggered",
cause: "Voltage sag upon radio startup.",
fix: "10–100 µF capacitor close to chip and a 5 V supply with sufficient current.",
},
{
code: "Guru Meditation Error",
cause: "Invalid pointer, stack overflow, or improper ISR usage.",
fix: "Inspect backtrace with addr2line and properly size FreeRTOS task stacks.",
},
{
code: "ADC2 unavailable with Wi-Fi",
cause: "Internal radio controller reserves ADC2 while active.",
fix: "Use ADC1 pins for analog sensors operating alongside Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Incorrect flash voltage/mode or strapping pin pulled during boot.",
fix: "Check 3.3 V rail, boot pull-ups, and flash configuration in esptool.",
},
];
const ERRORS_ES = [
{
code: "Brownout detector was triggered",
cause: "Caída de tensión al inicializar la etapa de radio.",
fix: "Condensador de 10–100 µF junto al chip y fuente de 5 V con corriente suficiente.",
},
{
code: "Guru Meditation Error",
cause: "Puntero inválido, desbordamiento de pila o uso incorrecto de interrupciones.",
fix: "Analice el backtrace con addr2line y dimensione la pila de la tarea en FreeRTOS.",
},
{
code: "ADC2 no disponible con Wi-Fi",
cause: "El controlador de radio reserva ADC2 mientras permanece activo.",
fix: "Utilice los pines de ADC1 para sensores analógicos que funcionen junto con Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tensión o modo de flash incorrectos, o pin de strapping forzado en el arranque.",
fix: "Compruebe la línea de 3,3 V, los pull-ups de arranque y la configuración de flash en esptool.",
},
];
const ERRORS_FR = [
{
code: "Brownout detector was triggered",
cause: "Baisse de tension lors du démarrage de la radio.",
fix: "Condensateur de 10 à 100 µF au plus près de la puce et alimentation 5 V avec courant suffisant.",
},
{
code: "Guru Meditation Error",
cause: "Pointeur invalide, dépassement de pile ou mauvaise utilisation des interruptions.",
fix: "Analysez le backtrace avec addr2line et dimensionnez la pile de la tâche sous FreeRTOS.",
},
{
code: "ADC2 indisponible avec le Wi-Fi",
cause: "Le contrôleur radio réserve l'ADC2 tant qu'il est actif.",
fix: "Utilisez les broches de l'ADC1 pour les capteurs analogiques fonctionnant conjointement avec le Wi-Fi.",
},
{
code: "Flash Read err / bootloader",
cause: "Tension ou mode de flash incorrect, ou broche de strapping forcée au démarrage.",
fix: "Vérifiez la ligne 3,3 V, les pull-ups de démarrage et la configuration de flash dans esptool.",
},
];
const ERRORS_DE = [
{
code: "Brownout detector was triggered",
cause: "Spannungseinbruch beim Starten der Funkeinheit.",
fix: "Kondensator mit 10–100 µF nah am Chip und 5-V-Netzteil mit ausreichender Stromstärke.",
},
{
code: "Guru Meditation Error",
cause: "Ungültiger Zeiger, Stack-Überlauf oder fehlerhafte Interrupt-Nutzung.",
fix: "Backtrace mit addr2line analysieren und Stack-Größe der FreeRTOS-Task anpassen.",
},
{
code: "ADC2 nicht verfügbar bei aktivem Wi-Fi",
cause: "Der Funk-Controller reserviert ADC2, solange er aktiv ist.",
fix: "Nutzen Sie ADC1-Pins für analoge Sensoren, die gleichzeitig mit Wi-Fi betrieben werden.",
},
{
code: "Flash Read err / bootloader",
cause: "Falsche Flash-Spannung/-Modus oder beim Booten falsch beschalteter Strapping-Pin.",
fix: "3,3-V-Schiene, Boot-Pull-ups und Flash-Konfiguration in esptool überprüfen.",
},
];
const ERRORS_ZH = [
{
code: "Brownout detector was triggered",
cause: "射频启动时电压跌落。",
fix: "在芯片附近加 10–100 µF 电容,并使用电流足够的 5 V 电源。",
},
{
code: "Guru Meditation Error",
cause: "无效指针、栈溢出,或 ISR 使用不当。",
fix: "用 addr2line 查看回溯信息,并合理设置 FreeRTOS 任务的栈大小。",
},
{
code: "Wi-Fi 开启时 ADC2 不可用",
cause: "射频控制器工作时会占用 ADC2。",
fix: "与 Wi-Fi 同时使用模拟传感器时,请用 ADC1 引脚。",
},
{
code: "Flash Read err / bootloader",
cause: "闪存电压/模式不正确,或启动时启动配置引脚被拉到错误电平。",
fix: "检查 3.3 V 电源轨、启动上拉,以及 esptool 中的闪存配置。",
},
];
export default async function Home({ params }) {
const { locale } = await params;
const isPt = locale === "pt";
const isEn = locale === "en";
const isEs = locale === "es";
const isFr = locale === "fr";
const isDe = locale === "de";
const isZh = locale === "zh-CN";
const getLinkHref = (href) => getLocalizedHref(`/${locale}${href}`, locale);
const seriesData = isPt ? seriesDataPt : isEs ? seriesDataEs : isFr ? seriesDataFr : isZh ? seriesDataZh : isDe ? seriesDataDe : seriesDataEn;
const frameworksData = isPt ? frameworksDataPt : isEs ? frameworksDataEs : isFr ? frameworksDataFr : isZh ? frameworksDataZh : isDe ? frameworksDataDe : frameworksDataEn;
const tools = isPt ? TOOLS_PT : isEs ? TOOLS_ES : isFr ? TOOLS_FR : isZh ? TOOLS_ZH : isDe ? TOOLS_DE : TOOLS_EN;
const errors = isPt ? ERRORS_PT : isEs ? ERRORS_ES : isFr ? ERRORS_FR : isZh ? ERRORS_ZH : isDe ? ERRORS_DE : ERRORS_EN;
const seriesCount = Object.keys(seriesData).length;
const frameworkCount = Object.keys(frameworksData).length;
const featured = FEATURED.map((key) => [key, seriesData[key]]).filter(([, serie]) => Boolean(serie));
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<section className="shell pb-10 pt-14 sm:pt-20 lg:pb-14 lg:pt-24">
<div className="mx-auto max-w-4xl text-center">
<span className="chip chip-accent">
<Cpu className="h-3.5 w-3.5" aria-hidden="true" />
{isPt ? "Documentação aberta do ESP32" : isEs ? "Documentación abierta de ESP32" : isFr ? "Documentation ouverte de l'ESP32" : isZh ? "ESP32 开放文档" : isDe ? "Offene ESP32-Dokumentation" : "Open ESP32 documentation"}
</span>
<h1 className="display mt-6 text-[clamp(2.9rem,7.4vw,5.4rem)]">
{isPt ? (
<>
O ESP32,
<br className="sm:hidden" /> sem ruído.
</>
) : isEs ? (
<>
El ESP32,
<br className="sm:hidden" /> sin ruido.
</>
) : isFr ? (
<>
L'ESP32,
<br className="sm:hidden" /> sans bruit.
</>
) : isZh ? ( <>
ESP32,<br className="sm:hidden" />去繁就简。
</> ) : isDe ? (
<>
Der ESP32,
<br className="sm:hidden" /> ohne Umwege.
</>
) : (
<>
The ESP32,
<br className="sm:hidden" /> without noise.
</>
)}
</h1>
<p className="lede mx-auto mt-6 max-w-2xl">
{isPt
? "Especificações, pinagem, comparações e diagnóstico em uma leitura só. Menos tradução de datasheet, mais tempo com o protótipo na bancada."
: isEs
? "Especificaciones, patillaje, comparaciones y diagnóstico en una sola lectura. Menos traducción de hojas de datos, más tiempo con el prototipo en el banco de trabajo."
: isFr
? "Spécifications, brochage, comparaisons et diagnostics en une seule lecture. Moins de traduction de fiches techniques, plus de temps à l'établi."
: isZh ? "规格、引脚、对比与故障诊断,一次读完。少啃数据手册,多花时间在工作台上做原型。" : isDe
? "Spezifikationen, Pinbelegung, Vergleiche und Diagnose auf einen Blick. Weniger Datenblatt-Übersetzung, mehr Zeit am Prüfplatz."
: "Specifications, pinouts, comparisons and diagnostics in a single read. Less datasheet translation, more workbench time."}
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href={getLinkHref("/seletor")} className="btn btn-primary w-full sm:w-auto">
<SlidersHorizontal className="h-4 w-4" aria-hidden="true" />
{isPt ? "Escolher meu chip" : isEs ? "Elegir mi chip" : isFr ? "Choisir ma puce" : isZh ? "选择我的芯片" : isDe ? "Meinen Chip wählen" : "Choose my chip"}
</Link>
<Link href={getLinkHref("/series")} className="btn btn-ghost w-full sm:w-auto">
{isPt ? (
<>Explorar as {seriesCount} séries</>
) : isEs ? (
<>Explorar las {seriesCount} series</>
) : isFr ? (
<>Explorer les {seriesCount} séries</>
) : isZh ? ( <>浏览全部 {seriesCount} 个系列</> ) : isDe ? (
<>Die {seriesCount} Serien erkunden</>
) : (
<>Explore the {seriesCount} series</>
)}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<p className="mt-7 flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-sm text-muted">
<span><strong className="font-semibold text-ink">{seriesCount}</strong> {isPt ? "séries" : isEs ? "series" : isFr ? "séries" : isZh ? "个系列" : isDe ? "Serien" : "series"}</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span><strong className="font-semibold text-ink">{frameworkCount}</strong> {isZh ? "个框架" : isDe ? "Frameworks" : "frameworks"}</span>
{isPt ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span><strong className="font-semibold text-ink">78</strong> capítulos no livro</span>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% em português</span>
</>
) : isEs ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% en español</span>
</>
) : isFr ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100 % en français</span>
</>
) : isZh ? ( <>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% 中文</span>
</> ) : isDe ? (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100 % auf Deutsch</span>
</>
) : (
<>
<span aria-hidden="true" className="text-line-strong">·</span>
<span>100% in English</span>
</>
)}
</p>
</div>
<div className="panel mt-12 overflow-hidden sm:mt-16">
<div className="flex flex-wrap items-center justify-between gap-3 px-5 py-4 sm:px-7">
<div>
<h2 className="text-sm font-semibold text-ink">{isPt ? "Séries em destaque" : isEs ? "Series destacadas" : isFr ? "Séries en vedette" : isZh ? "精选系列" : isDe ? "Vorgestellte Serien" : "Featured series"}</h2>
<p className="mt-0.5 text-xs text-muted">
{isPt ? "O essencial de cada família, antes de abrir o datasheet." : isEs ? "Lo esencial de cada familia, antes de abrir la hoja de datos." : isFr ? "L'essentiel de chaque famille, avant d'ouvrir la fiche technique." : isZh ? "打开数据手册之前,先看每个系列的要点。" : isDe ? "Das Wesentliche jeder Familie, bevor Sie das Datenblatt öffnen." : "The essentials of each family before opening the datasheet."}
</p>
</div>
<Link href={getLinkHref("/series")} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent transition-colors hover:text-accent-strong">
{isPt ? "Índice completo" : isEs ? "Índice completo" : isFr ? "Index complet" : isZh ? "完整索引" : isDe ? "Vollständiger Index" : "Full index"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<div className="grid gap-px border-t border-line bg-line sm:grid-cols-2 lg:grid-cols-3">
{featured.map(([key, serie]) => (
<Link
key={key}
href={getLinkHref(`/series/${key}`)}
className="group flex min-w-0 flex-col bg-surface p-5 transition-colors duration-300 hover:bg-surface-2 sm:p-6"
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<h3 className="font-display text-xl font-semibold tracking-[-0.035em] text-ink">{key}</h3>
<p className="mt-1 truncate text-xs text-muted">{serie.arquitetura}</p>
</div>
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-full bg-accent-soft text-accent transition-transform duration-300 group-hover:scale-105">
<Cpu className="h-4 w-4" aria-hidden="true" />
</span>
</div>
<p className="mt-5 line-clamp-2 text-sm leading-relaxed text-muted">{serie.descricao}</p>
<div className="mt-5 flex items-center justify-between gap-3 border-t border-line pt-3.5">
<span className="truncate font-mono text-[0.6875rem] text-ink-soft">{serie.frequencia}</span>
<span className="inline-flex shrink-0 items-center gap-1 text-xs font-medium text-accent">
{isPt ? "Ficha" : isEs ? "Ficha" : isFr ? "Fiche" : isZh ? "规格表" : isDe ? "Datenblatt" : "Spec sheet"}
<ArrowUpRight className="h-3.5 w-3.5 transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</div>
</Link>
))}
</div>
</div>
</section>
{isPt && (
<section className="shell section pt-8 sm:pt-12" aria-labelledby="livro-titulo">
<div className="relative isolate overflow-hidden rounded-[2rem] bg-[#0b0d10] ring-1 ring-white/10 dark:bg-[#05070a] dark:ring-white/15 sm:rounded-[2.5rem]">
<div
className="pointer-events-none absolute -left-24 top-1/2 -z-10 h-80 w-80 -translate-y-1/2 rounded-full bg-[#2dd4bf]/15 blur-3xl"
aria-hidden="true"
/>
<div className="grid lg:grid-cols-[0.82fr_1.18fr]">
<div className="order-1 flex flex-col justify-center p-7 sm:p-10 lg:order-2 lg:p-14">
<span className="inline-flex w-fit items-center gap-2 rounded-full border border-white/15 bg-white/5 px-3 py-1 text-xs font-semibold text-[#75cdc1]">
<BookOpen className="h-3.5 w-3.5" aria-hidden="true" />
Livro novo
</span>
<h2 id="livro-titulo" className="mt-5 font-display text-[clamp(2rem,4.2vw,3.2rem)] font-semibold leading-[1.05] tracking-[-0.04em] text-[#f4f6f8]">
{SITE.livroTitulo}
</h2>
<p className="mt-2 text-base text-[#a6afbd]">{SITE.livroSubtitulo}</p>
<p className="mt-5 max-w-xl text-sm leading-relaxed text-[#c4cbd5]">
Um percurso completo pelo hardware e pelo firmware do ESP32: da arquitetura do chip
à implantação de produtos conectados. São 12 partes e 78 capítulos sobre Arduino,
ESP-IDF, FreeRTOS, Wi-Fi, BLE, Thread e Matter, periféricos, depuração, baixo consumo
e segurança.
</p>
<p className="mt-6 flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-[#a6afbd]">
<span>12 partes</span>
<span aria-hidden="true" className="text-white/20">·</span>
<span>78 capítulos</span>
<span aria-hidden="true" className="text-white/20">·</span>
<span>ISBN {SITE.livroIsbn}</span>
</p>
<div className="mt-7 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
<a
href={SITE.livroAmazon}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-full bg-[#2dd4bf] px-5 text-sm font-semibold text-[#06201d] transition-colors duration-300 hover:bg-[#5eead4]"
>
Comprar digital
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<a
href={SITE.livroUiclap}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-full border border-white/20 px-5 text-sm font-semibold text-[#f4f6f8] transition-colors duration-300 hover:border-white/40 hover:bg-white/5"
>
Comprar impresso
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<Link href="/pt/livro" className="inline-flex min-h-11 items-center justify-center gap-1.5 rounded-full px-3 text-sm font-medium text-[#a6afbd] transition-colors duration-300 hover:text-[#f4f6f8]">
Ficha completa
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
<div className="order-2 flex items-center justify-center border-t border-white/10 p-8 sm:p-12 lg:order-1 lg:border-r lg:border-t-0 lg:p-14">
<div className="relative w-[min(15.5rem,68%)] lg:w-[min(17rem,100%)]">
<div className="absolute -inset-10 -z-10 rounded-full bg-[#2dd4bf]/10 blur-3xl" aria-hidden="true" />
<BookCover />
</div>
</div>
</div>
</div>
</section>
)}
<section className="shell section" aria-labelledby="ferramentas-titulo">
<div className="mx-auto max-w-2xl text-center">
<p className="eyebrow">{isPt ? "Ferramentas" : isEs ? "Herramientas" : isFr ? "Outils" : isZh ? "工具" : isDe ? "Werkzeuge" : "Tools"}</p>
<h2 id="ferramentas-titulo" className="display mt-4 text-[clamp(2rem,4.8vw,3.4rem)]">
{isPt ? "Comece pelo problema." : isEs ? "Empiece por el problema." : isFr ? "Commencez par le problème." : isZh ? "从问题出发。" : isDe ? "Beginnen Sie beim Problem." : "Start with the problem."}
</h2>
<p className="lede mt-4">
{isPt
? "Cada ferramenta resolve uma etapa concreta do projeto, sem cadastro e sem rodeio."
: isEs
? "Cada herramienta resuelve una fase concreta del proyecto, sin registros ni rodeos."
: isFr
? "Chaque outil répond à une étape concrète du projet, sans inscription ni détour."
: isZh ? "每个工具对应开发中的一个具体阶段,无需注册,没有废话。" : isDe
? "Jedes Werkzeug löst einen konkreten Projektschritt – ohne Registrierung und ohne Umwege."
: "Each tool addresses a concrete development phase, with no sign-ups and zero fluff."}
</p>
</div>
<div className="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{tools.map((tool) => {
const Icon = tool.icon;
return (
<Link key={tool.href} href={getLinkHref(tool.href)} className="card card-interactive group flex flex-col p-5 sm:p-6">
<span className="grid h-11 w-11 place-items-center rounded-2xl bg-accent-soft text-accent">
<Icon className="h-5 w-5" aria-hidden="true" />
</span>
<h3 className="mt-5 font-display text-lg font-semibold tracking-[-0.025em] text-ink">{tool.title}</h3>
<p className="mt-2 flex-1 text-sm leading-relaxed text-muted">{tool.desc}</p>
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-accent">
{tool.action}
<ArrowRight className="h-4 w-4 transition-transform duration-300 group-hover:translate-x-0.5" aria-hidden="true" />
</span>
</Link>
);
})}
</div>
</section>
<section className="shell section pt-0" aria-labelledby="diagnostico-titulo">
<div className="grid items-start gap-10 lg:grid-cols-[0.78fr_1.22fr] lg:gap-16">
<div className="lg:sticky lg:top-28">
<p className="eyebrow">{isPt ? "Diagnóstico" : isEs ? "Diagnóstico" : isFr ? "Diagnostic" : isZh ? "故障诊断" : isDe ? "Diagnose" : "Diagnostics"}</p>
<h2 id="diagnostico-titulo" className="display mt-4 text-[clamp(2rem,4.8vw,3.4rem)]">
{isPt ? "O primeiro boot não precisa virar noite." : isEs ? "El primer arranque no tiene por qué desvelarlo." : isFr ? "Le premier démarrage n'a pas à vous gâcher la nuit." : isZh ? "第一次启动,不必折腾一整晚。" : isDe ? "Der erste Boot muss nicht die Nacht kosten." : "First boot doesn't have to take all night."}
</h2>
<p className="lede mt-4">
{isPt
? "Os erros mais comuns têm causa conhecida. O guia parte da mensagem no terminal e chega ao ajuste de hardware ou firmware."
: isEs
? "Los errores más comunes tienen una causa conocida. Esta guía parte del mensaje en el terminal y llega al ajuste de hardware o firmware."
: isFr
? "Les erreurs les plus courantes ont une cause connue. Ce guide part du message dans le terminal pour arriver au réglage matériel ou logiciel."
: isZh ? "常见错误都有已知的原因。本指南从串口终端日志出发,引导你找到硬件或固件上的调整办法。" : isDe
? "Die häufigsten Fehler haben bekannte Ursachen. Dieser Leitfaden geht von der Terminalmeldung aus und führt zur passenden Hardware- oder Firmware-Anpassung."
: "Common errors have known causes. This guide starts with the serial terminal log and leads to the hardware or firmware adjustment."}
</p>
<Link href={getLinkHref("/diagnostico")} className="btn btn-accent mt-7">
<AlertTriangle className="h-4 w-4" aria-hidden="true" />
{isPt ? "Abrir os 30+ diagnósticos" : isEs ? "Abrir los 30+ diagnósticos" : isFr ? "Ouvrir les 30+ diagnostics" : isZh ? "查看 30 多项诊断" : isDe ? "Die 30+ Diagnosen öffnen" : "Open the 30+ diagnostics"}
</Link>
</div>
<div className="panel-dark min-w-0 overflow-hidden rounded-[1.75rem]">
<div className="flex flex-wrap items-center justify-between gap-3 border-b border-white/10 px-5 py-4 sm:px-6">
<span className="inline-flex items-center gap-2 font-mono text-xs text-[#75cdc1]">
<Terminal className="h-4 w-4" aria-hidden="true" />
boot.log
</span>
<span className="text-xs text-[#a6afbd]">{isPt ? "4 exemplos de 30+" : isEs ? "4 ejemplos de 30+" : isFr ? "4 exemples sur 30+" : isZh ? "30 多项中的 4 个示例" : isDe ? "4 Beispiele von 30+" : "4 examples of 30+"}</span>
</div>
<div className="divide-y divide-white/10">
{errors.map((item) => (
<Link key={item.code} href={getLinkHref("/diagnostico")} className="group grid gap-2 px-5 py-5 transition-colors duration-300 hover:bg-white/[0.035] sm:px-6">
<span className="break-words font-mono text-[0.75rem] font-medium leading-relaxed text-[#ffb39b]">{item.code}</span>
<span className="text-sm font-medium text-[#f4f6f8]">{item.cause}</span>
<span className="text-xs leading-relaxed text-[#a6afbd]">{item.fix}</span>
</Link>
))}
</div>
</div>
</div>
</section>
<section className="shell pb-20 pt-4 md:pb-28">
<div className="mx-auto max-w-3xl text-center">
<p className="eyebrow">{isPt ? "Curadoria independente" : isEs ? "Curaduría independiente" : isFr ? "Sélection indépendante" : isZh ? "独立整理" : isDe ? "Unabhängige Kuration" : "Independent curation"}</p>
<h2 className="display mt-4 text-[clamp(2rem,4.5vw,3.2rem)]">
{isPt ? "Feito para consultar no meio do projeto." : isEs ? "Diseñado para consultar en mitad del proyecto." : isFr ? "Conçu pour être consulté en plein projet." : isZh ? "为项目途中的快速查阅而做。" : isDe ? "Gemacht für das Nachschlagen mitten im Projekt." : "Built for quick lookup mid-project."}
</h2>
<p className="lede mx-auto mt-4 max-w-2xl">
{isPt
? "O ESPDocs organiza dados públicos da Espressif e aponta sempre para a fonte oficial. Para decisões críticas, o datasheet e o Technical Reference Manual continuam sendo a palavra final."
: isEs
? "ESPDocs organiza datos públicos de Espressif y apunta siempre a la fuente oficial. Para decisiones críticas, la hoja de datos y el Technical Reference Manual continúan teniendo la última palabra."
: isFr
? "ESPDocs organise les données publiques d'Espressif et renvoie systématiquement vers la source officielle. Pour les décisions critiques, la fiche technique et le Technical Reference Manual restent la référence définitive."
: isZh ? "ESPDocs 整理乐鑫的公开数据,并直接指向官方资料来源。对于关键的工程决策,数据手册和技术参考手册仍是最终依据。" : isDe
? "ESPDocs strukturiert öffentliche Espressif-Daten und verweist stets auf die offizielle Quelle. Für kritische Entscheidungen bleiben das Datenblatt und das Technical Reference Manual maßgeblich."
: "ESPDocs organizes public Espressif data and points directly to official sources. For critical engineering decisions, the datasheet and Technical Reference Manual remain the definitive authority."}
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<Link href={getLinkHref("/glossario")} className="btn btn-ghost w-full sm:w-auto">
<BookOpen className="h-4 w-4" aria-hidden="true" />
{isPt ? "Glossário" : isEs ? "Glosario" : isFr ? "Glossaire" : isZh ? "术语表" : isDe ? "Glossar" : "Glossary"}
</Link>
<Link href={getLinkHref("/sobre")} className="btn btn-primary w-full sm:w-auto">
{isPt ? "Sobre o projeto" : isEs ? "Acerca del proyecto" : isFr ? "À propos du projet" : isZh ? "关于本项目" : isDe ? "Über das Projekt" : "About the project"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}