Skip to content

Instantly share code, notes, and snippets.

@ali-master
Created August 4, 2024 14:05
Show Gist options
  • Save ali-master/b4b8620989e098e22c2739147252ae52 to your computer and use it in GitHub Desktop.
Save ali-master/b4b8620989e098e22c2739147252ae52 to your computer and use it in GitHub Desktop.
React Timeline component
import React, { useRef, useState } from "react";
import { motion } from "framer-motion";
const years = Array.from({ length: 2024 - 1993 + 1 }, (_, i) => 2024 - i);
export default function Timeline() {
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
const [selected, setSelected] = useState<number | null>(null);
const handleMouseEnter = (index: number) => {
setHoveredIndex(index);
};
const handleMouseLeave = () => {
setHoveredIndex(null);
};
const calculateScale = (index: number) => {
if (hoveredIndex === null) return 0.4;
const distance = Math.abs(index - hoveredIndex);
return Math.max(1 - distance * 0.2, 0.4);
};
return (
<div className="flex h-[500px] w-full items-center justify-center">
<div className="flex flex-col">
{years.map((year, i) => {
const isSelected = selected === i;
return (
<button
className="relative inline-flex items-end justify-center py-1"
onMouseEnter={() => handleMouseEnter(i)}
onMouseLeave={handleMouseLeave}
onClick={() => setSelected(i)}
onTouchStart={() => handleMouseEnter(i)}
onTouchEnd={handleMouseLeave}
>
<motion.div
key={i}
className={`h-1 w-10 rounded-[4px] ${
selected === i
? "bg-yellow-400"
: "bg-mauve-light-11 dark:bg-mauve-dark-11"
}`}
animate={{
scale: calculateScale(i),
}}
initial={{ scale: 0.4 }}
transition={{ type: "spring", stiffness: 300, damping: 20 }}
/>
{hoveredIndex === i ? (
<motion.span
className={`absolute -top-0.5 left-12 text-[11px] ${
isSelected
? "text-yellow-400"
: "text-mauve-light-11 dark:text-mauve-dark-11"
}`}
initial={{ opacity: 0, filter: `blur(4px)`, scale: 0.4 }}
animate={{ opacity: 1, filter: `blur(0px)`, scale: 1 }}
transition={{ duration: 0.15, delay: 0.1 }}
>
{year}
</motion.span>
) : null}
</button>
);
})}
</div>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment