Interactive Image Slider
Interactive Image Slider é um componente de formulário para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Bund UI
MIT
forms
O que é
Interactive Image Slider é um componente de formulário para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Precisa de
npm i motion
Licença
Este componente vem de Bund UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Interactive Image Slider
"use client";
import React, { useState, useRef } from "react";
import { motion, AnimatePresence } from "motion/react";
export const InteractiveImageSlider = ({ items }: { items: string[] }) => {
const [activeIndex, setActiveIndex] = useState(0);
const [direction, setDirection] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
const prevMouseX = useRef<number>(0);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const width = rect.width;
const percentage = x / width;
const mouseDirection = e.clientX - prevMouseX.current;
prevMouseX.current = e.clientX;
if (mouseDirection !== 0) {
setDirection(mouseDirection);
}
if (percentage < 0.33) {
setActiveIndex(0);
} else if (percentage < 0.66) {
setActiveIndex(1);
} else {
setActiveIndex(2);
}
};
const getVariants = (index: number) => {
const isActive = index === activeIndex;
const offset = (index - activeIndex) * 100;
return {
initial: {
x: direction > 0 ? "100%" : "-100%",
opacity: 0,
rotateY: direction > 0 ? 45 : -45
},
animate: {
x: isActive ? "0%" : `${offset}%`,
opacity: isActive ? 1 : 0.3,
rotateY: 0,
zIndex: isActive ? 3 : index < activeIndex ? 1 : 2
},
exit: {
x: direction > 0 ? "-100%" : "100%",
opacity: 0,
rotateY: direction > 0 ? -45 : 45
}
};
};
return (
<div className="flex h-[80vh] items-center justify-between">
<div
ref={containerRef}
onMouseMove={handleMouseMove}
className="relative aspect-square w-80 overflow-hidden"
style={{ perspective: "1000px" }}>
<AnimatePresence mode="sync">
{items.map((image, index) => (
<motion.div
key={index}
variants={getVariants(index)}
initial="initial"
animate="animate"
exit="exit"
transition={{
type: "spring",
stiffness: 500,
damping: 50,
opacity: { duration: 0.3 }
}}
className="absolute inset-0 flex aspect-square w-80 items-center justify-center"
style={{
transformStyle: "preserve-3d"
}}>
<img
src={image}
alt={`Product ${index + 1}`}
className="h-full w-full object-cover"
style={{
filter: activeIndex === index ? "brightness(1)" : "brightness(0.6)"
}}
/>
</motion.div>
))}
</AnimatePresence>
<div className="absolute bottom-4 left-1/2 z-10 flex -translate-x-1/2 transform gap-1">
{items.map((_, index) => (
<div
key={index}
className={`h-1 rounded-full transition-all duration-300 ${
index === activeIndex ? "w-4 bg-white" : "w-1 bg-white/40"
}`}
/>
))}
</div>
</div>
</div>
);
};
import React from "react";
import { InteractiveImageSlider } from "./interactive-image-slider";
const images = [
"/images/products/list1.png",
"/images/products/list2.png",
"/images/products/list3.png"
];
export default function InteractiveImageSliderExample() {
return <InteractiveImageSlider items={images} />;
}