Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 29 additions & 22 deletions src/components/testimonials/TestimonialCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,69 +36,76 @@ const TestimonialCard: React.FC<TestimonialCardProps> = ({

return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className={`rounded-2xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300 h-[250px] flex flex-col justify-between ${
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.5 }}
className={`relative rounded-2xl sm:rounded-3xl p-6 sm:p-8 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1 h-full min-h-[380px] flex flex-col ${
isDark ? "bg-[#1a1a1a] text-white" : "bg-white text-gray-900"
}`}
>
{/* Header with Avatar and Name */}
<div className="flex items-center gap-4">
<Avatar className="w-24 h-24 rounded-full">
<div className="flex items-center gap-3 sm:gap-4 mb-4 sm:mb-6">
<Avatar className="w-16 h-16 sm:w-20 sm:h-20 rounded-full flex-shrink-0 border-2 border-purple-200">
<AvatarImage src={avatar} className="object-contain" />
<AvatarFallback>CN</AvatarFallback>
<AvatarFallback className={isDark ? "bg-gray-700" : "bg-gray-200"}>CN</AvatarFallback>
</Avatar>
<div>
<h3 className={`font-semibold text-lg ${isDark ? "text-white" : "text-gray-900"}`}>
<div className="min-w-0">
<h3 className={`font-bold text-base sm:text-lg leading-tight truncate ${isDark ? "text-white" : "text-gray-900"}`}>
{name}
</h3>
<p className={`text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`}>
<p className={`text-xs sm:text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`}>
@{username}
</p>
</div>
</div>

{/* Content */}
<p className={`line-clamp-3 my-4 flex-grow ${isDark ? "text-gray-300" : "text-gray-700"}`}>
<p className={`line-clamp-4 text-sm sm:text-base leading-relaxed mb-4 sm:mb-6 flex-grow ${
isDark ? "text-gray-300" : "text-gray-600"
}`}>
{content}
</p>

{/* Footer with Hashtags and Date */}
<div
className={`flex flex-col gap-2 text-sm pt-2 border-t ${
isDark ? "border-gray-700" : "border-gray-100"
className={`flex flex-col gap-2 sm:gap-3 text-xs sm:text-sm pt-3 sm:pt-4 border-t ${
isDark ? "border-gray-700" : "border-gray-200"
}`}
>
{/* Hashtags */}
<div className="flex gap-2 flex-wrap">
{content.match(/#\w+/g)?.map((hashtag, index) => (
<span
key={index}
className="text-blue-500 hover:text-blue-600 cursor-pointer"
className={`font-medium transition-colors ${
isDark
? "text-purple-400 hover:text-purple-300"
: "text-purple-600 hover:text-purple-700"
}`}
>
{hashtag}
</span>
))}
</div>

{/* Link and Date Row */}
<div className="flex items-center justify-between">
<a
href={link}
target="_blank"
<div className="flex items-center justify-between gap-2 flex-wrap">
<a
href={link}
target="_blank"
rel="noopener noreferrer"
className={`hover:underline cursor-pointer ${
isDark ? "text-blue-400 hover:text-blue-300" : "text-blue-600 hover:text-blue-700"
className={`font-medium hover:underline cursor-pointer transition-colors truncate ${
isDark ? "text-purple-400 hover:text-purple-300" : "text-purple-600 hover:text-purple-700"
}`}
>
{formatLinkDisplay(link)}
</a>
<span className={isDark ? "text-gray-500" : "text-gray-400"}>{date}</span>
<span className={`text-xs sm:text-sm shrink-0 ${isDark ? "text-gray-500" : "text-gray-400"}`}>{date}</span>
</div>
</div>
</motion.div>
);
};

export default TestimonialCard;
export default TestimonialCard;
39 changes: 22 additions & 17 deletions src/components/testimonials/TestimonialCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ export function TestimonialCarousel() {
}, [api]);

return (
<div className="w-full">
<div className="text-center mb-10">
<h2 className="text-3xl font-bold mb-2">Loved by Many Users</h2>
<div className="w-32 h-1 bg-blue-500 mx-auto rounded-full"></div>
<div className="w-full px-4 py-8 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center mb-12">
<h2 className="text-3xl sm:text-5xl md:text-5xl font-bold mb-4">Loved by Many Users</h2>
<div className="w-24 sm:w-32 h-1 bg-gradient-to-r from-purple-500 to-pink-500 mx-auto rounded-full"></div>
</div>

<Carousel
setApi={setApi}
className="w-full"
className="w-full max-w-7xl mx-auto"
opts={{
align: "start",
loop: true,
Expand All @@ -77,30 +77,35 @@ export function TestimonialCarousel() {
}),
]}
>
<CarouselContent className="-ml-2 md:-ml-4 my-16">
<CarouselContent className="-ml-2 md:-ml-4 my-6 sm:my-12">
{testimonials.map((testimonial, index) => (
<CarouselItem key={index} className="pl-2 md:pl-4 md:basis-1/2 h-full">
<TestimonialCard {...testimonial} />
<CarouselItem key={index} className="pl-2 md:pl-4 md:basis-1/2">
<div className="h-full">
<TestimonialCard {...testimonial} />
</div>
</CarouselItem>
))}
</CarouselContent>

<div className="flex items-center justify-center gap-2 mt-8">
<CarouselPrevious className="static translate-y-0" />
<div className="flex gap-2">
<div className="flex items-center justify-center gap-4 mt-8">
<CarouselPrevious className="static translate-y-0 cursor-pointer" />
Copy link
Preview

Copilot AI Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Adding cursor-pointer class to navigation buttons is redundant since buttons already have pointer cursor by default. Consider removing this class for cleaner code.

Copilot uses AI. Check for mistakes.

<div className="flex gap-2 items-center">
{Array.from({ length: count }).map((_, index) => (
<Button
<button
key={index}
variant={current === index + 1 ? "default" : "outline"}
size="icon"
className="h-2 w-2 p-0 rounded-full"
onClick={() => api?.scrollTo(index)}
className={`rounded-full transition-all duration-300 cursor-pointer hover:scale-110 ${
current === index + 1
? "w-3 h-3 bg-gradient-to-r from-purple-500 to-pink-500"
: "w-2 h-2 bg-gray-400 hover:bg-gray-600"
}`}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
<CarouselNext className="static translate-y-0" />
<CarouselNext className="static translate-y-0 cursor-pointer" />
Copy link
Preview

Copilot AI Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Adding cursor-pointer class to navigation buttons is redundant since buttons already have pointer cursor by default. Consider removing this class for cleaner code.

Copilot uses AI. Check for mistakes.

</div>
</Carousel>
</div>
);
}
}
113 changes: 42 additions & 71 deletions src/components/topmate/TopMateCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,122 +28,93 @@ const TopMateCard: React.FC<TopMateCardProps> = ({
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className={`relative w-full max-w-md mx-auto rounded-3xl shadow-2xl overflow-hidden hover:shadow-3xl transition-all duration-300 transform hover:-translate-y-1 ${
className={`group relative w-full mx-auto rounded-2xl sm:rounded-3xl shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1 min-h-[365px] flex flex-col overflow-hidden ${
isDark ? "bg-[#1a1a1a] text-white" : "bg-white text-black"
}`}
>
{/* Decorative Arrows */}
<div className="absolute -top-4 -left-4 flex gap-2">
{[...Array(3)].map((_, i) => (
<motion.div
key={i}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: i * 0.1 }}
className="text-purple-500"
>
<ArrowUpRight size={24} className="transform rotate-45" />
</motion.div>
))}
</div>
{/* Gradient Overlay - Shows on Hover */}
<div className="absolute inset-0 bg-gradient-to-br from-purple-500/0 via-pink-500/0 to-purple-500/0 group-hover:from-purple-500/10 group-hover:via-pink-500/10 group-hover:to-purple-500/10 transition-all duration-500 pointer-events-none hover:cursor-pointer" />
Copy link
Preview

Copilot AI Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hover:cursor-pointer class is redundant with pointer-events-none. Since pointer events are disabled, the cursor style won't be applied. Remove hover:cursor-pointer or reconsider the pointer-events strategy.

Suggested change
<div className="absolute inset-0 bg-gradient-to-br from-purple-500/0 via-pink-500/0 to-purple-500/0 group-hover:from-purple-500/10 group-hover:via-pink-500/10 group-hover:to-purple-500/10 transition-all duration-500 pointer-events-none hover:cursor-pointer" />
<div className="absolute inset-0 bg-gradient-to-br from-purple-500/0 via-pink-500/0 to-purple-500/0 group-hover:from-purple-500/10 group-hover:via-pink-500/10 group-hover:to-purple-500/10 transition-all duration-500 pointer-events-none" />

Copilot uses AI. Check for mistakes.


{/* Card Content */}
<div className="p-6">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<span
className={`text-sm font-medium ${
isDark ? "text-gray-300" : "text-gray-600"
}`}
>
1:1 CALL
</span>
<div className="p-6 sm:p-8 flex flex-col h-full">
{/* Header - Badge and Close Button */}
<div className="flex items-center justify-between mb-4 sm:mb-6">
<div className="flex items-center gap-2 sm:gap-3">
<div
className={`flex items-center gap-1 ${
isDark ? "text-gray-400" : "text-gray-500"
className={`flex items-center gap-2 px-3 py-1.5 rounded-full ${
isDark ? "bg-purple-500/10" : "bg-purple-50"
}`}
>
<Clock size={16} />
<span className="text-sm">{duration}</span>
<Clock size={14} className="sm:w-4 sm:h-4" />
<span className={`text-xs sm:text-sm font-medium ${
isDark ? "text-purple-300" : "text-purple-700"
}`}>
{duration}
</span>
</div>
</div>
<button
className={`text-xl font-semibold ${
className={`p-1 rounded-full transition-all hover:rotate-90 ${
isDark
? "text-gray-500 hover:text-gray-300"
: "text-gray-400 hover:text-gray-600"
? "text-gray-400 hover:text-white hover:bg-gray-800"
: "text-gray-500 hover:text-gray-900 hover:bg-gray-100"
}`}
onClick={() => setShowTopmate(false)}
aria-label="Close"
>
<span className="sr-only">Close</span>×
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</button>
</div>

{/* Title */}
<h2
className={`text-2xl font-bold mb-4 ${
className={`text-xl sm:text-2xl font-bold mb-3 leading-tight ${
isDark ? "text-white" : "text-gray-900"
}`}
>
{title}
</h2>

{/* Description */}
<p className={`${isDark ? "text-gray-300" : "text-gray-600"} mb-6`}>
<p className={`text-sm sm:text-base leading-relaxed flex-grow ${
isDark ? "text-gray-300" : "text-gray-600"
}`}>
{description}
</p>

{/* Profile Section */}
<div className="flex items-center justify-between flex-wrap md:flex-nowrap gap-y-3">
<div className="flex items-center gap-3 min-w-0">
<div className={`mt-6 pt-4 sm:pt-5 border-t ${
isDark ? "border-gray-700" : "border-gray-200"
}`}>
<div className="flex items-center gap-3 sm:gap-4">
<img
src={profileImage}
alt="Profile"
className="w-12 h-12 rounded-full object-cover border-2 border-purple-200"
className="w-12 h-12 sm:w-14 sm:h-14 rounded-full object-cover ring-2 ring-purple-500/20 flex-shrink-0"
/>
<div className="flex flex-col">
<span
className={`text-sm ${
isDark ? "text-gray-300" : "text-gray-600"
}`}
>
Book a slot at
</span>
<div className="flex-1 min-w-0">
<p className={`text-xs mb-1 ${
isDark ? "text-gray-500" : "text-gray-400"
}`}>
Book your session
</p>
<a
href={`https://topmate.io/${username}`}
target="_blank"
rel="noopener noreferrer"
className="text-purple-500 font-semibold hover:text-purple-600 transition-colors flex items-center gap-1 truncate"
className={`group inline-flex items-center gap-1.5 font-semibold hover:gap-2 transition-all ${
isDark ? "text-purple-400 hover:text-purple-300" : "text-purple-600 hover:text-purple-700"
}`}
>
<span className="truncate">topmate.io/{username}</span>
<ArrowUpRight size={16} />
<span className="text-sm sm:text-base">topmate.io/{username}</span>
<ArrowUpRight size={16} className="group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform" />
</a>
</div>
</div>
<div className="flex items-center gap-2 shrink-0">
{/* Show only the circular icon part of the Topmate logo */}
<div className="h-4 w-4 overflow-hidden flex-shrink-0 rounded-sm">
<img
src="/icons/topmate.png"
alt="Topmate icon"
className="h-4 w-auto object-cover object-left opacity-90"
/>
</div>
{/* Theme-aware text to ensure readability on dark backgrounds */}
<span
className={`text-sm font-semibold shrink-0 ${
isDark ? "text-gray-200" : "text-gray-700"
}`}
>
topmate
</span>
</div>
</div>
</div>

{/* Gradient Border Effect */}
<div className="absolute inset-0 border-2 border-transparent rounded-3xl bg-gradient-to-br from-purple-500/20 to-pink-500/20 -z-10" />
</motion.div>
);
};
Expand Down
12 changes: 6 additions & 6 deletions src/components/topmate/TopMateSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,26 @@ const TopMateSection = ({ setShowTopmate }) => {
};

return (
<div className="px-4">
<div className="mx-auto">
<div className="mx-auto text-center mb-16">
<div className="px-4 py-8 sm:px-6 lg:px-8">
<div className="max-w-7xl mx-auto">
<div className="max-w-3xl mx-auto text-center mb-12">
<h1
className={`text-4xl font-bold mb-4 ${
className={`text-3xl sm:text-4xl md:text-5xl font-bold mb-4 ${
colorMode === "dark" ? "text-white" : "text-gray-900"
}`}
>
Book a Session
</h1>
<p
className={`text-lg ${
className={`text-base sm:text-lg md:text-xl ${
colorMode === "dark" ? "text-gray-300" : "text-gray-600"
}`}
>
Get personalized guidance and feedback through one-on-one sessions
</p>
</div>

<div>
<div className="max-w-2xl mx-auto">
<TopMateCard {...profileData} setShowTopmate={setShowTopmate} />
</div>
</div>
Expand Down
Loading