"use client"; import { useState, useMemo, useRef } from "react"; import { usePathname } from "next/navigation"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; import PageHero from "@/components/PageHero"; import Link from "next/link"; import * as glossarioPt from "@/lib/glossarioData"; import * as glossarioEn from "@/lib/data/en/glossario"; import * as glossarioEs from "@/lib/data/es/glossario"; import * as glossarioFr from "@/lib/data/fr/glossario"; import * as glossarioDe from "@/lib/data/de/glossario"; import * as glossarioZh from "@/lib/data/zh-CN/glossario"; import { getLocalizedHref } from "@/i18n/links"; import { ArrowRight, BookOpen, Check, Code2, Cpu, Database, HelpCircle, LayoutGrid, Lightbulb, Link2, BatteryCharging, RotateCcw, Search, ShieldCheck, Sliders, Sparkles, Wifi, X, } from "lucide-react"; const BUSCAS_POPULARES = ["GPIO", "ULP", "PSRAM", "Strapping Pins", "Deep Sleep", "OTA", "Matter", "Secure Boot", "Wi-Fi 6", "MIPI"]; const ICONES = { Cpu, Database, Wifi, Sliders, Sparkles, BatteryCharging, Code2, ShieldCheck }; /** "Processamento, CPU & Silício" vira "Processamento": cabe no filtro sem truncar. */ const nomeCurto = (nome) => nome.split(/,| &/)[0].trim(); export default function GlossarioPage() { 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 = isZh ? "zh-CN" : isDe ? "de" : isFr ? "fr" : isEs ? "es" : isEn ? "en" : "pt"; const { categoriasGlossario } = isZh ? glossarioZh : isDe ? glossarioDe : isFr ? glossarioFr : isEs ? glossarioEs : isEn ? glossarioEn : glossarioPt; const [busca, setBusca] = useState(""); const [categoriaSelecionada, setCategoriaSelecionada] = useState("todas"); const [letraFiltro, setLetraFiltro] = useState(null); const [copiadoSlug, setCopiadoSlug] = useState(null); const searchInputRef = useRef(null); const todosOsTermos = useMemo( () => categoriasGlossario.flatMap((cat) => cat.termos.map((t) => ({ ...t, categoriaId: cat.id, categoriaNome: cat.nome, categoriaIcone: cat.icone, slug: t.termo.toLowerCase().replace(/[\s()/²]+/g, "-"), primeiraLetra: t.termo.charAt(0).toUpperCase(), })) ), [categoriasGlossario] ); const alfabeto = useMemo(() => { const disponiveis = new Set(todosOsTermos.map((t) => t.primeiraLetra)); return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").map((letra) => ({ letra, temTermos: disponiveis.has(letra) })); }, [todosOsTermos]); const termosFiltrados = useMemo(() => { const termoBusca = busca.toLowerCase().trim(); return todosOsTermos.filter((item) => { const matchCategoria = categoriaSelecionada === "todas" || item.categoriaId === categoriaSelecionada; const matchLetra = !letraFiltro || item.primeiraLetra === letraFiltro; const matchBusca = !termoBusca || item.termo.toLowerCase().includes(termoBusca) || item.definicao.toLowerCase().includes(termoBusca) || item.exemplo.toLowerCase().includes(termoBusca) || item.categoriaNome.toLowerCase().includes(termoBusca); return matchCategoria && matchLetra && matchBusca; }); }, [todosOsTermos, categoriaSelecionada, letraFiltro, busca]); const temFiltroAtivo = busca.trim() !== "" || categoriaSelecionada !== "todas" || letraFiltro !== null; const limparTodosFiltros = () => { setBusca(""); setCategoriaSelecionada("todas"); setLetraFiltro(null); searchInputRef.current?.focus(); }; const copiarLinkTermo = (slug) => { const basePath = getLocalizedHref("/glossario", currentLocale); navigator.clipboard.writeText(`${window.location.origin}${basePath}#${slug}`); setCopiadoSlug(slug); setTimeout(() => setCopiadoSlug(null), 2000); }; const total = termosFiltrados.length; return (
{isZh ? "热门搜索" : isDe ? "Häufig gesucht" : isFr ? "Plus recherchés" : isEs ? "Más buscados" : isEn ? "Popular searches" : "Mais buscados"} {BUSCAS_POPULARES.map((rotulo) => ( ))}

{isZh ? "类别" : isDe ? "Kategorie" : isFr ? "Catégorie" : isEs ? "Categoría" : isEn ? "Category" : "Categoria"}

{categoriasGlossario.map((cat) => { const Icone = ICONES[cat.icone] ?? Cpu; return ( ); })}
{/* O filtro A–Z não faz sentido em chinês: os termos começam por ideogramas. */} {!isZh && (

{isZh ? "按字母顺序" : isDe ? "Alphabetische Reihenfolge" : isFr ? "Ordre alphabétique" : isEs ? "Orden alfabético" : isEn ? "Alphabetical order" : "Ordem alfabética"}

{alfabeto.map(({ letra, temTermos }) => ( ))}
)}

{total}{" "} {total === 1 ? isZh ? "个术语" : isDe ? "Begriff" : isFr ? "terme" : isEs ? "término" : isEn ? "term" : "termo" : isZh ? "个术语" : isDe ? "Begriffe" : isFr ? "termes" : isEs ? "términos" : isEn ? "terms" : "termos"} {temFiltroAtivo && ( {isZh ? "(当前筛选下)" : isDe ? " mit den aktuellen Filtern" : isFr ? " avec les filtres actuels" : isEs ? " con los filtros actuales" : isEn ? " with current filters" : " com os filtros atuais"} )}

{temFiltroAtivo && ( )}
{total === 0 ? (
) : (
{termosFiltrados.map((item) => { const Icone = ICONES[item.categoriaIcone] ?? Cpu; return (

{item.termo}

); })}
)}

{isZh ? "从概念到合适的芯片。" : isDe ? "Vom Konzept zum richtigen Chip." : isFr ? "Du concept à la bonne puce." : isEs ? "Del concepto al chip adecuado." : isEn ? "From concept to the right chip." : "Do conceito ao chip certo."}

{isZh ? "掌握这些术语后,可以并排对比各系列,或回答选型问题,找到适合你项目的型号。" : isDe ? "Mit den Begriffen zur Hand vergleichen Sie die Serien Seite an Seite oder nutzen Sie die Auswahlhilfe, um das Modell für Ihr Projekt zu finden." : isFr ? "Avec les termes sous la main, comparez les séries côte à côte ou répondez au sélecteur pour trouver le modèle adapté à votre projet." : isEs ? "Con los términos a mano, compare las series lado a lado o responda al selector para encontrar el modelo que se adapta a su proyecto." : isEn ? "With the terms in hand, compare series side by side or answer the selector to find the model that fits your project." : "Com os termos em mãos, compare as séries lado a lado ou responda ao seletor para chegar ao modelo que cabe no seu projeto."}

); } /** * Função utilitária que detecta nomes de séries do ESP32 dentro do texto e os converte em links clicáveis. */ function TextoComLinks({ texto, currentLocale = "pt" }) { if (!texto) return null; const seriesKeys = [ "ESP32-S31", "ESP32-C61", "ESP32-S2", "ESP32-S3", "ESP32-C2", "ESP32-C3", "ESP32-C5", "ESP32-C6", "ESP32-P4", "ESP32-H2", "ESP32-H4", "ESP32", ]; const regex = new RegExp(`\\b(${seriesKeys.join("|")})\\b`, "g"); const partes = texto.split(regex); return ( <> {partes.map((parte, i) => { if (seriesKeys.includes(parte)) { return ( {parte} ); } return parte; })} ); }