feat: enhance BrandShowcase component with improved layout and visual elements
This commit is contained in:
parent
d7c343ac7d
commit
bfe589be27
@ -1,96 +1,426 @@
|
||||
'use client';
|
||||
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
import { BRANDS, ROBOTS, type RobotBrand } from '@/data/robots';
|
||||
|
||||
type BrandVisual = {
|
||||
description: string;
|
||||
chips: string[];
|
||||
primary: { src: string; alt: string };
|
||||
secondary?: { src: string; alt: string };
|
||||
};
|
||||
|
||||
const BRAND_VISUALS: Record<RobotBrand, BrandVisual> = {
|
||||
unitree: {
|
||||
description:
|
||||
'Quadruped and humanoid robotics platforms — available exclusively in the UAE through YS Lootah Robotics.',
|
||||
chips: ['Quadruped', 'Humanoid', 'Inspection', 'Research'],
|
||||
primary: { src: '/images/robots/unitree-g1.png', alt: 'Unitree G1 humanoid robot' },
|
||||
secondary: { src: '/images/robots/unitree-go2.png', alt: 'Unitree Go2 quadruped robot' },
|
||||
},
|
||||
pudu: {
|
||||
description:
|
||||
'Service, delivery, cleaning, and hospitality robotics — available exclusively in the UAE through YS Lootah Robotics.',
|
||||
chips: ['Service', 'Delivery', 'Cleaning', 'Hospitality'],
|
||||
primary: { src: '/images/robots/pudu-bellabot.svg', alt: 'Pudu BellaBot delivery robot' },
|
||||
secondary: { src: '/images/robots/pudu-kettybot.svg', alt: 'Pudu KettyBot service robot' },
|
||||
},
|
||||
};
|
||||
|
||||
export function BrandShowcase() {
|
||||
const brandIds = Object.keys(BRANDS) as RobotBrand[];
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gap: '1.25rem',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(min(260px, 100%), 1fr))',
|
||||
gap: 'clamp(1rem, 2vw, 1.5rem)',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(min(360px, 100%), 1fr))',
|
||||
}}
|
||||
>
|
||||
{brandIds.map((id) => {
|
||||
const brand = BRANDS[id];
|
||||
const count = ROBOTS.filter((r) => r.brand === id).length;
|
||||
return (
|
||||
<Link
|
||||
key={id}
|
||||
href={`/brands/#${id}`}
|
||||
className="card"
|
||||
style={{
|
||||
padding: '1.75rem',
|
||||
textDecoration: 'none',
|
||||
color: '#FBFBFD',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem',
|
||||
minHeight: 220,
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
background: `radial-gradient(circle at 80% 0%, ${brand.accent}22, transparent 60%)`,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
<div style={{ position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: '1.45rem',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '0.04em',
|
||||
color: '#ffffff',
|
||||
}}
|
||||
>
|
||||
{brand.name.split(' ')[0]}
|
||||
<span style={{ color: brand.accent, marginLeft: 6 }}>
|
||||
{brand.name.split(' ').slice(1).join(' ')}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
style={{
|
||||
fontSize: '0.7rem',
|
||||
letterSpacing: '0.2em',
|
||||
textTransform: 'uppercase',
|
||||
color: brand.accent,
|
||||
}}
|
||||
>
|
||||
{count} model{count === 1 ? '' : 's'}
|
||||
</span>
|
||||
</div>
|
||||
<p style={{ position: 'relative', margin: 0, color: '#8891C7', lineHeight: 1.6, fontSize: '0.95rem' }}>
|
||||
{brand.tagline}
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
marginTop: 'auto',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.5rem',
|
||||
color: brand.accent,
|
||||
fontSize: '0.8rem',
|
||||
letterSpacing: '0.18em',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Explore {brand.name.split(' ')[0]}
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
<polyline points="12 5 19 12 12 19" />
|
||||
</svg>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
const visual = BRAND_VISUALS[id];
|
||||
return <BrandCard key={id} id={id} brand={brand} count={count} visual={visual} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BrandCard({
|
||||
id,
|
||||
brand,
|
||||
count,
|
||||
visual,
|
||||
}: {
|
||||
id: RobotBrand;
|
||||
brand: { name: string; tagline: string; description: string; url: string; accent: string };
|
||||
count: number;
|
||||
visual: BrandVisual;
|
||||
}) {
|
||||
const brandWord = brand.name.split(' ')[0];
|
||||
const brandRest = brand.name.split(' ').slice(1).join(' ');
|
||||
const accent = brand.accent;
|
||||
return (
|
||||
<Link
|
||||
href={`/brands/#${id}`}
|
||||
className="brand-card"
|
||||
style={{
|
||||
position: 'relative',
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'minmax(0, 1.05fr) minmax(0, 1fr)',
|
||||
gap: 'clamp(0.75rem, 2vw, 1.25rem)',
|
||||
padding: 'clamp(1.25rem, 2.5vw, 1.75rem)',
|
||||
minHeight: 280,
|
||||
borderRadius: 22,
|
||||
background:
|
||||
`radial-gradient(ellipse 60% 80% at 100% 0%, ${accent}1F, transparent 60%), linear-gradient(135deg, rgba(28,27,33,0.86), rgba(8,8,10,0.96))`,
|
||||
border: `1px solid ${accent}33`,
|
||||
color: '#FBFBFD',
|
||||
textDecoration: 'none',
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0 18px 50px rgba(0,0,0,0.6), inset 0 1px 0 rgba(222,224,240,0.06)',
|
||||
transition: 'transform 0.35s cubic-bezier(0.16,1,0.3,1), border-color 0.35s ease, box-shadow 0.35s ease',
|
||||
}}
|
||||
>
|
||||
{/* metallic edge */}
|
||||
<div
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
borderRadius: 22,
|
||||
padding: 1,
|
||||
background: `linear-gradient(135deg, ${accent}55, transparent 50%, ${accent}22)`,
|
||||
WebkitMask: 'linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)',
|
||||
WebkitMaskComposite: 'xor',
|
||||
maskComposite: 'exclude',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
{/* subtle grid */}
|
||||
<div
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
backgroundImage:
|
||||
'linear-gradient(rgba(191,195,226,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(191,195,226,0.04) 1px, transparent 1px)',
|
||||
backgroundSize: '32px 32px',
|
||||
maskImage: 'radial-gradient(ellipse 60% 80% at 50% 40%, #000 30%, transparent 80%)',
|
||||
WebkitMaskImage: 'radial-gradient(ellipse 60% 80% at 50% 40%, #000 30%, transparent 80%)',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
{/* hover glow */}
|
||||
<span
|
||||
className="brand-card-glow"
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: '-15%',
|
||||
background: `radial-gradient(circle at 70% 20%, ${accent}33, transparent 60%)`,
|
||||
opacity: 0,
|
||||
transition: 'opacity 0.5s ease',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* LEFT — copy */}
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '0.875rem',
|
||||
minWidth: 0,
|
||||
padding: '0.25rem 0',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '0.5rem', flexWrap: 'wrap' }}>
|
||||
<span
|
||||
style={{
|
||||
fontSize: '0.62rem',
|
||||
letterSpacing: '0.26em',
|
||||
textTransform: 'uppercase',
|
||||
color: '#8891C7',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
Available exclusively in UAE
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: '0.62rem',
|
||||
letterSpacing: '0.2em',
|
||||
textTransform: 'uppercase',
|
||||
color: accent,
|
||||
fontWeight: 700,
|
||||
padding: '0.2rem 0.5rem',
|
||||
borderRadius: 999,
|
||||
border: `1px solid ${accent}55`,
|
||||
background: 'rgba(14,13,18,0.6)',
|
||||
}}
|
||||
>
|
||||
{count} {count === 1 ? 'model' : 'models'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3
|
||||
style={{
|
||||
margin: 0,
|
||||
fontSize: 'clamp(1.4rem, 2.6vw, 1.85rem)',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '-0.01em',
|
||||
lineHeight: 1.1,
|
||||
color: '#FBFBFD',
|
||||
}}
|
||||
>
|
||||
{brandWord}
|
||||
{brandRest && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: 8,
|
||||
background: `linear-gradient(110deg, #FBFBFD, ${accent})`,
|
||||
WebkitBackgroundClip: 'text',
|
||||
backgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
color: 'transparent',
|
||||
}}
|
||||
>
|
||||
{brandRest}
|
||||
</span>
|
||||
)}
|
||||
</h3>
|
||||
|
||||
<p
|
||||
style={{
|
||||
margin: 0,
|
||||
color: '#BFC3E2',
|
||||
fontSize: '0.92rem',
|
||||
lineHeight: 1.55,
|
||||
}}
|
||||
>
|
||||
{visual.description}
|
||||
</p>
|
||||
|
||||
<ul
|
||||
style={{
|
||||
listStyle: 'none',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '0.4rem',
|
||||
}}
|
||||
>
|
||||
{visual.chips.map((chip) => (
|
||||
<li
|
||||
key={chip}
|
||||
style={{
|
||||
padding: '0.3rem 0.6rem',
|
||||
borderRadius: 999,
|
||||
fontSize: '0.68rem',
|
||||
letterSpacing: '0.16em',
|
||||
textTransform: 'uppercase',
|
||||
color: '#DEE0F0',
|
||||
background: `${accent}14`,
|
||||
border: `1px solid ${accent}44`,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{chip}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<span
|
||||
style={{
|
||||
marginTop: 'auto',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.5rem',
|
||||
color: accent,
|
||||
fontSize: '0.78rem',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '0.16em',
|
||||
textTransform: 'uppercase',
|
||||
paddingTop: '0.5rem',
|
||||
}}
|
||||
>
|
||||
Explore {brandWord} {brandRest && brandRest.replace(/^(.)/, (m) => m.toLowerCase())}
|
||||
<ArrowRight size={14} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* RIGHT — product visual */}
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
minHeight: 200,
|
||||
borderRadius: 16,
|
||||
overflow: 'hidden',
|
||||
background:
|
||||
`radial-gradient(ellipse 70% 50% at 50% 60%, ${accent}22 0%, transparent 65%), linear-gradient(180deg, rgba(28,27,33,0.6), rgba(10,10,12,0.95))`,
|
||||
border: '1px solid rgba(222,224,240,0.08)',
|
||||
}}
|
||||
>
|
||||
{/* inner grid */}
|
||||
<div
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
backgroundImage:
|
||||
'linear-gradient(rgba(191,195,226,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(191,195,226,0.06) 1px, transparent 1px)',
|
||||
backgroundSize: '24px 24px',
|
||||
maskImage: 'radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 80%)',
|
||||
WebkitMaskImage: 'radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 80%)',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
{/* spotlight */}
|
||||
<div
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '4%',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
width: '70%',
|
||||
height: '70%',
|
||||
background: `radial-gradient(ellipse 60% 70% at 50% 30%, ${accent}3A 0%, transparent 65%)`,
|
||||
filter: 'blur(10px)',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
{/* secondary product (back-left, smaller) */}
|
||||
{visual.secondary && (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '4%',
|
||||
bottom: '14%',
|
||||
width: '50%',
|
||||
height: '74%',
|
||||
opacity: 0.75,
|
||||
filter: 'drop-shadow(0 12px 18px rgba(0,0,0,0.65))',
|
||||
transform: 'scale(0.88)',
|
||||
transformOrigin: 'bottom left',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={visual.secondary.src}
|
||||
alt={visual.secondary.alt}
|
||||
fill
|
||||
sizes="240px"
|
||||
style={{ objectFit: 'contain', objectPosition: 'center bottom' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* primary product (front-right, large) */}
|
||||
<div
|
||||
className="brand-card-primary"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '2%',
|
||||
bottom: '12%',
|
||||
width: '70%',
|
||||
height: '92%',
|
||||
filter:
|
||||
'drop-shadow(0 18px 28px rgba(0,0,0,0.78)) drop-shadow(0 0 22px rgba(58,85,196,0.45))',
|
||||
transition: 'transform 0.5s cubic-bezier(0.16,1,0.3,1)',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={visual.primary.src}
|
||||
alt={visual.primary.alt}
|
||||
fill
|
||||
sizes="320px"
|
||||
style={{ objectFit: 'contain', objectPosition: 'center bottom' }}
|
||||
/>
|
||||
</div>
|
||||
{/* floor reflection (faded) */}
|
||||
<div
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '2%',
|
||||
bottom: '2%',
|
||||
width: '70%',
|
||||
height: '22%',
|
||||
opacity: 0.32,
|
||||
transform: 'scaleY(-1)',
|
||||
transformOrigin: 'center top',
|
||||
maskImage: 'linear-gradient(to bottom, rgba(0,0,0,0.7), transparent 75%)',
|
||||
WebkitMaskImage: 'linear-gradient(to bottom, rgba(0,0,0,0.7), transparent 75%)',
|
||||
pointerEvents: 'none',
|
||||
filter: 'blur(1.2px)',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={visual.primary.src}
|
||||
alt=""
|
||||
fill
|
||||
sizes="320px"
|
||||
style={{ objectFit: 'contain', objectPosition: 'center top' }}
|
||||
/>
|
||||
</div>
|
||||
{/* floor line */}
|
||||
<div
|
||||
aria-hidden
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '5%',
|
||||
right: '5%',
|
||||
bottom: '24%',
|
||||
height: 1,
|
||||
background: 'linear-gradient(90deg, transparent, rgba(222,224,240,0.55), transparent)',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
{/* UAE badge */}
|
||||
<span
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '0.625rem',
|
||||
right: '0.625rem',
|
||||
padding: '0.25rem 0.55rem',
|
||||
borderRadius: 999,
|
||||
border: `1px solid ${accent}55`,
|
||||
background: 'rgba(14,13,18,0.75)',
|
||||
color: accent,
|
||||
fontSize: '0.58rem',
|
||||
fontWeight: 800,
|
||||
letterSpacing: '0.24em',
|
||||
textTransform: 'uppercase',
|
||||
backdropFilter: 'blur(8px)',
|
||||
}}
|
||||
>
|
||||
UAE Exclusive
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<style jsx>{`
|
||||
.brand-card:hover {
|
||||
transform: translateY(-6px);
|
||||
border-color: ${accent}88;
|
||||
box-shadow: 0 26px 70px rgba(0, 0, 0, 0.75), 0 0 40px ${accent}33;
|
||||
}
|
||||
.brand-card:hover .brand-card-glow {
|
||||
opacity: 1;
|
||||
}
|
||||
.brand-card:hover .brand-card-primary {
|
||||
transform: translateY(-4px) scale(1.02);
|
||||
}
|
||||
@media (max-width: 540px) {
|
||||
.brand-card {
|
||||
grid-template-columns: 1fr !important;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user