Amiel's picture
Upload folder using huggingface_hub
676fc08 verified
"use client";
import {
useState,
useRef,
useEffect,
type RefObject,
type ReactNode,
} from "react";
type FloatingMenuProps = {
targetRef: RefObject<HTMLDivElement | null>;
children: ReactNode;
//Offset from the top of the browser when fixed (optional)
fixedTopOffset?: number;
fixedRightOffset?: number;
};
function FloatingMenu({
targetRef,
children,
fixedTopOffset = 10,
fixedRightOffset = 0,
}: FloatingMenuProps) {
const [isFixed, setIsFixed] = useState(false);
const [fixedTop, setFixedTop] = useState<number>(0);
const [fixedRight, setFixedRight] = useState<number>(0);
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleScroll = () => {
if (!targetRef.current || !menuRef.current) return;
const targetRect = targetRef.current.getBoundingClientRect();
// Determine whether the target Div is completely above the viewport (the top exceeds the screen)
if (targetRect.bottom < 0) {
// The target Div is completely scrolled out of the top, and the menu is no longer fixed
setIsFixed(false);
setFixedTop(0);
setFixedRight(0);
}
// Determine whether the target Div is within the viewport or partially within the viewport
else if (targetRect.top <= 0) {
// The target Div enters the viewport and starts to be fixed
setIsFixed(true);
// Set a fixed top value
setFixedTop(fixedTopOffset);
// Set a fixed right value
setFixedRight(targetRect.right - targetRect.width);
} else {
// The target Div is still above the viewport, the menu is not fixed
setIsFixed(false);
setFixedTop(0);
setFixedRight(0);
}
};
window.addEventListener("scroll", handleScroll);
// Execute once immediately when the component is loaded to initialize the state
handleScroll();
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, [targetRef, fixedTopOffset]);
return (
<div
ref={menuRef}
style={{
position: isFixed ? "fixed" : "absolute",
top: isFixed ? fixedTop : 0,
right: fixedRightOffset + (isFixed ? fixedRight : 0),
// Make sure the menu is above the content
zIndex: 30,
}}
>
{children}
</div>
);
}
export default FloatingMenu;