Hero: replace particle field with cobe globe (Capricorn view, multi-axis drag, reduced-motion safe), telemetry HUD with pointer parallax, particle text build effect, Space Grotesk display font. SEO: short titles with template, PT-BR accents, twitter cards on dynamic cases, escaped JSON-LD via lib/jsonld.ts, CSP report-only, 25 service FAQs answer-first. Design: fix TW4 layered reset killing spacing utilities, literal @theme tokens, mobile hero overflow, header overlap, empty case cards. Remove framer-motion (unified on motion/react), header version badge, phone number from hero CTA. Production build verified (24 static pages).
68 lines
1.6 KiB
TypeScript
68 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import type { ReactNode } from "react";
|
|
import { useEffect, useRef } from "react";
|
|
|
|
export function SmoothScrollProvider({ children }: { children: ReactNode }) {
|
|
const teardownRef = useRef<() => void>(() => {});
|
|
|
|
useEffect(() => {
|
|
const prefersReducedMotion = window.matchMedia(
|
|
"(prefers-reduced-motion: reduce)",
|
|
).matches;
|
|
const hasCoarsePointer = window.matchMedia("(pointer: coarse)").matches;
|
|
|
|
if (prefersReducedMotion || hasCoarsePointer) {
|
|
return undefined;
|
|
}
|
|
|
|
let isMounted = true;
|
|
|
|
const setupSmoothScroll = async () => {
|
|
const [{ default: Lenis }, { gsap }, { ScrollTrigger }] =
|
|
await Promise.all([
|
|
import("lenis"),
|
|
import("gsap"),
|
|
import("gsap/ScrollTrigger"),
|
|
]);
|
|
|
|
if (!isMounted) {
|
|
return;
|
|
}
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
const lenis = new Lenis({
|
|
duration: 1.2,
|
|
easing: (t) => Math.min(1, 1.001 - 2 ** (-10 * t)),
|
|
smoothWheel: true,
|
|
});
|
|
|
|
const handleScroll = () => ScrollTrigger.update();
|
|
const tick = (time: number) => {
|
|
lenis.raf(time * 1000);
|
|
};
|
|
|
|
lenis.on("scroll", handleScroll);
|
|
gsap.ticker.add(tick);
|
|
gsap.ticker.lagSmoothing(0);
|
|
|
|
teardownRef.current = () => {
|
|
lenis.off?.("scroll", handleScroll);
|
|
gsap.ticker.remove(tick);
|
|
lenis.destroy();
|
|
};
|
|
};
|
|
|
|
void setupSmoothScroll();
|
|
|
|
return () => {
|
|
isMounted = false;
|
|
teardownRef.current();
|
|
teardownRef.current = () => {};
|
|
};
|
|
}, []);
|
|
|
|
return <>{children}</>;
|
|
}
|