Files
ESPDocs/app/[locale]/livro/page.jsx
T
Lucas RayanandAntigravity 83c0ba3e74 feat(i18n): routing and localization infrastructure (phase 1)
Implement Phase 1 of i18n spec:
- Configure next-intl with 6 locales (pt, en, es, fr, de, zh-CN) and pathnames
- Move routes to app/[locale] structure with localized layouts and metadata
- Add middleware for root language negotiation (307), legacy redirects (308), and 404 for non-pt book
- Implement language selector dropdown in header with cookie persistence
- Add system typography rules for zh-CN and word-break/hyphenation for de/fr

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 09:31:22 -03:00

375 lines
12 KiB
React

import { notFound } from "next/navigation";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import BookCover from "@/components/BookCover";
import CodeSample from "@/components/CodeSample";
import Link from "next/link";
import { jsonLd, paginaMeta, SITE } from "@/lib/seo";
import {
ArrowRight,
ArrowUpRight,
BookOpen,
Cpu,
Gauge,
Radio,
ShieldCheck,
Terminal,
Wifi,
} from "lucide-react";
export function generateStaticParams() {
return [{ locale: "pt" }];
}
export async function generateMetadata({ params }) {
const { locale } = await params;
if (locale !== "pt") {
return {};
}
return paginaMeta({
titulo: "Microcontroladores ESP32, o livro",
descricao:
"Conheça o livro Microcontroladores ESP32: conectividade, eficiência e desempenho. 12 partes e 78 capítulos em português sobre arquitetura, energia, rádio, periféricos e firmware.",
caminho: "/pt/livro",
keywords: [
"livro ESP32",
"Microcontroladores ESP32",
"livro de ESP32 em português",
"Lucas Rayan Guerra",
"Ciência Embarcada",
],
});
}
const CHAPTERS = [
{
title: "O ecossistema ESP32",
desc: "Como as famílias se organizam, o que muda entre Xtensa e RISC-V e por que a escolha do chip começa pelo problema.",
topics: ["Famílias e sufixos", "Critérios de escolha", "Ferramentas de apoio"],
icon: Cpu,
},
{
title: "Arquitetura e memória",
desc: "Núcleos, caches, SRAM, PSRAM e o caminho entre o código em flash e a execução em alta velocidade.",
topics: ["Mapa de memória", "PSRAM na prática", "Caches e latência"],
icon: Gauge,
},
{
title: "Energia e autonomia",
desc: "Os modos de sono, o custo real do rádio e as decisões de hardware que definem a vida útil da bateria.",
topics: ["Deep sleep", "Domínios de energia", "Orçamento de consumo"],
icon: Gauge,
},
{
title: "Conectividade",
desc: "Wi-Fi, BLE, Thread, Zigbee e Matter: o que cada rádio resolve e onde a arquitetura começa a pesar.",
topics: ["Wi-Fi 6 e TWT", "BLE e malhas", "Matter e 802.15.4"],
icon: Radio,
},
{
title: "Periféricos e pinagem",
desc: "GPIO, ADC, I2S, USB, MIPI e as restrições que só aparecem quando o hardware já está na placa.",
topics: ["Pinos de strapping", "ADC e rádio", "USB nativo"],
icon: Wifi,
},
{
title: "Do protótipo ao produto",
desc: "Firmware, partições, OTA, segurança e os cuidados de engenharia que sobrevivem ao primeiro deploy.",
topics: ["ESP-IDF e Arduino", "OTA e rollback", "Secure boot"],
icon: ShieldCheck,
},
];
const ESP_IDF = `#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define LED GPIO_NUM_2
void app_main(void)
{
gpio_reset_pin(LED);
gpio_set_direction(LED, GPIO_MODE_OUTPUT);
while (1) {
gpio_set_level(LED, 1);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_level(LED, 0);
vTaskDelay(pdMS_TO_TICKS(500));
}
}`;
const ARDUINO = `#include <WiFi.h>
const char *ssid = "SUA_REDE";
const char *senha = "SUA_SENHA";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, senha);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(WiFi.localIP());
}
void loop() {}`;
const DEEP_SLEEP = `#include "esp_sleep.h"
#include "esp_log.h"
void app_main(void)
{
uint64_t intervalo_us = 30ULL * 1000000ULL;
esp_sleep_enable_timer_wakeup(intervalo_us);
ESP_LOGI("energia", "dormindo por 30 segundos");
esp_deep_sleep_start();
}`;
const FACTS = [
["Idioma", "Português"],
["Partes", "12"],
["Capítulos", "78"],
["Digital", "Amazon Kindle"],
["Impresso", "UICLAP"],
["ISBN", SITE.livroIsbn],
];
export default async function LivroPage({ params }) {
const { locale } = await params;
if (locale !== "pt") {
notFound();
}
return (
<div className="site-canvas min-h-screen">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd.livro()) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
jsonLd.trilha([
{ nome: "Início", caminho: "/" },
{ nome: "Livro", caminho: "/livro" },
])
),
}}
/>
<Header />
<main id="conteudo">
<section className="shell pt-8 sm:pt-12">
<nav aria-label="Trilha de navegação" className="flex items-center gap-2 text-sm text-muted">
<Link href="/" className="transition-colors hover:text-accent">
Início
</Link>
<span aria-hidden="true" className="text-line-strong">/</span>
<span aria-current="page" className="text-ink">Livro</span>
</nav>
<div className="mt-7 grid items-center gap-10 lg:grid-cols-[0.84fr_1.16fr] lg:gap-16">
<div className="order-1 lg:order-2">
<span className="chip chip-accent">
<BookOpen className="h-3.5 w-3.5" aria-hidden="true" />
Livro novo · 1ª edição
</span>
<h1 className="page-title mt-5 text-[clamp(1.85rem,8vw,2.5rem)] sm:text-[clamp(2.5rem,5.4vw,4.4rem)]">
Microcontroladores ESP32
</h1>
<p className="mt-3 text-lg font-medium text-copper">{SITE.livroSubtitulo}</p>
<p className="lede mt-6 max-w-2xl">
Um percurso completo pelo ecossistema ESP32 — da arquitetura do chip à implantação
de produtos conectados. São 12 partes e 78 capítulos que cobrem Arduino e ESP-IDF,
FreeRTOS, Wi-Fi, BLE, Thread e Matter, periféricos, depuração, baixo consumo e segurança.
</p>
<div className="mt-8 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
<a
href={SITE.livroAmazon}
target="_blank"
rel="noopener noreferrer"
className="btn btn-primary w-full sm:w-auto"
>
<BookOpen className="h-4 w-4" aria-hidden="true" />
Comprar digital
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<a
href={SITE.livroUiclap}
target="_blank"
rel="noopener noreferrer"
className="btn btn-ghost w-full sm:w-auto"
>
Comprar impresso
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<Link href="/series" className="inline-flex min-h-11 items-center justify-center gap-1.5 px-2 text-sm font-medium text-accent transition-colors hover:text-accent-strong">
Explorar a documentação
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
<dl className="mt-9 grid grid-cols-2 gap-2.5 sm:grid-cols-3">
{FACTS.map(([label, value]) => (
<div key={label} className="rounded-2xl bg-surface-2 px-4 py-3">
<dt className="text-[0.6875rem] font-semibold text-muted">{label}</dt>
<dd className="mt-0.5 text-sm font-semibold text-ink">{value}</dd>
</div>
))}
</dl>
</div>
<div className="relative order-2 overflow-hidden rounded-[2rem] bg-[#0b0d10] p-8 ring-1 ring-white/10 sm:rounded-[2.5rem] sm:p-12 lg:order-1">
<div
className="pointer-events-none absolute left-1/2 top-1/2 -z-0 h-72 w-72 -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#2dd4bf]/15 blur-3xl"
aria-hidden="true"
/>
<div className="relative mx-auto w-[min(16rem,76%)]">
<BookCover />
</div>
<div className="relative mt-9 flex items-end justify-between gap-4 border-t border-white/10 pt-4 text-xs text-[#a6afbd]">
<span>Lucas Rayan Guerra</span>
<span>Ciência Embarcada</span>
</div>
</div>
</div>
</section>
<section className="shell section" aria-labelledby="sumario-titulo">
<div className="grid gap-8 lg:grid-cols-[0.72fr_1.28fr] lg:gap-16">
<div>
<p className="eyebrow">Sumário</p>
<h2 id="sumario-titulo" className="display mt-4 text-[clamp(2rem,4.6vw,3.4rem)]">
Uma linha de raciocínio, do chip ao produto.
</h2>
</div>
<div className="lg:pt-2">
<p className="lede">
A ordem acompanha o projeto real: entender o chip, medir energia, conectar, expor
periféricos e sustentar o produto. Os seis eixos abaixo mostram como as 12 partes
se organizam.
</p>
<p className="mt-4 text-sm text-muted">
78 capítulos, com exercícios e projetos ao longo do percurso.
</p>
</div>
</div>
<div className="mt-10 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{CHAPTERS.map((chapter) => {
const Icon = chapter.icon;
return (
<article key={chapter.title} className="card 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-xl font-semibold tracking-[-0.03em] text-ink">{chapter.title}</h3>
<p className="mt-2 flex-1 text-sm leading-relaxed text-muted">{chapter.desc}</p>
<ul className="mt-5 flex flex-wrap gap-1.5">
{chapter.topics.map((topic) => (
<li key={topic} className="chip">
{topic}
</li>
))}
</ul>
</article>
);
})}
</div>
</section>
<section className="border-y border-line bg-surface/70" aria-labelledby="codigo-titulo">
<div className="shell section">
<div className="grid gap-10 lg:grid-cols-[0.7fr_1.3fr] lg:gap-16">
<div className="min-w-0 lg:sticky lg:top-28 lg:self-start">
<p className="eyebrow">Código</p>
<h2 id="codigo-titulo" className="display mt-4 text-[clamp(2rem,4.6vw,3.4rem)]">
Exemplos curtos, prontos para a bancada.
</h2>
<p className="lede mt-4">
Os trechos abaixo são originais e servem como ponto de partida. Ajuste o pino, a rede
e a frequência ao seu hardware antes de gravar.
</p>
<div className="mt-6 rounded-2xl border border-line bg-surface p-4">
<p className="flex items-center gap-2 text-sm font-semibold text-ink">
<Terminal className="h-4 w-4 text-accent" aria-hidden="true" />
Sem conteúdo protegido
</p>
<p className="mt-2 text-xs leading-relaxed text-muted">
Esta página apresenta apenas a ficha do livro e exemplos autorais. O texto integral,
PDF, EPUB e arquivos intermediários não são distribuídos pelo ESPDocs.
</p>
</div>
</div>
<div className="min-w-0 space-y-7">
<CodeSample
label="Ponto de partida · ESP-IDF"
language="C"
code={ESP_IDF}
note="Pisca o GPIO 2 usando a API atual do ESP-IDF e uma task do FreeRTOS."
/>
<CodeSample
label="Conectividade · Arduino"
language="C++"
code={ARDUINO}
note="Conexão Wi-Fi mínima, com espera ativa e impressão do IP obtido."
/>
<CodeSample
label="Energia · deep sleep"
language="C · ESP-IDF"
code={DEEP_SLEEP}
note="Timer de 30 segundos e entrada no modo de menor consumo disponível."
/>
</div>
</div>
</div>
</section>
<section className="shell section pb-20 md:pb-28">
<div className="mx-auto max-w-3xl text-center">
<p className="eyebrow">Para quem é</p>
<h2 className="display mt-4 text-[clamp(2rem,4.5vw,3.2rem)]">
Para quem já cansou de juntar pedaços de datasheet.
</h2>
<p className="lede mx-auto mt-4 max-w-2xl">
Estudantes, makers e engenheiros de firmware que querem uma visão coerente do
ecossistema — sem abandonar a fonte oficial.
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<a
href={SITE.livroAmazon}
target="_blank"
rel="noopener noreferrer"
className="btn btn-primary w-full sm:w-auto"
>
<BookOpen className="h-4 w-4" aria-hidden="true" />
Comprar digital
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
<a
href={SITE.livroUiclap}
target="_blank"
rel="noopener noreferrer"
className="btn btn-ghost w-full sm:w-auto"
>
Comprar impresso
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
</a>
</div>
</div>
</section>
</main>
<Footer />
</div>
);
}