Files

123 lines
6.1 KiB
TypeScript

import Image from "next/image";
import { getShowcaseAssets } from "@/lib/project-showcase";
import HoverPrefetchLink from "./HoverPrefetchLink";
import { BrowserFrame } from "./showcase/BrowserFrame";
import { PhoneFrame } from "./showcase/PhoneFrame";
/** Endereço mostrado na barra do navegador (mesmo formato de displayUrl em showcase/BrowserFrame). */
export type HeroWorkUrl = { text: string; secure: boolean } | null;
const DESKTOP_PROJECT = "lavacao-047";
const DESKTOP_PROJECT_TITLE = "Lavação 047";
const MOBILE_PROJECT = "as-servicos";
/** No celular o cartão mostra o site da SEV e leva ao case; o navegador da tela larga, ao lado do título, mostra o da Lavação 047. */
const SMALL_SCREEN_PROJECT = "sev-modaintima";
const SMALL_SCREEN_TITLE = "SEV Moda Íntima";
const SMALL_SCREEN_HREF = `/cases/${SMALL_SCREEN_PROJECT}`;
/**
* Altura da imagem do cartão de celular (px): a largura é a da coluna (cerca de 342 px num celular de 390 px). Com 72 px
* a área da imagem (cerca de 25 mil px²) fica abaixo da do H1 (cerca de 29 mil px² a 390 px): com 96 px ela era maior, e
* numa rede lenta a imagem, que chega depois, passava a ser o LCP no lugar do título (medido com rede e CPU limitadas).
*/
const SMALL_CARD_IMAGE_HEIGHT = 72;
/**
* Faixa de 72 px de altura: o pôster do computador (16:10) cortado nela mostrava só uma fatia do topo, e o título
* "Nova Coleção" saía pela metade. O pôster do celular (390x844, o mesmo site) tem o título em letras maiores: o
* `object-position` leva a faixa até a linha "Nova Coleção", que cabe inteira nela.
*/
const SMALL_CARD_IMAGE_POSITION = "object-[50%_57%]";
/**
* Trabalho real do hero, em dois formatos. Em telas de 1024 px ou mais, ao lado do título: o pôster do site da
* Lavação 047 no navegador (a barra de endereço só mostra domínio próprio; o da Lavação é de hospedagem, então ela
* fica com "pré-visualização") e o do aplicativo da AS Serviços no celular, numa coluna de cerca de 40% da largura. Abaixo de 1024 px, um cartão largo e clicável
* (a largura da coluna, cerca de 350 px num celular) com o pôster do site da SEV, abaixo dos botões, que leva ao
* case da SEV; antes era uma moldura de celular de 65 por 160 px, pequena demais para ver o que era.
* Os pôsteres vão pelo next/image com `sizes` do tamanho em que aparecem (um arquivo de 1440 px para 491 px de tela
* era banda desperdiçada), em `loading="lazy"` e prioridade baixa: no celular o título segue como o maior elemento da
* dobra (LCP; ver SMALL_CARD_IMAGE_HEIGHT), e a imagem que fica escondida pelo breakpoint (display: none) nem é
* baixada. Em tela larga o pôster do navegador é maior que o título e, numa rede lenta, vira o LCP quando chega.
*/
export default function HeroWork({ url = null }: { url?: HeroWorkUrl }) {
const desktop = getShowcaseAssets(DESKTOP_PROJECT, "desktop");
const phone = getShowcaseAssets(MOBILE_PROJECT, "mobile");
const smallCard = getShowcaseAssets(SMALL_SCREEN_PROJECT, "mobile");
return (
<>
<div
data-testid="hero-work"
className="hero-in pointer-events-none absolute top-1/2 right-sp-12 hidden w-[40%] -translate-y-[46%] [--d:.8s] lg:block"
>
<BrowserFrame url={url} className="w-[88%]">
{/* a moldura mostra ~491 px em 1440 px de tela: 36vw até 1400 px, e fixo dali em diante */}
<Image
src={desktop.poster}
alt={`Site da ${DESKTOP_PROJECT_TITLE} aberto no computador`}
width={desktop.width}
height={desktop.height}
sizes="(min-width: 1400px) 500px, 36vw"
loading="lazy"
fetchPriority="low"
className="block h-auto w-full"
/>
</BrowserFrame>
{/* position inline: .ds-phone (showcase.css, sem camada) define position: relative e vence a utilidade "absolute" */}
<PhoneFrame
className="right-0 bottom-[-12%] w-[26%]"
style={{ position: "absolute" }}
>
<Image
src={phone.poster}
alt="Site da AS Serviços aberto no celular"
width={phone.width}
height={phone.height}
sizes="(min-width: 1400px) 136px, 10vw"
loading="lazy"
fetchPriority="low"
className="absolute inset-0 block h-full w-full object-cover object-top"
/>
</PhoneFrame>
</div>
<HoverPrefetchLink
data-testid="hero-work-mobile"
href={SMALL_SCREEN_HREF}
className="hero-in group mt-sp-5 flex w-full flex-col overflow-hidden border border-white/20 bg-white/[0.05] font-display no-underline transition-colors hover:border-white/45 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--slash)] motion-reduce:transition-none [--d:.8s] lg:hidden"
>
<span
className="relative block w-full overflow-hidden bg-[var(--ink)]"
style={{ height: SMALL_CARD_IMAGE_HEIGHT }}
>
<Image
src={smallCard.poster}
alt=""
width={smallCard.width}
height={smallCard.height}
sizes="(min-width: 1024px) 1px, calc(100vw - 48px)"
loading="lazy"
fetchPriority="low"
className={`absolute inset-0 block h-full w-full object-cover ${SMALL_CARD_IMAGE_POSITION}`}
/>
</span>
<span className="flex min-h-12 items-center justify-between gap-sp-4 px-sp-4 py-sp-2 text-[15px] leading-6 text-[#f4f2ed]">
<span className="flex flex-col">
<span className="font-semibold">Site da {SMALL_SCREEN_TITLE}</span>{" "}
<span className="text-[rgba(244,242,237,.72)]">Ver case</span>
</span>
<svg
aria-hidden="true"
viewBox="0 0 16 16"
className="h-4 w-4 shrink-0 transition-transform group-hover:translate-x-1 motion-reduce:transition-none"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M2 8h11M9 3.5 13.5 8 9 12.5" />
</svg>
</span>
</HoverPrefetchLink>
</>
);
}