Skip to content

Instantly share code, notes, and snippets.

@kelvinpraises
Created March 15, 2024 19:41
Show Gist options
  • Save kelvinpraises/cca0ff162d5d43f285fc7caebec01443 to your computer and use it in GitHub Desktop.
Save kelvinpraises/cca0ff162d5d43f285fc7caebec01443 to your computer and use it in GitHub Desktop.
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
const items = [
"Community",
"NFT Marketplace",
"Partnerships",
"Events",
"Blog",
]; // Add more or remove but always try to make it odd or adjust the visibility from the css below
const DrumComponent = () => {
const [centerIndex, setCenterIndex] = useState(2); // Start with the middle item or make it random
const handleClick = (index) => {
// Calculate the shortest path to bring clicked item to center
let offset = index - centerIndex;
if (Math.abs(offset) > items.length / 2) {
offset -= Math.sign(offset) * items.length;
}
setCenterIndex(
(prevIndex) => (prevIndex + offset + items.length) % items.length
);
};
// This function generates the items with their positions adjusted based on the centerIndex
const generateItems = () => {
return items.map((item, index) => {
let position = index - centerIndex;
// Adjust position for circular buffer effect https://en.wikipedia.org/wiki/Circular_buffer
if (position < -Math.floor(items.length / 2)) {
position += items.length;
} else if (position > Math.floor(items.length / 2)) {
position -= items.length;
}
return (
<motion.div
key={item}
initial={{ y: 50 * position, opacity: 0 }} // Adjust y to 100 or higher for a spread in load effect or a lower number for a spread out effect, 50 makes it balanced
animate={{ y: 50 * position, opacity: 1 }}
exit={{ y: 50 * position, opacity: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }} // adjust the stiffness to a lower number like 30 to see how it works
style={{
position: "absolute",
top: "40%", // adjust this to position the items
transform: "translate(-50%, -50%)",
height: "50px",
width: "200px",
display: "flex",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
backgroundColor: position === 0 ? "lightgreen" : "transparent",
}}
onClick={() => handleClick(index)}
>
{item}
</motion.div>
);
});
};
return (
<div style={{ position: "relative", height: "250px", overflow: "hidden" }}>
<AnimatePresence>{generateItems()}</AnimatePresence>
</div>
);
};
export default DrumComponent;
@kelvinpraises
Copy link
Author

Video demo

Screen.Recording.2024-03-15.at.20.45.58.mov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment