Files
ESPDocs/app/[locale]/comparacao/page.jsx
T
Lucas RayanandClaude Sonnet 5.5 1f84f1f661
Release / Plano (reaproveitar a imagem?) (push) Successful in 12s
CI / Lint e auditorias (push) Successful in 1m39s
CI / Trivy (dependências e segredos) (push) Successful in 13s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m35s
Release / ci (push) Successful in 4m30s
Release / Publica a imagem (linux/arm64) (push) Successful in 19s
Release / Cria a release no Gitea (push) Skipped
Release / Deploy no Coolify (push) Successful in 22s
feat(placas): faixa de placas sugeridas nas séries, comparação e seletor
Sorteia uma placa dos chips da página, com preferência pelas de loja oficial, e
troca só pelas setas, com transição suave. Usa o link de afiliado do idioma
(rel=sponsored) e some quando o chip não tem placa. Vai nas páginas de série, na
comparação e nos dois modos de resultado do seletor.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 18:31:01 -03:00

805 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.
"use client";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import PlacasSugeridas from "@/components/PlacasSugeridas";
import PageHero from "@/components/PageHero";
import { useEffect, useState, useMemo, Fragment } from "react";
import { usePathname } from "next/navigation";
import Link from "next/link";
import seriesDataPt from "@/public/series.json";
import seriesDataEn from "@/data/en/series.json";
import seriesDataEs from "@/data/es/series.json";
import seriesDataFr from "@/data/fr/series.json";
import seriesDataDe from "@/data/de/series.json";
import seriesDataZh from "@/data/zh-CN/series.json";
import { getLocalizedHref } from "@/i18n/links";
import { ArrowRight, ArrowUpRight, Check, ChevronDown, Scale } from "lucide-react";
const MIN_SERIES = 2;
const MAX_SERIES = 4;
/* Lê "seguranca.ecc" além de chaves simples. */
function valorDe(objeto, caminho) {
return caminho.split(".").reduce((atual, parte) => atual?.[parte], objeto);
}
const COMPARE_FIELDS_PT = [
{ category: "Geral", fields: [
{ key: "nome_completo", label: "Nome Completo" },
{ key: "descricao", label: "Descrição" },
]},
{ category: "Disponibilidade e Ferramentas", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF mínimo" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Depuração / JTAG" },
{ key: "encapsulamento", label: "Encapsulamento" },
{ key: "modulos", label: "Módulos disponíveis" },
]},
{ category: "Processador", fields: [
{ key: "arquitetura", label: "Arquitetura" },
{ key: "nucleos", label: "Núcleos" },
{ key: "frequencia", label: "Frequência" },
{ key: "coprocessador_ulp", label: "Coprocessador ULP" },
{ key: "aceleradores_ia", label: "Aceleradores de IA" },
]},
{ category: "Conectividade", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memória", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash Externa" },
{ key: "psram_externa", label: "PSRAM Externa" },
]},
{ category: "Periféricos Digitais", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Depuração / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Periféricos Analógicos", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch Capacitivo" },
{ key: "sensor_hall", label: "Sensor Hall" },
{ key: "sensor_temperatura", label: "Sensor de Temperatura" },
]},
{ category: "Segurança", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (curvas elípticas)" },
{ key: "seguranca.ecdsa", label: "ECDSA em hardware" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Assinatura Digital (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Gerador aleatório (RNG)" },
{ key: "seguranca.criptografia_flash", label: "Criptografia de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Proteção contra DPA" },
]},
{ category: "Interfaces Especiais", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Câmera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Especificações Ambientais", fields: [
{ key: "temperatura_operacao", label: "Temp. Operação" },
{ key: "temperatura_armazenamento", label: "Temp. Armazenamento" },
]},
];
const COMPARE_FIELDS_EN = [
{ category: "General", fields: [
{ key: "nome_completo", label: "Full Name" },
{ key: "descricao", label: "Description" },
]},
{ category: "Availability and Tools", fields: [
{ key: "esp_idf_minimo", label: "Minimum ESP-IDF" },
{ key: "arduino_core", label: "Arduino Core" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "encapsulamento", label: "Package" },
{ key: "modulos", label: "Available Modules" },
]},
{ category: "Processor", fields: [
{ key: "arquitetura", label: "Architecture" },
{ key: "nucleos", label: "Cores" },
{ key: "frequencia", label: "Frequency" },
{ key: "coprocessador_ulp", label: "ULP Coprocessor" },
{ key: "aceleradores_ia", label: "AI Accelerators" },
]},
{ category: "Connectivity", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memory", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "RTC SRAM" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "External Flash" },
{ key: "psram_externa", label: "External PSRAM" },
]},
{ category: "Digital Peripherals", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Analog Peripherals", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Capacitive Touch" },
{ key: "sensor_hall", label: "Hall Sensor" },
{ key: "sensor_temperatura", label: "Temperature Sensor" },
]},
{ category: "Security", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (elliptic curves)" },
{ key: "seguranca.ecdsa", label: "Hardware ECDSA" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Digital Signature (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Random Generator (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Flash Encryption" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "DPA Protection" },
]},
{ category: "Special Interfaces", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Camera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Environmental Specifications", fields: [
{ key: "temperatura_operacao", label: "Operating Temp." },
{ key: "temperatura_armazenamento", label: "Storage Temp." },
]},
];
const COMPARE_FIELDS_ES = [
{ category: "General", fields: [
{ key: "nome_completo", label: "Nombre completo" },
{ key: "descricao", label: "Descripción" },
]},
{ category: "Disponibilidad y herramientas", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF mínimo" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Depuración / JTAG" },
{ key: "encapsulamento", label: "Encapsulado" },
{ key: "modulos", label: "Módulos disponibles" },
]},
{ category: "Procesador", fields: [
{ key: "arquitetura", label: "Arquitectura" },
{ key: "nucleos", label: "Núcleos" },
{ key: "frequencia", label: "Frecuencia" },
{ key: "coprocessador_ulp", label: "Coprocesador ULP" },
{ key: "aceleradores_ia", label: "Aceleradores de IA" },
]},
{ category: "Conectividad", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Memoria", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash externa" },
{ key: "psram_externa", label: "PSRAM externa" },
]},
{ category: "Periféricos digitales", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Depuración / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Periféricos analógicos", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch capacitivo" },
{ key: "sensor_hall", label: "Sensor Hall" },
{ key: "sensor_temperatura", label: "Sensor de temperatura" },
]},
{ category: "Seguridad", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (curvas elípticas)" },
{ key: "seguranca.ecdsa", label: "ECDSA en hardware" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Firma digital (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Generador aleatorio (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Cifrado de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Protección contra DPA" },
]},
{ category: "Interfaces especiales", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Cámara" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Especificaciones ambientales", fields: [
{ key: "temperatura_operacao", label: "Temp. operación" },
{ key: "temperatura_armazenamento", label: "Temp. almacenamiento" },
]},
];
const COMPARE_FIELDS_FR = [
{ category: "Général", fields: [
{ key: "nome_completo", label: "Nom complet" },
{ key: "descricao", label: "Description" },
]},
{ category: "Disponibilité et outils", fields: [
{ key: "esp_idf_minimo", label: "ESP-IDF minimum" },
{ key: "arduino_core", label: "Core Arduino" },
{ key: "depuracao", label: "Débogage / JTAG" },
{ key: "encapsulamento", label: "Boîtier" },
{ key: "modulos", label: "Modules disponibles" },
]},
{ category: "Processeur", fields: [
{ key: "arquitetura", label: "Architecture" },
{ key: "nucleos", label: "Cœurs" },
{ key: "frequencia", label: "Fréquence" },
{ key: "coprocessador_ulp", label: "Coprocesseur ULP" },
{ key: "aceleradores_ia", label: "Accélérateurs IA" },
]},
{ category: "Connectivité", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Mémoire", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "SRAM RTC" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Flash externe" },
{ key: "psram_externa", label: "PSRAM externe" },
]},
{ category: "Périphériques numériques", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Débogage / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Périphériques analogiques", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Touch capacitif" },
{ key: "sensor_hall", label: "Capteur Hall" },
{ key: "sensor_temperatura", label: "Capteur de température" },
]},
{ category: "Sécurité", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (courbes elliptiques)" },
{ key: "seguranca.ecdsa", label: "ECDSA matériel" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Signature numérique (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Générateur aléatoire (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Chiffrement de flash" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "Protection contre DPA" },
]},
{ category: "Interfaces spéciales", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Caméra" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Spécifications environnementales", fields: [
{ key: "temperatura_operacao", label: "Temp. de fonctionnement" },
{ key: "temperatura_armazenamento", label: "Temp. de stockage" },
]},
];
const COMPARE_FIELDS_DE = [
{ category: "Allgemein", fields: [
{ key: "nome_completo", label: "Vollständiger Name" },
{ key: "descricao", label: "Beschreibung" },
]},
{ category: "Verfügbarkeit und Werkzeuge", fields: [
{ key: "esp_idf_minimo", label: "Mindest-ESP-IDF" },
{ key: "arduino_core", label: "Arduino-Core" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "encapsulamento", label: "Gehäuse" },
{ key: "modulos", label: "Verfügbare Module" },
]},
{ category: "Prozessor", fields: [
{ key: "arquitetura", label: "Architektur" },
{ key: "nucleos", label: "Kerne" },
{ key: "frequencia", label: "Taktfrequenz" },
{ key: "coprocessador_ulp", label: "ULP-Coprozessor" },
{ key: "aceleradores_ia", label: "KI-Beschleuniger" },
]},
{ category: "Konnektivität", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "Bluetooth" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "Ethernet" },
]},
{ category: "Speicher", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "RTC-SRAM" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "Externer Flash" },
{ key: "psram_externa", label: "Externer PSRAM" },
]},
{ category: "Digitale Peripherie", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "Debugging / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "Analoge Peripherie", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "Kapazitiver Touch" },
{ key: "sensor_hall", label: "Hall-Sensor" },
{ key: "sensor_temperatura", label: "Temperatursensor" },
]},
{ category: "Sicherheit", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC (Elliptische Kurven)" },
{ key: "seguranca.ecdsa", label: "Hardware-ECDSA" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "Digitale Signatur (DS)" },
{ key: "seguranca.key_manager", label: "Key Manager" },
{ key: "seguranca.rng", label: "Zufallsgenerator (TRNG)" },
{ key: "seguranca.criptografia_flash", label: "Flash-Verschlüsselung" },
{ key: "seguranca.secure_boot", label: "Secure Boot" },
{ key: "seguranca.protecao_dpa", label: "DPA-Schutz" },
]},
{ category: "Spezielle Schnittstellen", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "Kamera" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "Ethernet MAC" },
]},
{ category: "Umgebungsbedingungen", fields: [
{ key: "temperatura_operacao", label: "Betriebstemp." },
{ key: "temperatura_armazenamento", label: "Lagertemp." },
]},
];
const COMPARE_FIELDS_ZH = [
{ category: "概览", fields: [
{ key: "nome_completo", label: "完整名称" },
{ key: "descricao", label: "描述" },
]},
{ category: "可用性与工具", fields: [
{ key: "esp_idf_minimo", label: "最低 ESP-IDF 版本" },
{ key: "arduino_core", label: "Arduino 核心" },
{ key: "depuracao", label: "调试 / JTAG" },
{ key: "encapsulamento", label: "封装" },
{ key: "modulos", label: "可用模组" },
]},
{ category: "处理器", fields: [
{ key: "arquitetura", label: "架构" },
{ key: "nucleos", label: "内核" },
{ key: "frequencia", label: "频率" },
{ key: "coprocessador_ulp", label: "ULP 协处理器" },
{ key: "aceleradores_ia", label: "AI 加速器" },
]},
{ category: "无线连接", fields: [
{ key: "wifi", label: "Wi-Fi" },
{ key: "bluetooth", label: "蓝牙" },
{ key: "zigbee_thread", label: "Zigbee/Thread" },
{ key: "matter", label: "Matter" },
{ key: "ethernet", label: "以太网" },
]},
{ category: "内存", fields: [
{ key: "memoria_sram", label: "SRAM" },
{ key: "memoria_sram_rtc", label: "RTC SRAM" },
{ key: "memoria_rom", label: "ROM" },
{ key: "flash_externa", label: "外部闪存" },
{ key: "psram_externa", label: "外部 PSRAM" },
]},
{ category: "数字外设", fields: [
{ key: "gpio", label: "GPIO" },
{ key: "uart", label: "UART" },
{ key: "spi", label: "SPI" },
{ key: "i2c", label: "I²C" },
{ key: "i2s", label: "I²S" },
{ key: "pwm", label: "PWM" },
{ key: "can", label: "CAN" },
{ key: "usb", label: "USB" },
{ key: "depuracao", label: "调试 / JTAG" },
{ key: "sdio", label: "SDIO" },
]},
{ category: "模拟外设", fields: [
{ key: "adc", label: "ADC" },
{ key: "dac", label: "DAC" },
{ key: "touch", label: "电容触摸" },
{ key: "sensor_hall", label: "霍尔传感器" },
{ key: "sensor_temperatura", label: "温度传感器" },
]},
{ category: "安全", fields: [
{ key: "seguranca.aes", label: "AES" },
{ key: "seguranca.sha", label: "SHA" },
{ key: "seguranca.rsa", label: "RSA / MPI" },
{ key: "seguranca.ecc", label: "ECC(椭圆曲线)" },
{ key: "seguranca.ecdsa", label: "硬件 ECDSA" },
{ key: "seguranca.hmac", label: "HMAC" },
{ key: "seguranca.assinatura_digital", label: "数字签名(DS)" },
{ key: "seguranca.key_manager", label: "密钥管理器" },
{ key: "seguranca.rng", label: "随机数发生器(TRNG)" },
{ key: "seguranca.criptografia_flash", label: "闪存加密" },
{ key: "seguranca.secure_boot", label: "安全启动" },
{ key: "seguranca.protecao_dpa", label: "DPA 防护" },
]},
{ category: "特殊接口", fields: [
{ key: "lcd", label: "LCD" },
{ key: "camera", label: "摄像头" },
{ key: "mipi_csi", label: "MIPI CSI" },
{ key: "mipi_dsi", label: "MIPI DSI" },
{ key: "ethernet_mac", label: "以太网 MAC" },
]},
{ category: "环境规格", fields: [
{ key: "temperatura_operacao", label: "工作温度" },
{ key: "temperatura_armazenamento", label: "存储温度" },
]},
];
export default function Comparacao() {
const pathname = usePathname();
const isEn = pathname?.startsWith("/en");
const isEs = pathname?.startsWith("/es");
const isFr = pathname?.startsWith("/fr");
const isDe = pathname?.startsWith("/de");
const isZh = pathname?.startsWith("/zh-CN");
const currentLocale = isEs ? "es" : isEn ? "en" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt";
const seriesData = isEs ? seriesDataEs : isEn ? seriesDataEn : isFr ? seriesDataFr : isZh ? seriesDataZh : isDe ? seriesDataDe : seriesDataPt;
const compareFields = isEs ? COMPARE_FIELDS_ES : isEn ? COMPARE_FIELDS_EN : isFr ? COMPARE_FIELDS_FR : isZh ? COMPARE_FIELDS_ZH : isDe ? COMPARE_FIELDS_DE : COMPARE_FIELDS_PT;
const [selectedSeries, setSelectedSeries] = useState(["ESP32", "ESP32-S3"]);
const [soDiferencas, setSoDiferencas] = useState(false);
const [collapsedCategories, setCollapsedCategories] = useState(() => ({
[isEs ? "Interfaces especiales" : isEn ? "Special Interfaces" : isFr ? "Interfaces spéciales" : isZh ? "特殊接口" : isDe ? "Spezielle Schnittstellen" : "Interfaces Especiais"]: true,
[isEs ? "Especificaciones ambientales" : isEn ? "Environmental Specifications" : isFr ? "Spécifications environnementales" : isZh ? "环境规格" : isDe ? "Umgebungsbedingungen" : "Especificações Ambientais"]: true,
}));
const series = Object.entries(seriesData);
// O seletor envia as séries finalistas em ?chips=ESP32-S3,ESP32-C6.
useEffect(() => {
const chips = new URLSearchParams(window.location.search).get("chips");
if (!chips) return;
const validas = [...new Set(chips.split(","))].filter((k) => seriesData[k]).slice(0, MAX_SERIES);
if (validas.length >= MIN_SERIES) setSelectedSeries(validas);
}, [seriesData]);
const toggleSeries = (seriesKey) => {
if (selectedSeries.includes(seriesKey)) {
if (selectedSeries.length > MIN_SERIES) setSelectedSeries(selectedSeries.filter((s) => s !== seriesKey));
} else if (selectedSeries.length < MAX_SERIES) {
setSelectedSeries([...selectedSeries, seriesKey]);
}
};
const toggleCategory = (category) => {
setCollapsedCategories({ ...collapsedCategories, [category]: !collapsedCategories[category] });
};
const renderValue = (value) => {
if (!value || value === "Não" || value === "No" || value === "Non" || (value === "Nein" || value === "否")) return <span className="text-muted">{isEs || isEn ? "No" : isFr ? "Non" : isZh ? "否" : isDe ? "Nein" : "Não"}</span>;
if (value === "Sim" || value === "Yes" || value === "Sí" || value === "Oui" || (value === "Ja" || value === "是")) {
return (
<span className="inline-flex items-center gap-1.5 font-medium text-ok">
<Check className="h-4 w-4" aria-hidden="true" />
{isEs ? "Sí" : isEn ? "Yes" : isFr ? "Oui" : isZh ? "是" : isDe ? "Ja" : "Sim"}
</span>
);
}
return <span className="font-medium text-ink">{value}</span>;
};
const valores = (key) => selectedSeries.map((k) => String(valorDe(seriesData[k], key) ?? (isEs || isEn ? "No" : isFr ? "Non" : isZh ? "否" : isDe ? "Nein" : "Não")));
const diferem = (key) => new Set(valores(key)).size > 1;
return (
<div className="site-canvas min-h-screen">
<Header />
<main id="conteudo">
<PageHero
isEn={isEn}
isEs={isEs}
isFr={isFr}
isDe={isDe} isZh={isZh}
trail={[{ label: isEs ? "Comparador" : isEn ? "Comparator" : isFr ? "Comparateur" : isZh ? "对比工具" : isDe ? "Vergleich" : "Comparador" }]}
icon={Scale}
label={isEs ? "Hasta cuatro series lado a lado" : isEn ? "Up to four series side by side" : isFr ? "Jusqu'à quatre séries côte à côte" : isZh ? "最多四个系列并排对比" : isDe ? "Bis zu vier Serien im Vergleich" : "Até quatro séries lado a lado"}
title={isEs ? "Comparador de series ESP32" : isEn ? "ESP32 Series Comparator" : isFr ? "Comparateur de séries ESP32" : isZh ? "系列对比工具" : isDe ? "ESP32-Serien-Vergleich" : "Comparador de séries"}
lede={
isEs
? "Ponga núcleos, radio, memoria, periféricos y seguridad en la misma tabla y vea lo que realmente cambia de un chip a otro."
: isEn
? "Put cores, radio, memory, peripherals, and security in the same table and see what really changes from chip to chip."
: isFr
? "Placez les cœurs, la radio, la mémoire, les périphériques et la sécurité dans le même tableau et voyez ce qui change réellement d'une puce à l'autre."
: isZh ? "把内核、无线、内存、外设和安全放进同一张表,看看芯片之间到底有什么不同。" : isDe
? "Stellen Sie Kerne, Funk, Speicher, Peripherie und Sicherheit in derselben Tabelle gegenüber und sehen Sie, was sich wirklich von Chip zu Chip ändert."
: "Coloque núcleos, rádio, memória, periféricos e segurança na mesma tabela e veja o que realmente muda de um chip para outro."
}
/>
<section className="shell pt-10 sm:pt-12" aria-labelledby="escolha-titulo">
<div className="panel p-5 sm:p-7">
<div className="flex flex-wrap items-end justify-between gap-3">
<div>
<h2 id="escolha-titulo" className="text-base font-semibold text-ink">
{isEs ? (
<>Elija de {MIN_SERIES} a {MAX_SERIES} series</>
) : isEn ? (
<>Choose {MIN_SERIES} to {MAX_SERIES} series</>
) : isFr ? (
<>Choisissez de {MIN_SERIES} à {MAX_SERIES} séries</>
) : isZh ? ( <>请选择 {MIN_SERIES} 到 {MAX_SERIES} 个系列</> ) : isDe ? (
<>Wählen Sie {MIN_SERIES} bis {MAX_SERIES} Serien</>
) : (
<>Escolha de {MIN_SERIES} a {MAX_SERIES} séries</>
)}
</h2>
<p role="status" aria-live="polite" className="mt-1 text-sm text-muted">
{isEs ? (
<>
{selectedSeries.length} de {MAX_SERIES} seleccionadas
{selectedSeries.length === MAX_SERIES && ". Elimine una para cambiar."}
</>
) : isEn ? (
<>
{selectedSeries.length} of {MAX_SERIES} selected
{selectedSeries.length === MAX_SERIES && ". Remove one to switch."}
</>
) : isFr ? (
<>
{selectedSeries.length} sur {MAX_SERIES} sélectionnées
{selectedSeries.length === MAX_SERIES && ". Supprimez-en une pour en changer."}
</>
) : isZh ? ( <>
已选 {selectedSeries.length} / {MAX_SERIES} 个{selectedSeries.length === MAX_SERIES && "。请先移除一个再更换。"}
</> ) : isDe ? (
<>
{selectedSeries.length} von {MAX_SERIES} ausgewählt
{selectedSeries.length === MAX_SERIES && ". Entfernen Sie eine zum Wechseln."}
</>
) : (
<>
{selectedSeries.length} de {MAX_SERIES} selecionadas
{selectedSeries.length === MAX_SERIES && ". Remova uma para trocar."}
</>
)}
</p>
</div>
</div>
<div className="mt-4 flex flex-wrap gap-2">
{series.map(([key]) => {
const marcada = selectedSeries.includes(key);
const bloqueada = !marcada && selectedSeries.length >= MAX_SERIES;
return (
<button
key={key}
type="button"
onClick={() => toggleSeries(key)}
aria-pressed={marcada}
aria-disabled={bloqueada}
className={`chip-btn ${bloqueada ? "opacity-50" : ""}`}
>
{marcada && <Check className="h-4 w-4" aria-hidden="true" />}
{key}
</button>
);
})}
</div>
</div>
</section>
<section className="shell mt-8" aria-labelledby="tabela-titulo">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="tabela-titulo" className="text-base font-semibold text-ink">
{isEs ? "Especificaciones" : isEn ? "Specifications" : isFr ? "Spécifications" : isZh ? "规格" : isDe ? "Spezifikationen" : "Especificações"}
</h2>
<label className="flex min-h-11 cursor-pointer items-center gap-2.5 text-sm font-medium text-ink-soft">
<input
type="checkbox"
checked={soDiferencas}
onChange={(e) => setSoDiferencas(e.target.checked)}
className="h-5 w-5 cursor-pointer accent-[var(--accent)]"
/>
{isEs ? "Mostrar solo diferencias" : isEn ? "Show differences only" : isFr ? "Afficher uniquement les différences" : isZh ? "仅显示差异" : isDe ? "Nur Unterschiede anzeigen" : "Mostrar só as diferenças"}
</label>
</div>
<div className="panel mt-3 overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full min-w-[30rem] border-collapse text-sm">
<caption className="sr-only">
{isEs ? (
<>Comparación de las series {selectedSeries.join(", ")}</>
) : isEn ? (
<>Comparison of series {selectedSeries.join(", ")}</>
) : isFr ? (
<>Comparaison des séries {selectedSeries.join(", ")}</>
) : isZh ? ( <>系列对比:{selectedSeries.join(", ")}</> ) : isDe ? (
<>Vergleich der Serien {selectedSeries.join(", ")}</>
) : (
<>Comparação das séries {selectedSeries.join(", ")}</>
)}
</caption>
<thead>
<tr className="border-b border-line bg-surface-2">
<th scope="col" className="sticky left-0 z-20 w-28 bg-surface-2 px-4 py-4 text-left font-semibold text-muted sm:w-52 sm:px-6">
{isEs ? "Especificación" : isEn ? "Specification" : isFr ? "Spécification" : isZh ? "规格项" : isDe ? "Spezifikation" : "Especificação"}
</th>
{selectedSeries.map((seriesKey) => (
<th key={seriesKey} scope="col" className="min-w-40 px-4 py-4 text-left sm:px-6">
<Link href={getLocalizedHref(`/series/${seriesKey}`, currentLocale)} className="inline-flex min-h-11 items-center gap-1 font-display text-lg font-semibold tracking-[-0.03em] text-ink hover:text-accent">
{seriesKey}
<ArrowUpRight className="h-4 w-4 text-muted" aria-hidden="true" />
</Link>
</th>
))}
</tr>
</thead>
<tbody>
{compareFields.map(({ category, fields }) => {
const visiveis = soDiferencas ? fields.filter(({ key }) => diferem(key)) : fields;
if (soDiferencas && visiveis.length === 0) return null;
const isCollapsed = collapsedCategories[category] && !soDiferencas;
return (
<Fragment key={category}>
<tr className="border-y border-line bg-surface-2/60">
<th scope="rowgroup" colSpan={selectedSeries.length + 1} className="p-0 text-left">
<button
type="button"
onClick={() => toggleCategory(category)}
aria-expanded={!isCollapsed}
className="flex min-h-12 w-full cursor-pointer items-center justify-between gap-3 px-4 py-3 text-left font-semibold text-ink sm:px-6"
>
<span className="sticky left-4 sm:left-6">{category}</span>
<ChevronDown className={`h-4 w-4 shrink-0 text-muted transition-transform ${isCollapsed ? "" : "rotate-180"}`} aria-hidden="true" />
</button>
</th>
</tr>
{!isCollapsed &&
visiveis.map(({ key, label }) => (
<tr key={key} className="border-b border-line last:border-b-0 hover:bg-surface-2/50">
<th scope="row" className="sticky left-0 z-10 bg-surface px-4 py-3.5 text-left align-top font-medium text-muted sm:px-6">
{label}
</th>
{selectedSeries.map((seriesKey) => (
<td key={seriesKey} className="px-4 py-3.5 align-top sm:px-6">
{renderValue(valorDe(seriesData[seriesKey], key))}
</td>
))}
</tr>
))}
</Fragment>
);
})}
</tbody>
</table>
</div>
</div>
</section>
<div className="shell mt-8">
<PlacasSugeridas chips={selectedSeries} />
</div>
<section className="shell section" aria-labelledby="docs-titulo">
<h2 id="docs-titulo" className="section-title">
{isEs ? "Documentación oficial" : isEn ? "Official documentation" : isFr ? "Documentation officielle" : isZh ? "官方文档" : isDe ? "Offizielle Dokumentation" : "Documentação oficial"}
</h2>
<div className="mt-6 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
{selectedSeries.map((seriesKey) => {
const seriesItem = seriesData[seriesKey];
return (
<div key={seriesKey} className="card flex flex-col justify-between gap-5 p-5">
<Link href={getLocalizedHref(`/series/${seriesKey}`, currentLocale)} className="inline-flex min-h-11 items-center font-display text-lg font-semibold tracking-[-0.03em] text-ink hover:text-accent">
{seriesKey}
</Link>
{seriesItem.datasheet ? (
<a href={seriesItem.datasheet} target="_blank" rel="noopener noreferrer" className="btn btn-ghost btn-sm">
{isEs ? "Datasheet oficial" : isEn ? "Official datasheet" : isFr ? "Fiche technique officielle" : isZh ? "官方数据手册" : isDe ? "Offizielles Datenblatt" : "Datasheet oficial"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only"> {isEs ? "(abre en una nueva pestaña)" : isEn ? "(opens in a new tab)" : isFr ? "(ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? "(öffnet in neuem Tab)" : "(abre em nova aba)"}</span>
</a>
) : (
<span className="text-sm text-muted">
{isEs ? "Datasheet aún no publicado" : isEn ? "Datasheet not yet published" : isFr ? "Fiche technique pas encore publiée" : isZh ? "数据手册尚未发布" : isDe ? "Datenblatt noch nicht veröffentlicht" : "Datasheet ainda não publicado"}
</span>
)}
</div>
);
})}
</div>
<div className="panel mt-10 flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
<div className="max-w-2xl">
<h2 className="section-title">
{isEs ? "¿Desea probar en banco?" : isEn ? "Want to test on the bench?" : isFr ? "Envie de tester sur l'établi ?" : isZh ? "想在工作台上试试?" : isDe ? "Möchten Sie es auf dem Prüfplatz testen ?" : "Quer testar na bancada?"}
</h2>
<p className="mt-3 text-base text-muted">
{isEs
? "Vea las placas de desarrollo con patillaje, periféricos y enlace a la tienda oficial."
: isEn
? "Explore development boards with pinouts, peripherals, and official store links."
: isFr
? "Découvrez les cartes de développement avec brochage, périphériques et lien vers la boutique officielle."
: isZh ? "查看带引脚、外设和商店链接的开发板。" : isDe
? "Entdecken Sie die Entwicklungsboards mit Pinbelegung, Peripherie und Link zum offiziellen Store."
: "Veja as placas de desenvolvimento com pinagem, periféricos e link para a loja."}
</p>
</div>
<Link href={getLocalizedHref("/catalogo", currentLocale)} className="btn btn-primary shrink-0">
{isEs ? "Ver catálogo de placas" : isEn ? "View boards catalog" : isFr ? "Voir le catalogue de cartes" : isZh ? "查看开发板目录" : isDe ? "Board-Katalog ansehen" : "Ver catálogo de placas"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
</section>
</main>
<Footer />
</div>
);
}