"use client"; import { AnimatePresence, motion, useReducedMotion } from "framer-motion"; import { useEffect, useState } from "react"; import { EASE_OUT_EXPO } from "@/lib/motion"; /** * Appears once the visitor is far enough down that the navbar is a long way * back — a game page is five full bands tall, and the only way up was the * scrollbar. * * Threshold is in viewport heights rather than pixels, so it does not pop up * on the second scroll tick of a tall desktop screen. */ export function BackToTop() { const reduced = useReducedMotion(); const [visible, setVisible] = useState(false); useEffect(() => { const onScroll = () => setVisible(window.scrollY > window.innerHeight * 1.5); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); return ( {visible && ( window.scrollTo({ top: 0, behavior: reduced ? "auto" : "smooth" }) } initial={{ opacity: 0, scale: 0.8, y: 12 }} animate={{ opacity: 1, scale: 1, y: 0 }} exit={{ opacity: 0, scale: 0.8, y: 12 }} transition={{ duration: 0.3, ease: EASE_OUT_EXPO }} whileHover={{ y: -3 }} whileTap={{ scale: 0.92 }} className="group fixed bottom-6 right-6 z-40 flex h-11 w-11 items-center justify-center rounded-full border border-border bg-background/80 text-foreground-muted backdrop-blur-md transition-colors hover:border-accent hover:text-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent lg:bottom-10 lg:right-10" > )} ); }