feat: add robotics components and data structures
CI/CD / test-and-build (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions

- Introduced RobotProductCard component for displaying robot details.
- Added WhyUs component highlighting key reasons for choosing our robotics solutions.
- Implemented CursorSpotlight for enhanced user interaction.
- Created GlassPanel for a stylish UI element.
- Developed MotionSection for animated section visibility.
- Added PremiumButton for versatile button options.
- Established data structures for industries and robots, including detailed specifications and use cases.
- Included utility functions for retrieving robots by slug and category.
This commit is contained in:
Najjar\NajjarV02
2026-05-20 17:22:47 +04:00
parent 2eac53dac3
commit 92cf4aba3b
87 changed files with 6887 additions and 1430 deletions
+361
View File
@@ -0,0 +1,361 @@
'use client';
import Image from 'next/image';
import { useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { PremiumButton } from '@/components/ui/PremiumButton';
import { CursorSpotlight } from '@/components/ui/CursorSpotlight';
import { FEATURED_ROBOTS } from '@/data/robots';
const HERO_STATS = [
{ value: 'Exclusive', label: 'UAE access' },
{ value: '2', label: 'Premier brands' },
{ value: 'Dubai', label: 'Showroom & demo' },
];
type LabelPos = {
text: string;
delay: number;
top?: string;
bottom?: string;
left?: string;
right?: string;
};
const FLOATING_LABELS: LabelPos[] = [
{ text: 'Exclusive UAE Access', top: '10%', left: '5%', delay: 0 },
{ text: 'Unitree Robotics', top: '22%', right: '4%', delay: 0.3 },
{ text: 'Pudu Service Robots', bottom: '28%', left: '4%', delay: 0.6 },
{ text: 'Demo & Sales · Dubai', bottom: '12%', right: '6%', delay: 0.9 },
];
export function Hero3DRobotics() {
const wrapRef = useRef<HTMLDivElement | null>(null);
const [tilt, setTilt] = useState({ rx: 0, ry: 0 });
const [activeIdx, setActiveIdx] = useState(0);
useEffect(() => {
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduce) return;
const el = wrapRef.current;
if (!el) return;
const onMove = (e: MouseEvent) => {
const rect = el.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
setTilt({ rx: -y * 9, ry: x * 14 });
};
const onLeave = () => setTilt({ rx: 0, ry: 0 });
el.addEventListener('mousemove', onMove);
el.addEventListener('mouseleave', onLeave);
return () => {
el.removeEventListener('mousemove', onMove);
el.removeEventListener('mouseleave', onLeave);
};
}, []);
useEffect(() => {
const t = setInterval(() => setActiveIdx((i) => (i + 1) % FEATURED_ROBOTS.length), 5400);
return () => clearInterval(t);
}, []);
const robot = FEATURED_ROBOTS[activeIdx];
return (
<section
style={{
position: 'relative',
minHeight: 'min(960px, 100svh)',
display: 'flex',
alignItems: 'center',
overflow: 'hidden',
paddingTop: 'clamp(6rem, 12vw, 9rem)',
paddingBottom: 'clamp(4rem, 8vw, 6rem)',
}}
>
<div className="hero-gradient" />
<div className="grid-overlay" />
<CursorSpotlight color="rgba(224, 200, 150, 0.22)" size={620} />
<div
aria-hidden
style={{
position: 'absolute',
inset: 0,
background:
'conic-gradient(from 220deg at 60% 50%, transparent 0deg, rgba(196,162,101,0.06) 25deg, transparent 50deg, rgba(224,200,150,0.05) 180deg, transparent 220deg, rgba(196,162,101,0.05) 320deg, transparent 360deg)',
mixBlendMode: 'screen',
pointerEvents: 'none',
}}
/>
<div className="container-wide" style={{ position: 'relative', display: 'grid', gridTemplateColumns: '1fr', gap: 'clamp(2rem, 5vw, 4rem)', alignItems: 'center', width: '100%' }}>
<div className="hero-grid" style={{ display: 'grid', gap: 'clamp(2rem, 6vw, 4rem)', alignItems: 'center' }}>
<div className="fade-in-up" style={{ display: 'flex', flexDirection: 'column', gap: '1.75rem' }}>
<span
className="eyebrow"
style={{
color: '#e0c896',
border: '1px solid rgba(196,162,101,0.35)',
background: 'rgba(196,162,101,0.06)',
padding: '0.5rem 0.9rem',
borderRadius: 999,
alignSelf: 'flex-start',
gap: '0.625rem',
}}
>
<span aria-hidden style={{ width: 6, height: 6, borderRadius: 999, background: '#e0c896', boxShadow: '0 0 12px rgba(224,200,150,0.8)' }} />
Exclusive UAE Access · Dubai
</span>
<h1
style={{
margin: 0,
fontSize: 'clamp(2.6rem, 6.4vw, 4.6rem)',
lineHeight: 1.02,
letterSpacing: '-0.035em',
fontWeight: 300,
}}
>
<span style={{ display: 'block', color: '#f5f1e8', fontWeight: 200 }}>Advanced robotics.</span>
<span className="text-gradient-accent" style={{ display: 'block', fontWeight: 600 }}>
Exclusive UAE access.
</span>
</h1>
<p style={{ margin: 0, color: '#cbc4b3', fontSize: 'clamp(1rem, 2vw, 1.18rem)', lineHeight: 1.7, maxWidth: 600, fontWeight: 300 }}>
YS Lootah Robotics is the exclusive UAE sales destination for selected Unitree and Pudu Robotics solutions — helping businesses explore, configure, book demos, and deploy advanced robots across Dubai and the UAE.
</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', marginTop: '0.5rem' }}>
<PremiumButton href="/robots/">Explore exclusive robots</PremiumButton>
<PremiumButton href="/book-demo/" variant="ghost">Book a demo</PremiumButton>
<PremiumButton href="/configure/" variant="outline">Configure your solution</PremiumButton>
</div>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
gap: 'clamp(0.5rem, 2vw, 1.25rem)',
paddingTop: '1.25rem',
marginTop: '0.5rem',
borderTop: '1px solid rgba(196,162,101,0.18)',
}}
>
{HERO_STATS.map((s) => (
<div key={s.label} style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem' }}>
<span className="text-gradient-accent" style={{ fontSize: 'clamp(1.3rem, 2.6vw, 1.8rem)', fontWeight: 700, letterSpacing: '-0.02em' }}>
{s.value}
</span>
<span style={{ fontSize: '0.7rem', color: '#94908a', letterSpacing: '0.22em', textTransform: 'uppercase' }}>
{s.label}
</span>
</div>
))}
</div>
</div>
<div
ref={wrapRef}
style={{
position: 'relative',
perspective: '1500px',
minHeight: 'clamp(420px, 56vw, 620px)',
width: '100%',
}}
>
<div
style={{
position: 'absolute',
inset: '-3rem',
background:
`radial-gradient(ellipse 60% 50% at 50% 50%, ${robot.accent}55 0%, transparent 65%)`,
filter: 'blur(28px)',
pointerEvents: 'none',
}}
/>
<div
className="float-y"
style={{
position: 'relative',
width: '100%',
height: '100%',
minHeight: 'clamp(420px, 56vw, 620px)',
borderRadius: '1.75rem',
background:
'linear-gradient(180deg, rgba(20,17,11,0.7) 0%, rgba(5,5,5,0.92) 100%)',
border: '1px solid rgba(196,162,101,0.28)',
backdropFilter: 'blur(18px)',
boxShadow:
'0 30px 100px rgba(0,0,0,0.75), inset 0 1px 0 rgba(255,240,200,0.08), 0 0 60px rgba(196,162,101,0.15)',
transform: `rotateX(${tilt.rx}deg) rotateY(${tilt.ry}deg)`,
transition: 'transform 0.25s ease-out',
overflow: 'hidden',
}}
>
<div
aria-hidden
style={{
position: 'absolute',
inset: 0,
background:
'linear-gradient(rgba(196,162,101,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(196,162,101,0.06) 1px, transparent 1px)',
backgroundSize: '40px 40px',
maskImage: 'radial-gradient(ellipse 70% 70% at 50% 50%, #000 30%, transparent 80%)',
WebkitMaskImage: 'radial-gradient(ellipse 70% 70% at 50% 50%, #000 30%, transparent 80%)',
pointerEvents: 'none',
}}
/>
<div
aria-hidden
style={{
position: 'absolute',
bottom: '-30%',
left: '50%',
transform: 'translateX(-50%)',
width: '70%',
height: '60%',
background:
'radial-gradient(ellipse 50% 50% at 50% 30%, rgba(224,200,150,0.30) 0%, transparent 70%)',
filter: 'blur(20px)',
pointerEvents: 'none',
}}
/>
{FEATURED_ROBOTS.map((r, idx) => (
<div
key={r.id}
style={{
position: 'absolute',
inset: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: 'clamp(1.5rem, 5vw, 3rem)',
opacity: idx === activeIdx ? 1 : 0,
transform: idx === activeIdx ? 'translateY(0) scale(1)' : 'translateY(14px) scale(0.97)',
transition: 'opacity 0.9s ease, transform 0.9s ease',
}}
aria-hidden={idx !== activeIdx}
>
<Image
src={r.image}
alt={`${r.brandLabel} ${r.name}`}
fill
sizes="(max-width: 768px) 90vw, 620px"
style={{ objectFit: 'contain', padding: 'clamp(1rem, 4vw, 2rem)' }}
priority={idx === 0}
/>
</div>
))}
<div className="hero-labels" aria-hidden>
{FLOATING_LABELS.map((l) => (
<span
key={l.text}
style={{
position: 'absolute',
top: l.top,
bottom: l.bottom,
left: l.left,
right: l.right,
padding: '0.4rem 0.75rem',
borderRadius: 999,
background: 'rgba(10,9,7,0.7)',
border: '1px solid rgba(196,162,101,0.3)',
color: '#e0c896',
fontSize: '0.66rem',
letterSpacing: '0.22em',
textTransform: 'uppercase',
fontWeight: 600,
backdropFilter: 'blur(8px)',
animation: `floatY 6s ease-in-out ${l.delay}s infinite`,
whiteSpace: 'nowrap',
}}
>
{l.text}
</span>
))}
</div>
<div
style={{
position: 'absolute',
bottom: '1.25rem',
left: '1.25rem',
right: '1.25rem',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: '1rem',
flexWrap: 'wrap',
}}
>
<Link
href={`/robots/${robot.slug}/`}
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '0.75rem',
padding: '0.65rem 1rem',
borderRadius: 14,
background: 'rgba(10,9,7,0.7)',
border: '1px solid rgba(196,162,101,0.35)',
backdropFilter: 'blur(10px)',
color: '#f5f1e8',
textDecoration: 'none',
}}
>
<span style={{ display: 'flex', flexDirection: 'column' }}>
<span style={{ fontSize: '0.62rem', color: '#94908a', letterSpacing: '0.24em', textTransform: 'uppercase' }}>
Featured · {robot.brandLabel}
</span>
<span style={{ fontSize: '0.95rem', fontWeight: 600 }}>{robot.name}</span>
</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={robot.accent} 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>
</Link>
<div style={{ display: 'flex', gap: '0.4rem' }}>
{FEATURED_ROBOTS.map((r, idx) => (
<button
key={r.id}
type="button"
onClick={() => setActiveIdx(idx)}
aria-label={`Show ${r.name}`}
style={{
width: idx === activeIdx ? 24 : 8,
height: 8,
borderRadius: 999,
border: 'none',
background: idx === activeIdx ? r.accent : 'rgba(196,162,101,0.3)',
cursor: 'pointer',
transition: 'all 0.4s ease',
}}
/>
))}
</div>
</div>
</div>
</div>
</div>
</div>
<style jsx>{`
@media (min-width: 1024px) {
.hero-grid {
grid-template-columns: 1.05fr 1fr !important;
}
}
.hero-labels { display: none; }
@media (min-width: 768px) {
.hero-labels { display: block; }
}
`}</style>
</section>
);
}