CI / verify (push) Failing after 5m9s
Align the notebook browser with the physical LCD, refresh real project captures and navigation, simplify service content, and stabilize hero hydration.
268 lines
9.0 KiB
TypeScript
268 lines
9.0 KiB
TypeScript
"use client";
|
|
|
|
import { motion, type Variants } from "motion/react";
|
|
import Link from "next/link";
|
|
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
|
|
import { serviceHubLinks } from "@/lib/site-content";
|
|
import { DrawLine } from "./animations/DrawLine";
|
|
import MagneticButton from "./cinematic/MagneticButton";
|
|
import { Section } from "./Section";
|
|
|
|
interface Tier {
|
|
id: string;
|
|
badge: string;
|
|
level: string;
|
|
title: string;
|
|
tagline: string;
|
|
description: string;
|
|
deliverables: string[];
|
|
pricing: string;
|
|
pricingNote: string;
|
|
featured?: boolean;
|
|
ctaLabel: string;
|
|
ctaHref: string;
|
|
}
|
|
|
|
const TIERS: Tier[] = [
|
|
{
|
|
id: "discovery",
|
|
badge: "Entrada / Baixo Risco",
|
|
level: "01",
|
|
title: "Auditoria & Diagnóstico Técnico",
|
|
tagline: "Fotografia clara do problema antes de qualquer comprometimento.",
|
|
description:
|
|
"Análise profunda de arquitetura, performance ou segurança com entrega de um plano de ação executável. Ideal para quem precisa de direção antes de contratar execução.",
|
|
deliverables: [
|
|
"Relatório de gargalos e dívida técnica",
|
|
"Mapeamento de riscos e dependências",
|
|
"Sugestão de stack e cronograma de mitigação",
|
|
"Plano de ação priorizado",
|
|
],
|
|
pricing: "Valor Fixo",
|
|
pricingNote: "Contrato único. Entrega em até 5 dias úteis.",
|
|
featured: false,
|
|
ctaLabel: "Solicitar diagnóstico",
|
|
ctaHref: "#contact",
|
|
},
|
|
{
|
|
id: "cycles",
|
|
badge: "Mais Escolhido",
|
|
level: "02",
|
|
title: "Ciclos de Engenharia",
|
|
tagline: "Capacidade produtiva garantida. Entrega a cada 2 semanas.",
|
|
description:
|
|
"Desenvolvimento contínuo com a previsibilidade de orçamento do escopo fechado e a agilidade de sprints. Milestones claros, sem amarras de contrato longo.",
|
|
deliverables: [
|
|
"Features em produção a cada ciclo",
|
|
"Refatoração iterativa com rastreabilidade",
|
|
"Documentação técnica atualizada",
|
|
"Capacidade de pivotar prioridades no início de cada sprint",
|
|
],
|
|
pricing: "Fixo por Ciclo",
|
|
pricingNote: "Assinatura quinzenal ou mensal. Cancele a qualquer ciclo.",
|
|
featured: true,
|
|
ctaLabel: "Iniciar ciclo de engenharia",
|
|
ctaHref: "#contact",
|
|
},
|
|
{
|
|
id: "fractional",
|
|
badge: "Premium / High-Ticket",
|
|
level: "03",
|
|
title: "Fractional Tech Lead",
|
|
tagline: "Liderança técnica sênior. Sem o custo de um CTO full-time.",
|
|
description:
|
|
"Direção arquitetural, gestão de risco e sustentação de operações críticas. Para empresas que precisam de decisões de alto impacto com responsabilidade contínua.",
|
|
deliverables: [
|
|
"SLA prioritário Zero-Risk",
|
|
"Code review e lideranca do time interno",
|
|
"Decisoes de infra: Cloud, VPS, CI/CD",
|
|
"Consultoria estrategica recorrente",
|
|
],
|
|
pricing: "Retainer Mensal",
|
|
pricingNote: "Renovação mensal. Vagas limitadas.",
|
|
featured: false,
|
|
ctaLabel: "Agendar conversa estratégica",
|
|
ctaHref: "#contact",
|
|
},
|
|
];
|
|
|
|
function TierCard({ tier }: Readonly<{ tier: Tier }>) {
|
|
const shouldReduceMotion = useReducedMotion();
|
|
|
|
return (
|
|
<motion.article
|
|
className={`ds-card relative flex h-full min-w-0 flex-col overflow-hidden outline-none max-md:w-full max-md:max-w-none max-md:px-sp-5 max-md:py-sp-5 ${
|
|
tier.featured ? "border-[var(--slash)] shadow-sm" : ""
|
|
}`}
|
|
style={{
|
|
borderWidth: tier.featured ? "2px" : "1px",
|
|
}}
|
|
whileHover={
|
|
shouldReduceMotion
|
|
? undefined
|
|
: {
|
|
y: -4,
|
|
boxShadow: "0 24px 50px rgba(0, 0, 0, 0.08)",
|
|
}
|
|
}
|
|
whileTap={shouldReduceMotion ? undefined : { scale: 0.99 }}
|
|
transition={{ type: "spring", stiffness: 180, damping: 18 }}
|
|
>
|
|
<div className="flex min-w-0 items-start justify-between gap-sp-4">
|
|
<span className="ds-kicker max-md:text-[10px] max-md:leading-[1.6]">
|
|
{tier.badge}
|
|
</span>
|
|
<span className="text-[11px] tracking-[0.08em] text-[var(--meta)]">
|
|
{tier.level}
|
|
</span>
|
|
</div>
|
|
|
|
<DrawLine delay={0.04} />
|
|
|
|
<div className="mt-sp-4 min-w-0">
|
|
<h3 className="ds-card-title !mt-0 text-balance !text-[clamp(19px,5vw,28px)] !leading-[1.02] !tracking-[-0.035em] [overflow-wrap:break-word] [word-break:normal]">
|
|
{tier.title}
|
|
</h3>
|
|
<p className="mt-sp-2 text-[12px] leading-[1.7] text-[var(--meta)] md:text-[11px]">
|
|
{tier.tagline}
|
|
</p>
|
|
</div>
|
|
|
|
<p
|
|
className="ds-copy !mt-sp-4 !text-[13px] !leading-[1.75] [overflow-wrap:break-word] [word-break:normal] md:!text-[12px]"
|
|
data-reel="right"
|
|
>
|
|
{tier.description}
|
|
</p>
|
|
|
|
<ul
|
|
className="ds-list !mt-sp-5 !pl-[1.15rem] !text-[13px] !leading-[1.75] [overflow-wrap:break-word] [word-break:normal] md:!text-[12px]"
|
|
data-reel-stagger="fade"
|
|
>
|
|
{tier.deliverables.map((deliverable) => (
|
|
<li key={deliverable} className="pl-sp-1">
|
|
{deliverable}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<div className="mt-sp-6 space-y-sp-2 border-t border-[var(--border)] pt-sp-5">
|
|
<div className="font-display text-[clamp(17px,4.6vw,18px)] font-extrabold leading-none tracking-tight">
|
|
{tier.pricing}
|
|
</div>
|
|
<div className="text-[12px] leading-[1.7] text-[var(--meta)]">
|
|
{tier.pricingNote}
|
|
</div>
|
|
</div>
|
|
|
|
<MagneticButton
|
|
as="a"
|
|
href={tier.ctaHref}
|
|
className={`ds-link mt-sp-6 min-h-[50px] w-full justify-center px-sp-4 py-sp-3 text-center text-[11px] leading-none ${
|
|
tier.featured ? "ds-link-accent" : "ds-link-muted"
|
|
}`}
|
|
strength={0.25}
|
|
>
|
|
{tier.ctaLabel}
|
|
</MagneticButton>
|
|
</motion.article>
|
|
);
|
|
}
|
|
|
|
export function WorkModalities() {
|
|
const shouldReduceMotion = useReducedMotion();
|
|
|
|
const containerVariants: Variants = {
|
|
hidden: {},
|
|
visible: {
|
|
transition: {
|
|
delayChildren: 0.08,
|
|
staggerChildren: 0.08,
|
|
},
|
|
},
|
|
};
|
|
|
|
const itemVariants: Variants = {
|
|
hidden: shouldReduceMotion
|
|
? { opacity: 0 }
|
|
: { opacity: 0, y: 20, clipPath: "inset(100% 0 0 0)" },
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
clipPath: "inset(0% 0 0 0)",
|
|
transition: shouldReduceMotion
|
|
? { duration: 0.25 }
|
|
: { duration: 0.75, ease: [0.16, 1, 0.3, 1] },
|
|
},
|
|
};
|
|
|
|
return (
|
|
<Section
|
|
id="modalities"
|
|
eyebrow="Serviços e contratação"
|
|
title="Sites, sistemas e aplicativos para o seu negócio."
|
|
description="Desenvolvimento para web, mobile e desktop Windows e Linux. Da primeira ideia à melhoria de um sistema existente, o trabalho começa pelo que você precisa resolver."
|
|
disableChildrenAnimation
|
|
>
|
|
<div className="mb-sp-8 ds-card bg-[rgba(10,10,10,0.02)]">
|
|
<div className="flex flex-col gap-sp-4 lg:flex-row lg:items-end lg:justify-between">
|
|
<div className="max-w-[760px]">
|
|
<div className="ds-kicker">O que você pode contratar</div>
|
|
<h3 className="ds-card-title !mt-sp-3" data-reel="left">
|
|
Uma solução para a sua rotina, não uma lista de tecnologias.
|
|
</h3>
|
|
<p className="ds-copy !mt-sp-3 max-w-[62ch]" data-reel="right">
|
|
Apresentar sua empresa na internet, organizar a operação, criar um
|
|
aplicativo ou conectar ferramentas. Veja exemplos, etapas e
|
|
limites de cada serviço; os detalhes técnicos estão disponíveis
|
|
nas páginas para quem quiser aprofundar.
|
|
</p>
|
|
</div>
|
|
<MagneticButton
|
|
as="a"
|
|
href="/servicos"
|
|
className="ds-link ds-link-accent"
|
|
strength={0.2}
|
|
>
|
|
Conhecer todos os serviços
|
|
</MagneticButton>
|
|
</div>
|
|
|
|
<div
|
|
className="mt-sp-6 grid gap-sp-3 md:grid-cols-2 xl:grid-cols-3"
|
|
data-reel-stagger="left"
|
|
>
|
|
{serviceHubLinks.map((service) => (
|
|
<Link
|
|
key={service.href}
|
|
href={service.href}
|
|
className="min-w-0 rounded-[8px] border border-[var(--border)] bg-white/70 px-sp-4 py-sp-4 transition-colors duration-200 hover:border-[var(--slash)] hover:bg-white"
|
|
>
|
|
<div className="text-base font-semibold leading-snug text-[var(--ink)]">
|
|
{service.label}
|
|
</div>
|
|
<div className="mt-sp-2 text-sm leading-6 text-[var(--ink-80)]">
|
|
{service.description}
|
|
</div>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<motion.div
|
|
className="grid grid-cols-1 gap-sp-4 md:grid-cols-2 md:gap-sp-5 lg:grid-cols-3 lg:gap-sp-6"
|
|
initial="hidden"
|
|
whileInView="visible"
|
|
viewport={{ once: true, amount: 0.2 }}
|
|
variants={containerVariants}
|
|
>
|
|
{TIERS.map((tier) => (
|
|
<motion.div key={tier.id} variants={itemVariants} className="min-w-0">
|
|
<TierCard tier={tier} />
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
</Section>
|
|
);
|
|
}
|