google review added
This commit is contained in:
@@ -4,6 +4,7 @@ import { ImageWithFallback } from "./figma/ImageWithFallback";
|
||||
import clutchLogo from '../src/images/clutch-logo.png';
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import React from "react";
|
||||
import googleLogo from '../src/images/google-logo.jpg';
|
||||
|
||||
const testimonials = [
|
||||
{
|
||||
@@ -199,11 +200,10 @@ const StarRating = ({ rating }: { rating: number }) => {
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Star
|
||||
key={i}
|
||||
className={`w-4 h-4 ${
|
||||
i < rating
|
||||
className={`w-4 h-4 ${i < rating
|
||||
? 'text-yellow-400 fill-yellow-400'
|
||||
: 'text-gray-600 fill-gray-600'
|
||||
}`}
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -211,17 +211,17 @@ const StarRating = ({ rating }: { rating: number }) => {
|
||||
};
|
||||
|
||||
// Individual testimonial card
|
||||
const TestimonialCard = ({
|
||||
testimonial,
|
||||
onHover,
|
||||
onLeave
|
||||
}: {
|
||||
const TestimonialCard = ({
|
||||
testimonial,
|
||||
onHover,
|
||||
onLeave
|
||||
}: {
|
||||
testimonial: typeof testimonials[0];
|
||||
onHover?: () => void;
|
||||
onLeave?: () => void;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
className="bg-card rounded-[10px] border border-border p-6 w-[400px] flex-shrink-0 hover:border-border/80 hover:shadow-lg transition-all duration-300 select-none"
|
||||
onMouseEnter={onHover}
|
||||
onMouseLeave={onLeave}
|
||||
@@ -238,12 +238,12 @@ const TestimonialCard = ({
|
||||
</div>
|
||||
<StarRating rating={testimonial.rating} />
|
||||
</div>
|
||||
|
||||
|
||||
{/* Quote */}
|
||||
<p className="text-muted-foreground leading-relaxed text-base mb-6">
|
||||
"{testimonial.quote}"
|
||||
</p>
|
||||
|
||||
|
||||
{/* Author Info - Without Avatar */}
|
||||
<div className="pt-2 border-t border-border/50">
|
||||
<div className="font-medium text-foreground text-base">
|
||||
@@ -272,9 +272,9 @@ const MarqueeRow = ({ testimonials: rowTestimonials }: { testimonials: typeof te
|
||||
const startAnimation = async (fromPosition: number = 0) => {
|
||||
const remainingDistance = TOTAL_DISTANCE - fromPosition;
|
||||
const remainingDuration = (Math.abs(remainingDistance) / Math.abs(TOTAL_DISTANCE)) * ANIMATION_DURATION;
|
||||
|
||||
|
||||
startTimeRef.current = Date.now();
|
||||
|
||||
|
||||
try {
|
||||
await controls.start({
|
||||
x: [fromPosition, TOTAL_DISTANCE],
|
||||
@@ -294,7 +294,7 @@ const MarqueeRow = ({ testimonials: rowTestimonials }: { testimonials: typeof te
|
||||
const pauseAnimation = () => {
|
||||
controls.stop();
|
||||
pauseTimeRef.current = Date.now();
|
||||
|
||||
|
||||
// Calculate current position based on elapsed time
|
||||
const elapsedTime = (pauseTimeRef.current - startTimeRef.current) / 1000;
|
||||
const progress = (elapsedTime % ANIMATION_DURATION) / ANIMATION_DURATION;
|
||||
@@ -331,7 +331,7 @@ const MarqueeRow = ({ testimonials: rowTestimonials }: { testimonials: typeof te
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
className="flex overflow-hidden"
|
||||
role="region"
|
||||
aria-label="Client testimonials carousel"
|
||||
@@ -345,8 +345,8 @@ const MarqueeRow = ({ testimonials: rowTestimonials }: { testimonials: typeof te
|
||||
>
|
||||
{/* First set */}
|
||||
{rowTestimonials.map((testimonial, index) => (
|
||||
<TestimonialCard
|
||||
key={`first-${index}`}
|
||||
<TestimonialCard
|
||||
key={`first-${index}`}
|
||||
testimonial={testimonial}
|
||||
onHover={handleCardHover}
|
||||
onLeave={handleCardLeave}
|
||||
@@ -354,8 +354,8 @@ const MarqueeRow = ({ testimonials: rowTestimonials }: { testimonials: typeof te
|
||||
))}
|
||||
{/* Duplicate set for seamless loop */}
|
||||
{rowTestimonials.map((testimonial, index) => (
|
||||
<TestimonialCard
|
||||
key={`second-${index}`}
|
||||
<TestimonialCard
|
||||
key={`second-${index}`}
|
||||
testimonial={testimonial}
|
||||
onHover={handleCardHover}
|
||||
onLeave={handleCardLeave}
|
||||
@@ -384,7 +384,7 @@ const ClutchRating = () => {
|
||||
className="w-16 h-16 object-contain rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Rating Info */}
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
@@ -427,7 +427,7 @@ export const CarouselTestimonials = () => {
|
||||
Don't just take our word for it. Here's what founders and product leaders say about working with us.
|
||||
</motion.p>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Single Row Marquee Testimonials */}
|
||||
<div className="mb-16">
|
||||
<motion.div
|
||||
@@ -439,10 +439,45 @@ export const CarouselTestimonials = () => {
|
||||
<MarqueeRow testimonials={testimonials} />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Centered Clutch Rating */}
|
||||
<div className="flex justify-center">
|
||||
|
||||
<div className="flex justify-center gap-6 flex-wrap">
|
||||
<ClutchRating />
|
||||
|
||||
{/* Google Reviews Rating */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.1 }}
|
||||
viewport={{ once: true }}
|
||||
className="flex items-center gap-4 bg-card rounded-[10px] border border-border p-6 shadow-sm w-full max-w-sm mx-auto"
|
||||
>
|
||||
{/* Google Logo */}
|
||||
<div className="flex-shrink-0">
|
||||
<ImageWithFallback
|
||||
src={googleLogo}
|
||||
alt="Clutch"
|
||||
className="w-16 h-16 object-contain rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Rating Info */}
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="font-semibold text-foreground text-xl">4.8</span>
|
||||
<div className="flex gap-0.5">
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<Star key={i} className="w-4 h-4 fill-[#FBBC05] text-[#FBBC05]" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-muted-foreground text-base mb-1">
|
||||
(38 reviews)
|
||||
</div>
|
||||
<div className="text-muted-foreground text-sm">
|
||||
Highly Rated on Google Reviews
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user