TF
The Family

Equipment Data - Copy this React, Tailwind Component to your project

"use client"; import { useState, useRef, useCallback } from "react"; import { FaChevronLeft, FaChevronRight } from "react-icons/fa"; import { equipment } from "@/data/equipment"; const EquipmentCard = ({ equipment }) => { const [isExpanded, setIsExpanded] = useState(false); return ( <div className="flex flex-col bg-card p-4 rounded-lg shadow-sm transition-all duration-300 hover:shadow-lg h-full"> {equipment.map( item( <div id={item.id}> <div className="relative overflow-hidden rounded-lg aspect-video mb-4 group"> <img src={equipment.image} alt={equipment.name} className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105" onError={(e) => { e.target.src = "https://images.unsplash.com/photo-1545259741-2ea3ebf61fa3"; }} /> </div> <h3 className="text-heading font-heading truncate mb-2"> {equipment.name} </h3> <div className={`text-accent-foreground mb-4 ${ isExpanded ? "" : "line-clamp-2" }`} onClick={() => setIsExpanded(!isExpanded)} > {equipment.description} </div> <div className="mt-auto"> <div className="flex justify-between items-center mb-4"> <div> <p className="text-muted-foreground">Hourly Rate</p> <p className="text-accent-foreground"> ${equipment.hourlyRate} </p> </div> <div className="text-right"> <p className="text-muted-foreground">Daily Rate</p> <p className="text-heading font-heading"> ${equipment.dailyRate} </p> </div> </div> <button disabled={!equipment.availability} className={`w-full py-2 px-4 rounded-lg transition-all duration-300 ${ equipment.availability ? "bg-primary text-primary-foreground hover:bg-primary/90 active:scale-95" : "bg-muted text-muted-foreground cursor-not-allowed" }`} > {equipment.availability ? "Rent Now" : "Currently Unavailable"} </button> </div> </div> ) )} </div> ); }; const EquipmentCarousel = () => { const [currentIndex, setCurrentIndex] = useState(0); const scrollRef = useRef(null); const scroll = useCallback((direction) => { if (scrollRef.current) { const { scrollLeft, clientWidth } = scrollRef.current; const scrollTo = direction === "left" ? scrollLeft - clientWidth : scrollLeft + clientWidth; scrollRef.current.scrollTo({ left: scrollTo, behavior: "smooth", }); } }, []); return ( <div className="relative w-full py-8"> <div ref={scrollRef} className="flex gap-6 overflow-x-auto scrollbar-hide scroll-smooth" style={{ scrollbarWidth: "none", msOverflowStyle: "none" }} > {equipment.map((item) => ( <div key={item.id} className="flex-none w-full sm:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)] xl:w-[calc(25%-18px)]" > <EquipmentCard item={item} /> </div> ))} </div> <button onClick={() => scroll("left")} className="absolute left-0 top-1/2 -translate-y-1/2 bg-card/80 p-2 rounded-full shadow-sm hover:bg-card transition-all duration-300 z-10" aria-label="Previous equipment" > <FaChevronLeft className="text-xl text-accent-foreground" /> </button> <button onClick={() => scroll("right")} className="absolute right-0 top-1/2 -translate-y-1/2 bg-card/80 p-2 rounded-full shadow-sm hover:bg-card transition-all duration-300 z-10" aria-label="Next equipment" > <FaChevronRight className="text-xl text-accent-foreground" /> </button> </div> ); }; export default EquipmentCarousel;

Prompt
Component Preview

About

equipmentData - Showcase equipment with detailed cards, image scaling, and rental rates. Built with React and Tailwind. Get free template!

Share

Last updated 1 month ago