- Add full message catalogs and content for French (fr) and German (de) - Implement ASCII canonical slugs for French and German routes - Add language-specific search endpoints (/api/busca/fr, /api/busca/de) - Configure strict 404 responses for /fr/livro and /de/livro - Localize SEO, OpenGraph (fr_FR, de_DE), Twitter and JSON-LD schemas - Add localized code example comments across 14 examples for fr and de - Enable 'fr' and 'de' in ENABLED_LOCALES with root negotiation and redirect - Extend test suite in check-i18n, smoke-imagem and verifica-vazamentos Co-Authored-By: Antigravity <noreply@google.com>
728 lines
31 KiB
React
728 lines
31 KiB
React
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 frameworksDataDe from "@/data/de/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 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.",
|
||
},
|
||
];
|
||
|
||
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 getLinkHref = (href) => getLocalizedHref(`/${locale}${href}`, locale);
|
||
|
||
const seriesData = isPt ? seriesDataPt : isEs ? seriesDataEs : isFr ? seriesDataFr : isDe ? seriesDataDe : seriesDataEn;
|
||
const frameworksData = isPt ? frameworksDataPt : isEs ? frameworksDataEs : isFr ? frameworksDataFr : isDe ? frameworksDataDe : frameworksDataEn;
|
||
const tools = isPt ? TOOLS_PT : isEs ? TOOLS_ES : isFr ? TOOLS_FR : isDe ? TOOLS_DE : TOOLS_EN;
|
||
const errors = isPt ? ERRORS_PT : isEs ? ERRORS_ES : isFr ? ERRORS_FR : 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" : 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.
|
||
</>
|
||
) : 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."
|
||
: 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" : 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</>
|
||
) : 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" : isDe ? "Serien" : "series"}</span>
|
||
<span aria-hidden="true" className="text-line-strong">·</span>
|
||
<span><strong className="font-semibold text-ink">{frameworkCount}</strong> 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>
|
||
</>
|
||
) : 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" : 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." : 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" : 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" : 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" : 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." : 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."
|
||
: 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" : 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." : 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."
|
||
: 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" : 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+" : 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" : 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." : 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."
|
||
: 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" : 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" : isDe ? "Über das Projekt" : "About the project"}
|
||
<ArrowRight className="h-4 w-4" aria-hidden="true" />
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<Footer />
|
||
</div>
|
||
);
|
||
}
|