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.
29 lines
884 B
TypeScript
29 lines
884 B
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
const QUERY = "(prefers-reduced-motion: reduce)";
|
|
|
|
/**
|
|
* Preferência `prefers-reduced-motion` do sistema operacional, lida com matchMedia (sem biblioteca de animação).
|
|
* Falso no servidor e na primeira renderização no navegador, para o HTML hidratar igual ao do servidor.
|
|
*
|
|
* @example
|
|
* const reducedMotion = useReducedMotion();
|
|
* return <div data-calm={reducedMotion || undefined} />;
|
|
*/
|
|
export function useReducedMotion(): boolean {
|
|
const [reduced, setReduced] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (typeof window.matchMedia !== "function") return;
|
|
const query = window.matchMedia(QUERY);
|
|
const update = () => setReduced(query.matches);
|
|
update();
|
|
query.addEventListener("change", update);
|
|
return () => query.removeEventListener("change", update);
|
|
}, []);
|
|
|
|
return reduced;
|
|
}
|