Files

110 lines
4.2 KiB
TypeScript

"use client";
import { motion, useReducedMotion } from "framer-motion";
import { Section } from "./Section";
const METRICS = [
{
score: 100,
label: "Performance",
description:
"Cada milissegundo conta. Tempos de carregamento instantâneos retêm mais usuários, aumentam a conversão e garantem que a interface pareça nativa.",
},
{
score: 100,
label: "Acessibilidade",
description:
"Acesso universal. Contraste perfeito, navegação por teclado e semântica adequada garantindo o uso por todos os perfis e mitigando riscos.",
},
{
score: 100,
label: "Best Practices",
description:
"Código seguro e moderno. Uso das APIs mais recentes, prevenção inteligente contra vulnerabilidades comuns e front-end limpo.",
},
{
score: 100,
label: "SEO",
description:
"Rankeamento orgânico superior. Estrutura impecável para indexação precisa pelos motores de busca e otimização para crawlers sociais.",
},
];
export default function LighthouseMetrics() {
const shouldReduceMotion = useReducedMotion();
return (
<Section
id="lighthouse"
eyebrow="Quality & Performance"
title="Engenharia de ponta a ponta: 100/100 não é vaidade."
description="Sistemas não podem apenas parecer bons. Eles precisam ser consistentes, rápidos, acessíveis, seguros e fáceis de processar. Entregar métricas máximas significa que a fundação técnica do projeto está preparada para escalar sem fricção."
dark
disableChildrenAnimation={false}
>
<div className="mt-sp-4 grid grid-cols-1 gap-sp-4 md:grid-cols-2 lg:grid-cols-4">
{METRICS.map((metric, i) => (
<motion.article
key={metric.label}
className="ds-card flex flex-col items-center gap-sp-6 text-center lg:items-start lg:text-left"
initial={shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: 20 }}
whileInView={
shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }
}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.6, delay: i * 0.1 }}
>
{/* The Ring Container */}
<div className="relative flex h-[100px] w-[100px] shrink-0 items-center justify-center rounded-full bg-[rgba(0,0,0,0.3)] shadow-inner">
<svg
className="absolute inset-0 h-full w-full rotate-[-90deg] drop-shadow-[0_0_12px_rgba(12,206,107,0.35)]"
viewBox="0 0 36 36"
aria-hidden="true"
>
{/* Background Track */}
<path
className="text-[rgba(255,255,255,0.1)]"
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
/>
{/* Animated Value Track */}
<motion.path
className="text-[#0cce6b]"
initial={{ strokeDasharray: "0, 100" }}
whileInView={{ strokeDasharray: `${metric.score}, 100` }}
viewport={{ once: true }}
transition={{
duration: 1.5,
ease: "easeOut",
delay: i * 0.15 + 0.2,
}}
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
/>
</svg>
<div className="font-mono text-[24px] font-bold tracking-tight text-[#0cce6b]">
{metric.score}
</div>
</div>
{/* Content Details */}
<div className="flex-1">
<h3 className="font-display text-[17px] font-bold text-[rgba(255,255,255,0.92)]">
{metric.label}
</h3>
<p className="mt-sp-3 text-[13px] leading-[1.8] text-[rgba(255,255,255,.75)]">
{metric.description}
</p>
</div>
</motion.article>
))}
</div>
</Section>
);
}