refactor: replace team member section with feature cards and add associated SVG icons
This commit is contained in:
4
public/assets/icons/clean-honest-platform-icon.svg
Normal file
4
public/assets/icons/clean-honest-platform-icon.svg
Normal 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 |
7
public/assets/icons/equal-playing-field-icon.svg
Normal file
7
public/assets/icons/equal-playing-field-icon.svg
Normal 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 |
4
public/assets/icons/no-lead-funnels-icon.svg
Normal file
4
public/assets/icons/no-lead-funnels-icon.svg
Normal 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 |
@@ -55,10 +55,14 @@ export default function AboutPage() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'team':
|
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;
|
const teamData = c as unknown as AboutTeamContent;
|
||||||
for (const member of teamData.members) {
|
if (Array.isArray(teamData.cards)) {
|
||||||
member.imageUrl = await resolveImageUrl(member.imageUrl);
|
for (const card of teamData.cards) {
|
||||||
|
card.iconPath = await resolveImageUrl(card.iconPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
teamData.cards = [];
|
||||||
}
|
}
|
||||||
setTeam(teamData);
|
setTeam(teamData);
|
||||||
}
|
}
|
||||||
@@ -196,24 +200,32 @@ export default function AboutPage() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Team Section */}
|
{/* 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">
|
<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">
|
<div className="text-center mb-12">
|
||||||
<h2 className="font-fractul font-bold text-[30px] text-[#00293d] mb-3">
|
{team.title && (
|
||||||
{team.title}
|
<h2 className="font-fractul font-bold text-[30px] text-[#00293d] mb-3">
|
||||||
</h2>
|
{team.title}
|
||||||
<p className="font-serif text-[14px] text-[#00293d] max-w-[471px] mx-auto">
|
</h2>
|
||||||
{team.subtitle}
|
)}
|
||||||
</p>
|
{team.subtitle && (
|
||||||
<p className="font-serif text-[14px] text-[#00293d] max-w-[600px] mx-auto mt-4">
|
<p className="font-serif text-[14px] text-[#00293d] max-w-[471px] mx-auto">
|
||||||
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.subtitle}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
)}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-4xl mx-auto">
|
{team.intro && (
|
||||||
{team.members.map((member, index) => (
|
<p className="font-serif text-[14px] text-[#00293d] max-w-[600px] mx-auto mt-4 whitespace-pre-line">
|
||||||
<TeamCard key={index} member={member} />
|
{team.intro}
|
||||||
))}
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{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>
|
</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-[36px] w-[350px] max-w-full rounded-lg" />
|
||||||
<div className="shimmer-loading h-[14px] w-[400px] max-w-full rounded-lg" />
|
<div className="shimmer-loading h-[14px] w-[400px] max-w-full rounded-lg" />
|
||||||
</div>
|
</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) => (
|
{[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 key={i} className="border border-[#00293d]/10 rounded-[15px] p-6 flex flex-col items-center gap-3">
|
||||||
<div className="shimmer-loading w-full h-[211px] rounded-[15px]" />
|
<div className="shimmer-loading w-[36px] h-[36px] rounded-full" />
|
||||||
<div className="shimmer-loading h-[14px] w-[80px] rounded-lg" />
|
<div className="shimmer-loading h-[16px] w-[140px] rounded-lg" />
|
||||||
<div className="shimmer-loading h-[12px] w-[100px] 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>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -436,38 +450,40 @@ function FeatureCard({ feature }: { feature: AboutFeaturesContent['features'][nu
|
|||||||
// Team card — shimmer image while loading
|
// Team card — shimmer image while loading
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function TeamCard({ member }: { member: AboutTeamContent['members'][number] }) {
|
function TeamCard({ card }: { card: AboutTeamContent['cards'][number] }) {
|
||||||
const [imgStatus, setImgStatus] = useState<'loading' | 'loaded' | 'error'>(
|
const [iconStatus, setIconStatus] = useState<'loading' | 'loaded' | 'error'>(
|
||||||
member.imageUrl ? 'loading' : 'error'
|
card.iconPath ? 'loading' : 'error'
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setImgStatus(member.imageUrl ? 'loading' : 'error');
|
setIconStatus(card.iconPath ? 'loading' : 'error');
|
||||||
}, [member.imageUrl]);
|
}, [card.iconPath]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border border-[#00293d]/10 rounded-[15px] p-4 text-center">
|
<div className="border border-[#00293d]/10 rounded-[15px] p-6 text-center h-full flex flex-col">
|
||||||
<div className="w-full h-[211px] rounded-[15px] overflow-hidden mb-4 border border-[#00293d]/10 bg-gray-50">
|
<div className="flex items-center justify-center mb-4 h-[36px]">
|
||||||
{imgStatus === 'loading' && (
|
<div className="relative w-[36px] h-[36px]">
|
||||||
<div className="w-full h-full shimmer-loading rounded-[15px]" />
|
{iconStatus === 'loading' && (
|
||||||
)}
|
<div className="absolute inset-0 rounded-full shimmer-loading" />
|
||||||
{member.imageUrl && imgStatus !== 'error' && (
|
)}
|
||||||
/* eslint-disable-next-line @next/next/no-img-element */
|
{card.iconPath && iconStatus !== 'error' && (
|
||||||
<img
|
/* eslint-disable-next-line @next/next/no-img-element */
|
||||||
ref={(el) => { if (el?.complete) setImgStatus(el.naturalWidth > 0 ? 'loaded' : 'error'); }}
|
<img
|
||||||
src={member.imageUrl}
|
ref={(el) => { if (el?.complete) setIconStatus(el.naturalWidth > 0 ? 'loaded' : 'error'); }}
|
||||||
alt={member.name}
|
src={card.iconPath}
|
||||||
className={`w-full h-full object-cover transition-opacity duration-300 ${imgStatus === 'loaded' ? 'opacity-100' : 'opacity-0'}`}
|
alt=""
|
||||||
onLoad={() => setImgStatus('loaded')}
|
className={`w-[36px] h-[36px] object-contain transition-opacity duration-300 ${iconStatus === 'loaded' ? 'opacity-100' : 'opacity-0'}`}
|
||||||
onError={() => setImgStatus('error')}
|
onLoad={() => setIconStatus('loaded')}
|
||||||
/>
|
onError={() => setIconStatus('error')}
|
||||||
)}
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-fractul font-bold text-[14px] text-black">
|
<h3 className="font-fractul font-bold text-[16px] text-[#00293d] mb-3">
|
||||||
{member.name}
|
{card.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-fractul font-light text-[14px] text-black">
|
<p className="font-serif text-[14px] text-[#00293d] leading-relaxed">
|
||||||
{member.role}
|
{card.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -95,16 +95,17 @@ export interface AboutFeaturesContent {
|
|||||||
features: AboutFeatureItem[];
|
features: AboutFeatureItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AboutTeamMember {
|
export interface AboutTeamCard {
|
||||||
name: string;
|
title: string;
|
||||||
role: string;
|
description: string;
|
||||||
imageUrl: string;
|
iconPath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AboutTeamContent {
|
export interface AboutTeamContent {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
members: AboutTeamMember[];
|
intro: string;
|
||||||
|
cards: AboutTeamCard[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AboutCtaContent {
|
export interface AboutCtaContent {
|
||||||
|
|||||||
Reference in New Issue
Block a user