feat: add theme consistency guidelines and pin restrictions component

- Introduced DESIGN.md to outline rules for maintaining consistent light and dark themes, including color scales, symmetry rules, and contrast requirements.
- Added PinRestrictions component to display pin usage restrictions based on series data, ensuring accurate representation of pin functionalities.
- Implemented auditing script (auditar-temas.mjs) to check for theme consistency issues, including nonexistent tones, inverted pairs, low contrast, and inline fixed colors.
This commit is contained in:
Lucas Rayan committed 2026-08-20 05:37:56 -03:00
1 parent d4872fcf07
commit 8a52e79d21
23 files changed
+1253 -282

No files matched your search

+17 -17
View File
@@ -149,13 +149,13 @@ export default function PlacasPage() {
if (loading) {
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 flex flex-col justify-between">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 flex flex-col justify-between">
<Header />
<main className="max-w-7xl mx-auto px-6 py-24 flex-1 flex items-center justify-center">
<div className="text-center select-none animate-pulse">
<RefreshCw className="w-12 h-12 text-purple-500 animate-spin mx-auto mb-4" />
<p className="text-xs font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest">Consultando banco de placas...</p>
<p className="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest">Consultando banco de placas...</p>
</div>
</main>
@@ -166,20 +166,20 @@ export default function PlacasPage() {
if (error) {
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 flex flex-col justify-between">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 flex flex-col justify-between">
<Header />
<main className="max-w-7xl mx-auto px-6 py-24 flex-1 flex items-center justify-center">
<div className="text-center bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-8 max-w-md shadow-2xl select-none">
<div className="text-center bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-8 max-w-md shadow-2xl select-none">
<div className="w-12 h-12 bg-red-500/10 border border-red-500/20 rounded-2xl flex items-center justify-center text-red-500 mx-auto mb-4">
<AlertTriangle className="w-6 h-6" />
</div>
<p className="text-sm font-bold text-red-600 dark:text-red-400 mb-2 uppercase tracking-widest">Falha ao sincronizar dados</p>
<p className="text-xs text-slate-450 dark:text-slate-550 mb-6 leading-relaxed">{error}</p>
<p className="text-xs text-slate-500 dark:text-slate-400 mb-6 leading-relaxed">{error}</p>
<button
onClick={fetchBoards}
className="inline-flex items-center gap-2 bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 px-5 py-3 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 active:scale-95 transition-all shadow-md cursor-pointer"
className="inline-flex items-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-5 py-3 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 active:scale-95 transition-all shadow-md cursor-pointer"
>
<RefreshCw className="w-4 h-4" />
<span>Tentar Novamente</span>
@@ -195,13 +195,13 @@ export default function PlacasPage() {
const filterableColumns = headers.filter(h => !excludedColumns.includes(h));
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main id="conteudo" className="max-w-7xl mx-auto px-6 pt-16 pb-24">
{/* Top Hero Heading Block */}
<section className="text-center mb-16 select-none">
<div className="inline-flex items-center gap-2 bg-white/70 dark:bg-slate-900/50 backdrop-blur-md px-4 py-2 rounded-full mb-6 border border-slate-200/60 dark:border-slate-800/60 shadow-xs">
<div className="inline-flex items-center gap-2 bg-white dark:bg-slate-900/50 backdrop-blur-md px-4 py-2 rounded-full mb-6 border border-slate-300 dark:border-slate-800/60 shadow-xs">
<ShoppingCart className="w-4 h-4 text-purple-500" />
<span className="text-xs font-bold text-slate-700 dark:text-slate-350 uppercase tracking-wider">Encontre sua placa ideal</span>
</div>
@@ -225,7 +225,7 @@ export default function PlacasPage() {
<div className="grid lg:grid-cols-4 gap-8">
{/* Left Filters Sidebar */}
<div className="lg:col-span-1">
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl shadow-xl overflow-hidden sticky top-4">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl shadow-xl overflow-hidden sticky top-4">
{/* Sidebar Banner Header */}
<div className="bg-gradient-to-r from-blue-600 to-purple-600 p-6 text-white select-none">
@@ -257,7 +257,7 @@ export default function PlacasPage() {
<div className="p-6 space-y-6">
{/* Text search by name */}
<div>
<label className="block text-[9px] font-bold text-slate-400 dark:text-slate-500 mb-2.5 uppercase tracking-widest select-none">
<label className="block text-[9px] font-bold text-slate-500 dark:text-slate-400 mb-2.5 uppercase tracking-widest select-none">
Buscar Placa
</label>
<div className="relative">
@@ -266,13 +266,13 @@ export default function PlacasPage() {
placeholder="Digite o nome da placa..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-4 py-3 pl-10 border border-slate-200 dark:border-slate-800 rounded-2xl focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-500 focus:outline-none transition-colors text-xs bg-slate-50/50 dark:bg-slate-950/20 text-slate-800 dark:text-slate-100"
className="w-full px-4 py-3 pl-10 border border-slate-300 dark:border-slate-800 rounded-2xl focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-500 focus:outline-none transition-colors text-xs bg-slate-50/50 dark:bg-slate-950/20 text-slate-800 dark:text-slate-100"
/>
<Search className="absolute left-3.5 top-3.5 w-4 h-4 text-slate-400 dark:text-slate-500" />
<Search className="absolute left-3.5 top-3.5 w-4 h-4 text-slate-500 dark:text-slate-400" />
</div>
</div>
<div className="border-t border-slate-100 dark:border-slate-850/45 my-2"></div>
<div className="border-t border-slate-200 dark:border-slate-850/45 my-2"></div>
{/* Dinamic filters container with customized scrollbar */}
<div className="space-y-4 max-h-[calc(100vh-450px)] overflow-y-auto pr-2 custom-scrollbar">
@@ -283,7 +283,7 @@ export default function PlacasPage() {
const isActive = activeFilters[column]?.length > 0;
return (
<div key={column} className={`pb-3 border-b border-slate-100 dark:border-slate-850/30 last:border-b-0 ${isActive ? 'bg-purple-500/5 dark:bg-purple-400/5 p-3 rounded-2xl border border-purple-500/10 dark:border-purple-400/10' : ''}`}>
<div key={column} className={`pb-3 border-b border-slate-200 dark:border-slate-850/30 last:border-b-0 ${isActive ? 'bg-purple-500/5 dark:bg-purple-400/5 p-3 rounded-2xl border border-purple-500/10 dark:border-purple-400/10' : ''}`}>
{filterData.isBinary ? (
// Binary filter (checkbox inside title wrapper)
<label className="flex justify-between items-center cursor-pointer p-1 rounded-lg transition-all group select-none">
@@ -341,14 +341,14 @@ export default function PlacasPage() {
{/* Right Catalog Boards Grid */}
<div className="lg:col-span-3">
<div className="mb-6 flex justify-between items-center select-none">
<p className="text-xs font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest">
<p className="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest">
Total Encontrado: <span className="text-purple-650 dark:text-purple-400">{filteredBoards.length}</span> Placa(s)
</p>
</div>
{filteredBoards.length === 0 ? (
<div className="text-center py-20 bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-8 shadow-md select-none">
<Search className="w-12 h-12 text-slate-300 dark:text-slate-700 mx-auto mb-4" />
<div className="text-center py-20 bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-8 shadow-md select-none">
<Search className="w-12 h-12 text-slate-450 mx-auto mb-4" />
<p className="text-base font-display font-extrabold text-slate-800 dark:text-slate-200 mb-1">Nenhuma Placa Correspondente</p>
<p className="text-xs text-slate-500 dark:text-slate-400">Tente ajustar ou redefinir seus filtros laterais para expandir a busca.</p>
</div>
+46 -20
View File
@@ -22,7 +22,8 @@ import {
Activity,
HelpCircle,
Thermometer,
ShieldCheck
ShieldCheck,
Package
} from "lucide-react";
// Category to Icon mapping
@@ -34,10 +35,16 @@ const categoryIcons = {
"Periféricos Digitais": <Sliders className="w-4 h-4 text-sky-500" />,
"Periféricos Analógicos": <Activity className="w-4 h-4 text-emerald-500" />,
"Segurança": <ShieldCheck className="w-4 h-4 text-teal-500" />,
"Disponibilidade e Ferramentas": <Package className="w-4 h-4 text-amber-500" />,
"Interfaces Especiais": <Activity className="w-4 h-4 text-cyan-500" />,
"Especificações Ambientais": <Thermometer className="w-4 h-4 text-red-500" />,
};
/* Lê "seguranca.ecc" além de chaves simples. */
function valorDe(objeto, caminho) {
return caminho.split(".").reduce((atual, parte) => atual?.[parte], objeto);
}
export default function Comparacao() {
const [selectedSeries, setSelectedSeries] = useState(["ESP32", "ESP32-S3"]);
const [collapsedCategories, setCollapsedCategories] = useState({
@@ -71,6 +78,13 @@ export default function Comparacao() {
{ 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" },
@@ -101,6 +115,7 @@ export default function Comparacao() {
{ 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: [
@@ -111,7 +126,18 @@ export default function Comparacao() {
{ key: "sensor_temperatura", label: "Sensor de Temperatura" },
]},
{ category: "Segurança", fields: [
{ key: "aceleradores_cripto", label: "Aceleradores Criptográficos" },
{ 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" },
@@ -128,7 +154,7 @@ export default function Comparacao() {
const renderValue = (value) => {
if (!value || value === "Não") {
return <span className="text-slate-400 dark:text-slate-600 font-medium select-none">—</span>;
return <span className="text-slate-500 dark:text-slate-400 font-medium select-none">—</span>;
}
if (value === "Sim") {
return (
@@ -141,7 +167,7 @@ export default function Comparacao() {
};
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main id="conteudo" className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
@@ -163,13 +189,13 @@ export default function Comparacao() {
{/* Model Selector Card */}
<section className="mb-12">
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-6 md:p-8 shadow-2xl relative overflow-hidden">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-6 md:p-8 shadow-2xl relative overflow-hidden">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6">
<div>
<h2 className="text-lg font-bold text-slate-800 dark:text-slate-100 mb-1">
Escolha as Séries
</h2>
<p className="text-xs text-slate-400 dark:text-slate-500">
<p className="text-xs text-slate-500 dark:text-slate-400">
Selecione de 2 a até 4 modelos simultâneos para montar sua planilha de comparação.
</p>
</div>
@@ -189,12 +215,12 @@ export default function Comparacao() {
key={key}
onClick={() => toggleSeries(key)}
style={{
borderColor: isSelected ? seriesItem.cor : 'transparent'
borderColor: isSelected ? seriesItem.cor : undefined
}}
className={`p-4 border rounded-2xl transition-all duration-300 cursor-pointer active:scale-95 text-center flex flex-col items-center justify-center shadow-xs ${
isSelected
? 'bg-slate-100 dark:bg-slate-950 shadow-md scale-[1.02] border-2'
: 'border-slate-200/60 dark:border-slate-800/80 bg-white/70 dark:bg-slate-900/30 hover:border-purple-400/50 hover:bg-purple-500/5'
: 'border-slate-300 dark:border-slate-800/80 bg-white dark:bg-slate-900/30 hover:border-purple-400/50 hover:bg-purple-500/5'
}`}
>
<div className="text-3xl mb-2 select-none transform hover:scale-110 transition-transform">{seriesItem.icone}</div>
@@ -214,7 +240,7 @@ export default function Comparacao() {
</section>
{/* Side by side interactive Table */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl overflow-hidden shadow-2xl">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl overflow-hidden shadow-2xl">
<div className="overflow-x-auto scrollbar-thin">
<table className="w-full border-collapse">
<thead>
@@ -267,14 +293,14 @@ export default function Comparacao() {
{!isCollapsed && fields.map(({ key, label }) => (
<tr
key={key}
className="border-b border-slate-100 dark:border-slate-800/40 hover:bg-purple-500/5 dark:hover:bg-purple-400/5 transition-colors group"
className="border-b border-slate-200 dark:border-slate-800/40 hover:bg-purple-500/5 dark:hover:bg-purple-400/5 transition-colors group"
>
<td className="px-6 py-4 font-bold text-slate-600 dark:text-slate-400 text-xs bg-white dark:bg-slate-900/10 sticky left-0 border-r border-slate-150/60 dark:border-slate-800/60 shrink-0 z-10">
{label}
</td>
{selectedSeries.map(seriesKey => {
const seriesItem = seriesData[seriesKey];
const value = seriesItem[key];
const value = valorDe(seriesItem, key);
return (
<td key={seriesKey} className="px-6 py-4 text-center text-xs">
{renderValue(value)}
@@ -292,26 +318,26 @@ export default function Comparacao() {
</div>
{/* Professional CTA Banner for the Catalog */}
<div className="my-20 bg-gradient-to-br from-slate-900 to-indigo-950 dark:from-slate-950 dark:to-purple-950/20 border border-slate-800/80 rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden">
<div className="my-20 bg-gradient-to-br from-indigo-50 to-purple-50 dark:from-slate-950 dark:to-purple-950/20 border border-indigo-200 dark:border-slate-800/80 rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden">
<div className="absolute right-0 bottom-0 w-96 h-96 bg-purple-500/5 rounded-full blur-3xl pointer-events-none" />
<div className="flex flex-col md:flex-row items-center justify-between gap-8 relative z-10">
<div className="flex-1 max-w-2xl text-center md:text-left">
<div className="inline-flex items-center gap-2 bg-white/10 text-slate-350 px-3 py-1 rounded-full mb-4 text-xs font-semibold select-none">
<div className="inline-flex items-center gap-2 bg-indigo-500/10 text-indigo-700 dark:bg-white/10 dark:text-slate-350 px-3 py-1 rounded-full mb-4 text-xs font-semibold select-none">
<ShoppingBag className="w-3.5 h-3.5" />
<span>Hardware Adicional</span>
</div>
<h3 className="text-2xl md:text-3xl font-display font-extrabold text-white mb-4">
<h3 className="text-2xl md:text-3xl font-display font-extrabold text-slate-900 dark:text-white mb-4">
Catálogo de Placas de Desenvolvimento
</h3>
<p className="text-sm text-slate-400 leading-relaxed">
<p className="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
Quer testar o chip selecionado na bancada? Compare placas de desenvolvimento com layouts de pinos mapeados, conexões de periféricos e links oficiais dos melhores fornecedores.
</p>
</div>
<Link
href="/catalogo"
className="inline-flex items-center justify-center gap-2 bg-white text-slate-900 px-6 py-3.5 rounded-xl font-bold text-sm hover:bg-slate-100 transition-all duration-300 shrink-0 shadow-md active:scale-95"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-6 py-3.5 rounded-xl font-bold text-sm hover:opacity-90 transition-all duration-300 shrink-0 shadow-md active:scale-95"
>
<span>Acessar Catálogo</span>
<ArrowRight className="w-4 h-4" />
@@ -330,7 +356,7 @@ export default function Comparacao() {
return (
<div
key={seriesKey}
className="bg-white/70 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/80 dark:border-slate-800/80 p-5 rounded-2xl hover:border-purple-500/50 dark:hover:border-purple-400/50 hover:shadow-lg transition-all duration-300 flex flex-col justify-between"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 p-5 rounded-2xl hover:border-purple-500/50 dark:hover:border-purple-400/50 hover:shadow-lg transition-all duration-300 flex flex-col justify-between"
>
<div className="flex gap-4 items-start mb-4">
<div className="text-4xl select-none">{seriesItem.icone}</div>
@@ -340,7 +366,7 @@ export default function Comparacao() {
{seriesKey}
</h4>
</Link>
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-bold uppercase tracking-wider mt-1">Guia de Hardware</p>
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-bold uppercase tracking-wider mt-1">Guia de Hardware</p>
</div>
</div>
@@ -349,13 +375,13 @@ export default function Comparacao() {
href={seriesItem.datasheet}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-1.5 w-full text-center py-2 bg-slate-100 dark:bg-slate-950 hover:bg-purple-500/10 dark:hover:bg-purple-400/10 border border-slate-200 dark:border-slate-800 rounded-xl text-xs font-bold text-slate-650 dark:text-slate-350 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
className="inline-flex items-center justify-center gap-1.5 w-full text-center py-2 bg-slate-100 dark:bg-slate-950 hover:bg-purple-500/10 dark:hover:bg-purple-400/10 border border-slate-300 dark:border-slate-800 rounded-xl text-xs font-bold text-slate-650 dark:text-slate-350 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
>
<span>Datasheet Oficial</span>
<ExternalLink className="w-3.5 h-3.5" />
</a>
) : (
<span className="inline-flex items-center justify-center gap-1.5 w-full text-center py-2 bg-slate-100 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl text-xs font-bold text-slate-400 dark:text-slate-500 select-none">
<span className="inline-flex items-center justify-center gap-1.5 w-full text-center py-2 bg-slate-100 dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl text-xs font-bold text-slate-500 dark:text-slate-400 select-none">
<span>Datasheet ainda não publicado</span>
</span>
)}
+20 -20
View File
@@ -31,7 +31,7 @@ export default async function FrameworkDetail({ params }) {
const useCases = framework.casos_uso || [];
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
@@ -47,7 +47,7 @@ export default async function FrameworkDetail({ params }) {
{/* Top Info Banner Panel */}
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 shadow-2xl border relative overflow-hidden"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 shadow-2xl border relative overflow-hidden"
style={{ borderColor: `${framework.cor}40` }}
>
<div className="flex flex-col lg:flex-row items-start lg:items-center justify-between gap-8">
@@ -57,7 +57,7 @@ export default async function FrameworkDetail({ params }) {
<h1 className="text-4xl font-display font-extrabold text-slate-850 dark:text-slate-100 tracking-tight leading-none mb-3">
{framework.nome}
</h1>
<p className="text-sm font-semibold text-slate-400 dark:text-slate-500 mb-4">{framework.nome_completo}</p>
<p className="text-sm font-semibold text-slate-500 dark:text-slate-400 mb-4">{framework.nome_completo}</p>
<span
className="inline-block px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest select-none"
style={{ backgroundColor: `${framework.cor}18`, color: framework.cor, border: `1px solid ${framework.cor}30` }}
@@ -74,7 +74,7 @@ export default async function FrameworkDetail({ params }) {
href={framework.documentacao}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-2 bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 px-5 py-3 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-lg"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-5 py-3 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-lg"
>
<BookOpen className="w-4 h-4" />
<span>Documentação Oficial</span>
@@ -104,10 +104,10 @@ export default async function FrameworkDetail({ params }) {
{/* Framework Core Specifications Grid */}
<div className="grid md:grid-cols-3 gap-6 mb-8 select-none animate-fadeIn">
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
style={{ borderColor: framework.cor }}
>
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5">
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1.5 flex items-center gap-1.5">
<Code className="w-3.5 h-3.5 text-blue-500" />
<span>LINGUAGEM DE DESENVOLVIMENTO</span>
</h3>
@@ -116,10 +116,10 @@ export default async function FrameworkDetail({ params }) {
</div>
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
style={{ borderColor: framework.cor }}
>
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5">
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1.5 flex items-center gap-1.5">
<Layers className="w-3.5 h-3.5 text-purple-500" />
<span>CATEGORIA DO FRAMEWORK</span>
</h3>
@@ -128,10 +128,10 @@ export default async function FrameworkDetail({ params }) {
</div>
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
style={{ borderColor: framework.cor }}
>
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-450 mb-1.5 flex items-center gap-1.5">
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 mb-1.5 flex items-center gap-1.5">
<Target className="w-3.5 h-3.5 text-emerald-500" />
<span>OBJETIVO PRINCIPAL</span>
</h3>
@@ -142,7 +142,7 @@ export default async function FrameworkDetail({ params }) {
{/* side-by-side details block */}
<div className="grid lg:grid-cols-3 gap-6 mb-8 items-start">
{/* Left specs card */}
<div className="lg:col-span-2 bg-white/80 dark:bg-slate-900/45 backdrop-blur-xl rounded-3xl p-8 border border-slate-200/60 dark:border-slate-800/80 shadow-2xl space-y-8">
<div className="lg:col-span-2 bg-white dark:bg-slate-900/45 backdrop-blur-xl rounded-3xl p-8 border border-slate-300 dark:border-slate-800/80 shadow-2xl space-y-8">
<div>
<h2
className="text-lg font-display font-extrabold text-slate-850 dark:text-slate-100 mb-6 pb-3 border-b flex items-center gap-2.5 select-none"
@@ -183,7 +183,7 @@ export default async function FrameworkDetail({ params }) {
</div>
{/* Right summary metadata card */}
<div className="bg-white/80 dark:bg-slate-900/45 backdrop-blur-xl rounded-3xl p-8 border border-slate-200/60 dark:border-slate-800/80 shadow-2xl select-none">
<div className="bg-white dark:bg-slate-900/45 backdrop-blur-xl rounded-3xl p-8 border border-slate-300 dark:border-slate-800/80 shadow-2xl select-none">
<h2
className="text-lg font-display font-extrabold text-slate-850 dark:text-slate-100 mb-6 pb-3 border-b flex items-center gap-2.5"
style={{ borderBottomColor: `${framework.cor}30` }}
@@ -193,20 +193,20 @@ export default async function FrameworkDetail({ params }) {
</h2>
<div className="space-y-4 text-xs font-bold text-slate-650 dark:text-slate-200">
<div className="flex justify-between items-center py-2 border-b border-slate-100 dark:border-slate-850/45">
<span className="text-slate-400 dark:text-slate-500 uppercase tracking-wider text-[9px]">Nome Oficial</span>
<div className="flex justify-between items-center py-2 border-b border-slate-200 dark:border-slate-850/45">
<span className="text-slate-500 dark:text-slate-400 uppercase tracking-wider text-[9px]">Nome Oficial</span>
<span className="text-slate-800 dark:text-slate-200 font-extrabold">{framework.nome}</span>
</div>
<div className="flex justify-between items-center py-2 border-b border-slate-100 dark:border-slate-850/45">
<span className="text-slate-400 dark:text-slate-500 uppercase tracking-wider text-[9px]">Linguagem</span>
<div className="flex justify-between items-center py-2 border-b border-slate-200 dark:border-slate-850/45">
<span className="text-slate-500 dark:text-slate-400 uppercase tracking-wider text-[9px]">Linguagem</span>
<span className="text-slate-800 dark:text-slate-200 font-extrabold">{framework.linguagem}</span>
</div>
<div className="flex justify-between items-center py-2 border-b border-slate-100 dark:border-slate-850/45">
<span className="text-slate-400 dark:text-slate-500 uppercase tracking-wider text-[9px]">Tipo / Suite</span>
<div className="flex justify-between items-center py-2 border-b border-slate-200 dark:border-slate-850/45">
<span className="text-slate-500 dark:text-slate-400 uppercase tracking-wider text-[9px]">Tipo / Suite</span>
<span className="text-slate-800 dark:text-slate-200 font-extrabold">{framework.tipo}</span>
</div>
<div className="flex justify-between items-center py-2">
<span className="text-slate-400 dark:text-slate-500 uppercase tracking-wider text-[9px]">Cor Temática</span>
<span className="text-slate-500 dark:text-slate-400 uppercase tracking-wider text-[9px]">Cor Temática</span>
<div className="flex items-center gap-2">
<code className="text-[10px] text-slate-500 uppercase">{framework.cor}</code>
<span className="inline-block w-4 h-4 rounded-md shadow-xs border border-white/20" style={{ backgroundColor: framework.cor }} />
@@ -230,7 +230,7 @@ export default async function FrameworkDetail({ params }) {
href={framework.documentacao}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-2 bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 px-6 py-3.5 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-lg"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-6 py-3.5 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-lg"
>
<BookOpen className="w-4 h-4" />
<span>Documentação do Desenvolvedor</span>
+18 -18
View File
@@ -23,13 +23,13 @@ export default function Frameworks() {
const frameworks = Object.entries(frameworksData);
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main id="conteudo" className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
{/* Top Hero Section */}
<section className="text-center mb-16 select-none">
<div className="inline-flex items-center gap-2 bg-white/70 dark:bg-slate-900/50 backdrop-blur-md px-4 py-2 rounded-full mb-6 border border-slate-200/60 dark:border-slate-800/60 shadow-xs">
<div className="inline-flex items-center gap-2 bg-white dark:bg-slate-900/50 backdrop-blur-md px-4 py-2 rounded-full mb-6 border border-slate-300 dark:border-slate-800/60 shadow-xs">
<Layers className="w-4 h-4 text-purple-500" />
<span className="text-xs font-bold text-slate-700 dark:text-slate-350 uppercase tracking-wider">Ferramentas de Desenvolvimento</span>
</div>
@@ -53,11 +53,11 @@ export default function Frameworks() {
className="group flex"
>
<div
className="bg-white/70 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 hover:-translate-y-1.5 flex flex-col justify-between overflow-hidden w-full"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl shadow-lg hover:shadow-2xl transition-all duration-500 hover:-translate-y-1.5 flex flex-col justify-between overflow-hidden w-full"
style={{ borderTop: `4px solid ${framework.cor}` }}
>
<div className="p-6 pb-4 border-b border-slate-100 dark:border-slate-850/40 flex-1">
<div className="p-6 pb-4 border-b border-slate-200 dark:border-slate-850/40 flex-1">
<div className="flex items-center justify-between mb-4">
<span className="text-5xl select-none filter drop-shadow-md">{framework.icone}</span>
<div className="flex flex-col gap-1 items-end select-none">
@@ -78,7 +78,7 @@ export default function Frameworks() {
{framework.nome}
</h2>
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-bold uppercase tracking-wider mb-4 leading-none select-none">
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-bold uppercase tracking-wider mb-4 leading-none select-none">
{framework.nome_completo}
</p>
@@ -91,7 +91,7 @@ export default function Frameworks() {
<div className="space-y-4">
{/* Main Feature */}
<div>
<h4 className="text-[9px] font-bold text-slate-400 dark:text-slate-450 mb-1.5 uppercase tracking-widest flex items-center gap-1.5">
<h4 className="text-[9px] font-bold text-slate-500 dark:text-slate-400 mb-1.5 uppercase tracking-widest flex items-center gap-1.5">
<Target className="w-3.5 h-3.5 text-blue-500" />
<span>Objetivo Principal</span>
</h4>
@@ -102,7 +102,7 @@ export default function Frameworks() {
{/* Key Specs */}
<div>
<h4 className="text-[9px] font-bold text-slate-400 dark:text-slate-450 mb-2 uppercase tracking-widest flex items-center gap-1.5">
<h4 className="text-[9px] font-bold text-slate-500 dark:text-slate-400 mb-2 uppercase tracking-widest flex items-center gap-1.5">
<Zap className="w-3.5 h-3.5 text-amber-500" />
<span>Recursos Chave</span>
</h4>
@@ -118,13 +118,13 @@ export default function Frameworks() {
{/* Use Cases tags */}
<div>
<h4 className="text-[9px] font-bold text-slate-400 dark:text-slate-450 mb-2 uppercase tracking-widest flex items-center gap-1.5">
<h4 className="text-[9px] font-bold text-slate-500 dark:text-slate-400 mb-2 uppercase tracking-widest flex items-center gap-1.5">
<Compass className="w-3.5 h-3.5 text-emerald-500" />
<span>Aplicações Ideais</span>
</h4>
<div className="flex flex-wrap gap-1.5">
{framework.casos_uso.slice(0, 3).map((caso, idx) => (
<span key={idx} className="text-[9px] font-bold bg-slate-100 dark:bg-slate-900/60 text-slate-650 dark:text-slate-200 px-2.5 py-1 rounded-md border border-slate-200/40 dark:border-slate-800/80">
<span key={idx} className="text-[9px] font-bold bg-slate-100 dark:bg-slate-900/60 text-slate-650 dark:text-slate-200 px-2.5 py-1 rounded-md border border-slate-300 dark:border-slate-800/80">
{caso}
</span>
))}
@@ -133,7 +133,7 @@ export default function Frameworks() {
</div>
{/* CTA Link */}
<div className="pt-4 border-t border-slate-100 dark:border-slate-850/40 mt-auto flex items-center justify-between text-xs font-bold text-slate-700 dark:text-slate-300 group-hover:text-purple-650 dark:group-hover:text-purple-400 transition-colors">
<div className="pt-4 border-t border-slate-200 dark:border-slate-850/40 mt-auto flex items-center justify-between text-xs font-bold text-slate-700 dark:text-slate-300 group-hover:text-purple-650 dark:group-hover:text-purple-400 transition-colors">
<span>Acessar Detalhes e Exemplos</span>
<ArrowRight className="w-4 h-4 transform group-hover:translate-x-1.5 transition-transform" />
</div>
@@ -146,7 +146,7 @@ export default function Frameworks() {
{/* Bottom Informative Cards Section */}
<div className="mt-16 grid md:grid-cols-2 gap-8 select-none">
{/* Card 1: Beginner Guide */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl shadow-xl p-8 border border-slate-200/60 dark:border-slate-800/80 flex flex-col justify-between relative overflow-hidden">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl shadow-xl p-8 border border-slate-300 dark:border-slate-800/80 flex flex-col justify-between relative overflow-hidden">
<div>
<div className="flex items-center gap-3.5 mb-5">
<div className="w-12 h-12 bg-blue-500/10 border border-blue-500/20 rounded-2xl flex items-center justify-center text-blue-500">
@@ -169,7 +169,7 @@ export default function Frameworks() {
</p>
</div>
<div className="flex flex-wrap gap-2.5 pt-4 border-t border-slate-100 dark:border-slate-850/40 mt-auto">
<div className="flex flex-wrap gap-2.5 pt-4 border-t border-slate-200 dark:border-slate-850/40 mt-auto">
<Link href="/frameworks/Arduino" className="inline-flex items-center gap-1.5 px-4 py-2.5 bg-blue-500/10 text-blue-600 dark:text-blue-400 border border-blue-500/20 rounded-xl text-xs font-bold hover:bg-blue-500/20 transition-all">
<span>Arduino</span>
<ArrowRight className="w-3.5 h-3.5" />
@@ -186,7 +186,7 @@ export default function Frameworks() {
</div>
{/* Card 2: Specialized Solutions */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl shadow-xl p-8 border border-slate-200/60 dark:border-slate-800/80 flex flex-col justify-between relative overflow-hidden">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl shadow-xl p-8 border border-slate-300 dark:border-slate-800/80 flex flex-col justify-between relative overflow-hidden">
<div>
<div className="flex items-center gap-3.5 mb-5">
<div className="w-12 h-12 bg-purple-500/10 border border-purple-500/20 rounded-2xl flex items-center justify-center text-purple-500">
@@ -210,20 +210,20 @@ export default function Frameworks() {
</p>
</div>
<div className="flex flex-wrap gap-2.5 pt-4 border-t border-slate-100 dark:border-slate-850/40 mt-auto">
<Link href="/frameworks/ESP-ADF" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-200/60 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<div className="flex flex-wrap gap-2.5 pt-4 border-t border-slate-200 dark:border-slate-850/40 mt-auto">
<Link href="/frameworks/ESP-ADF" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Music className="w-3.5 h-3.5 text-blue-500" />
<span>Áudio</span>
</Link>
<Link href="/frameworks/ESP-WHO" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-200/60 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Link href="/frameworks/ESP-WHO" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Camera className="w-3.5 h-3.5 text-orange-500" />
<span>Visão</span>
</Link>
<Link href="/frameworks/ESP-NN" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-200/60 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Link href="/frameworks/ESP-NN" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Brain className="w-3.5 h-3.5 text-teal-500" />
<span>Inteligência Artificial</span>
</Link>
<Link href="/frameworks/ESP-Matter" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-200/60 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Link href="/frameworks/ESP-Matter" className="inline-flex items-center gap-1.5 px-3.5 py-2 bg-slate-150/45 dark:bg-slate-850 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-850/60 rounded-xl text-xs font-bold hover:bg-slate-200 dark:hover:bg-slate-800 transition-all">
<Home className="w-3.5 h-3.5 text-yellow-500" />
<span>Matter</span>
</Link>
+32 -4
View File
@@ -8,6 +8,26 @@
--color-brand-purple: #8b5cf6;
--color-brand-blue: #3b82f6;
--color-brand-pink: #ec4899;
/* ---------------------------------------------------------------------
Meios-tons de slate.
A escala do Tailwind anda de 100 em 100 (50, 100, 200 ... 950), então
classes como text-slate-350 ou border-slate-850 — usadas em ~190 pontos
do projeto — não geravam CSS nenhum: o elemento herdava a cor do pai e
ficava diferente em cada tema, sem padrão.
Cada valor abaixo é o ponto médio exato entre os dois degraus oficiais
vizinhos, então a intenção original de cada classe é preservada.
--------------------------------------------------------------------- */
--color-slate-150: #eaeef4; /* entre 100 e 200 */
--color-slate-250: #d6dee8; /* entre 200 e 300 */
--color-slate-350: #b0bccc; /* entre 300 e 400 */
--color-slate-450: #7c8ca2; /* entre 400 e 500 */
--color-slate-550: #56647a; /* entre 500 e 600 */
--color-slate-650: #3d4b5f; /* entre 600 e 700 */
--color-slate-750: #283548; /* entre 700 e 800 */
--color-slate-850: #162032; /* entre 800 e 900 */
}
/* Enable class-based dark mode selector in Tailwind v4 */
@@ -21,14 +41,22 @@
body {
@apply bg-slate-50 text-slate-900 transition-colors duration-300;
}
body.dark {
/* next-themes aplica a classe .dark no <html>, não no <body>.
O seletor body.dark nunca casava, então o fundo escuro do body vinha
só das classes utilitárias do layout. */
.dark body {
@apply bg-slate-950 text-slate-50;
}
/* Sleek selection highlighting */
/* Seleção de texto: o texto precisa de contraste contra o realce em cada
tema. Roxo claro sobre fundo claro era ilegível no tema claro. */
::selection {
@apply bg-purple-500/30 text-purple-200;
@apply bg-purple-500/30 text-purple-950;
}
.dark ::selection {
@apply bg-purple-500/40 text-purple-50;
}
/* Scrollbar customization for a premium, non-default OS look */
+38 -3
View File
@@ -41,8 +41,43 @@ export default function Glossario() {
},
{
termo: "Aceleradores Criptográficos",
definicao: "Blocos de hardware dedicados que executam algoritmos de criptografia (AES, SHA, RSA, ECC/ECDSA, HMAC) muito mais rápido e com menor consumo do que a CPU, além de sustentarem recursos como Secure Boot, criptografia de flash e assinatura digital.",
exemplo: "ESP32-C5 e ESP32-P4 incluem AES, SHA, RSA, ECC/ECDSA e Key Manager para provisionamento seguro de chaves.",
definicao: "Blocos de hardware dedicados que executam algoritmos de criptografia muito mais rápido e com menor consumo do que a CPU. Praticamente toda série tem algum, mas o conjunto varia bastante — por isso vale olhar item por item.",
exemplo: "ESP32-C2 e ESP32-C61 não têm acelerador AES: só SHA e curvas elípticas.",
},
{
termo: "ECC (Criptografia de Curvas Elípticas)",
definicao: "Família de algoritmos de chave pública que atinge a mesma segurança do RSA com chaves muito menores, o que economiza memória e tempo em microcontrolador. As curvas usadas são identificadas por nome, como P-256.",
exemplo: "ESP32, ESP32-S2, ESP32-S3 e ESP32-C3 não têm ECC em hardware; ESP32-C5, P4, S31 e H4 chegam à curva P-384.",
},
{
termo: "ECDSA",
definicao: "Algoritmo de assinatura digital baseado em curvas elípticas. Ter o periférico ECDSA no silício significa assinar e verificar sem carregar a CPU — é o que o Matter exige para o atestado de dispositivo.",
exemplo: "Só ESP32-S31, C5, C61, P4, H2 e H4 têm ECDSA em hardware.",
},
{
termo: "Key Manager",
definicao: "Periférico que provisiona e usa chaves criptográficas sem que elas fiquem legíveis para o firmware. Mesmo que alguém extraia a imagem do firmware, a chave privada não está lá.",
exemplo: "Disponível apenas no ESP32-S31, ESP32-C5 e ESP32-P4.",
},
{
termo: "Secure Boot",
definicao: "Verificação da assinatura do firmware durante o boot: o chip se recusa a executar código que não tenha sido assinado pela sua chave. A versão V2 usa RSA-3072 ou ECDSA; a V1, do ESP32 original, é um esquema mais antigo.",
exemplo: "ESP32 tem apenas o Secure Boot V1; do ESP32-S2 em diante todos têm V2.",
},
{
termo: "Criptografia de Flash",
definicao: "Cifra o conteúdo da memória flash externa, impedindo que alguém leia o firmware soldando um gravador no chip de memória. O esquema atual usa XTS-AES.",
exemplo: "XTS-AES-128 na maioria das séries; ESP32-S2, S3, S31, C5, P4 e H4 também suportam XTS-AES-256.",
},
{
termo: "Assinatura Digital (DS)",
definicao: "Periférico que assina dados usando uma chave RSA guardada em eFuse de forma que o firmware nunca a enxerga. É o antecessor mais simples do Key Manager.",
exemplo: "Ausente no ESP32 original, no C2, no C61 e no H4.",
},
{
termo: "Proteção contra DPA",
definicao: "Defesa contra Differential Power Analysis, ataque que deduz a chave secreta medindo variações no consumo de energia do chip durante a operação criptográfica. Exige acesso físico ao dispositivo.",
exemplo: "Presente no ESP32-C5, C6, C61 e H2.",
},
],
},
@@ -334,7 +369,7 @@ export default function Glossario() {
<main id="conteudo" className="px-4 pt-16 pb-20 max-w-7xl mx-auto">
{/* Hero Section */}
<section className="text-center mb-16">
<div className="inline-flex items-center gap-2 bg-white/70 backdrop-blur-sm px-4 py-2 rounded-full mb-6 border border-purple-200 shadow-sm">
<div className="inline-flex items-center gap-2 bg-white backdrop-blur-sm px-4 py-2 rounded-full mb-6 border border-purple-200 shadow-sm">
<span className="text-xl">📖</span>
<span className="text-sm font-semibold text-gray-700">Aprenda os Conceitos</span>
</div>
+1 -1
View File
@@ -23,7 +23,7 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="pt-BR" className={`${outfit.variable} ${inter.variable}`} suppressHydrationWarning>
<body className="font-sans antialiased bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-50 transition-colors duration-300">
<body className="font-sans antialiased bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-50 transition-colors duration-300" suppressHydrationWarning>
<Providers>
{children}
</Providers>
+7 -7
View File
@@ -85,7 +85,7 @@ export default function Home() {
];
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
@@ -115,7 +115,7 @@ export default function Home() {
</Link>
<Link
className="group inline-flex items-center gap-2.5 bg-slate-900 hover:bg-slate-800 dark:bg-slate-800 dark:hover:bg-slate-700 text-white px-7 py-3.5 rounded-xl font-bold text-sm shadow-md hover:-translate-y-0.5 transition-all duration-300 cursor-pointer active:scale-95"
className="group inline-flex items-center gap-2.5 bg-blue-600 hover:bg-blue-700 text-white px-7 py-3.5 rounded-xl font-bold text-sm shadow-md hover:-translate-y-0.5 transition-all duration-300 cursor-pointer active:scale-95"
href="/series"
>
<Cpu className="w-4 h-4" />
@@ -123,7 +123,7 @@ export default function Home() {
</Link>
<Link
className="group inline-flex items-center gap-2.5 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-300 px-7 py-3.5 rounded-xl font-bold text-sm shadow-xs border border-slate-200 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 hover:-translate-y-0.5 transition-all duration-300 cursor-pointer active:scale-95"
className="group inline-flex items-center gap-2.5 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-300 px-7 py-3.5 rounded-xl font-bold text-sm shadow-xs border border-slate-300 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 hover:-translate-y-0.5 transition-all duration-300 cursor-pointer active:scale-95"
href="/frameworks"
>
<Terminal className="w-4 h-4" />
@@ -131,7 +131,7 @@ export default function Home() {
</Link>
<Link
className="group inline-flex items-center gap-2.5 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-300 px-7 py-3.5 rounded-xl font-bold text-sm shadow-xs border border-slate-200 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 hover:-translate-y-0.5 transition-all duration-300 cursor-pointer active:scale-95"
className="group inline-flex items-center gap-2.5 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-300 px-7 py-3.5 rounded-xl font-bold text-sm shadow-xs border border-slate-300 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 hover:-translate-y-0.5 transition-all duration-300 cursor-pointer active:scale-95"
href="/catalogo"
>
<ShoppingBag className="w-4 h-4" />
@@ -155,7 +155,7 @@ export default function Home() {
{resources.map((resource) => (
<div
key={resource.name}
className="group bg-white/70 dark:bg-slate-900/40 backdrop-blur-md p-6 rounded-2xl border border-slate-200/60 dark:border-slate-800/80 hover:border-purple-500/40 dark:hover:border-purple-400/40 shadow-xs hover:shadow-xl hover:shadow-purple-500/5 hover:-translate-y-1 transition-all duration-300"
className="group bg-white dark:bg-slate-900/40 backdrop-blur-md p-6 rounded-2xl border border-slate-300 dark:border-slate-800/80 hover:border-purple-500/40 dark:hover:border-purple-400/40 shadow-xs hover:shadow-xl hover:shadow-purple-500/5 hover:-translate-y-1 transition-all duration-300"
>
<div className="flex items-start gap-4">
<div className={`w-12 h-12 rounded-xl flex items-center justify-center shrink-0 transform group-hover:scale-105 transition-transform duration-300 shadow-xs ${resource.colorClass}`}>
@@ -177,7 +177,7 @@ export default function Home() {
{/* Ciência Embarcada Section */}
<section className="mb-8">
<div className="bg-gradient-to-br from-white to-purple-50/50 dark:from-slate-900/40 dark:to-purple-950/10 rounded-3xl shadow-xs border border-slate-200/80 dark:border-slate-800/80 p-8 md:p-12 relative overflow-hidden">
<div className="bg-gradient-to-br from-white to-purple-50/50 dark:from-slate-900/40 dark:to-purple-950/10 rounded-3xl shadow-xs border border-slate-300 dark:border-slate-800/80 p-8 md:p-12 relative overflow-hidden">
{/* Background soft glow decoration */}
<div className="absolute right-0 bottom-0 w-80 h-80 bg-purple-500/5 rounded-full blur-3xl pointer-events-none" />
@@ -223,7 +223,7 @@ export default function Home() {
</div>
{/* Disclaimer */}
<div className="border-t border-slate-200/80 dark:border-slate-800/80 pt-8 mt-10">
<div className="border-t border-slate-300 dark:border-slate-800/80 pt-8 mt-10">
<div className="bg-slate-100/60 dark:bg-slate-900/60 border-l-4 border-purple-500 p-5 rounded-r-2xl">
<div className="flex gap-4">
<Info className="w-5 h-5 text-purple-600 dark:text-purple-400 mt-0.5 shrink-0" />
+90 -56
View File
@@ -33,7 +33,9 @@ import {
BookOpen,
Compass,
Smartphone,
ShieldCheck
ShieldCheck,
KeyRound,
Lock
} from "lucide-react";
// Dynamic icon mapper to convert choices to sleek Lucide vectors
@@ -48,7 +50,7 @@ const iconMap = {
"connectivity_wifi-ble": <Wifi className="w-6 h-6 text-blue-500" />,
"connectivity_mesh": <Network className="w-6 h-6 text-orange-500" />,
"connectivity_ethernet": <Cable className="w-6 h-6 text-emerald-500" />,
"connectivity_none": <Ban className="w-6 h-6 text-slate-450 dark:text-slate-500" />,
"connectivity_none": <Ban className="w-6 h-6 text-slate-500 dark:text-slate-450" />,
// Alimentacao
"power_battery": <Battery className="w-6 h-6 text-green-500" />,
@@ -63,15 +65,15 @@ const iconMap = {
),
"hardware_usb-native": <Cable className="w-6 h-6 text-teal-500" />,
"hardware_many-gpios": <Sliders className="w-6 h-6 text-sky-500" />,
"hardware_basic": <HelpCircle className="w-6 h-6 text-slate-450 dark:text-slate-550" />,
"hardware_basic": <HelpCircle className="w-6 h-6 text-slate-500 dark:text-slate-400" />,
// IA
"ai_ai-ml": <Bot className="w-6 h-6 text-pink-500" />,
"ai_standard": <Ban className="w-6 h-6 text-slate-450 dark:text-slate-550" />,
"ai_standard": <Ban className="w-6 h-6 text-slate-500 dark:text-slate-400" />,
// Segurança
"security_critical": <ShieldCheck className="w-6 h-6 text-teal-500" />,
"security_standard": <HelpCircle className="w-6 h-6 text-slate-450 dark:text-slate-550" />,
"security_standard": <HelpCircle className="w-6 h-6 text-slate-500 dark:text-slate-400" />,
};
const getOptionIcon = (questionId, value) => {
@@ -147,11 +149,13 @@ export default function Seletor() {
},
{
id: "security",
question: "Qual o nível de segurança criptográfica exigido pelo produto?",
description: "Aceleradores criptográficos no silício executam AES, SHA, RSA e curvas elípticas em hardware, viabilizando Secure Boot, criptografia de flash e provisionamento seguro de chaves sem penalizar a CPU.",
question: "Qual requisito de segurança o produto precisa atender?",
description: "As séries diferem bastante aqui: nem todas têm curvas elípticas (ECC), ECDSA em hardware ou Key Manager, e duas delas sequer têm acelerador AES. Escolha o requisito mais forte do seu projeto.",
options: [
{ value: "critical", label: "Crítico (Matter, pagamentos, provisionamento seguro de chaves)", icon: "security_critical" },
{ value: "standard", label: "Padrão (TLS comum e projetos sem requisitos regulatórios)", icon: "security_standard" },
{ value: "matter", label: "Atestado de dispositivo para Matter ou assinatura digital (ECDSA)", icon: "security_matter" },
{ value: "chaves", label: "Chave privada que nunca pode ser lida pelo firmware (Key Manager)", icon: "security_chaves" },
{ value: "boot", label: "Boot seguro e flash criptografada contra cópia do firmware", icon: "security_boot" },
{ value: "tls", label: "Só TLS/HTTPS comum, sem requisito regulatório", icon: "security_tls" },
]
}
];
@@ -372,24 +376,54 @@ export default function Seletor() {
}
// 6. SEGURANÇA CRIPTOGRÁFICA (security)
if (answers.security === "critical") {
const cripto = serie.aceleradores_cripto || "";
// Agora lê os campos destrinchados, então cada requisito pontua o
// bloco de hardware que realmente o atende.
const seg = serie.seguranca || {};
const temECDSA = String(seg.ecdsa).startsWith("Sim");
const temECC = String(seg.ecc).startsWith("Sim");
const temAES = String(seg.aes).startsWith("AES");
if (cripto.includes("Key Manager")) {
if (answers.security === "matter") {
if (temECDSA) {
scores[key] += 30;
reasons[key].push("Suíte criptográfica completa em hardware com Key Manager (provisionamento e uso de chaves sem exposição ao firmware)");
} else if (cripto.includes("ECDSA")) {
scores[key] += 20;
reasons[key].push("Aceleradores criptográficos com ECC/ECDSA dedicados (assinatura digital e Secure Boot eficientes)");
} else if (cripto) {
reasons[key].push(`ECDSA em hardware (${seg.ecc}) — atestado de dispositivo Matter assinado sem custo de CPU`);
} else if (temECC) {
scores[key] += 10;
reasons[key].push("Aceleradores criptográficos básicos em hardware (AES, SHA, Secure Boot e criptografia de flash)");
reasons[key].push(`Tem ECC (${seg.ecc}) mas não o periférico ECDSA: a assinatura roda parcialmente em software`);
} else {
scores[key] -= 25;
reasons[key].push("Sem curvas elípticas em hardware: assinatura ECDSA inteiramente por software, lenta no provisionamento");
}
} else if (answers.security === "chaves") {
if (seg.key_manager === "Sim") {
scores[key] += 30;
reasons[key].push("Key Manager: a chave é provisionada e usada sem nunca ficar legível para o firmware");
} else if (seg.assinatura_digital === "Sim") {
scores[key] += 15;
reasons[key].push("Periférico Digital Signature protege a chave RSA via eFuse, mas sem Key Manager para as demais");
} else {
scores[key] -= 20;
reasons[key].push("Sem aceleração criptográfica dedicada: operações de segurança ficam a cargo da CPU");
reasons[key].push("Sem Key Manager nem Digital Signature: a chave privada fica exposta na memória do firmware");
}
} else if (answers.security === "boot") {
if (String(seg.secure_boot).includes("V2")) {
scores[key] += 20;
reasons[key].push(`Secure Boot ${seg.secure_boot} com criptografia de flash ${seg.criptografia_flash}`);
} else if (String(seg.secure_boot).includes("V1")) {
scores[key] += 5;
reasons[key].push("Secure Boot apenas na versão V1 (legada), sem as proteções do esquema V2");
} else {
scores[key] -= 20;
reasons[key].push(`Secure Boot indisponível: ${seg.secure_boot}`);
}
} else if (answers.security === "tls") {
if (temAES) {
scores[key] += 10;
reasons[key].push(`Handshake e tráfego TLS acelerados por hardware (${seg.aes}, ${seg.sha})`);
} else {
scores[key] -= 10;
reasons[key].push(`Sem acelerador AES (só ${seg.sha}): o tráfego TLS é cifrado pela CPU e pesa no desempenho`);
}
} else if (answers.security === "standard") {
scores[key] += 5;
}
});
@@ -418,7 +452,7 @@ export default function Seletor() {
const progress = ((currentStep + 1) / questions.length) * 100;
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main id="conteudo" className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
@@ -442,7 +476,7 @@ export default function Seletor() {
{!showResults && !showSummary && (
<div className="max-w-2xl mx-auto mb-10">
<div className="flex justify-between items-center mb-3">
<span className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest">
<span className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest">
Etapa {currentStep + 1} de {questions.length}
</span>
<span className="text-xs font-extrabold text-purple-600 dark:text-purple-400">
@@ -463,12 +497,12 @@ export default function Seletor() {
{/* STEP 1: Quiz Card Interface */}
{currentStep < questions.length && !showResults && !showSummary && (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl border border-slate-200/60 dark:border-slate-800/80 p-6 md:p-10 max-w-2xl mx-auto shadow-2xl transition-all duration-300">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl border border-slate-300 dark:border-slate-800/80 p-6 md:p-10 max-w-2xl mx-auto shadow-2xl transition-all duration-300">
<div className="text-center mb-8">
<h2 className="text-xl md:text-2xl font-display font-extrabold text-slate-850 dark:text-slate-100 mb-3 leading-snug">
{questions[currentStep].question}
</h2>
<p className="text-xs md:text-sm text-slate-450 dark:text-slate-400 max-w-xl mx-auto leading-relaxed">
<p className="text-xs md:text-sm text-slate-500 dark:text-slate-400 max-w-xl mx-auto leading-relaxed">
{questions[currentStep].description}
</p>
</div>
@@ -483,7 +517,7 @@ export default function Seletor() {
className={`group flex items-center gap-4 text-left border rounded-2xl p-4 transition-all duration-300 cursor-pointer hover:shadow-md active:scale-[0.99] ${
isSelected
? 'bg-purple-500/10 dark:bg-purple-400/10 border-purple-500 dark:border-purple-400 shadow-xs'
: 'bg-slate-50/50 dark:bg-slate-900/20 hover:bg-purple-500/5 dark:hover:bg-purple-400/5 border-slate-200 dark:border-slate-800/80 hover:border-purple-400/50'
: 'bg-slate-50/50 dark:bg-slate-900/20 hover:bg-purple-500/5 dark:hover:bg-purple-400/5 border-slate-300 dark:border-slate-800/80 hover:border-purple-400/50'
}`}
>
{/* Icon Badge */}
@@ -514,13 +548,13 @@ export default function Seletor() {
</div>
{/* Bottom Navigation Buttons */}
<div className="flex flex-col sm:flex-row justify-between items-stretch sm:items-center gap-3 mt-8 pt-6 border-t border-slate-200/60 dark:border-slate-800/60">
<div className="flex flex-col sm:flex-row justify-between items-stretch sm:items-center gap-3 mt-8 pt-6 border-t border-slate-300 dark:border-slate-800/60">
<button
onClick={goBack}
disabled={currentStep === 0}
className={`inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl font-bold text-xs uppercase tracking-wider transition-all duration-300 cursor-pointer ${
currentStep === 0
? 'bg-slate-100 dark:bg-slate-900 text-slate-400 dark:text-slate-600 cursor-not-allowed border border-transparent'
? 'bg-slate-100 dark:bg-slate-900 text-slate-500 dark:text-slate-400 cursor-not-allowed border border-transparent'
: 'bg-slate-200/60 dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-250 dark:hover:bg-slate-700 hover:shadow-xs'
}`}
>
@@ -541,7 +575,7 @@ export default function Seletor() {
disabled={currentAnswer === null}
className={`inline-flex items-center justify-center gap-2 px-6 py-2.5 rounded-xl font-bold text-xs uppercase tracking-wider transition-all duration-300 cursor-pointer ${
currentAnswer === null
? 'bg-slate-100 dark:bg-slate-900 text-slate-400 dark:text-slate-600 cursor-not-allowed border border-transparent'
? 'bg-slate-100 dark:bg-slate-900 text-slate-500 dark:text-slate-400 cursor-not-allowed border border-transparent'
: 'bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 text-white hover:shadow-lg transform hover:-translate-y-0.5 active:translate-y-0'
}`}
>
@@ -554,7 +588,7 @@ export default function Seletor() {
{/* STEP 2: Choice Summary */}
{showSummary && !showResults && (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl border border-slate-200/60 dark:border-slate-800/80 p-6 md:p-10 max-w-3xl mx-auto shadow-2xl transition-all duration-300">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl border border-slate-300 dark:border-slate-800/80 p-6 md:p-10 max-w-3xl mx-auto shadow-2xl transition-all duration-300">
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center w-14 h-14 bg-purple-500/10 text-purple-600 dark:text-purple-400 rounded-full mb-4 border border-purple-500/20">
<Award className="w-6 h-6" />
@@ -562,7 +596,7 @@ export default function Seletor() {
<h2 className="text-xl md:text-2xl font-display font-extrabold text-slate-850 dark:text-slate-100 mb-2">
Resumo das suas Configurações
</h2>
<p className="text-xs text-slate-450 dark:text-slate-400 max-w-xl mx-auto leading-relaxed">
<p className="text-xs text-slate-500 dark:text-slate-400 max-w-xl mx-auto leading-relaxed">
Revise suas escolhas de arquitetura abaixo. Você pode ajustar qualquer especificação individual antes de processar as recomendações.
</p>
</div>
@@ -574,9 +608,9 @@ export default function Seletor() {
const selectedOption = question.options.find(opt => opt.value === answer);
return (
<div key={question.id} className="bg-slate-50/50 dark:bg-slate-900/20 rounded-xl p-4 border border-slate-200/60 dark:border-slate-800/80 hover:shadow-xs transition-all flex justify-between items-center gap-3">
<div key={question.id} className="bg-slate-50/50 dark:bg-slate-900/20 rounded-xl p-4 border border-slate-300 dark:border-slate-800/80 hover:shadow-xs transition-all flex justify-between items-center gap-3">
<div className="flex-1 min-w-0">
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1 truncate select-none">
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1 truncate select-none">
{question.id.replace('connectivity', 'conectividade').replace('hardware', 'periféricos').replace('power', 'alimentação').toUpperCase()}
</h3>
{selectedOption && (
@@ -597,7 +631,7 @@ export default function Seletor() {
setCurrentAnswer(answers[question.id]);
setShowSummary(false);
}}
className="p-2 border border-slate-200 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 bg-white dark:bg-slate-900 hover:bg-purple-50 dark:hover:bg-purple-950/20 rounded-lg text-slate-400 hover:text-purple-650 dark:hover:text-purple-400 transition-all cursor-pointer shrink-0"
className="p-2 border border-slate-300 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 bg-white dark:bg-slate-900 hover:bg-purple-50 dark:hover:bg-purple-950/20 rounded-lg text-slate-400 hover:text-purple-650 dark:hover:text-purple-400 transition-all cursor-pointer shrink-0"
title="Editar esta resposta"
>
<Edit2 className="w-3.5 h-3.5" />
@@ -607,7 +641,7 @@ export default function Seletor() {
})}
</div>
<div className="flex flex-col sm:flex-row gap-3 justify-center items-stretch sm:items-center border-t border-slate-200/60 dark:border-slate-800/60 pt-6">
<div className="flex flex-col sm:flex-row gap-3 justify-center items-stretch sm:items-center border-t border-slate-300 dark:border-slate-800/60 pt-6">
<button
onClick={() => {
setCurrentStep(questions.length - 1);
@@ -654,7 +688,7 @@ export default function Seletor() {
},
{
badge: "🥈 2º Recomendado",
cardClass: "border-slate-200/80 dark:border-slate-800 bg-linear-to-b from-slate-500/5 to-transparent min-h-[540px] opacity-95 hover:opacity-100",
cardClass: "border-slate-300 dark:border-slate-800 bg-linear-to-b from-slate-500/5 to-transparent min-h-[540px] opacity-95 hover:opacity-100",
badgeClass: "text-slate-650 bg-slate-500/10 border-slate-500/20 dark:text-slate-350 dark:bg-slate-850",
scoreClass: "text-slate-500 dark:text-slate-300"
},
@@ -669,7 +703,7 @@ export default function Seletor() {
return (
<div
key={seriesKey}
className={`relative flex flex-col bg-white/70 dark:bg-slate-900/40 backdrop-blur-xl border rounded-3xl overflow-hidden transition-all duration-500 hover:scale-[1.05] hover:shadow-2xl hover:z-20 ${rankConfig.cardClass}`}
className={`relative flex flex-col bg-white dark:bg-slate-900/40 backdrop-blur-xl border rounded-3xl overflow-hidden transition-all duration-500 hover:scale-[1.05] hover:shadow-2xl hover:z-20 ${rankConfig.cardClass}`}
>
{/* Top Color Band */}
<div className="h-1 w-full shrink-0" style={{ backgroundColor: serie.cor }} />
@@ -687,11 +721,11 @@ export default function Seletor() {
<h3 className="text-xl font-display font-extrabold text-slate-850 dark:text-slate-100 mb-1 leading-none">
{seriesKey}
</h3>
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-semibold uppercase tracking-wider truncate">
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-semibold uppercase tracking-wider truncate">
{serie.nome_completo}
</p>
<div className="mt-3.5 inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-slate-50 dark:bg-slate-950 border border-slate-200/60 dark:border-slate-800 shadow-xs">
<div className="mt-3.5 inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-slate-50 dark:bg-slate-950 border border-slate-300 dark:border-slate-800 shadow-xs">
<span className="text-[9px] font-bold text-slate-450 uppercase tracking-wider">Afinidade:</span>
<span className={`text-xs font-extrabold ${rankConfig.scoreClass}`}>
{score} pts
@@ -700,8 +734,8 @@ export default function Seletor() {
</div>
{/* Specifications Checklist */}
<div className="space-y-2 border-t border-slate-200/50 dark:border-slate-850/60 pt-4 mb-6 select-none">
<h4 className="text-[9px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-2.5">Principais Vantagens</h4>
<div className="space-y-2 border-t border-slate-300 dark:border-slate-850/60 pt-4 mb-6 select-none">
<h4 className="text-[9px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-2.5">Principais Vantagens</h4>
<ul className="space-y-2">
{matchReasons.slice(0, 3).map((reason, idx) => (
<li key={idx} className="flex items-start gap-2 text-xs leading-normal text-slate-600 dark:text-slate-350">
@@ -710,7 +744,7 @@ export default function Seletor() {
</li>
))}
{matchReasons.length > 3 && (
<li className="text-[10px] text-slate-400 dark:text-slate-500 italic pl-5.5">
<li className="text-[10px] text-slate-500 dark:text-slate-400 italic pl-5.5">
+{matchReasons.length - 3} outros requisitos atendidos
</li>
)}
@@ -719,7 +753,7 @@ export default function Seletor() {
</div>
{/* Spec Mini Badges */}
<div className="grid grid-cols-2 gap-2 bg-slate-50/50 dark:bg-slate-950/40 p-2.5 rounded-xl border border-slate-100 dark:border-slate-800/40 mb-4 select-none">
<div className="grid grid-cols-2 gap-2 bg-slate-50/50 dark:bg-slate-950/40 p-2.5 rounded-xl border border-slate-200 dark:border-slate-800/40 mb-4 select-none">
<div className="flex flex-col">
<span className="text-[8px] font-bold uppercase text-slate-400 tracking-wider">Frequência</span>
<span className="text-xs font-extrabold text-slate-700 dark:text-slate-200 truncate">{serie.frequencia}</span>
@@ -750,7 +784,7 @@ export default function Seletor() {
{/* Stacked Layout for mobile */}
<div className="lg:hidden space-y-6 max-w-xl mx-auto">
<h3 className="text-sm font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest text-center select-none mb-1">Grade de Resultados</h3>
<h3 className="text-sm font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest text-center select-none mb-1">Grade de Resultados</h3>
{topThree.map(([seriesKey, score], index) => {
const serie = seriesData[seriesKey];
const matchReasons = allReasons[seriesKey] || [];
@@ -760,8 +794,8 @@ export default function Seletor() {
return (
<div
key={seriesKey}
className={`bg-white/70 dark:bg-slate-900/40 backdrop-blur-xl border rounded-3xl overflow-hidden shadow-xl flex flex-col ${
isFirst ? "border-amber-500 dark:border-amber-400" : "border-slate-200/80 dark:border-slate-800"
className={`bg-white dark:bg-slate-900/40 backdrop-blur-xl border rounded-3xl overflow-hidden shadow-xl flex flex-col ${
isFirst ? "border-amber-500 dark:border-amber-400" : "border-slate-300 dark:border-slate-800"
}`}
>
<div className="p-5 flex-1">
@@ -780,7 +814,7 @@ export default function Seletor() {
<span className="text-4xl select-none shrink-0">{serie.icone}</span>
<div>
<h4 className="text-base font-bold text-slate-850 dark:text-slate-100 leading-tight">{seriesKey}</h4>
<p className="text-xs text-slate-450 dark:text-slate-400 leading-snug line-clamp-2 mt-1">{serie.descricao}</p>
<p className="text-xs text-slate-500 dark:text-slate-400 leading-snug line-clamp-2 mt-1">{serie.descricao}</p>
</div>
</div>
@@ -808,7 +842,7 @@ export default function Seletor() {
{/* Other options */}
{otherRecommendations.length > 0 && (
<div className="bg-slate-50/50 dark:bg-slate-900/10 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-200/50 dark:border-slate-850/50 max-w-6xl mx-auto shadow-inner">
<div className="bg-slate-50/50 dark:bg-slate-900/10 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-300 dark:border-slate-850/50 max-w-6xl mx-auto shadow-inner">
<h3 className="text-lg font-display font-extrabold text-slate-850 dark:text-slate-150 mb-6 text-center select-none">
Outras Opções Compatíveis
</h3>
@@ -818,12 +852,12 @@ export default function Seletor() {
return (
<div
key={seriesKey}
className="bg-white/80 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800/80 rounded-2xl p-4 hover:shadow-lg hover:-translate-y-0.5 transition-all duration-300 flex flex-col justify-between"
className="bg-white dark:bg-slate-900/60 border border-slate-300 dark:border-slate-800/80 rounded-2xl p-4 hover:shadow-lg hover:-translate-y-0.5 transition-all duration-300 flex flex-col justify-between"
>
<div className="text-center mb-4">
<div className="text-3xl mb-2 select-none">{serie.icone}</div>
<h4 className="text-xs font-bold text-slate-850 dark:text-slate-250 truncate leading-none">{seriesKey}</h4>
<span className="text-[10px] text-slate-450 dark:text-slate-500 font-semibold">Afinidade: {score} pts</span>
<span className="text-[10px] text-slate-500 dark:text-slate-450 font-semibold">Afinidade: {score} pts</span>
</div>
<Link
href={`/series/${seriesKey}`}
@@ -840,10 +874,10 @@ export default function Seletor() {
)}
{/* Bottom navigation buttons */}
<div className="flex flex-col sm:flex-row gap-3 justify-center items-center max-w-2xl mx-auto border-t border-slate-200 dark:border-slate-850/60 pt-8 select-none">
<div className="flex flex-col sm:flex-row gap-3 justify-center items-center max-w-2xl mx-auto border-t border-slate-300 dark:border-slate-850/60 pt-8 select-none">
<Link
href="/comparacao"
className="inline-flex items-center justify-center gap-2 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-300 px-6 py-3 rounded-xl font-bold text-xs uppercase tracking-wider shadow-xs border border-slate-200 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 hover:-translate-y-0.5 transition-all duration-300 cursor-pointer w-full sm:w-auto"
className="inline-flex items-center justify-center gap-2 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-300 px-6 py-3 rounded-xl font-bold text-xs uppercase tracking-wider shadow-xs border border-slate-300 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 hover:-translate-y-0.5 transition-all duration-300 cursor-pointer w-full sm:w-auto"
>
<SlidersHorizontal className="w-3.5 h-3.5" />
<span>Comparar Lado a Lado</span>
@@ -859,7 +893,7 @@ export default function Seletor() {
</div>
{/* Secondary showcase tools */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-6 md:p-8 max-w-6xl mx-auto shadow-2xl">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-6 md:p-8 max-w-6xl mx-auto shadow-2xl">
<h3 className="text-lg font-display font-extrabold text-slate-850 dark:text-slate-100 mb-6 text-center select-none">
Próximos Passos de Desenvolvimento
</h3>
@@ -915,7 +949,7 @@ export default function Seletor() {
{/* STEP 3B: No Results Found */}
{showResults && recommendations.length === 0 && (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl border border-slate-200/60 dark:border-slate-800/80 p-8 md:p-10 max-w-2xl mx-auto shadow-2xl transition-all duration-300">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl border border-slate-300 dark:border-slate-800/80 p-8 md:p-10 max-w-2xl mx-auto shadow-2xl transition-all duration-300">
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center w-16 h-16 bg-amber-500/10 text-amber-600 dark:text-amber-400 rounded-full mb-4 border border-amber-500/20">
<HelpCircle className="w-8 h-8" />
@@ -927,7 +961,7 @@ export default function Seletor() {
Não foi possível encontrar um único microcontrolador ESP32 que atenda simultaneamente a todos os critérios. Isso ocorre quando requisitamos combinações extremas (ex: Ethernet industrial cabeada + BLE portátil com economia de bateria ultra-baixa).
</p>
<div className="bg-slate-50/50 dark:bg-slate-950/40 border border-slate-200/60 dark:border-slate-850 p-5 rounded-2xl max-w-xl mx-auto mb-6 text-left select-none">
<div className="bg-slate-50/50 dark:bg-slate-950/40 border border-slate-300 dark:border-slate-850 p-5 rounded-2xl max-w-xl mx-auto mb-6 text-left select-none">
<h3 className="text-xs font-bold text-slate-800 dark:text-slate-200 mb-2">💡 Dicas Rápidas de Seleção:</h3>
<ul className="space-y-2 text-xs text-slate-500 dark:text-slate-400 leading-relaxed">
<li className="flex items-start gap-2">
@@ -952,7 +986,7 @@ export default function Seletor() {
<Link
href="/comparacao"
className="inline-flex items-center justify-center gap-2 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-350 px-6 py-2.5 rounded-xl font-bold text-xs uppercase tracking-wider border border-slate-200 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 transition-all duration-300 cursor-pointer"
className="inline-flex items-center justify-center gap-2 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-350 px-6 py-2.5 rounded-xl font-bold text-xs uppercase tracking-wider border border-slate-300 dark:border-slate-800 hover:border-purple-500 dark:hover:border-purple-400 hover:text-purple-600 dark:hover:text-purple-400 transition-all duration-300 cursor-pointer"
>
<SlidersHorizontal className="w-4 h-4" />
<span>Ver Grade Completa</span>
+69 -36
View File
@@ -6,6 +6,7 @@ import { notFound } from "next/navigation";
import seriesData from "@/public/series.json";
import ConnectionsDiagram from "@/components/ConnectionsDiagram";
import SeriesTabMenu from "@/components/SeriesTabMenu";
import PinRestrictions from "@/components/PinRestrictions";
import {
Cpu,
Activity,
@@ -41,7 +42,17 @@ import {
ChevronRight,
Lightbulb,
ShieldCheck,
KeyRound
KeyRound,
Lock,
Hash,
Spline,
FileSignature,
Dices,
Waves,
Bug,
Box,
Package,
Terminal
} from "lucide-react";
export default async function SerieDetail({ params }) {
@@ -72,9 +83,28 @@ export default async function SerieDetail({ params }) {
{ label: "Aceleradores IA", value: serie.aceleradores_ia || "Não", icon: <Sparkles className="w-5 h-5 text-purple-500" /> },
];
const seg = serie.seguranca || {};
const segurancaSpecs = [
{ label: "Aceleradores Criptográficos", value: serie.aceleradores_cripto || "Não", icon: <ShieldCheck className="w-5 h-5 text-teal-500" /> },
{ label: "Gerador de Números Aleatórios", value: serie.aceleradores_cripto ? "Sim (RNG por hardware)" : "Não", icon: <KeyRound className="w-5 h-5 text-teal-500" /> },
{ label: "AES", value: seg.aes || "Não", icon: <Lock className="w-5 h-5 text-teal-500" /> },
{ label: "SHA", value: seg.sha || "Não", icon: <Hash className="w-5 h-5 text-teal-500" /> },
{ label: "RSA / MPI", value: seg.rsa || "Não", icon: <KeyRound className="w-5 h-5 text-teal-500" /> },
{ label: "ECC (curvas elípticas)", value: seg.ecc || "Não", icon: <Spline className="w-5 h-5 text-teal-500" /> },
{ label: "ECDSA em hardware", value: seg.ecdsa || "Não", icon: <FileSignature className="w-5 h-5 text-teal-500" /> },
{ label: "HMAC", value: seg.hmac || "Não", icon: <Fingerprint className="w-5 h-5 text-teal-500" /> },
{ label: "Assinatura Digital (DS)", value: seg.assinatura_digital || "Não", icon: <FileSignature className="w-5 h-5 text-teal-500" /> },
{ label: "Key Manager", value: seg.key_manager || "Não", icon: <KeyRound className="w-5 h-5 text-teal-500" /> },
{ label: "Gerador aleatório (RNG)", value: seg.rng || "Não", icon: <Dices className="w-5 h-5 text-teal-500" /> },
{ label: "Criptografia de flash", value: seg.criptografia_flash || "Não", icon: <HardDrive className="w-5 h-5 text-teal-500" /> },
{ label: "Secure Boot", value: seg.secure_boot || "Não", icon: <ShieldCheck className="w-5 h-5 text-teal-500" /> },
{ label: "Proteção contra DPA", value: seg.protecao_dpa || "Não", icon: <Waves className="w-5 h-5 text-teal-500" /> },
];
const ferramentasSpecs = [
{ label: "ESP-IDF mínimo", value: serie.esp_idf_minimo || "—", icon: <Code className="w-5 h-5 text-amber-500" /> },
{ label: "Core Arduino", value: serie.arduino_core || "—", icon: <Terminal className="w-5 h-5 text-amber-500" /> },
{ label: "Depuração", value: serie.depuracao || "—", icon: <Bug className="w-5 h-5 text-amber-500" /> },
{ label: "Encapsulamento", value: serie.encapsulamento || "—", icon: <Box className="w-5 h-5 text-amber-500" /> },
{ label: "Módulos disponíveis", value: serie.modulos || "—", icon: <Package className="w-5 h-5 text-amber-500" /> },
];
const conectividadeSpecs = [
@@ -149,13 +179,13 @@ export default async function SerieDetail({ params }) {
label: 'Placa de Desenvolvimento',
available: serie.placa,
content: (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-200/60 dark:border-slate-800/80 shadow-2xl">
<h2 className="text-xl font-bold text-slate-800 dark:text-slate-100 mb-6 pb-3 border-b border-slate-200/65 dark:border-slate-800/65 flex items-center gap-3">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-300 dark:border-slate-800/80 shadow-2xl">
<h2 className="text-xl font-bold text-slate-800 dark:text-slate-100 mb-6 pb-3 border-b border-slate-300 dark:border-slate-800/65 flex items-center gap-3">
<Sliders className="w-5 h-5" style={{ color: serie.cor }} />
<span>Kit de Desenvolvimento Oficial</span>
</h2>
<div className="flex justify-center">
<div className="relative w-full max-w-3xl bg-white dark:bg-white overflow-hidden rounded-2xl border border-slate-200/50 dark:border-slate-850/50 shadow-lg p-4">
<div className="relative w-full max-w-3xl bg-white dark:bg-white overflow-hidden rounded-2xl border border-slate-300 dark:border-slate-850/50 shadow-lg p-4">
<Image
src={serie.placa}
alt={`${key} DevKit - Placa de Desenvolvimento`}
@@ -177,7 +207,7 @@ export default async function SerieDetail({ params }) {
label: 'Diagrama de Conexões',
available: conexoes.length > 0,
content: (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-200/60 dark:border-slate-800/80 shadow-2xl">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-300 dark:border-slate-800/80 shadow-2xl">
<div className="bg-amber-500/10 text-amber-600 dark:text-amber-400 border border-amber-500/20 p-5 mb-8 rounded-2xl">
<div className="flex items-start gap-3">
<AlertTriangle className="w-5 h-5 shrink-0 mt-0.5" />
@@ -192,7 +222,7 @@ export default async function SerieDetail({ params }) {
<ConnectionsDiagram connections={conexoes} serie={serie} />
<div className="bg-slate-100/50 dark:bg-slate-950/40 rounded-2xl p-6 border border-slate-200/60 dark:border-slate-800/80 mt-8">
<div className="bg-slate-100/50 dark:bg-slate-950/40 rounded-2xl p-6 border border-slate-300 dark:border-slate-800/80 mt-8">
<h3 className="text-sm font-bold text-slate-800 dark:text-slate-100 mb-3 flex items-center gap-2 select-none">
<Lightbulb className="w-4 h-4 text-purple-500" />
<span>Flexibilidade das Portas GPIO</span>
@@ -217,7 +247,7 @@ export default async function SerieDetail({ params }) {
];
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
@@ -234,7 +264,7 @@ export default async function SerieDetail({ params }) {
{/* Top Info Banner Card */}
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 shadow-2xl border relative overflow-hidden"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 shadow-2xl border relative overflow-hidden"
style={{ borderColor: `${serie.cor}40` }}
>
<div className="flex flex-col lg:flex-row items-start lg:items-center justify-between gap-8">
@@ -244,7 +274,7 @@ export default async function SerieDetail({ params }) {
<h1 className="text-4xl md:text-5xl font-display font-extrabold text-slate-850 dark:text-slate-100 tracking-tight leading-none mb-3">
{key}
</h1>
<p className="text-sm font-semibold text-slate-400 dark:text-slate-500 mb-4">{serie.nome_completo}</p>
<p className="text-sm font-semibold text-slate-500 dark:text-slate-400 mb-4">{serie.nome_completo}</p>
<span
className="inline-block px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest"
style={{ backgroundColor: `${serie.cor}18`, color: serie.cor, border: `1px solid ${serie.cor}30` }}
@@ -261,7 +291,7 @@ export default async function SerieDetail({ params }) {
href={serie.datasheet}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-2 bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 px-5 py-3 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-lg"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-5 py-3 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-lg"
>
<FileText className="w-4 h-4" />
<span>Datasheet Oficial</span>
@@ -318,28 +348,28 @@ export default async function SerieDetail({ params }) {
{/* Primary Features Highlight Grid */}
<div className="grid md:grid-cols-3 gap-6 mb-8">
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
style={{ borderColor: serie.cor }}
>
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1.5 select-none">PROCESSADOR</h3>
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1.5 select-none">PROCESSADOR</h3>
<p className="text-2xl font-extrabold text-slate-800 dark:text-slate-100">{serie.nucleos.includes("2") ? "Dual-Core" : "Single-Core"}</p>
<p className="text-xs text-slate-400 mt-1">{serie.frequencia}</p>
</div>
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
style={{ borderColor: serie.cor }}
>
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1.5 select-none">MEMÓRIA SRAM</h3>
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1.5 select-none">MEMÓRIA SRAM</h3>
<p className="text-2xl font-extrabold text-slate-800 dark:text-slate-100">{serie.memoria_sram}</p>
<p className="text-xs text-slate-400 mt-1">+ {serie.memoria_sram_rtc} RTC SRAM</p>
</div>
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl shadow-lg p-6 border-l-4"
style={{ borderColor: serie.cor }}
>
<h3 className="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1.5 select-none">GPIO DISPONÍVEIS</h3>
<h3 className="text-[10px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1.5 select-none">GPIO DISPONÍVEIS</h3>
<p className="text-2xl font-extrabold text-slate-800 dark:text-slate-100">{serie.gpio}</p>
<p className="text-xs text-slate-400 mt-1">Pinos I/O programáveis</p>
</div>
@@ -348,17 +378,20 @@ export default async function SerieDetail({ params }) {
{/* DevBoard and Connections Tabs */}
<SeriesTabMenu tabs={tabs} color={serie.cor} />
<PinRestrictions conexoes={conexoes} serieKey={key} cor={serie.cor} />
{/* Specs List Cards */}
<div className="space-y-6 mt-12">
<SpecSection title="Processador" specs={processadorSpecs} cor={serie.cor} icon={<Cpu className="w-5 h-5" style={{ color: serie.cor }} />} />
<SpecSection title="Conectividade RF" specs={conectividadeSpecs} cor={serie.cor} icon={<Wifi className="w-5 h-5" style={{ color: serie.cor }} />} />
<SpecSection title="Disponibilidade e Ferramentas" specs={ferramentasSpecs} cor={serie.cor} icon={<Package className="w-5 h-5" style={{ color: serie.cor }} />} />
<SpecSection title="Segurança e Criptografia" specs={segurancaSpecs} cor={serie.cor} icon={<ShieldCheck className="w-5 h-5" style={{ color: serie.cor }} />} />
<SpecSection title="Estrutura de Memória" specs={memoriaSpecs} cor={serie.cor} icon={<Database className="w-5 h-5" style={{ color: serie.cor }} />} />
{/* Power Consumption section */}
{consumoEnergia.length > 0 && (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl p-6 md:p-8 border border-slate-200/60 dark:border-slate-800/80 shadow-2xl">
<h2 className="text-xl font-bold text-slate-800 dark:text-slate-100 mb-6 pb-3 border-b border-slate-200/65 dark:border-slate-800/65 flex items-center gap-3 select-none">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl p-6 md:p-8 border border-slate-300 dark:border-slate-800/80 shadow-2xl">
<h2 className="text-xl font-bold text-slate-800 dark:text-slate-100 mb-6 pb-3 border-b border-slate-300 dark:border-slate-800/65 flex items-center gap-3 select-none">
<Battery className="w-5 h-5" style={{ color: serie.cor }} />
<span>Consumo de Energia</span>
</h2>
@@ -375,11 +408,11 @@ export default async function SerieDetail({ params }) {
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
{consumoEnergia.map((spec, index) => (
<div key={index} className="flex items-center gap-3.5 p-3.5 bg-slate-50/50 dark:bg-slate-950/20 rounded-xl hover:bg-purple-500/5 dark:hover:bg-purple-400/5 border border-slate-150/40 dark:border-slate-850/40 transition-colors">
<div className="p-2 bg-white dark:bg-slate-900 rounded-lg shadow-xs border border-slate-200/30 dark:border-slate-850/30 shrink-0">
<div className="p-2 bg-white dark:bg-slate-900 rounded-lg shadow-xs border border-slate-300 dark:border-slate-850/30 shrink-0">
{spec.icon}
</div>
<div className="min-w-0">
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-bold uppercase tracking-wider">{spec.label}</p>
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-bold uppercase tracking-wider">{spec.label}</p>
<p className="text-sm font-extrabold text-slate-800 dark:text-slate-200 mt-0.5">{spec.value}</p>
</div>
</div>
@@ -406,26 +439,26 @@ export default async function SerieDetail({ params }) {
</div>
{/* DevBoard CTA Panel */}
<div className="my-20 bg-gradient-to-br from-slate-900 to-indigo-950 dark:from-slate-950 dark:to-purple-950/20 border border-slate-800/80 rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden">
<div className="my-20 bg-gradient-to-br from-indigo-50 to-purple-50 dark:from-slate-950 dark:to-purple-950/20 border border-indigo-200 dark:border-slate-800/80 rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden">
<div className="absolute right-0 bottom-0 w-96 h-96 bg-purple-500/5 rounded-full blur-3xl pointer-events-none" />
<div className="flex flex-col md:flex-row items-center justify-between gap-8 relative z-10">
<div className="flex-1 max-w-2xl text-center md:text-left">
<div className="inline-flex items-center gap-2 bg-white/10 text-slate-350 px-3 py-1 rounded-full mb-4 text-xs font-semibold select-none">
<div className="inline-flex items-center gap-2 bg-indigo-500/10 text-indigo-700 dark:bg-white/10 dark:text-slate-350 px-3 py-1 rounded-full mb-4 text-xs font-semibold select-none">
<Home className="w-3.5 h-3.5" />
<span>Hardware Fisico</span>
</div>
<h3 className="text-2xl md:text-3xl font-display font-extrabold text-white mb-4">
<h3 className="text-2xl md:text-3xl font-display font-extrabold text-slate-900 dark:text-white mb-4">
Pronto para começar a prototipar?
</h3>
<p className="text-sm text-slate-400 leading-relaxed">
<p className="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
Explore toda a nossa grade de placas de desenvolvimento de parceiros oficiais para a série {key}. Compare dimensões, conversores USB-serial e pinagens prontas para protoboards.
</p>
</div>
<Link
href="/catalogo"
className="inline-flex items-center justify-center gap-2 bg-white text-slate-900 px-6 py-3.5 rounded-xl font-bold text-sm hover:bg-slate-100 transition-all duration-300 shrink-0 shadow-md active:scale-95"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-6 py-3.5 rounded-xl font-bold text-sm hover:opacity-90 transition-all duration-300 shrink-0 shadow-md active:scale-95"
>
<span>Ver Placas Disponíveis</span>
<ArrowRight className="w-4 h-4" />
@@ -438,11 +471,11 @@ export default async function SerieDetail({ params }) {
{previousKey ? (
<Link
href={`/series/${previousKey}`}
className="flex items-center gap-3 bg-white/70 dark:bg-slate-900/40 backdrop-blur-xl px-5 py-3.5 rounded-2xl shadow-lg border border-slate-200/60 dark:border-slate-800/80 hover:border-purple-500/55 dark:hover:border-purple-400/55 transition-all group shrink-0"
className="flex items-center gap-3 bg-white dark:bg-slate-900/40 backdrop-blur-xl px-5 py-3.5 rounded-2xl shadow-lg border border-slate-300 dark:border-slate-800/80 hover:border-purple-500/55 dark:hover:border-purple-400/55 transition-all group shrink-0"
>
<ArrowLeft className="w-4 h-4 text-slate-400 group-hover:-translate-x-1.5 transition-transform" />
<div className="text-left">
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-bold uppercase tracking-wider">Anterior</p>
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-bold uppercase tracking-wider">Anterior</p>
<p className="text-sm font-extrabold text-slate-800 dark:text-slate-200">{previousKey}</p>
</div>
</Link>
@@ -452,7 +485,7 @@ export default async function SerieDetail({ params }) {
<Link
href="/comparacao"
className="inline-flex items-center justify-center gap-2 bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 px-6 py-3.5 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-md"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-6 py-3.5 rounded-xl font-bold text-xs uppercase tracking-wider hover:opacity-90 transition-opacity shadow-md"
>
<Scale className="w-4 h-4" />
<span>Comparar Séries</span>
@@ -461,10 +494,10 @@ export default async function SerieDetail({ params }) {
{nextKey ? (
<Link
href={`/series/${nextKey}`}
className="flex items-center gap-3 bg-white/70 dark:bg-slate-900/40 backdrop-blur-xl px-5 py-3.5 rounded-2xl shadow-lg border border-slate-200/60 dark:border-slate-800/80 hover:border-purple-500/55 dark:hover:border-purple-400/55 transition-all group shrink-0"
className="flex items-center gap-3 bg-white dark:bg-slate-900/40 backdrop-blur-xl px-5 py-3.5 rounded-2xl shadow-lg border border-slate-300 dark:border-slate-800/80 hover:border-purple-500/55 dark:hover:border-purple-400/55 transition-all group shrink-0"
>
<div className="text-right">
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-bold uppercase tracking-wider">Próximo</p>
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-bold uppercase tracking-wider">Próximo</p>
<p className="text-sm font-extrabold text-slate-800 dark:text-slate-200">{nextKey}</p>
</div>
<ArrowRight className="w-4 h-4 text-slate-400 group-hover:translate-x-1.5 transition-transform" />
@@ -482,19 +515,19 @@ export default async function SerieDetail({ params }) {
function SpecSection({ title, specs, cor, icon }) {
return (
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl p-6 md:p-8 border border-slate-200/60 dark:border-slate-800/80 shadow-2xl">
<h2 className="text-xl font-bold text-slate-800 dark:text-slate-100 mb-6 pb-3 border-b border-slate-200/65 dark:border-slate-800/65 flex items-center gap-3 select-none">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-2xl p-6 md:p-8 border border-slate-300 dark:border-slate-800/80 shadow-2xl">
<h2 className="text-xl font-bold text-slate-800 dark:text-slate-100 mb-6 pb-3 border-b border-slate-300 dark:border-slate-800/65 flex items-center gap-3 select-none">
{icon}
<span>{title}</span>
</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
{specs.map((spec, index) => (
<div key={index} className="flex items-center gap-3.5 p-3.5 bg-slate-50/50 dark:bg-slate-950/20 rounded-xl hover:bg-purple-500/5 dark:hover:bg-purple-400/5 border border-slate-150/40 dark:border-slate-850/40 transition-colors">
<div className="p-2 bg-white dark:bg-slate-900 rounded-lg shadow-xs border border-slate-200/30 dark:border-slate-850/30 shrink-0">
<div className="p-2 bg-white dark:bg-slate-900 rounded-lg shadow-xs border border-slate-300 dark:border-slate-850/30 shrink-0">
{spec.icon}
</div>
<div className="min-w-0">
<p className="text-[10px] text-slate-400 dark:text-slate-500 font-bold uppercase tracking-wider">{spec.label}</p>
<p className="text-[10px] text-slate-500 dark:text-slate-400 font-bold uppercase tracking-wider">{spec.label}</p>
<p className="text-sm font-extrabold text-slate-800 dark:text-slate-200 mt-0.5">{spec.value}</p>
</div>
</div>
+35 -25
View File
@@ -24,7 +24,7 @@ export default function Series() {
const series = Object.entries(seriesData);
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<Header />
<main id="conteudo" className="px-6 pt-16 pb-24 max-w-7xl mx-auto">
@@ -57,9 +57,8 @@ export default function Series() {
>
{/* Glassmorphic card container with dynamic color borders and shadows */}
<div
className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-200/60 dark:border-slate-800/80 hover:shadow-2xl transition-all duration-500 h-full flex flex-col justify-between"
className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-6 md:p-8 border border-slate-300 dark:border-slate-800/80 hover:shadow-2xl transition-all duration-500 h-full flex flex-col justify-between"
style={{
borderColor: 'rgba(148, 163, 184, 0.1)',
transition: 'border-color 0.3s, box-shadow 0.3s, transform 0.3s'
}}
onMouseEnter={(e) => {
@@ -90,14 +89,14 @@ export default function Series() {
{key}
</h2>
<p className="text-xs text-slate-450 dark:text-slate-500 line-clamp-2 leading-relaxed mb-6">
<p className="text-xs text-slate-500 dark:text-slate-450 line-clamp-2 leading-relaxed mb-6">
{serie.descricao}
</p>
{/* Detailed specs micro-grid */}
<div className="space-y-3.5 border-t border-slate-100 dark:border-slate-800/60 pt-6">
<div className="space-y-3.5 border-t border-slate-200 dark:border-slate-800/60 pt-6">
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-2 text-slate-400 dark:text-slate-500 font-semibold select-none">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-400 font-semibold select-none">
<Cpu className="w-3.5 h-3.5 text-blue-500/80" />
<span>Núcleos:</span>
</div>
@@ -105,7 +104,7 @@ export default function Series() {
</div>
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-2 text-slate-400 dark:text-slate-500 font-semibold select-none">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-400 font-semibold select-none">
<Activity className="w-3.5 h-3.5 text-amber-500/80" />
<span>Frequência:</span>
</div>
@@ -113,7 +112,7 @@ export default function Series() {
</div>
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-2 text-slate-400 dark:text-slate-500 font-semibold select-none">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-400 font-semibold select-none">
<Database className="w-3.5 h-3.5 text-pink-500/80" />
<span>SRAM:</span>
</div>
@@ -121,13 +120,13 @@ export default function Series() {
</div>
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-2 text-slate-400 dark:text-slate-500 font-semibold select-none">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-400 font-semibold select-none">
<Wifi className="w-3.5 h-3.5 text-emerald-500/80" />
<span>Wi-Fi:</span>
</div>
<span className="font-bold text-slate-800 dark:text-slate-200">
{String(serie.wifi).includes("Não") ? (
<span className="text-slate-350 dark:text-slate-650">—</span>
<span className="text-slate-500 dark:text-slate-400">—</span>
) : (
<span className="text-emerald-500 dark:text-emerald-400 font-extrabold">Sim</span>
)}
@@ -135,13 +134,13 @@ export default function Series() {
</div>
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-2 text-slate-400 dark:text-slate-500 font-semibold select-none">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-400 font-semibold select-none">
<Bluetooth className="w-3.5 h-3.5 text-indigo-500/80" />
<span>Bluetooth:</span>
</div>
<span className="font-bold text-slate-800 dark:text-slate-200">
{serie.bluetooth === "Não" ? (
<span className="text-slate-350 dark:text-slate-650">—</span>
<span className="text-slate-500 dark:text-slate-400">—</span>
) : (
<span className="text-indigo-500 dark:text-indigo-400 font-extrabold">Sim</span>
)}
@@ -150,7 +149,7 @@ export default function Series() {
{serie.consumo_energia?.deep_sleep && (
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-2 text-slate-400 dark:text-slate-500 font-semibold select-none">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-400 font-semibold select-none">
<Battery className="w-3.5 h-3.5 text-green-500/80" />
<span>Deep Sleep:</span>
</div>
@@ -177,12 +176,23 @@ export default function Series() {
</span>
)}
{serie.aceleradores_cripto && (
<span className="inline-flex items-center gap-1 px-2.5 py-1 bg-teal-500/10 text-teal-600 dark:text-teal-400 text-[10px] font-bold uppercase rounded-lg border border-teal-500/20 shadow-xs select-none">
<ShieldCheck className="w-3 h-3" />
<span>Cripto por Hardware</span>
</span>
)}
{/* Marcador de segurança: mostra o recurso que DIFERENCIA a série,
não o que todas têm. Ordem = do mais raro ao mais comum. */}
{(() => {
const seg = serie.seguranca || {};
const nivel =
seg.key_manager === "Sim" ? "Key Manager"
: String(seg.ecdsa).startsWith("Sim") ? "ECDSA em hardware"
: String(seg.ecc).startsWith("Sim") ? "ECC em hardware"
: String(seg.aes).startsWith("AES") ? "AES + SHA"
: "Só SHA";
return (
<span className="inline-flex items-center gap-1 px-2.5 py-1 bg-teal-500/10 text-teal-600 dark:text-teal-400 text-[10px] font-bold uppercase rounded-lg border border-teal-500/20 select-none">
<ShieldCheck className="w-3 h-3" />
<span>{nivel}</span>
</span>
);
})()}
{serie.matter === "Sim" && (
<span className="inline-flex items-center gap-1 px-2.5 py-1 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 text-[10px] font-bold uppercase rounded-lg border border-emerald-500/20 shadow-xs select-none">
@@ -192,7 +202,7 @@ export default function Series() {
)}
</div>
<div className="flex items-center justify-between text-xs font-bold text-slate-500 group-hover:text-purple-600 dark:group-hover:text-purple-400 transition-colors uppercase tracking-wider select-none border-t border-slate-100 dark:border-slate-800/60 pt-4">
<div className="flex items-center justify-between text-xs font-bold text-slate-500 group-hover:text-purple-600 dark:group-hover:text-purple-400 transition-colors uppercase tracking-wider select-none border-t border-slate-200 dark:border-slate-800/60 pt-4">
<span>Ver Detalhes</span>
<ArrowRight className="w-4 h-4 transform group-hover:translate-x-2 transition-transform duration-300" />
</div>
@@ -204,26 +214,26 @@ export default function Series() {
</div>
{/* Quick comparison CTA Box */}
<div className="mt-20 bg-gradient-to-br from-slate-900 to-indigo-950 dark:from-slate-950 dark:to-purple-950/20 rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden border border-slate-800/80">
<div className="mt-20 bg-gradient-to-br from-indigo-50 to-purple-50 dark:from-slate-950 dark:to-purple-950/20 rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden border border-indigo-200 dark:border-slate-800/80">
<div className="absolute right-0 bottom-0 w-96 h-96 bg-purple-500/5 rounded-full blur-3xl pointer-events-none" />
<div className="flex flex-col md:flex-row items-center justify-between gap-8 relative z-10">
<div className="flex-1 max-w-2xl text-center md:text-left">
<div className="inline-flex items-center gap-2 bg-white/10 text-slate-350 px-3 py-1 rounded-full mb-4 text-xs font-semibold select-none animate-pulse">
<div className="inline-flex items-center gap-2 bg-indigo-500/10 text-indigo-700 dark:bg-white/10 dark:text-slate-350 px-3 py-1 rounded-full mb-4 text-xs font-semibold select-none animate-pulse">
<Scale className="w-3.5 h-3.5" />
<span>Decisão Técnica</span>
</div>
<h3 className="text-2xl md:text-3xl font-display font-extrabold text-white mb-4">
<h3 className="text-2xl md:text-3xl font-display font-extrabold text-slate-900 dark:text-white mb-4">
Ficou em dúvida de qual escolher?
</h3>
<p className="text-sm text-slate-400 leading-relaxed">
<p className="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
Use nosso comparador técnico dinâmico para posicionar as especificações de conectividade RF, potência de rádio e suporte a barramentos de periféricos lado a lado.
</p>
</div>
<Link
href="/comparacao"
className="inline-flex items-center justify-center gap-2 bg-white text-slate-900 px-6 py-3.5 rounded-xl font-bold text-sm hover:bg-slate-100 transition-all duration-300 shrink-0 shadow-md active:scale-95"
className="inline-flex items-center justify-center gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-6 py-3.5 rounded-xl font-bold text-sm hover:opacity-90 transition-all duration-300 shrink-0 shadow-md active:scale-95"
>
<span>Comparar Séries</span>
<ArrowRight className="w-4 h-4" />
+9 -9
View File
@@ -27,7 +27,7 @@ export default function Sobre() {
];
return (
<div className="bg-gradient-to-br from-slate-50 via-white to-purple-50/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<div className="bg-gradient-to-br from-slate-100 via-slate-50 to-purple-100/40 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900 min-h-screen text-slate-900 dark:text-slate-100 transition-colors duration-300">
<a href="#conteudo" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:bg-white focus:px-4 focus:py-2 focus:rounded-md focus:shadow focus:ring-2 focus:ring-purple-500">
Ir para o conteúdo
</a>
@@ -75,7 +75,7 @@ export default function Sobre() {
<div className="mt-12 grid grid-cols-1 lg:grid-cols-3 gap-8">
<section className="lg:col-span-2 space-y-8">
{/* Missao article */}
<article className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-8 shadow-xl border border-slate-200/60 dark:border-slate-800/80 hover:border-purple-500/20 dark:hover:border-purple-400/20 transition-all">
<article className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-8 shadow-xl border border-slate-300 dark:border-slate-800/80 hover:border-purple-500/20 dark:hover:border-purple-400/20 transition-all">
<div className="flex items-center gap-3.5 mb-5 select-none">
<div className="w-12 h-12 bg-purple-500/10 border border-purple-500/20 rounded-2xl flex items-center justify-center text-purple-500">
<Target className="w-6 h-6" />
@@ -91,7 +91,7 @@ export default function Sobre() {
</article>
{/* Por que o ESPDocs article */}
<article className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-8 shadow-xl border border-slate-200/60 dark:border-slate-800/80">
<article className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-8 shadow-xl border border-slate-300 dark:border-slate-800/80">
<div className="flex items-center gap-3.5 mb-5 select-none">
<div className="w-12 h-12 bg-blue-500/10 border border-blue-500/20 rounded-2xl flex items-center justify-center text-blue-500">
<HelpCircle className="w-6 h-6" />
@@ -120,7 +120,7 @@ export default function Sobre() {
</article>
{/* Contribuir article */}
<article className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-8 shadow-xl border border-slate-200/60 dark:border-slate-800/80">
<article className="bg-white dark:bg-slate-900/40 backdrop-blur-xl rounded-3xl p-8 shadow-xl border border-slate-300 dark:border-slate-800/80">
<div className="flex items-center gap-3.5 mb-5 select-none">
<div className="w-12 h-12 bg-emerald-500/10 border border-emerald-500/20 rounded-2xl flex items-center justify-center text-emerald-500">
<Users className="w-6 h-6" />
@@ -160,7 +160,7 @@ export default function Sobre() {
{/* Sidebar area */}
<aside className="space-y-6">
{/* Author Card */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-8 shadow-xl">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-8 shadow-xl">
<div className="flex flex-col items-center mb-6 select-none">
<div className="w-20 h-20 bg-gradient-to-br from-purple-500/10 to-pink-500/10 rounded-2xl flex items-center justify-center mb-4 border border-purple-500/20 shadow-inner">
<img
@@ -206,7 +206,7 @@ export default function Sobre() {
</div>
{/* Repository / Contributions card */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-6 shadow-xl">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-6 shadow-xl">
<div className="flex items-center justify-between mb-4 select-none">
<h3 className="text-sm font-display font-extrabold text-slate-800 dark:text-slate-200">Contribua</h3>
<span className="text-[9px] bg-emerald-500/10 text-emerald-600 dark:text-emerald-450 px-2.5 py-0.5 rounded-full font-bold uppercase tracking-wider border border-emerald-500/20">Open Source</span>
@@ -220,7 +220,7 @@ export default function Sobre() {
href="https://github.com/lucasrguerra/ESPDocs"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-2 w-full px-4 py-3 rounded-xl bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 font-bold text-xs uppercase tracking-wider shadow-md hover:opacity-90 active:scale-98 transition-all"
className="inline-flex items-center justify-center gap-2 w-full px-4 py-3 rounded-xl bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-bold text-xs uppercase tracking-wider shadow-md hover:opacity-90 active:scale-98 transition-all"
aria-label="Abrir repositório no GitHub"
>
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -229,13 +229,13 @@ export default function Sobre() {
<span>Ver Repositório</span>
</a>
<div className="mt-4 text-[10px] text-slate-450 dark:text-slate-500 leading-relaxed font-semibold border-t border-slate-100 dark:border-slate-850/45 pt-4">
<div className="mt-4 text-[10px] text-slate-500 dark:text-slate-450 leading-relaxed font-semibold border-t border-slate-200 dark:border-slate-850/45 pt-4">
<strong>Aviso Legal:</strong> O ESPDocs é um agregador e organizador. Manuais técnicos detalhados e repositórios oficiais referenciados são de propriedade exclusiva da Espressif Systems. Para projetos críticos comerciais, consulte sempre a documentação nativa oficial.
</div>
</div>
{/* Summary sidebar card */}
<div className="bg-white/80 dark:bg-slate-900/40 backdrop-blur-xl border border-slate-200/60 dark:border-slate-800/80 rounded-3xl p-6 shadow-xl select-none">
<div className="bg-white dark:bg-slate-900/40 backdrop-blur-xl border border-slate-300 dark:border-slate-800/80 rounded-3xl p-6 shadow-xl select-none">
<h4 className="text-xs font-display font-extrabold text-slate-800 dark:text-slate-200 mb-3 uppercase tracking-wider">Conteúdo Técnico</h4>
<ul className="text-xs text-slate-600 dark:text-slate-400 space-y-2.5 font-bold">
<li className="flex items-center gap-2">