/servicos abre com as 3 ofertas e depois outros serviços; H1 de criação de sites e de engenharia com o nome da oferta; capa de cada serviço pelo assunto (SEV fora do próprio case cai de ~11 para 2 imagens); diagrama de fluxo em SVG nos serviços sem case; cases com o que o cliente passou a poder fazer e contato logo depois de Como ficou; FAQ num componente só; lastmod por rota; ProfessionalService com areaServed.
72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import { secondaryButtonLight, textLink } from "@/app/components/button-styles";
|
|
import HoverPrefetchLink from "@/app/components/HoverPrefetchLink";
|
|
import {
|
|
buttonLabels,
|
|
caseStudies,
|
|
type ServiceOffer,
|
|
} from "@/lib/site-content";
|
|
|
|
function OfferCard({ offer }: { offer: ServiceOffer }) {
|
|
const proofCases = offer.proof.caseIds.flatMap((id) => {
|
|
const caseStudy = caseStudies.find((item) => item.id === id);
|
|
return caseStudy ? [caseStudy] : [];
|
|
});
|
|
|
|
return (
|
|
<article className="ds-card">
|
|
<h3 className="ds-card-title !mt-0 text-balance">{offer.name}</h3>
|
|
<p className="ds-copy !flex-grow-0">{offer.summary}</p>
|
|
<ul className="ds-list space-y-sp-2">
|
|
{offer.deliverables.map((item) => (
|
|
<li key={item}>{item}</li>
|
|
))}
|
|
</ul>
|
|
<p className="ds-kicker mt-sp-6">{offer.proof.label}</p>
|
|
{proofCases.length > 0 ? (
|
|
<ul className="mt-sp-2 flex flex-wrap gap-x-sp-4">
|
|
{proofCases.map((caseStudy) => (
|
|
<li key={caseStudy.id}>
|
|
<HoverPrefetchLink
|
|
href={`/cases/${caseStudy.id}`}
|
|
className={`${textLink} focus-visible:outline-2 focus-visible:outline-offset-4`}
|
|
>
|
|
<span className="sr-only">{buttonLabels.case} </span>
|
|
{caseStudy.title}
|
|
</HoverPrefetchLink>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : null}
|
|
{offer.proof.note ? (
|
|
<p className="ds-copy !mt-sp-2 !flex-grow-0 text-[15px]">
|
|
{offer.proof.note}
|
|
</p>
|
|
) : null}
|
|
<div className="mt-sp-6">
|
|
<HoverPrefetchLink
|
|
href={offer.href}
|
|
className={`${secondaryButtonLight} focus-visible:outline-2 focus-visible:outline-offset-4`}
|
|
>
|
|
{buttonLabels.service}
|
|
<span className="sr-only"> {offer.name}</span>
|
|
</HoverPrefetchLink>
|
|
</div>
|
|
</article>
|
|
);
|
|
}
|
|
|
|
/** As três ofertas, lado a lado no computador: nome, o que a pessoa recebe, onde ver funcionando e o link da página certa. */
|
|
export function ServiceOfferCards({
|
|
offers,
|
|
}: {
|
|
offers: readonly ServiceOffer[];
|
|
}) {
|
|
return (
|
|
<div className="mt-sp-8 grid items-stretch gap-sp-6 lg:grid-cols-3">
|
|
{offers.map((offer) => (
|
|
<OfferCard key={offer.id} offer={offer} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|