perf(movimento): sem tela vazia, passagens em CSS e vitrine leve
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.
This commit is contained in:
1 parent
10f170abf4
commit
318a764190
77 files changed
+4293
-4951
No files matched your search
+20
-44
@@ -1,22 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "motion/react";
|
||||
import type { ReactNode } from "react";
|
||||
import { useState } from "react";
|
||||
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
|
||||
import { type CSSProperties, type ReactNode, useRef } from "react";
|
||||
import { useInView } from "@/app/hooks/useInView";
|
||||
|
||||
interface RevealProps {
|
||||
children: ReactNode;
|
||||
y?: number;
|
||||
duration?: number;
|
||||
delay?: number;
|
||||
ease?: string;
|
||||
start?: string;
|
||||
end?: string;
|
||||
scrub?: boolean | 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,
|
||||
@@ -24,46 +23,23 @@ export function Reveal({
|
||||
delay = 0,
|
||||
className = "",
|
||||
}: RevealProps) {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
const [animating, setAnimating] = useState(!shouldReduceMotion);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const shown = useInView(ref);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
initial={
|
||||
shouldReduceMotion
|
||||
? { opacity: 0 }
|
||||
: { opacity: 0, y, clipPath: "inset(100% 0 0 0)" }
|
||||
<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
|
||||
}
|
||||
whileInView={
|
||||
shouldReduceMotion
|
||||
? { opacity: 1 }
|
||||
: { opacity: 1, y: 0, clipPath: "inset(0% 0 0 0)" }
|
||||
}
|
||||
viewport={{ once: true, amount: 0.2 }}
|
||||
transition={
|
||||
shouldReduceMotion
|
||||
? { duration: 0.25 }
|
||||
: {
|
||||
duration,
|
||||
delay,
|
||||
ease: [0.16, 1, 0.3, 1],
|
||||
}
|
||||
}
|
||||
style={{
|
||||
willChange:
|
||||
animating && !shouldReduceMotion
|
||||
? "transform, opacity, clip-path"
|
||||
: undefined,
|
||||
}}
|
||||
onAnimationStart={() => {
|
||||
if (!shouldReduceMotion) {
|
||||
setAnimating(true);
|
||||
}
|
||||
}}
|
||||
onAnimationComplete={() => setAnimating(false)}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user