Projetos sobem sobre o palco do hero e o celular tem hero de uma tela sem mergulho; passagens com animation-timeline em CSS, sem GSAP nem motion; troca da vitrine sem texto duplicado; moldura de celular só com pôster e scrub reencodado em 960 px (9,4 para 5,2 MB); 3D monta na primeira interação e para quando parado; transição entre páginas do mesmo segmento; foco em anel duplo; texto de 15 px no celular; código morto removido.
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
"use client";
|
|
|
|
import { type CSSProperties, type ReactNode, useRef } from "react";
|
|
import { useInView } from "@/app/hooks/useInView";
|
|
|
|
interface RevealProps {
|
|
children: ReactNode;
|
|
y?: number;
|
|
duration?: number;
|
|
delay?: number;
|
|
className?: string;
|
|
}
|
|
|
|
/**
|
|
* Conteúdo que sobe e aparece uma vez, quando chega à janela. A animação é CSS (.ds-reveal em globals.css):
|
|
* só opacidade e deslocamento, que a placa de vídeo compõe sem redesenhar. Sem JavaScript ou com movimento
|
|
* reduzido, o conteúdo já nasce visível.
|
|
*/
|
|
export function Reveal({
|
|
children,
|
|
y = 36,
|
|
duration = 0.8,
|
|
delay = 0,
|
|
className = "",
|
|
}: RevealProps) {
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
const shown = useInView(ref);
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={`ds-reveal ${className}`.trim()}
|
|
data-shown={shown ? "" : undefined}
|
|
style={
|
|
{
|
|
"--reveal-y": `${y}px`,
|
|
"--reveal-duration": `${duration}s`,
|
|
"--reveal-delay": `${delay}s`,
|
|
} as CSSProperties
|
|
}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|