"use client"; import { useState, useMemo, useRef } from "react"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; import PageHero from "@/components/PageHero"; import Link from "next/link"; import { categoriasGlossario } from "@/lib/glossarioData"; 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 [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(), })) ), [] ); 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) => { navigator.clipboard.writeText(`${window.location.origin}/glossario#${slug}`); setCopiadoSlug(slug); setTimeout(() => setCopiadoSlug(null), 2000); }; const total = termosFiltrados.length; return (
Mais buscados {BUSCAS_POPULARES.map((rotulo) => ( ))}

Categoria

{categoriasGlossario.map((cat) => { const Icone = ICONES[cat.icone] ?? Cpu; return ( ); })}

Ordem alfabética

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

{total} {total === 1 ? "termo" : "termos"} {temFiltroAtivo && com os filtros atuais}

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

{item.termo}

); })}
)}

Do conceito ao chip certo.

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 }) { 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; })} ); }