init: init repo with existing code
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { Star, ChevronLeft, ChevronRight, Quote } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import useEmblaCarousel from 'embla-carousel-react';
|
||||
import Autoplay from 'embla-carousel-autoplay';
|
||||
|
||||
const testimonials = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Jennifer Martinez',
|
||||
role: 'CEO, InnovateTech',
|
||||
avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150&h=150&fit=crop&crop=face',
|
||||
rating: 5,
|
||||
quote: 'TechZaa transformed our entire digital infrastructure. Their AI solutions increased our operational efficiency by 40%. Absolutely incredible team to work with!',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Michael Chen',
|
||||
role: 'CTO, FutureScale',
|
||||
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face',
|
||||
rating: 5,
|
||||
quote: 'The mobile app they developed for us exceeded all expectations. User engagement increased by 200% within the first month. Highly recommend their services.',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Sarah Thompson',
|
||||
role: 'Director of Operations, CloudFirst',
|
||||
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150&h=150&fit=crop&crop=face',
|
||||
rating: 5,
|
||||
quote: 'Their cloud migration expertise saved us countless hours and reduced our infrastructure costs by 35%. Professional, efficient, and always available.',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'David Rodriguez',
|
||||
role: 'Founder, StartupLabs',
|
||||
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face',
|
||||
rating: 5,
|
||||
quote: 'From concept to launch, TechZaa was with us every step. Their attention to detail and innovative approach made our product stand out in a crowded market.',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Emily Watson',
|
||||
role: 'VP Engineering, DataFlow',
|
||||
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150&h=150&fit=crop&crop=face',
|
||||
rating: 5,
|
||||
quote: 'The best tech partner we\'ve ever worked with. Their team understood our vision and delivered a solution that perfectly aligned with our business goals.',
|
||||
},
|
||||
];
|
||||
|
||||
export default function TestimonialsSection() {
|
||||
const [emblaRef, emblaApi] = useEmblaCarousel(
|
||||
{ loop: true, align: 'center' },
|
||||
[Autoplay({ delay: 5000, stopOnInteraction: false })]
|
||||
);
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
const scrollPrev = useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);
|
||||
const scrollNext = useCallback(() => emblaApi?.scrollNext(), [emblaApi]);
|
||||
|
||||
const onSelect = useCallback(() => {
|
||||
if (!emblaApi) return;
|
||||
setSelectedIndex(emblaApi.selectedScrollSnap());
|
||||
}, [emblaApi]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!emblaApi) return;
|
||||
onSelect();
|
||||
emblaApi.on('select', onSelect);
|
||||
return () => {
|
||||
emblaApi.off('select', onSelect);
|
||||
};
|
||||
}, [emblaApi, onSelect]);
|
||||
|
||||
return (
|
||||
<section id="testimonials" className="py-24 relative overflow-hidden">
|
||||
{/* Background */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-primary/10 rounded-full blur-3xl" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-neon-purple/10 rounded-full blur-3xl" />
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
{/* Section Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<span className="inline-block px-4 py-2 rounded-full glass text-primary text-sm font-medium mb-4">
|
||||
Client Stories
|
||||
</span>
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-6">
|
||||
What Our <span className="text-primary neon-text-glow">Clients Say</span>
|
||||
</h2>
|
||||
<p className="text-muted-foreground max-w-2xl mx-auto text-lg">
|
||||
Don't just take our word for it - hear from the amazing companies we've had the pleasure of working with.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Carousel */}
|
||||
<div className="relative max-w-5xl mx-auto">
|
||||
{/* Navigation Buttons */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={scrollPrev}
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-4 z-10 rounded-full glass border-primary/30 hover:neon-glow hidden md:flex"
|
||||
>
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={scrollNext}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-4 z-10 rounded-full glass border-primary/30 hover:neon-glow hidden md:flex"
|
||||
>
|
||||
<ChevronRight className="w-5 h-5" />
|
||||
</Button>
|
||||
|
||||
{/* Carousel Container */}
|
||||
<div className="overflow-hidden" ref={emblaRef}>
|
||||
<div className="flex">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<div
|
||||
key={testimonial.id}
|
||||
className="flex-[0_0_100%] min-w-0 px-4 md:flex-[0_0_80%] lg:flex-[0_0_60%]"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{
|
||||
opacity: selectedIndex === index ? 1 : 0.5,
|
||||
scale: selectedIndex === index ? 1 : 0.9,
|
||||
}}
|
||||
transition={{ duration: 0.4 }}
|
||||
className="glass-strong rounded-3xl p-8 md:p-10 relative"
|
||||
>
|
||||
{/* Quote Icon */}
|
||||
<div className="absolute -top-4 -left-4 w-12 h-12 rounded-full bg-primary flex items-center justify-center neon-glow">
|
||||
<Quote className="w-6 h-6 text-primary-foreground" />
|
||||
</div>
|
||||
|
||||
{/* Stars */}
|
||||
<div className="flex gap-1 mb-6">
|
||||
{[...Array(testimonial.rating)].map((_, i) => (
|
||||
<Star
|
||||
key={i}
|
||||
className="w-5 h-5 fill-primary text-primary"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Quote */}
|
||||
<p className="text-lg md:text-xl text-foreground/90 mb-8 leading-relaxed">
|
||||
"{testimonial.quote}"
|
||||
</p>
|
||||
|
||||
{/* Author */}
|
||||
<div className="flex items-center gap-4">
|
||||
<img
|
||||
src={testimonial.avatar}
|
||||
alt={testimonial.name}
|
||||
className="w-14 h-14 rounded-full object-cover border-2 border-primary/50"
|
||||
/>
|
||||
<div>
|
||||
<h4 className="font-bold text-foreground">
|
||||
{testimonial.name}
|
||||
</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{testimonial.role}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dots Indicator */}
|
||||
<div className="flex justify-center gap-2 mt-8">
|
||||
{testimonials.map((_, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => emblaApi?.scrollTo(index)}
|
||||
className={`w-2 h-2 rounded-full transition-all duration-300 ${
|
||||
selectedIndex === index
|
||||
? 'w-8 bg-primary neon-glow'
|
||||
: 'bg-muted-foreground/30 hover:bg-muted-foreground/50'
|
||||
}`}
|
||||
aria-label={`Go to slide ${index + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user