"use client"; import { useState, useMemo } from "react"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; import PageHero from "@/components/PageHero"; import SectionHead from "@/components/SectionHead"; import { CATEGORIAS_COMPONENTES, COMPONENTES_REGISTRY, GUIA_COMPONENT_MANAGER } from "@/lib/componentRegistryData"; import { ArrowUpRight, Box, Brain, Check, CircuitBoard, Cloud, Copy, Cpu, Download, HelpCircle, Home, Layers, Monitor, Plus, Search, ShieldCheck, Terminal, Trash2, Wrench, X, } from "lucide-react"; const ICONES_CATEGORIA = { ui_display: Monitor, cloud_conectividade: Cloud, audio_voz_ia: Brain, smart_home_mesh: Home, drivers_perifericos: Cpu, bsp_placas: CircuitBoard, sistema_utilitarios: Wrench, }; export default function ComponentRegistryPage() { const [busca, setBusca] = useState(""); const [categoriaAtiva, setCategoriaAtiva] = useState("todos"); const [chipFiltro, setChipFiltro] = useState("todos"); const [copiadoId, setCopiadoId] = useState(null); const [manifestoCopiado, setManifestoCopiado] = useState(false); // Componentes selecionados no construtor de idf_component.yml const [componentesSelecionados, setComponentesSelecionados] = useState([ "espressif-esp_lvgl_port", "espressif-led_indicator" ]); // Lista de chips únicos para filtro const chipsDisponiveis = ["todos", "ESP32", "ESP32-S3", "ESP32-C6", "ESP32-P4", "ESP32-H2", "ESP32-C3"]; // Filtragem dos componentes const componentesFiltrados = useMemo(() => { return COMPONENTES_REGISTRY.filter((comp) => { const matchCategoria = categoriaAtiva === "todos" || comp.categoria === categoriaAtiva; const matchChip = chipFiltro === "todos" || (comp.chips && comp.chips.includes(chipFiltro)); const matchBusca = busca.trim() === "" || comp.name.toLowerCase().includes(busca.toLowerCase()) || comp.namespace.toLowerCase().includes(busca.toLowerCase()) || comp.titulo.toLowerCase().includes(busca.toLowerCase()) || comp.descricao.toLowerCase().includes(busca.toLowerCase()) || comp.tags.some((t) => t.toLowerCase().includes(busca.toLowerCase())); return matchCategoria && matchChip && matchBusca; }); }, [busca, categoriaAtiva, chipFiltro]); // Manipuladores de cópia const copiarComando = (id, comando) => { navigator.clipboard.writeText(comando); setCopiadoId(id); setTimeout(() => setCopiadoId(null), 2000); }; const toggleSelecaoManifesto = (id) => { setComponentesSelecionados((prev) => prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] ); }; // Geração dinâmica do manifesto YAML const manifestoYaml = useMemo(() => { const selecionados = COMPONENTES_REGISTRY.filter((c) => componentesSelecionados.includes(c.id) ); if (selecionados.length === 0) { return `# Nenhum componente selecionado.\n# Clique em "+ Adicionar ao Manifesto" nos cards abaixo.`; } let yaml = `# main/idf_component.yml\n# Gerado via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/componentes)\n\ndependencies:\n`; selecionados.forEach((c) => { yaml += ` ${c.namespace}/${c.name}: "${c.versao}"\n`; }); return yaml; }, [componentesSelecionados]); const copiarManifesto = () => { navigator.clipboard.writeText(manifestoYaml); setManifestoCopiado(true); setTimeout(() => setManifestoCopiado(false), 2000); }; const baixarManifesto = () => { const blob = new Blob([manifestoYaml], { type: "text/yaml;charset=utf-8" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "idf_component.yml"; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); }; const limparFiltros = () => { setBusca(""); setCategoriaAtiva("todos"); setChipFiltro("todos"); }; const totalFiltros = (busca.trim() ? 1 : 0) + (categoriaAtiva !== "todos" ? 1 : 0) + (chipFiltro !== "todos" ? 1 : 0); return (
Abrir o registro oficial Gerar idf_component.yml

Categoria

{CATEGORIAS_COMPONENTES.map((cat) => { const Icone = ICONES_CATEGORIA[cat.id] ?? Layers; const contagem = cat.id === "todos" ? COMPONENTES_REGISTRY.length : COMPONENTES_REGISTRY.filter((c) => c.categoria === cat.id).length; return ( ); })}

Chip compatível

{chipsDisponiveis.map((chip) => ( ))}

{componentesFiltrados.length} {componentesFiltrados.length === 1 ? "componente" : "componentes"}

{componentesFiltrados.length === 0 ? (
) : (
{componentesFiltrados.map((comp) => { const selecionado = componentesSelecionados.includes(comp.id); const cliCmd = `idf.py add-dependency "${comp.namespace}/${comp.name}${comp.versao}"`; const foiCopiado = copiadoId === comp.id; return (

{comp.namespace}/ {comp.oficial && ( )}

{comp.name}

{comp.titulo}

{comp.versao}

{comp.descricao}

    {comp.tags.map((tag) => (
  • {tag}
  • ))}

{foiCopiado ? "Comando copiado" : ""}

Chips: {comp.chips.join(", ")}

); })}
)}

Gerador de manifesto

Seu idf_component.yml

Salve o arquivo na pasta main/ do projeto e o ESP-IDF baixa todas as bibliotecas na compilação.

{componentesSelecionados.length > 0 && ( )}
{manifestoYaml}
{componentesSelecionados.length > 0 && (
    {componentesSelecionados.map((id) => { const c = COMPONENTES_REGISTRY.find((item) => item.id === id); if (!c) return null; return (
  • {c.name}
  • ); })}
)}
    {GUIA_COMPONENT_MANAGER.vantagens.map((v) => (
  • {v.titulo}

    {v.descricao}

  • ))}

    {GUIA_COMPONENT_MANAGER.comandosCli.map((cmd, i) => (
  • $ {cmd.exemplo}

    {cmd.explicacao}

  • ))}

  • ^1.2.0: aceita atualizações menores e correções (1.2.1, 1.3.0), mas bloqueia mudanças grandes de API (2.0.0). Recomendado.
  • ~1.2.0: aceita só correções de bugs (1.2.1, 1.2.5).
  • 1.2.0: trava na versão exata.
  • *: aceita qualquer versão. Evite em produção.
); }