refactor: replace team member section with feature cards and add associated SVG icons

This commit is contained in:
pradeepkumar
2026-04-15 07:15:56 +05:30
parent 3897a47756
commit 5e787f2720
5 changed files with 85 additions and 53 deletions

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#e58625" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2l8 4v6c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6l8-4z"/>
<path d="M9 12l2 2 4-4"/>
</svg>

After

Width:  |  Height:  |  Size: 277 B

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#e58625" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 3v18"/>
<path d="M6 21h12"/>
<path d="M5 7l-3 7a4 4 0 0 0 6 0l-3-7z"/>
<path d="M19 7l-3 7a4 4 0 0 0 6 0l-3-7z"/>
<path d="M5 7h14"/>
</svg>

After

Width:  |  Height:  |  Size: 343 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#e58625" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 4h18l-7 9v7l-4-2v-5L3 4z"/>
<line x1="3" y1="21" x2="21" y2="3"/>
</svg>

After

Width:  |  Height:  |  Size: 268 B

View File

@@ -55,10 +55,14 @@ export default function AboutPage() {
}
break;
case 'team':
if (Array.isArray(c.members) && c.members.length > 0) {
if (c.title || c.subtitle || c.intro || (Array.isArray(c.cards) && c.cards.length > 0)) {
const teamData = c as unknown as AboutTeamContent;
for (const member of teamData.members) {
member.imageUrl = await resolveImageUrl(member.imageUrl);
if (Array.isArray(teamData.cards)) {
for (const card of teamData.cards) {
card.iconPath = await resolveImageUrl(card.iconPath);
}
} else {
teamData.cards = [];
}
setTeam(teamData);
}
@@ -196,24 +200,32 @@ export default function AboutPage() {
)}
{/* Team Section */}
{team && team.members.length > 0 && (
{team && (team.title || team.subtitle || team.intro || team.cards.length > 0) && (
<section className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-16 lg:pb-20">
<div className="text-center mb-12">
{team.title && (
<h2 className="font-fractul font-bold text-[30px] text-[#00293d] mb-3">
{team.title}
</h2>
)}
{team.subtitle && (
<p className="font-serif text-[14px] text-[#00293d] max-w-[471px] mx-auto">
{team.subtitle}
</p>
<p className="font-serif text-[14px] text-[#00293d] max-w-[600px] mx-auto mt-4">
RE-Quest is a unique platform in real estate where no agent can pay to be pushed to the top. RE-Quest elevates ethical, skilled, service-oriented professionals who genuinely care about their clients with no sponsorship tiers. With RE-Quest you receive:
)}
{team.intro && (
<p className="font-serif text-[14px] text-[#00293d] max-w-[600px] mx-auto mt-4 whitespace-pre-line">
{team.intro}
</p>
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-4xl mx-auto">
{team.members.map((member, index) => (
<TeamCard key={index} member={member} />
{team.cards.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-5xl mx-auto items-stretch">
{team.cards.map((card, index) => (
<TeamCard key={index} card={card} />
))}
</div>
)}
</section>
)}
@@ -334,12 +346,14 @@ function AboutSkeleton() {
<div className="shimmer-loading h-[36px] w-[350px] max-w-full rounded-lg" />
<div className="shimmer-loading h-[14px] w-[400px] max-w-full rounded-lg" />
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-4xl mx-auto">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-5xl mx-auto">
{[1, 2, 3].map((i) => (
<div key={i} className="border border-[#00293d]/10 rounded-[15px] p-4 flex flex-col items-center gap-3">
<div className="shimmer-loading w-full h-[211px] rounded-[15px]" />
<div className="shimmer-loading h-[14px] w-[80px] rounded-lg" />
<div className="shimmer-loading h-[12px] w-[100px] rounded-lg" />
<div key={i} className="border border-[#00293d]/10 rounded-[15px] p-6 flex flex-col items-center gap-3">
<div className="shimmer-loading w-[36px] h-[36px] rounded-full" />
<div className="shimmer-loading h-[16px] w-[140px] rounded-lg" />
<div className="shimmer-loading h-[12px] w-full rounded-lg" />
<div className="shimmer-loading h-[12px] w-[90%] rounded-lg" />
<div className="shimmer-loading h-[12px] w-[80%] rounded-lg" />
</div>
))}
</div>
@@ -436,38 +450,40 @@ function FeatureCard({ feature }: { feature: AboutFeaturesContent['features'][nu
// Team card — shimmer image while loading
// ---------------------------------------------------------------------------
function TeamCard({ member }: { member: AboutTeamContent['members'][number] }) {
const [imgStatus, setImgStatus] = useState<'loading' | 'loaded' | 'error'>(
member.imageUrl ? 'loading' : 'error'
function TeamCard({ card }: { card: AboutTeamContent['cards'][number] }) {
const [iconStatus, setIconStatus] = useState<'loading' | 'loaded' | 'error'>(
card.iconPath ? 'loading' : 'error'
);
useEffect(() => {
setImgStatus(member.imageUrl ? 'loading' : 'error');
}, [member.imageUrl]);
setIconStatus(card.iconPath ? 'loading' : 'error');
}, [card.iconPath]);
return (
<div className="border border-[#00293d]/10 rounded-[15px] p-4 text-center">
<div className="w-full h-[211px] rounded-[15px] overflow-hidden mb-4 border border-[#00293d]/10 bg-gray-50">
{imgStatus === 'loading' && (
<div className="w-full h-full shimmer-loading rounded-[15px]" />
<div className="border border-[#00293d]/10 rounded-[15px] p-6 text-center h-full flex flex-col">
<div className="flex items-center justify-center mb-4 h-[36px]">
<div className="relative w-[36px] h-[36px]">
{iconStatus === 'loading' && (
<div className="absolute inset-0 rounded-full shimmer-loading" />
)}
{member.imageUrl && imgStatus !== 'error' && (
{card.iconPath && iconStatus !== 'error' && (
/* eslint-disable-next-line @next/next/no-img-element */
<img
ref={(el) => { if (el?.complete) setImgStatus(el.naturalWidth > 0 ? 'loaded' : 'error'); }}
src={member.imageUrl}
alt={member.name}
className={`w-full h-full object-cover transition-opacity duration-300 ${imgStatus === 'loaded' ? 'opacity-100' : 'opacity-0'}`}
onLoad={() => setImgStatus('loaded')}
onError={() => setImgStatus('error')}
ref={(el) => { if (el?.complete) setIconStatus(el.naturalWidth > 0 ? 'loaded' : 'error'); }}
src={card.iconPath}
alt=""
className={`w-[36px] h-[36px] object-contain transition-opacity duration-300 ${iconStatus === 'loaded' ? 'opacity-100' : 'opacity-0'}`}
onLoad={() => setIconStatus('loaded')}
onError={() => setIconStatus('error')}
/>
)}
</div>
<h3 className="font-fractul font-bold text-[14px] text-black">
{member.name}
</div>
<h3 className="font-fractul font-bold text-[16px] text-[#00293d] mb-3">
{card.title}
</h3>
<p className="font-fractul font-light text-[14px] text-black">
{member.role}
<p className="font-serif text-[14px] text-[#00293d] leading-relaxed">
{card.description}
</p>
</div>
);

View File

@@ -95,16 +95,17 @@ export interface AboutFeaturesContent {
features: AboutFeatureItem[];
}
export interface AboutTeamMember {
name: string;
role: string;
imageUrl: string;
export interface AboutTeamCard {
title: string;
description: string;
iconPath: string;
}
export interface AboutTeamContent {
title: string;
subtitle: string;
members: AboutTeamMember[];
intro: string;
cards: AboutTeamCard[];
}
export interface AboutCtaContent {