reactbits-mcp-server
Version:
MCP Server for React Bits - Access 99+ React components with animations, backgrounds, and UI elements
133 lines (116 loc) • 5.38 kB
JSX
import { useEffect, useRef, useState } from "react";
import { motion, useMotionValue, useAnimation, useTransform } from "framer-motion";
import "./RollingGallery.css";
const IMGS = [
"https://images.unsplash.com/photo-1528181304800-259b08848526?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1506665531195-3566af2b4dfa?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?q=80&w=3456&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1495103033382-fe343886b671?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1506781961370-37a89d6b3095?q=80&w=3264&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1599576838688-8a6c11263108?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1494094892896-7f14a4433b7a?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://plus.unsplash.com/premium_photo-1664910706524-e783eed89e71?q=80&w=3869&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1503788311183-fa3bf9c4bc32?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1585970480901-90d6bb2a48b5?q=80&w=3774&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
];
const RollingGallery = ({ autoplay = false, pauseOnHover = false, images = [] }) => {
images = IMGS;
const [isScreenSizeSm, setIsScreenSizeSm] = useState(window.innerWidth <= 640);
const cylinderWidth = isScreenSizeSm ? 1100 : 1800;
const faceCount = images.length;
const faceWidth = (cylinderWidth / faceCount) * 1.5;
const dragFactor = 0.05;
const radius = cylinderWidth / (2 * Math.PI);
const rotation = useMotionValue(0);
const controls = useAnimation();
const autoplayRef = useRef();
const handleDrag = (_, info) => {
rotation.set(rotation.get() + info.offset.x * dragFactor);
};
const handleDragEnd = (_, info) => {
controls.start({
rotateY: rotation.get() + info.velocity.x * dragFactor,
transition: { type: "spring", stiffness: 60, damping: 20, mass: 0.1, ease: "easeOut" },
});
};
const transform = useTransform(rotation, (value) => {
return `rotate3d(0, 1, 0, ${value}deg)`;
});
useEffect(() => {
if (autoplay) {
autoplayRef.current = setInterval(() => {
controls.start({
rotateY: rotation.get() - (360 / faceCount),
transition: { duration: 2, ease: "linear" },
});
rotation.set(rotation.get() - (360 / faceCount));
}, 2000);
return () => clearInterval(autoplayRef.current);
}
}, [autoplay, rotation, controls, faceCount]);
useEffect(() => {
const handleResize = () => {
setIsScreenSizeSm(window.innerWidth <= 640);
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const handleMouseEnter = () => {
if (autoplay && pauseOnHover) {
clearInterval(autoplayRef.current);
controls.stop();
}
};
const handleMouseLeave = () => {
if (autoplay && pauseOnHover) {
controls.start({
rotateY: rotation.get() - (360 / faceCount),
transition: { duration: 2, ease: "linear" },
});
rotation.set(rotation.get() - (360 / faceCount));
autoplayRef.current = setInterval(() => {
controls.start({
rotateY: rotation.get() - (360 / faceCount),
transition: { duration: 2, ease: "linear" },
});
rotation.set(rotation.get() - (360 / faceCount));
}, 2000);
}
};
return (
<div className="gallery-container">
<div className="gallery-gradient gallery-gradient-left"></div>
<div className="gallery-gradient gallery-gradient-right"></div>
<div className="gallery-content">
<motion.div
drag="x"
className="gallery-track"
onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}
style={{
transform: transform,
rotateY: rotation,
width: cylinderWidth,
transformStyle: "preserve-3d",
}}
onDrag={handleDrag}
onDragEnd={handleDragEnd}
animate={controls}
>
{images.map((url, i) => (
<div
key={i}
className="gallery-item"
style={{
width: `${faceWidth}px`,
transform: `rotateY(${i * (360 / faceCount)}deg) translateZ(${radius}px)`,
}}
>
<img src={url} alt="gallery" className="gallery-img" />
</div>
))}
</motion.div>
</div>
</div>
);
};
export default RollingGallery;