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
107 changes: 72 additions & 35 deletions src/components/testimonials/TestimonialCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// prettier-ignore
import React from "react";
import { motion } from "framer-motion";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
Expand All @@ -23,13 +24,11 @@ const TestimonialCard: React.FC<TestimonialCardProps> = ({
const { colorMode } = useColorMode();
const isDark = colorMode === "dark";

// Function to format the link display
const formatLinkDisplay = (url: string) => {
try {
const urlObj = new URL(url);
return urlObj.hostname + urlObj.pathname;
} catch {
// If URL parsing fails, return the original link
return url;
}
};
Expand All @@ -39,66 +38,104 @@ const TestimonialCard: React.FC<TestimonialCardProps> = ({
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 ${
className={`rounded-2xl p-6 shadow-md hover:shadow-lg transition-all duration-300 flex flex-col justify-between h-full ${
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">
<AvatarImage src={avatar} className="object-contain" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<div>
<h3 className={`font-semibold text-lg ${isDark ? "text-white" : "text-gray-900"}`}>
{/* Header */}
<div className="flex items-center gap-4 mb-4">
<div className="relative w-16 h-16 flex-shrink-0">
<div className="w-full h-full rounded-full overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 flex items-center justify-center">
{avatar ? (
<img
src={avatar}
alt={name}
className="w-full h-[180px] overflow-hidden object-cover rounded-full"
loading="lazy"
/>
) : (
<span className="text-sm font-semibold">
{name?.charAt(0)?.toUpperCase() ?? "U"}
</span>
)}
</div>
</div>

<div className="flex flex-col">
<h3
className={`font-semibold text-lg leading-tight ${
isDark ? "text-white" : "text-gray-900"
}`}
>
{name}
</h3>
<p className={`text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`}>
<p
className={`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"}`}>
{content}
<p
className={`text-sm line-clamp-4 ${
isDark ? "text-gray-300" : "text-gray-700"
}`}
>
{content.length > 111 ? content.slice(0, 111) + "..." : content}
</p>

{/* Footer with Hashtags and Date */}
{/* Footer */}
<div
className={`flex flex-col gap-2 text-sm pt-2 border-t ${
isDark ? "border-gray-700" : "border-gray-100"
className={`pt-1 border-t text-sm flex flex-col gap-2 ${
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"
>
{hashtag}
</span>
))}
</div>
{content.match(/#\w+/g) && (
<div className="flex flex-wrap gap-2">
{content
.match(/#\w+/g)
?.slice(0, 3)
.map((tag, i) => (
<span
key={i}
className={`px-2 py-0.5 rounded-md text-xs font-medium ${
isDark
? "bg-blue-900/40 text-blue-300"
: "bg-blue-50 text-blue-700"
}`}
>
{tag}
</span>
))}
</div>
)}

{/* Link and Date Row */}
{/* Link and Date */}
<div className="flex items-center justify-between">
<a
href={link}
target="_blank"
<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={`truncate max-w-[70%] hover:underline cursor-pointer ${
isDark
? "text-blue-400 hover:text-blue-300"
: "text-blue-600 hover:text-blue-700"
}`}
>
{formatLinkDisplay(link)}
</a>
<span className={isDark ? "text-gray-500" : "text-gray-400"}>{date}</span>
<span
className={`text-xs ${isDark ? "text-gray-500" : "text-gray-400"}`}
>
{date}
</span>
</div>
</div>
</motion.div>
);
};

export default TestimonialCard;
export default TestimonialCard;
2 changes: 1 addition & 1 deletion src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default function Home(): ReactNode {
<OurProjects OurProjectsData={projectsData} />
</div>

<div className="m-4 grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-8">
<div className="m-4 grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
{showTopmate && (
<div className="col-span-1">
<TopMateSection setShowTopmate={setShowTopmate} />
Expand Down
Loading