"use client";
import { useState, useMemo } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import Link from "next/link";
import {
CATEGORIAS_COMPONENTES,
COMPONENTES_REGISTRY,
GUIA_COMPONENT_MANAGER
} from "@/lib/componentRegistryData";
import {
Layers,
Search,
Copy,
Check,
ExternalLink,
Sparkles,
Terminal,
Code2,
Plus,
Trash2,
Download,
Cpu,
Box,
CheckCircle2,
ChevronRight,
HelpCircle,
ArrowRight,
BookOpen,
ShieldCheck,
Zap,
Monitor,
Cloud,
Brain,
Home,
CircuitBoard,
Wrench
} from "lucide-react";
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);
};
// Mapeamento de ícones de categoria
const renderIconeCategoria = (id) => {
switch (id) {
case "ui_display":
return ;
case "cloud_conectividade":
return ;
case "audio_voz_ia":
return ;
case "smart_home_mesh":
return ;
case "drivers_perifericos":
return ;
case "bsp_placas":
return ;
case "sistema_utilitarios":
return ;
default:
return ;
}
};
return (
{/* Top Hero Section */}
ESP-IDF Component Manager
Oficial
ESP Component Registry
O catálogo oficial de pacotes reutilizáveis da Espressif para o ESP-IDF.
Adicione drivers de displays, reconhecimento de voz, pilhas industriais e bibliotecas
com comandos de um clique e geração de manifesto declarativo.
{/* Interactive Search & Filter Bar */}
{/* Search Input */}
setBusca(e.target.value)}
placeholder="Buscar componentes por nome, namespace, funcionalidade ou tags (ex: lvgl, rainmaker, ws2812)..."
className="w-full pl-10 pr-4 py-2.5 bg-slate-50 dark:bg-slate-950/70 border border-slate-250 dark:border-slate-800 rounded-2xl text-xs md:text-sm font-semibold text-slate-800 dark:text-slate-100 placeholder:text-slate-400 focus:outline-hidden focus:ring-2 focus:ring-purple-500 transition-all"
/>
{busca && (
setBusca("")}
className="absolute right-3 top-1/2 -translate-y-1/2 text-xs font-bold text-slate-400 hover:text-slate-600 dark:hover:text-slate-200"
>
Limpar
)}
{/* Chip Filter */}
SoC:
{chipsDisponiveis.map((chip) => (
setChipFiltro(chip)}
className={`px-3 py-1.5 rounded-xl text-xs font-bold shrink-0 transition-all cursor-pointer ${
chipFiltro === chip
? "bg-purple-600 text-white shadow-xs"
: "bg-slate-100 dark:bg-slate-800/80 text-slate-650 dark:text-slate-350 hover:bg-slate-200 dark:hover:bg-slate-700"
}`}
>
{chip === "todos" ? "Todos SoCs" : chip}
))}
{/* Category Tabs */}
{CATEGORIAS_COMPONENTES.map((cat) => {
const ativa = categoriaAtiva === cat.id;
const contagem =
cat.id === "todos"
? COMPONENTES_REGISTRY.length
: COMPONENTES_REGISTRY.filter((c) => c.categoria === cat.id).length;
return (
setCategoriaAtiva(cat.id)}
className={`inline-flex items-center gap-2 px-3.5 py-2 rounded-xl text-xs font-bold shrink-0 transition-all cursor-pointer ${
ativa
? "bg-purple-50 dark:bg-purple-950/60 text-purple-600 dark:text-purple-400 border border-purple-200 dark:border-purple-800/60 shadow-xs"
: "text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/60"
}`}
>
{renderIconeCategoria(cat.id)}
{cat.nome}
{contagem}
);
})}
{/* Components Grid */}
Componentes Disponíveis ({componentesFiltrados.length})
Clique em um comando para copiar para o terminal
{componentesFiltrados.length === 0 ? (
Nenhum componente encontrado para esses filtros.
Tente buscar por termos mais genéricos ou resetar a categoria.
{
setBusca("");
setCategoriaAtiva("todos");
setChipFiltro("todos");
}}
className="mt-4 px-4 py-2 bg-purple-600 text-white rounded-xl text-xs font-bold"
>
Limpar Todos os Filtros
) : (
{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 (
{/* Top Header Card */}
{comp.namespace}/
{comp.oficial && (
Oficial
)}
{comp.name}
{comp.titulo}
{comp.versao}
{comp.descricao}
{/* Tags */}
{comp.tags.map((tag) => (
{tag}
))}
{/* Interactive CLI Action Box */}
Comando CLI
{foiCopiado && (
Copiado!
)}
copiarComando(comp.id, cliCmd)}
className="w-full text-left bg-slate-900 text-slate-100 p-2.5 rounded-xl font-mono text-[11px] hover:bg-slate-800 border border-slate-800 flex items-center justify-between group/cmd transition-colors cursor-pointer"
title="Clique para copiar comando"
>
{cliCmd}
{/* Compatible Chips */}
SoCs Compatíveis:
{comp.chips.map((chip) => (
{chip}
))}
{/* Bottom Actions */}
toggleSelecaoManifesto(comp.id)}
className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl transition-all cursor-pointer ${
selecionado
? "bg-purple-600 text-white shadow-xs"
: "bg-purple-50 dark:bg-purple-950/40 text-purple-600 dark:text-purple-400 border border-purple-200 dark:border-purple-800/40 hover:bg-purple-100"
}`}
>
{selecionado ? (
<>
No Manifesto
>
) : (
<>
Adicionar ao Manifesto
>
)}
);
})}
)}
{/* Interactive Manifest Builder Section */}
Gerador de Manifesto Declarativo
Construtor de `idf_component.yml`
Adicione este arquivo na pasta main/ do seu projeto ESP-IDF para
instalar todas as bibliotecas automaticamente na compilação.
{manifestoCopiado ? (
<>
Manifesto Copiado!
>
) : (
<>
Copiar YAML
>
)}
Baixar .yml
{componentesSelecionados.length > 0 && (
setComponentesSelecionados([])}
className="p-2.5 text-slate-400 hover:text-rose-500 rounded-xl hover:bg-rose-50 dark:hover:bg-rose-950/30 transition-colors"
title="Limpar seleção"
>
)}
{/* YAML Output Terminal */}
{/* Selected components badges */}
Componentes Inclusos ({componentesSelecionados.length}):
{componentesSelecionados.map((id) => {
const c = COMPONENTES_REGISTRY.find((item) => item.id === id);
if (!c) return null;
return (
{c.name}
toggleSelecaoManifesto(id)}
className="hover:text-rose-500 ml-1 cursor-pointer"
title="Remover"
>
×
);
})}
{/* Educational Guide: O que é o Component Manager */}
{GUIA_COMPONENT_MANAGER.titulo}
{GUIA_COMPONENT_MANAGER.resumo}
{/* Vantagens Grid */}
{GUIA_COMPONENT_MANAGER.vantagens.map((v, i) => (
0{i + 1}
{v.titulo}
{v.descricao}
))}
{/* Comandos Essenciais da CLI */}
Comandos Essenciais no Terminal
{GUIA_COMPONENT_MANAGER.comandosCli.map((cmd, i) => (
$ {cmd.exemplo}
{cmd.explicacao}
copiarComando(`cmd-${i}`, cmd.exemplo)}
className="self-start md:self-auto inline-flex items-center gap-1 bg-slate-800 hover:bg-slate-700 px-3 py-1.5 rounded-lg text-[11px] font-bold text-slate-200 transition-colors shrink-0"
>
{copiadoId === `cmd-${i}` ? (
<>
Copiado
>
) : (
<>
Copiar
>
)}
))}
{/* Versioning Semantics Callout */}
Regras de Versionamento Semântico no ESP-IDF
^1.2.0: Permite atualizações menores e correções (ex: 1.2.1, 1.3.0),
mas bloqueia grandes mudanças de API (2.0.0). (Recomendado)
~1.2.0: Permite apenas correções de bugs (ex: 1.2.1, 1.2.5), travando
na mesma versão menor.
1.2.0: Trava na versão exata indicada, sem receber atualizações.
*: Aceita qualquer versão disponível (não recomendado para produção).
);
}