Redesign das páginas internas no novo design system (AAA) (#2)
* feat(design): redesign das páginas internas no novo design system Padroniza todas as páginas e componentes internos nos tokens e primitivos de app/globals.css, com contraste AAA (7:1) nos dois temas e alvos de toque de 44px. - Páginas reescritas: glossário, séries, série, seletor, comparador, diagnóstico, catálogo, component registry, frameworks, framework, sobre e a nova 404. - Componentes: PageHero e SectionHead novos; BoardCard, CodeExample, PinRestrictions, SeriesTabMenu e ConnectionsDiagram refeitos, com abas e diálogo acessíveis. - Remove emojis, cores avulsas por série, caixa alta com tracking, texto menor que 12px e os pares slate-*/dark:*. - Comparador: "mostrar só as diferenças" e leitura de ?chips=. - Corrige overflow em 320/390px e ajusta accent/copper do tema claro para fechar 7:1. - scripts/auditar-temas.mjs passa a travar paleta crua, dark:, texto pequeno, emoji e contraste dos tokens. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016W1xmizFcmXLrmabSvfSuc * ci: roda lint, auditorias de design e build em cada PR Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016W1xmizFcmXLrmabSvfSuc --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4f27f5858b
commit
bc9ae5c036
34 files changed
+4911
-6874
No files matched your search
+41
-102
@@ -1,19 +1,18 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Code, Copy, CheckCircle, ExternalLink, HelpCircle } from 'lucide-react'
|
||||
import { useEffect, useState } from "react";
|
||||
import { Check, Copy, ExternalLink } from "lucide-react";
|
||||
|
||||
export default function CodeExample({ framework }) {
|
||||
const examplesUrl = framework?.exemplos;
|
||||
const color = framework?.cor || '#6B7280';
|
||||
|
||||
const [sample, setSample] = useState('');
|
||||
const [sample, setSample] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setSample('');
|
||||
setSample("");
|
||||
setError(null);
|
||||
setLoading(false);
|
||||
|
||||
@@ -21,12 +20,11 @@ export default function CodeExample({ framework }) {
|
||||
|
||||
const exemploPath = framework.exemplo;
|
||||
if (!exemploPath) {
|
||||
const msg = `// Exemplos completos: ${examplesUrl || 'Ver repositório'}\n// Abra o link acima para ver exemplos e código completo.\n`;
|
||||
setSample(msg);
|
||||
setSample(`// Exemplos completos: ${examplesUrl || "ver repositório"}\n`);
|
||||
return;
|
||||
}
|
||||
|
||||
const url = exemploPath.startsWith('/') ? exemploPath : `/${exemploPath}`;
|
||||
const url = exemploPath.startsWith("/") ? exemploPath : `/${exemploPath}`;
|
||||
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
@@ -41,14 +39,14 @@ export default function CodeExample({ framework }) {
|
||||
if (text && text.trim().length > 0) {
|
||||
setSample(text);
|
||||
} else {
|
||||
setSample(`// Arquivo de exemplo está vazio. Consulte o repositório oficial.\n`);
|
||||
setError('Arquivo vazio');
|
||||
setSample("// O arquivo de exemplo está vazio. Consulte o repositório oficial.\n");
|
||||
setError("arquivo vazio");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (cancelled) return;
|
||||
setSample(`// Não foi possível carregar o exemplo localmente.\n// Consulte o link do GitHub acima para exemplos funcionais.\n`);
|
||||
setError(err.message || 'Falha ao carregar exemplo');
|
||||
setSample("// Não foi possível carregar o exemplo.\n// Consulte o repositório oficial para exemplos completos.\n");
|
||||
setError(err.message || "falha ao carregar");
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false);
|
||||
@@ -59,7 +57,7 @@ export default function CodeExample({ framework }) {
|
||||
};
|
||||
}, [framework?.exemplo, framework?.exemplos]);
|
||||
|
||||
const lines = (sample || '').split('\n');
|
||||
const lines = (sample || "").replace(/\n$/, "").split("\n");
|
||||
|
||||
async function handleCopy() {
|
||||
try {
|
||||
@@ -70,109 +68,50 @@ export default function CodeExample({ framework }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<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 mb-8 animate-fadeIn">
|
||||
<div className="md:flex items-center justify-between gap-6 mb-6">
|
||||
<div className="select-none">
|
||||
<h3 className="text-xl font-display font-extrabold text-slate-850 dark:text-slate-100 mb-1 flex items-center gap-2">
|
||||
<Code className="w-5 h-5" style={{ color }} />
|
||||
<span>Demonstração de Código</span>
|
||||
</h3>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 font-semibold">Trecho de inicialização rápida. Copie e personalize em seu projeto.</p>
|
||||
<div className="card p-5 sm:p-7">
|
||||
<div className="flex flex-wrap items-start justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="font-display text-xl font-semibold tracking-[-0.03em] text-ink">Exemplo de código</h2>
|
||||
<p className="mt-1 text-sm text-muted">Trecho de partida em {framework?.linguagem}. Ajuste pinos e configuração à sua placa.</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2.5 mt-4 md:mt-0 select-none">
|
||||
<span
|
||||
className="inline-flex items-center text-[10px] font-bold px-2.5 py-1 rounded-full uppercase tracking-wider"
|
||||
style={{
|
||||
backgroundColor: `${color}18`,
|
||||
color,
|
||||
border: `1px solid ${color}25`
|
||||
}}
|
||||
>
|
||||
{framework?.linguagem || 'Código'}
|
||||
</span>
|
||||
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
className="inline-flex items-center gap-1.5 bg-slate-50 dark:bg-slate-850 hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-250 px-3.5 py-2 rounded-xl font-bold text-xs shadow-xs border border-slate-300 dark:border-slate-800/80 cursor-pointer transition active:scale-95"
|
||||
title="Copiar código para a área de transferência"
|
||||
>
|
||||
{copied ? (
|
||||
<>
|
||||
<CheckCircle className="w-3.5 h-3.5 text-emerald-500" />
|
||||
<span className="text-emerald-600 dark:text-emerald-450">Copiado!</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Copy className="w-3.5 h-3.5" />
|
||||
<span>Copiar</span>
|
||||
</>
|
||||
)}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<button type="button" onClick={handleCopy} className="btn btn-ghost btn-sm">
|
||||
{copied ? <Check className="h-4 w-4 text-ok" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
|
||||
<span role="status">{copied ? "Copiado" : "Copiar"}</span>
|
||||
</button>
|
||||
|
||||
{examplesUrl && (
|
||||
<a
|
||||
href={examplesUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl text-xs font-bold text-white shadow-lg active:scale-95 transition hover:opacity-95"
|
||||
style={{
|
||||
background: `linear-gradient(90deg, ${color} 0%, rgba(147,51,234,1) 100%)`,
|
||||
boxShadow: `0 8px 20px -8px ${color}`
|
||||
}}
|
||||
title="Abrir exemplos no GitHub"
|
||||
>
|
||||
<span>Mais Exemplos</span>
|
||||
<ExternalLink className="w-3.5 h-3.5" />
|
||||
<a href={examplesUrl} target="_blank" rel="noopener noreferrer" className="btn btn-ghost btn-sm">
|
||||
Mais exemplos
|
||||
<ExternalLink className="h-4 w-4" aria-hidden="true" />
|
||||
<span className="sr-only"> (abre em nova aba)</span>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl overflow-hidden border border-slate-300 dark:border-slate-800/80 shadow-md">
|
||||
<div className="select-none">
|
||||
<div className="flex items-center justify-between bg-slate-100/80 dark:bg-slate-950/70 border-b border-slate-300 dark:border-slate-850/60 px-4 py-3.5">
|
||||
<div className="text-xs font-bold text-slate-750 dark:text-slate-250 flex items-center gap-1.5">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-red-500/80" />
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-yellow-500/80" />
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-green-500/80" />
|
||||
<span className="ml-2 font-mono text-[10px] text-slate-500 dark:text-slate-400">{framework?.nome} example</span>
|
||||
</div>
|
||||
<div className="text-[9px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest">
|
||||
{loading ? 'Buscando exemplo...' : (framework?.exemplo ? 'Local Source' : 'External GitHub')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="code-panel mt-5" aria-busy={loading}>
|
||||
<div className="flex items-center justify-between border-b border-white/10 px-4 py-2.5 text-xs text-[#a6afbd]">
|
||||
<span className="font-mono">{framework?.nome}</span>
|
||||
<span>{loading ? "Carregando exemplo…" : framework?.linguagem}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex bg-slate-950">
|
||||
<pre
|
||||
className="text-slate-200 p-5 w-full overflow-auto text-xs leading-relaxed scrollbar-thin select-text"
|
||||
style={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace' }}
|
||||
>
|
||||
<pre tabIndex={0} aria-label={`Código de exemplo em ${framework?.linguagem}`}>
|
||||
<code>
|
||||
{lines.map((line, idx) => (
|
||||
<div key={idx} className="flex">
|
||||
<span className="text-slate-500 pr-4 text-right w-8 select-none border-r border-slate-900/60 mr-4 font-semibold">{idx + 1}</span>
|
||||
<code className="whitespace-pre flex-1 text-left">{line === '' ? '\u00A0' : line}</code>
|
||||
</div>
|
||||
<span key={idx} className="flex">
|
||||
<span className="mr-4 w-7 shrink-0 select-none text-right text-[#7d8794]">{idx + 1}</span>
|
||||
<span className="min-w-0 whitespace-pre text-[#e9eef4]">{line || " "}</span>
|
||||
</span>
|
||||
))}
|
||||
</pre>
|
||||
</div>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="bg-red-500/10 border border-red-500/20 rounded-xl p-3.5 mt-3 select-none">
|
||||
<p className="text-[10px] font-bold text-red-600 dark:text-red-400">
|
||||
Nota: Não foi possível carregar o arquivo de exemplo local ({error}). Use o botão "Mais Exemplos" para ver os códigos oficiais.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex items-start gap-2 bg-slate-50/50 dark:bg-slate-950/20 border border-slate-150/40 dark:border-slate-850/40 p-4 rounded-2xl select-none">
|
||||
<HelpCircle className="w-4.5 h-4.5 text-purple-500 shrink-0 mt-0.5" />
|
||||
<p className="text-[10px] font-semibold text-slate-500 dark:text-slate-400 leading-relaxed">
|
||||
<strong>Dica de Desenvolvimento:</strong> Personalize o trecho de inicialização com as pinagens e configurações corretas correspondentes à série do seu microcontrolador (ex: ESP32-S3, ESP32-C6). A documentação detalhada da API pode ser acessada na barra superior do framework.
|
||||
<p role="alert" className="callout callout-warn mt-4">
|
||||
Não foi possível carregar o exemplo local ({error}). Use “Mais exemplos” para ver o código oficial.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user