Initial commit
This commit is contained in:
252
src/components/home/Hero.tsx
Normal file
252
src/components/home/Hero.tsx
Normal file
@@ -0,0 +1,252 @@
|
||||
import Image from "next/image";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const QUICK_LINKS = [
|
||||
{
|
||||
name: "Hot Meals",
|
||||
icon: "fastfood",
|
||||
label: "Quick & tasty",
|
||||
},
|
||||
{
|
||||
name: "Daily Groceries",
|
||||
icon: "shopping_basket",
|
||||
label: "Fresh & On-Time",
|
||||
},
|
||||
{
|
||||
name: "Health & Care",
|
||||
icon: "medical_services",
|
||||
label: "Essential & Trusted",
|
||||
},
|
||||
{
|
||||
name: "More Services",
|
||||
icon: "grid_view",
|
||||
label: "Explore More",
|
||||
},
|
||||
];
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<div className="hero">
|
||||
|
||||
{/* ─── Base Dark Background Panel (Clipped diagonally) ─── */}
|
||||
<div className="hero-dark-panel select-none pointer-events-none">
|
||||
|
||||
{/* Flat Dotted World Map Layer */}
|
||||
<div className="hero-map-layer select-none mix-blend-screen">
|
||||
<Image
|
||||
src="/images/slider-glob.png"
|
||||
alt="Dotted World Map"
|
||||
fill
|
||||
sizes="(max-width: 768px) 100vw, 75vw"
|
||||
className="object-contain object-left"
|
||||
priority
|
||||
/>
|
||||
|
||||
{/* Animated Route Lines & Glowing Location Nodes */}
|
||||
<svg
|
||||
className="absolute inset-0 w-full h-full opacity-85 pointer-events-none"
|
||||
viewBox="0 0 1000 800"
|
||||
preserveAspectRatio="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<filter id="heroRouteGlow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="5" result="blur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="blur" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
{/* Glowing nodes */}
|
||||
<circle cx="150" cy="180" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="150" cy="180" r="2.5" className="fill-white" />
|
||||
|
||||
<circle cx="350" cy="110" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="350" cy="110" r="2.5" className="fill-white" />
|
||||
|
||||
<circle cx="280" cy="300" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="280" cy="300" r="2.5" className="fill-white" />
|
||||
|
||||
<circle cx="480" cy="220" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="480" cy="220" r="2.5" className="fill-white" />
|
||||
|
||||
<circle cx="650" cy="165" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="650" cy="165" r="2.5" className="fill-white" />
|
||||
|
||||
<circle cx="780" cy="250" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="780" cy="250" r="2.5" className="fill-white" />
|
||||
|
||||
<circle cx="580" cy="140" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
|
||||
<circle cx="580" cy="140" r="2.5" className="fill-white" />
|
||||
|
||||
{/* Arc dashed lines with moving stroke-dash animation */}
|
||||
<path
|
||||
d="M150,180 Q250,120 350,110"
|
||||
fill="none"
|
||||
stroke="#c02cff"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="6,6"
|
||||
className="animate-route opacity-70"
|
||||
filter="url(#heroRouteGlow)"
|
||||
/>
|
||||
<path
|
||||
d="M150,180 Q200,240 280,300"
|
||||
fill="none"
|
||||
stroke="#c02cff"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="6,6"
|
||||
className="animate-route opacity-70"
|
||||
filter="url(#heroRouteGlow)"
|
||||
/>
|
||||
<path
|
||||
d="M350,110 Q420,165 480,220"
|
||||
fill="none"
|
||||
stroke="#c02cff"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="6,6"
|
||||
className="animate-route opacity-70"
|
||||
filter="url(#heroRouteGlow)"
|
||||
/>
|
||||
<path
|
||||
d="M280,300 Q380,250 480,220"
|
||||
fill="none"
|
||||
stroke="#c02cff"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="6,6"
|
||||
className="animate-route opacity-70"
|
||||
filter="url(#heroRouteGlow)"
|
||||
/>
|
||||
<path
|
||||
d="M480,220 Q520,180 580,140 Q630,120 650,165"
|
||||
fill="none"
|
||||
stroke="#c02cff"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="6,6"
|
||||
className="animate-route opacity-70"
|
||||
filter="url(#heroRouteGlow)"
|
||||
/>
|
||||
<path
|
||||
d="M480,220 Q620,250 780,250"
|
||||
fill="none"
|
||||
stroke="#c02cff"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="6,6"
|
||||
className="animate-route opacity-70"
|
||||
filter="url(#heroRouteGlow)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Soft purple radial glow behind the bike near the diagonal edge (clipped) */}
|
||||
<div className="absolute right-0 top-1/4 z-0 h-[60%] w-[45%] rounded-full bg-primary/45 blur-[120px] opacity-50 pointer-events-none" />
|
||||
</div>
|
||||
|
||||
{/* ─── Main Content Wrapper ─── */}
|
||||
<div className="hero-stage relative w-full flex flex-col z-10 md:justify-center md:items-start">
|
||||
|
||||
{/* Left Column: Text & Search Content */}
|
||||
<div className="hero-content text-white select-none">
|
||||
<span className="inline-block text-label-sm text-brand-accent font-black tracking-widest uppercase mb-4 bg-brand-accent/10 px-4 py-1.5 rounded-full border border-brand-accent/20">
|
||||
Express Services
|
||||
</span>
|
||||
|
||||
<h1 className="text-5xl lg:text-[82px] font-display font-black leading-[0.98] tracking-tight mb-7">
|
||||
Express
|
||||
<br />
|
||||
<span className="text-brand-accent drop-shadow-md">Neighborhood</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-body-lg md:text-[20px] md:leading-8 text-white/80 mb-11 leading-relaxed max-w-2xl">
|
||||
Get groceries, hot meals, daily essentials, and local professional services delivered from trusted partners within <span className="text-brand-accent font-bold">25-30 minutes</span>.
|
||||
</p>
|
||||
|
||||
{/* Search Input Bar */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center bg-white p-2 rounded-full shadow-2xl border border-white/10 focus-within:ring-4 focus-within:ring-brand-accent/30 transition-all duration-300 max-w-[620px]">
|
||||
<MaterialIcon
|
||||
icon="location_on"
|
||||
size={22}
|
||||
className="ml-4 text-brand-accent animate-pulse-subtle"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter your neighbourhood or delivery location..."
|
||||
className="w-full border-none focus:ring-0 focus:outline-none text-body-md text-on-surface font-semibold placeholder-on-surface-variant/50 px-3 py-2 bg-transparent"
|
||||
/>
|
||||
<button className="bg-brand-accent hover:bg-brand-accent/90 text-brand-dark font-black px-6 py-3 rounded-full text-label-sm hover:shadow-lg transition-all active:scale-95 duration-200 whitespace-nowrap cursor-pointer">
|
||||
Find Shops
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Popular tags below */}
|
||||
<div className="flex gap-3 items-center flex-wrap px-4 mt-2">
|
||||
<span className="text-label-sm text-white/40 uppercase tracking-widest font-black text-[10px]">
|
||||
Popular:
|
||||
</span>
|
||||
{["Fresh Produce", "African Bakery", "Pet Care"].map((tag) => (
|
||||
<a
|
||||
key={tag}
|
||||
href="#"
|
||||
className="text-label-sm text-brand-accent-light hover:text-brand-accent transition-colors font-bold"
|
||||
>
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Dominant Purple Scooter Rider (Overlapping) */}
|
||||
<div className="hero-bike select-none pointer-events-none">
|
||||
<div className="relative w-full h-full flex items-end">
|
||||
<Image
|
||||
src="/images/slider-courier-mask-purple-v4.png"
|
||||
alt="Nearle Delivery Courier"
|
||||
fill
|
||||
sizes="(max-width: 768px) 95vw, 48vw"
|
||||
className="object-contain object-bottom drop-shadow-2xl"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Overlapping Quick Category Links (Anchored at the bottom edge) */}
|
||||
<div className="hero-cards absolute bottom-0 left-0 right-0 transform translate-y-[50%] z-20">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{QUICK_LINKS.map((item) => (
|
||||
<div
|
||||
key={item.name}
|
||||
className="flex items-center gap-4 bg-white p-5 rounded-2xl border border-outline-variant/15 shadow-xl hover:shadow-2xl premium-card cursor-pointer group"
|
||||
>
|
||||
<div className="flex-shrink-0 w-12 h-12 rounded-full bg-brand-accent/10 flex items-center justify-center group-hover:bg-brand-accent/20 transition-colors">
|
||||
<MaterialIcon
|
||||
icon={item.icon}
|
||||
size={24}
|
||||
className="text-brand-accent"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<h3 className="text-label-md font-extrabold text-brand-dark group-hover:text-primary transition-colors">
|
||||
{item.name}
|
||||
</h3>
|
||||
<p className="text-[11px] text-on-surface-variant font-medium mt-0.5 leading-tight">
|
||||
{item.label}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-surface-container flex items-center justify-center opacity-0 group-hover:opacity-100 group-hover:translate-x-1 transition-all duration-300">
|
||||
<MaterialIcon
|
||||
icon="arrow_forward"
|
||||
size={16}
|
||||
className="text-primary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user