feat(cases): prova certa por serviço, páginas internas com trabalho no topo

Diagnóstico sem case que não cabe; desktop com o GCC Installer como projeto próprio; IoT com o Twins Lab e a nota da Apolo. Mosaico de pôsteres em /servicos e /cases, faixa baixa em uma coluna no currículo, privacidade e laboratório; Laboratório como lista compacta; SEV começando por catálogo, pedido no WhatsApp e painel; Joinville e SC nos títulos; imagens do LCP com fetchPriority e sizes reais; pré-carregamento só no hover; 404 com Open Graph próprio.
This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 17:01:35 -03:00
1 parent 7b633f0f4a
commit de6af74a0c
37 files changed
+1062 -254

No files matched your search

+32 -3
View File
@@ -5,12 +5,40 @@ import {
} from "@/app/components/showcase/BrowserFrame";
import { getCaseMedia } from "./case-media";
/** Capa do case: o pôster do site dentro de uma moldura de navegador. Sem captura gravada, não mostra nada. */
/**
* Largura real da capa em cada lugar da página, para o navegador baixar a imagem do tamanho certo
* (com 100vw, um celular de 390 px pedia a versão de 750 px para uma capa de 300 px). As contas seguem o
* padding das seções (20 px até 768 px; depois 6vw, no máximo 64 px), a coluna central de 1240 px e os cartões
* (borda e 20 a 28 px de padding).
*/
export const coverSizes = {
/** Topo do case e do serviço: coluna da direita a partir de 1024 px, e a largura da página abaixo disso. */
hero: "(min-width: 1440px) 560px, (min-width: 1024px) 40vw, (min-width: 769px) 88vw, calc(100vw - 40px)",
/** Capa dentro de um cartão (`ds-card`) da grade de duas colunas, que vira uma só até 1024 px. */
card: "(min-width: 1440px) 560px, (min-width: 1025px) calc(50vw - 134px), (min-width: 769px) calc(88vw - 56px), calc(100vw - 88px)",
/** Capa solta numa grade de duas colunas, sem cartão em volta (a partir de 768 px). */
column:
"(min-width: 1440px) 604px, (min-width: 1068px) calc(50vw - 80px), (min-width: 768px) calc(44vw - 16px), calc(100vw - 40px)",
} as const;
/**
* Props da imagem que abre a página (a maior acima da dobra): carrega na hora e com prioridade de rede alta.
* No Next 16 a prop `priority` do `Image` só gera o `<link rel="preload">`; a prioridade de rede vem do `fetchPriority`.
*/
export const priorityImageProps = {
loading: "eager",
fetchPriority: "high",
} as const;
/**
* Capa do case: o pôster do site dentro de uma moldura de navegador. Sem captura gravada, não mostra nada.
* `priority` é para a imagem que abre a página: aplica `priorityImageProps`.
*/
export function CaseCover({
id,
title,
demoUrl,
sizes = "(min-width: 1024px) 560px, 100vw",
sizes = coverSizes.card,
priority = false,
}: {
id: string;
@@ -21,6 +49,7 @@ export function CaseCover({
}) {
const media = getCaseMedia(id, "desktop");
if (!media) return null;
const priorityProps = priority ? priorityImageProps : {};
return (
<BrowserFrame url={displayUrl({ demoUrl, title })}>
@@ -30,7 +59,7 @@ export function CaseCover({
alt={`Captura de tela do site ${title}`}
fill
sizes={sizes}
priority={priority}
{...priorityProps}
className="object-cover object-top"
/>
</div>