CI / verify (push) Failing after 5m29s
Estado do disco em 14/10/2026, sem filtrar. Inclui as copias .sync-conflict-* do Syncthing de 07/10 e os 15 arquivos que o Syncthing apagou; todo esse conteudo ja existia em outros commits. So havia fora do Git: AGENTS.md, CLAUDE.md e a alteracao em data/project-health.json.
344 lines
10 KiB
TypeScript
344 lines
10 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
|
|
const METRICS = [
|
|
{
|
|
id: "performance",
|
|
label: "Performance",
|
|
code: "LCP / INP / CLS",
|
|
title: "O essencial chega primeiro.",
|
|
description:
|
|
"O carregamento começa pelo que importa. Imagens, fontes e JavaScript precisam trabalhar a favor da experiência, não competir com ela.",
|
|
checks: [
|
|
"Conteúdo principal com prioridade de carregamento",
|
|
"Dimensões reservadas para evitar saltos de layout",
|
|
"JavaScript carregado onde faz diferença",
|
|
],
|
|
caption: "Em foco: o conteúdo principal e a estabilidade da página.",
|
|
},
|
|
{
|
|
id: "accessibility",
|
|
label: "Acessibilidade",
|
|
code: "TECLADO / FOCO / SEMÂNTICA",
|
|
title: "A interface inclui mais pessoas.",
|
|
description:
|
|
"Uma boa interface não exige um jeito único de navegar. Teclado, leitores de tela e preferências de movimento fazem parte do projeto.",
|
|
checks: [
|
|
"Foco visível e navegação por teclado",
|
|
"Controles com nomes e estrutura semântica",
|
|
"Contraste legível e movimento reduzido",
|
|
],
|
|
caption:
|
|
"Em foco: controles reconhecíveis e um caminho claro pelo teclado.",
|
|
},
|
|
{
|
|
id: "practices",
|
|
label: "Boas práticas",
|
|
code: "HTTPS / PRIVACIDADE / DEPENDÊNCIAS",
|
|
title: "Confiança também se constrói.",
|
|
description:
|
|
"Cuidar da entrega também é cuidar dos dados, das dependências e dos limites do navegador. Segurança não se resume a uma nota.",
|
|
checks: [
|
|
"Conexões seguras e políticas do navegador",
|
|
"Analytics condicionado ao consentimento",
|
|
"Dependências verificadas e atualizadas",
|
|
],
|
|
caption: "Em foco: a conexão e os limites de acesso aos dados.",
|
|
},
|
|
{
|
|
id: "seo",
|
|
label: "SEO",
|
|
code: "HTML / METADATA / INDEXAÇÃO",
|
|
title: "Conteúdo pronto para ser encontrado.",
|
|
description:
|
|
"Estrutura antes de promessas. Conteúdo claro, títulos coerentes e dados estruturados ajudam pessoas e buscadores a entender cada página.",
|
|
checks: [
|
|
"Títulos, descrições e URLs canônicas",
|
|
"HTML semântico e conteúdo rastreável",
|
|
"Sitemap e dados estruturados factuais",
|
|
],
|
|
caption: "Em foco: a estrutura que dá contexto ao conteúdo.",
|
|
},
|
|
];
|
|
|
|
const BLUEPRINT = (
|
|
<svg
|
|
className="quality-blueprint"
|
|
viewBox="0 0 640 440"
|
|
fill="none"
|
|
aria-hidden="true"
|
|
focusable="false"
|
|
>
|
|
<g className="quality-dimensions">
|
|
<path d="M64 68V48m512 20V48M64 58h512M44 86H24m20 284H24M34 86v284" />
|
|
<path d="m60 54 8 8m504-8 8 8M30 82l8 8m-8 276 8 8" />
|
|
<text x="304" y="47">
|
|
RESPONSIVE
|
|
</text>
|
|
<path d="M64 390v18m512-18v18M64 400h180m152 0h180" />
|
|
<text x="272" y="405">
|
|
WEB / BLUEPRINT
|
|
</text>
|
|
</g>
|
|
<rect
|
|
className="quality-browser-frame"
|
|
x="64"
|
|
y="86"
|
|
width="512"
|
|
height="284"
|
|
rx="8"
|
|
/>
|
|
<path className="quality-wire" d="M64 123h512" />
|
|
<g className="quality-browser-dots">
|
|
<circle cx="83" cy="105" r="3" />
|
|
<circle cx="95" cy="105" r="3" />
|
|
<circle cx="107" cy="105" r="3" />
|
|
</g>
|
|
<rect
|
|
className="quality-wire"
|
|
x="142"
|
|
y="96"
|
|
width="350"
|
|
height="18"
|
|
rx="3"
|
|
/>
|
|
<text className="quality-address" x="158" y="109">
|
|
evandro.dev.br
|
|
</text>
|
|
<path className="quality-wire" d="M539 100h15m-15 5h15m-15 5h15" />
|
|
<text className="quality-browser-heading" x="96" y="176">
|
|
Engenharia
|
|
</text>
|
|
<text className="quality-browser-heading" x="96" y="203">
|
|
que funciona.
|
|
</text>
|
|
<path className="quality-wire" d="M96 222h170M96 230h130" />
|
|
<rect
|
|
className="quality-browser-button"
|
|
x="96"
|
|
y="254"
|
|
width="142"
|
|
height="32"
|
|
rx="2"
|
|
/>
|
|
<text className="quality-browser-button-label" x="112" y="274">
|
|
EXPLORAR PROJETO
|
|
</text>
|
|
<rect
|
|
className="quality-wire"
|
|
x="330"
|
|
y="144"
|
|
width="216"
|
|
height="142"
|
|
rx="3"
|
|
/>
|
|
<g className="quality-wire">
|
|
<path d="m438 164 58 33v55l-58 33-58-33v-55zM380 197l58 33 58-33m-58 33v55m0-121v66" />
|
|
<path d="m409 181 58 33v55m-58 0v-55l58-33" />
|
|
<path d="M96 306h450M96 324h113m-113 10h80m84-10h113m-113 10h80m84-10h122m-122 10h80" />
|
|
</g>
|
|
<g className="quality-layer" data-layer="performance">
|
|
<rect
|
|
className="quality-highlight"
|
|
x="318"
|
|
y="133"
|
|
width="240"
|
|
height="165"
|
|
rx="4"
|
|
/>
|
|
<path className="quality-trace" pathLength="1" d="M558 216h43V59h-91" />
|
|
<circle cx="558" cy="216" r="4" />
|
|
<text x="393" y="63">
|
|
LCP / CONTEÚDO
|
|
</text>
|
|
<path d="M330 299v12m216-12v12m-216-6h216" />
|
|
<rect
|
|
className="quality-annotation"
|
|
x="368"
|
|
y="311"
|
|
width="154"
|
|
height="18"
|
|
/>
|
|
<text x="376" y="323">
|
|
ESPAÇO RESERVADO
|
|
</text>
|
|
</g>
|
|
<g className="quality-layer" data-layer="accessibility">
|
|
<rect
|
|
className="quality-highlight quality-focus-frame"
|
|
x="88"
|
|
y="246"
|
|
width="158"
|
|
height="48"
|
|
rx="5"
|
|
/>
|
|
<path className="quality-trace" pathLength="1" d="M88 270H50v149h20" />
|
|
<circle cx="88" cy="270" r="4" />
|
|
<text x="79" y="424">
|
|
TAB / FOCO VISÍVEL
|
|
</text>
|
|
<rect x="260" y="259" width="45" height="24" rx="3" />
|
|
<text x="270" y="275">
|
|
TAB
|
|
</text>
|
|
</g>
|
|
<g className="quality-layer" data-layer="practices">
|
|
<rect
|
|
className="quality-highlight"
|
|
x="134"
|
|
y="91"
|
|
width="366"
|
|
height="28"
|
|
rx="4"
|
|
/>
|
|
<path className="quality-trace" pathLength="1" d="M500 105h101v314h-90" />
|
|
<circle cx="500" cy="105" r="4" />
|
|
<path
|
|
className="quality-highlight"
|
|
d="m499 220 36 13v32c0 25-36 41-36 41s-36-16-36-41v-32z"
|
|
/>
|
|
<rect x="487" y="255" width="24" height="20" rx="2" />
|
|
<path d="M491 255v-7a8 8 0 0 1 16 0v7m-8 6v7" />
|
|
<text x="290" y="424">
|
|
HTTPS / CONSENTIMENTO
|
|
</text>
|
|
</g>
|
|
<g className="quality-layer" data-layer="seo">
|
|
<rect
|
|
className="quality-highlight"
|
|
x="85"
|
|
y="144"
|
|
width="224"
|
|
height="95"
|
|
rx="3"
|
|
/>
|
|
<path className="quality-trace" pathLength="1" d="M85 159H48V58h135" />
|
|
<circle cx="85" cy="159" r="4" />
|
|
<text x="74" y="49">
|
|
HTML / SEMÂNTICA
|
|
</text>
|
|
<text x="99" y="140">
|
|
<h1>
|
|
</text>
|
|
<path d="M331 317h213v29H331z" />
|
|
<text x="350" y="337">
|
|
<article> / <nav>
|
|
</text>
|
|
</g>
|
|
</svg>
|
|
);
|
|
|
|
export default function LighthouseMetrics() {
|
|
const [active, setActive] = useState(METRICS[0]);
|
|
|
|
return (
|
|
<section
|
|
id="lighthouse"
|
|
className="ds-section ds-section-dark quality-lab"
|
|
aria-labelledby="quality-title"
|
|
data-inspection={active.id}
|
|
>
|
|
<div className="ds-section-shell">
|
|
<div className="quality-intro">
|
|
<header className="quality-copy">
|
|
<p className="ds-eyebrow">Quality & Performance</p>
|
|
<h2 id="quality-title" className="ds-section-title">
|
|
Engenharia de ponta a ponta.
|
|
<span>Qualidade em cada camada.</span>
|
|
</h2>
|
|
<p>
|
|
Sistemas precisam mais do que uma boa aparência. Explore as
|
|
decisões que tornam uma interface rápida, acessível, confiável e
|
|
fácil de encontrar.
|
|
</p>
|
|
<a
|
|
className="ds-link ds-link-accent"
|
|
href="/servicos/consultoria-nextjs"
|
|
>
|
|
Conversar sobre a qualidade do seu projeto
|
|
</a>
|
|
</header>
|
|
|
|
<figure className="quality-visual bg-grid-light">
|
|
<div className="quality-visual-label">
|
|
<span>Laboratório de qualidade</span>
|
|
<span>Modelo interativo</span>
|
|
</div>
|
|
{BLUEPRINT}
|
|
<figcaption>
|
|
{METRICS.map((metric) => (
|
|
<span key={metric.id} aria-hidden={active.id !== metric.id}>
|
|
{metric.caption}
|
|
</span>
|
|
))}
|
|
</figcaption>
|
|
</figure>
|
|
</div>
|
|
|
|
<fieldset className="quality-controls" aria-describedby="quality-hint">
|
|
<legend className="sr-only">Escolha um aspecto da qualidade</legend>
|
|
{METRICS.map((metric) => (
|
|
<label key={metric.id} className="quality-control">
|
|
<input
|
|
type="radio"
|
|
name="quality-pillar"
|
|
value={metric.id}
|
|
checked={active.id === metric.id}
|
|
onChange={() => setActive(metric)}
|
|
aria-controls="quality-report"
|
|
/>
|
|
<span className="quality-control-content">
|
|
<span className="quality-control-name">{metric.label}</span>
|
|
<span className="quality-control-target">
|
|
Meta <strong>100</strong>
|
|
<span>/100</span>
|
|
</span>
|
|
</span>
|
|
</label>
|
|
))}
|
|
</fieldset>
|
|
|
|
<p id="quality-hint" className="quality-hint">
|
|
Selecione um pilar para explorar. No teclado, use as setas.
|
|
</p>
|
|
|
|
<section
|
|
id="quality-report"
|
|
className="quality-report-stack"
|
|
aria-label="Inspeção de qualidade"
|
|
aria-live="polite"
|
|
aria-atomic="true"
|
|
>
|
|
{METRICS.map((metric) => (
|
|
<div
|
|
key={metric.id}
|
|
className="quality-report"
|
|
aria-hidden={active.id !== metric.id}
|
|
>
|
|
<div className="quality-report-copy">
|
|
<p className="quality-code">{metric.code}</p>
|
|
<h3>{metric.title}</h3>
|
|
<p>{metric.description}</p>
|
|
</div>
|
|
<ul>
|
|
{metric.checks.map((check) => (
|
|
<li key={check}>
|
|
<span aria-hidden="true">/</span>
|
|
{check}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</section>
|
|
|
|
<p className="quality-disclaimer">
|
|
Metas de qualidade, não uma auditoria em tempo real. Resultados
|
|
Lighthouse variam conforme página, dispositivo e condições do teste.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|