Implement scrolling testimonials component with improved layout and animation

This commit is contained in:
fgrreloaded
2025-03-25 21:34:30 +05:30
parent 42dc91aed6
commit 7f91dd7592
2 changed files with 71 additions and 36 deletions

View File

@@ -1,3 +1,5 @@
import { useRef } from "react";
const testimonials = [ const testimonials = [
{ {
name: "$ user@dev.sh", name: "$ user@dev.sh",
@@ -26,12 +28,20 @@ const testimonials = [
]; ];
const Testimonials = () => { const Testimonials = () => {
const scrollContainerRef = useRef<HTMLDivElement>(null);
const duplicatedTestimonials = [
...testimonials,
...testimonials,
...testimonials,
];
return ( return (
<section className="py-20 relative dark:bg-black"> <section className="py-20 relative overflow-hidden w-screen">
<div className="absolute inset-0 opacity-90 z-0" /> <div className="absolute inset-0 opacity-90 z-0" />
<div className="max-w-6xl mx-auto relative z-10"> <div className="w-full mx-auto relative z-10">
<div className="text-center mb-16"> <div className="text-center mb-16 max-w-6xl mx-auto">
<h2 className="text-4xl font-bold text-gray-900 dark:text-white"> <h2 className="text-4xl font-bold text-gray-900 dark:text-white">
<span className="text-gray-600 dark:text-gray-400">$</span> cat <span className="text-gray-600 dark:text-gray-400">$</span> cat
testimonials.log testimonials.log
@@ -42,41 +52,53 @@ const Testimonials = () => {
</p> </p>
</div> </div>
<div className="grid md:grid-cols-3 gap-6"> <div className="w-full overflow-hidden relative">
{testimonials.map((testimonial) => ( <div className="absolute left-0 top-0 bottom-0 w-[100px] z-10 bg-gradient-to-r from-white to-transparent dark:from-black pointer-events-none" />
<div <div
key={testimonial.name} ref={scrollContainerRef}
className="group rounded-md border border-gray-200 dark:border-gray-800 bg-gray-50/50 dark:bg-black/30 p-6 hover:border-blue-500/30 transition-colors duration-200" className="flex animate-scroll px-[5%]"
> style={{
<div className="flex items-center space-x-4 mb-4"> animation: "scroll 30s linear infinite",
<div className="shrink-0"> willChange: "transform",
<div className="w-10 h-10 rounded-sm bg-gradient-to-r from-gray-100 to-gray-200 dark:from-gray-900 dark:to-gray-800 flex items-center justify-center text-gray-700 dark:text-gray-300 font-mono"> }}
{testimonial.avatar} >
{duplicatedTestimonials.map((testimonial) => (
<div
key={testimonial.name}
className="group rounded-md border border-gray-200 dark:border-gray-800 bg-gray-50/50 dark:bg-black/10 p-6 hover:border-blue-500/30 transition-colors duration-200 w-[25%] md:w-[30%] mx-4 flex-shrink-0"
>
<div className="flex items-center space-x-4 mb-4">
<div className="shrink-0">
<div className="w-10 h-10 rounded-sm bg-gradient-to-r from-gray-100 to-gray-200 dark:from-gray-900 dark:to-gray-800 flex items-center justify-center text-gray-700 dark:text-gray-300 font-mono">
{testimonial.avatar}
</div>
</div>
<div>
<h3 className="text-gray-900 dark:text-white font-mono">
{testimonial.name}
</h3>
<p className="text-sm font-mono">
<span className="text-gray-600 dark:text-gray-400">
{testimonial.role}
</span>
<span className="text-gray-500 mx-1">@</span>
<span className="text-gray-600 dark:text-gray-400">
{testimonial.company}
</span>
</p>
</div> </div>
</div> </div>
<div> <p className="text-gray-700 dark:text-gray-300 leading-relaxed font-mono border-l-2 border-blue-700 pl-4">
<h3 className="text-gray-900 dark:text-white font-mono"> {testimonial.content}
{testimonial.name} </p>
</h3>
<p className="text-sm font-mono">
<span className="text-gray-600 dark:text-gray-400">
{testimonial.role}
</span>
<span className="text-gray-500 mx-1">@</span>
<span className="text-gray-600 dark:text-gray-400">
{testimonial.company}
</span>
</p>
</div>
</div> </div>
<p className="text-gray-700 dark:text-gray-300 leading-relaxed font-mono border-l-2 border-blue-700 pl-4"> ))}
{testimonial.content} </div>
</p>
</div> <div className="absolute right-0 top-0 bottom-0 w-[100px] z-10 bg-gradient-to-l from-white to-transparent dark:from-black pointer-events-none" />
))}
</div> </div>
<div className="text-center mt-12"> <div className="text-center mt-12 max-w-6xl mx-auto">
<div className="inline-block py-2 px-4 bg-gray-50 dark:bg-black border border-gray-200 dark:border-gray-800 rounded-md"> <div className="inline-block py-2 px-4 bg-gray-50 dark:bg-black border border-gray-200 dark:border-gray-800 rounded-md">
<span className="text-blue-500 font-bold mr-2">$</span> <span className="text-blue-500 font-bold mr-2">$</span>
<span className="text-gray-900 dark:text-white font-mono"> <span className="text-gray-900 dark:text-white font-mono">
@@ -85,6 +107,20 @@ const Testimonials = () => {
</div> </div>
</div> </div>
</div> </div>
<style jsx>{`
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(calc(-29% * ${testimonials.length}));
}
}
.animate-scroll:hover {
animation-play-state: paused;
}
`}</style>
</section> </section>
); );
}; };

View File

@@ -5,8 +5,7 @@ import CodeContainer from "./_components/CodeContainer";
import CustomizableSection from "./_components/CustomizableSection"; import CustomizableSection from "./_components/CustomizableSection";
import NpmPackage from "./_components/NpmPackage"; import NpmPackage from "./_components/NpmPackage";
import TechShowcase from "./_components/TechShowcase"; import TechShowcase from "./_components/TechShowcase";
// import TerminalDisplay from "./_components/Terminal"; import Testimonials from "./_components/Testimonials";
// import Testimonials from "./_components/Testimonials";
export default function HomePage() { export default function HomePage() {
return ( return (
@@ -126,7 +125,7 @@ export default function HomePage() {
</div> </div>
</div> </div>
</div> </div>
{/* <Testimonials /> */} <Testimonials />
</main> </main>
); );
} }