update redesign
This commit is contained in:
@@ -208,7 +208,7 @@ export function ContactForm() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-primary hover:bg-primary-container disabled:bg-primary-container/60 text-on-primary font-black px-8 py-4 rounded-xl text-label-md hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 active:translate-y-0 active:scale-[0.98] flex items-center justify-center gap-2 cursor-pointer"
|
||||
className="w-full bg-[#6330D6] hover:bg-[#5225b8] disabled:bg-[#6330D6]/60 text-on-primary font-black px-8 py-4 rounded-xl text-label-md hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 active:translate-y-0 active:scale-[0.98] flex items-center justify-center gap-2 cursor-pointer"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
|
||||
@@ -31,7 +31,7 @@ const BENEFITS = [
|
||||
|
||||
export function BusinessSection() {
|
||||
return (
|
||||
<section className="pt-4 md:pt-5 lg:pt-6 pb-4 md:pb-5 lg:pb-6">
|
||||
<section className="px-6 py-12 md:py-16">
|
||||
<div className="w-full">
|
||||
|
||||
{/* Merchant Section Grid */}
|
||||
|
||||
@@ -1,179 +1,178 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const QUICK_LINKS = [
|
||||
{
|
||||
name: "Daily Groceries",
|
||||
icon: "shopping_basket",
|
||||
label: "Fresh & On-Time",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Hot Meals",
|
||||
icon: "fastfood",
|
||||
label: "Quick & tasty",
|
||||
},
|
||||
{
|
||||
name: "wellness ",
|
||||
icon: "medical_services",
|
||||
label: "Essential & Trusted",
|
||||
},
|
||||
{
|
||||
name: "More Services",
|
||||
icon: "store",
|
||||
label: "Explore More",
|
||||
},
|
||||
const PROOF_ITEMS = [
|
||||
{ label: "1000+", text: "Verified Stores", icon: "store" },
|
||||
{ label: "2km", text: "Neighbourhood Coverage", icon: "location_on" },
|
||||
{ label: "50,000+", text: "Happy Customers", icon: "mood" },
|
||||
{ label: "4.7 ★", text: "Average Rating", icon: "star" },
|
||||
];
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<section className="relative pb-4 md:pb-6">
|
||||
<div className="relative overflow-hidden rounded-[1.75rem] md:rounded-[2.25rem] bg-[#16001F]">
|
||||
{/* ─── Base Dark Background Panel (Clipped diagonally) ─── */}
|
||||
<div className="hero-dark-panel select-none pointer-events-none">
|
||||
{/* Subtle Background Dot Texture */}
|
||||
<div className="hero-map-layer select-none">
|
||||
<Image
|
||||
src="/images/slider-glob.png"
|
||||
alt="Subtle Background"
|
||||
fill
|
||||
sizes="(max-width: 768px) 100vw, 40vw"
|
||||
className="object-contain object-left-top"
|
||||
priority
|
||||
/>
|
||||
<section className="relative overflow-hidden bg-white select-none w-full">
|
||||
{/* ─── DECORATIONS (BEHIND CONTENT) ─── */}
|
||||
|
||||
{/* 1. Large pale lavender partial circle (top-left) */}
|
||||
<div className="hidden md:block absolute top-[-100px] left-[-100px] w-[350px] h-[350px] rounded-full border-[1.5px] border-[#6D28D9]/15 bg-[#6D28D9]/5 opacity-[0.55] z-0 pointer-events-none" />
|
||||
|
||||
{/* 2. Purple solid circle (center-right around collage) */}
|
||||
<div className="hidden lg:block absolute right-[22%] top-[38%] w-[84px] h-[84px] rounded-full bg-[#6D28D9] z-0 shadow-[0_8px_32px_rgba(109,40,217,0.3)] pointer-events-none animate-pulse" />
|
||||
|
||||
{/* 3. Striped purple circle (lower-middle collage area) */}
|
||||
<div
|
||||
className="hidden lg:block absolute left-[45%] bottom-[15%] w-[100px] h-[100px] rounded-full opacity-80 z-0 pointer-events-none"
|
||||
style={{
|
||||
backgroundImage: 'repeating-linear-gradient(45deg, rgba(109, 40, 217, 0.2) 0px, rgba(109, 40, 217, 0.2) 2px, transparent 2px, transparent 8px)'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 4. Dotted pattern (between left text and right collage) */}
|
||||
<div className="hidden lg:block absolute left-[41%] top-[25%] w-48 h-48 opacity-[0.35] z-0 pointer-events-none">
|
||||
<svg className="w-full h-full text-[#6D28D9]" fill="currentColor">
|
||||
<pattern id="hero-decor-dots" x="0" y="0" width="16" height="16" patternUnits="userSpaceOnUse">
|
||||
<circle cx="2" cy="2" r="1.5" />
|
||||
</pattern>
|
||||
<rect width="100%" height="100%" fill="url(#hero-decor-dots)" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* 5. Three small X marks */}
|
||||
<div className="absolute top-[8%] left-[48%] text-[#6D28D9]/25 font-bold text-xl pointer-events-none select-none z-0">✕</div>
|
||||
<div className="hidden lg:block absolute top-[52%] left-[44%] text-[#6D28D9]/20 font-bold text-lg pointer-events-none select-none z-0">✕</div>
|
||||
<div className="absolute bottom-[14%] right-[5%] text-[#6D28D9]/25 font-bold text-xl pointer-events-none select-none z-0">✕</div>
|
||||
|
||||
{/* 6. Large partial purple circle (bottom-right corner) */}
|
||||
<div className="absolute bottom-[-100px] right-[-100px] w-[200px] h-[200px] rounded-full bg-[#7C3AED]/80 z-0 pointer-events-none" />
|
||||
|
||||
{/* ─── TWO-COLUMN CONTENT GRID ─── */}
|
||||
<div className="relative mx-auto grid min-h-[650px] grid-cols-1 lg:grid-cols-[0.92fr_1.08fr] items-center px-8 py-16 md:px-12 lg:px-16 xl:px-20 z-10 gap-12 lg:gap-6">
|
||||
|
||||
{/* LEFT COLUMN: Editorial Typography & Copy */}
|
||||
<div className="flex flex-col text-left max-w-xl z-20 relative">
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6D28D9]/10 text-[#6D28D9] uppercase mb-6 w-fit">
|
||||
Welcome to Nearle
|
||||
</span>
|
||||
|
||||
<h1 className="font-display text-4xl sm:text-5xl lg:text-[68px] xl:text-[76px] font-black text-[#16001D] leading-[0.95] tracking-[-0.05em]">
|
||||
Everything Local.
|
||||
<br />
|
||||
Everything <span className="text-[#6D28D9]">Near.</span>
|
||||
</h1>
|
||||
|
||||
<p className="max-w-[480px] text-base md:text-lg text-[#6D6172] leading-relaxed font-bold mt-6">
|
||||
Discover verified local stores, exclusive offers, fast delivery, and a better way to shop within your neighbourhood.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto">
|
||||
<Link
|
||||
href="/people"
|
||||
className="bg-[#6D28D9] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-98"
|
||||
>
|
||||
Explore Stores
|
||||
</Link>
|
||||
<Link
|
||||
href="/people#download-section"
|
||||
className="border-2 border-[#6D28D9]/20 hover:border-[#6D28D9]/40 text-[#6D28D9] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6D28D9]/5 active:scale-98"
|
||||
>
|
||||
Get the App
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Soft purple radial glow */}
|
||||
<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 min-h-0 pb-10 md:pb-12 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-xs font-black tracking-widest uppercase mb-5 bg-brand-accent/15 px-4 py-1.5 rounded-full border border-brand-accent/20 text-brand-accent">
|
||||
Neighbourhood commerce, made simple
|
||||
</span>
|
||||
|
||||
<h1 className="text-4xl sm:text-5xl lg:text-[52px] xl:text-[62px] 2xl:text-[74px] lg:leading-[1.15] font-display font-black tracking-tight mb-8">
|
||||
Your Favourite Local Stores,
|
||||
<br />
|
||||
<span className="text-brand-accent drop-shadow-md">
|
||||
Now at Your Doorstep.
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-body-lg md:text-[20px] md:leading-8 text-white/90 mb-10 leading-relaxed max-w-2xl">
|
||||
Order groceries, medicines, food and everyday essentials from trusted stores near you — all in one convenient app.
|
||||
</p>
|
||||
|
||||
{/* CTAs */}
|
||||
<div className="flex flex-col md:flex-row md:flex-wrap gap-4 mt-8 w-full md:w-auto">
|
||||
<Link
|
||||
href="/people"
|
||||
className="bg-brand-accent hover:bg-brand-accent-light text-brand-dark font-black px-8 py-4 rounded-xl text-sm md:text-base hover:shadow-xl transition-all duration-300 active:scale-95 flex items-center justify-center gap-2 w-full md:w-auto min-h-[48px] whitespace-nowrap"
|
||||
>
|
||||
Explore Nearby Stores
|
||||
</Link>
|
||||
<Link
|
||||
href="/businesses"
|
||||
className="bg-white/10 hover:bg-white/15 border border-white/20 text-white font-black px-8 py-4 rounded-xl text-sm md:text-base transition-all duration-300 active:scale-95 flex items-center justify-center gap-2 w-full md:w-auto min-h-[48px] whitespace-nowrap"
|
||||
>
|
||||
List Your Store
|
||||
</Link>
|
||||
{/* RIGHT COLUMN: Creative Overlapping Strips Collage */}
|
||||
<div className="w-full z-20">
|
||||
|
||||
{/* DESKTOP LAYOUT (lg and above) */}
|
||||
<div className="hidden lg:block relative h-[500px] lg:h-[560px] w-full">
|
||||
{/* left image: absolute left-[10%] top-[20%] w-[170px] h-[360px] */}
|
||||
<div className="absolute left-[10%] top-[20%] w-[170px] h-[360px] rounded-[1.5rem] overflow-hidden shadow-lg border-2 border-white z-10 transition-transform duration-300 hover:scale-[1.02]">
|
||||
<Image
|
||||
src="/images/cat-daily-essentials.png"
|
||||
alt="Local grocery products"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="170px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Trust points */}
|
||||
<div className="flex flex-wrap gap-x-8 gap-y-3 mt-12 text-sm md:text-base text-white/90">
|
||||
<div className="flex items-center gap-2">
|
||||
<MaterialIcon icon="store" size={18} className="text-brand-accent" />
|
||||
<span>Real local shops</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<MaterialIcon icon="sell" size={18} className="text-brand-accent" />
|
||||
<span>Fair local prices</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<MaterialIcon icon="local_shipping" size={18} className="text-brand-accent" />
|
||||
<span>Neighbourhood delivery</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Mobile/Tablet Only Nearle Bag Logo with context pins */}
|
||||
<div className="hero-mobile-logo block lg:hidden mt-8 select-none pointer-events-none relative">
|
||||
<div className="relative w-[280px] h-[230px] mx-auto">
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
alt="Nearle delivery"
|
||||
fill
|
||||
sizes="(max-width: 1023px) 280px, 0px"
|
||||
className="object-contain drop-shadow-2xl"
|
||||
priority
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Centered Nearle bag visual with local commerce context pins and route line */}
|
||||
<div className="hero-visual-layer select-none pointer-events-none relative">
|
||||
<div className="hero-visual-panel" />
|
||||
|
||||
|
||||
<div className="hero-visual-image relative">
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
alt="Nearle delivery"
|
||||
fill
|
||||
sizes="(max-width: 768px) 95vw, 48vw"
|
||||
className="object-contain drop-shadow-2xl"
|
||||
{/* middle image: absolute left-[38%] top-[8%] w-[190px] h-[430px] */}
|
||||
<div className="absolute left-[38%] top-[8%] w-[190px] h-[430px] rounded-[1.5rem] overflow-hidden shadow-xl border-2 border-white z-20 transition-transform duration-300 hover:scale-[1.02]">
|
||||
<Image
|
||||
src="/Nearle Business.png"
|
||||
alt="Local merchant delivery"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="190px"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overlapping Quick Category Links */}
|
||||
<div className="service-cards-wrapper max-w-container-max mx-auto relative z-20 -mt-8 md:-mt-10 lg:-mt-12">
|
||||
<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-sm md:text-base font-extrabold text-brand-dark group-hover:text-primary transition-colors">
|
||||
{item.name}
|
||||
</h3>
|
||||
<p className="text-xs 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>
|
||||
{/* right image: absolute right-[2%] top-[18%] w-[180px] h-[390px] */}
|
||||
<div className="absolute right-[2%] top-[18%] w-[180px] h-[390px] rounded-[1.5rem] overflow-hidden shadow-lg border-2 border-white z-10 transition-transform duration-300 hover:scale-[1.02]">
|
||||
<Image
|
||||
src="/nearle people.png"
|
||||
alt="Local customer shopping"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="180px"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* MOBILE/TABLET COLLAGE (below lg) */}
|
||||
<div className="lg:hidden flex items-center justify-center gap-2 mt-2 w-full relative h-[280px]">
|
||||
<div className="relative w-[95px] h-[200px] rounded-2xl overflow-hidden border border-white shadow-md z-10">
|
||||
<Image
|
||||
src="/images/cat-daily-essentials.png"
|
||||
alt="Grocery products"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="95px"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative w-[115px] h-[240px] rounded-2xl overflow-hidden border border-white shadow-lg -mx-5 z-20">
|
||||
<Image
|
||||
src="/Nearle Business.png"
|
||||
alt="Merchant"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="115px"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative w-[105px] h-[220px] rounded-2xl overflow-hidden border border-white shadow-md z-10">
|
||||
<Image
|
||||
src="/nearle people.png"
|
||||
alt="Customer"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="105px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* ─── BOTTOM PROOF STATS ROW ─── */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 border-t border-[#EEE7F4] bg-white px-8 py-8 md:px-12 lg:px-16 z-20 relative">
|
||||
{PROOF_ITEMS.map((item) => (
|
||||
<div key={item.label} className="flex flex-col items-start text-left pl-2 md:pl-4">
|
||||
<div className="w-8 h-8 rounded-full bg-[#6D28D9]/10 text-[#6D28D9] flex items-center justify-center mb-3">
|
||||
<MaterialIcon icon={item.icon} size={16} />
|
||||
</div>
|
||||
<div className="text-2xl md:text-3xl font-black text-[#16001D] leading-none tracking-tight">
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="text-xs text-[#6D6172] font-semibold mt-1">
|
||||
{item.text}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const STEPS = [
|
||||
|
||||
export function HowItWorks() {
|
||||
return (
|
||||
<section className="border-t border-brand-dark/10 pt-12 md:pt-16 lg:pt-20 pb-6 md:pb-8 lg:pb-10">
|
||||
<section className="px-6 py-12 md:py-16">
|
||||
<div className="w-full">
|
||||
{/* Header Section */}
|
||||
<div className="text-center mb-12 md:mb-16">
|
||||
|
||||
@@ -27,7 +27,7 @@ const FEATURES = [
|
||||
|
||||
export function HyperlocalFeatures() {
|
||||
return (
|
||||
<section className="pt-4 md:pt-5 lg:pt-6 pb-2 md:pb-3 lg:pb-4 relative">
|
||||
<section className="px-6 py-12 md:py-16 relative">
|
||||
{/* Scoped CSS styles for precise layout enforcement */}
|
||||
<style>{`
|
||||
@media (min-width: 901px) {
|
||||
|
||||
@@ -55,7 +55,7 @@ const CATEGORIES = [
|
||||
|
||||
export function ServiceCategories() {
|
||||
return (
|
||||
<section className="pt-10 md:pt-14 lg:pt-16 pb-2 md:pb-3 lg:pb-4">
|
||||
<section className="px-6 pt-20 md:pt-24 lg:pt-28 pb-12 md:pb-16">
|
||||
<div className="w-full">
|
||||
{/* Header Section */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-end mb-12 md:mb-16 gap-6">
|
||||
|
||||
@@ -9,7 +9,7 @@ const FLOW_STEPS = [
|
||||
|
||||
export function StoreQRSection() {
|
||||
return (
|
||||
<section id="download" className="bg-gradient-to-br from-[#1C0024] to-[#0D0012] rounded-[1.75rem] md:rounded-[2.25rem] border border-white/10 shadow-[0_20px_50px_rgba(20,0,30,0.28)] overflow-hidden py-16 md:py-20 px-6 md:px-12 lg:px-20 text-white relative flex items-center mt-2 md:mt-3 mb-2 md:mb-3">
|
||||
<section id="download" className="section-card-dark py-16 md:py-20 px-6 md:px-12 lg:px-20 text-white relative flex items-center">
|
||||
{/* Background ambient glowing details */}
|
||||
<div className="absolute right-[-10%] top-[-10%] w-[50%] h-[50%] rounded-full bg-brand-accent/5 blur-[120px] pointer-events-none" />
|
||||
<div className="absolute left-[-10%] bottom-[-10%] w-[50%] h-[50%] rounded-full bg-primary/10 blur-[120px] pointer-events-none" />
|
||||
|
||||
@@ -29,7 +29,7 @@ const CARDS = [
|
||||
|
||||
export function WhyNearle() {
|
||||
return (
|
||||
<section className="pt-4 md:pt-5 lg:pt-6 pb-4 md:pb-5 lg:pb-6">
|
||||
<section className="px-6 py-12 md:py-16">
|
||||
<div className="w-full">
|
||||
{/* Header Section */}
|
||||
<div className="text-center mb-8 md:mb-10">
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const COMPANY = [
|
||||
@@ -27,392 +26,131 @@ const LEGAL = [
|
||||
{ label: "Sitemap", href: "#" },
|
||||
];
|
||||
|
||||
type FooterFormData = {
|
||||
name: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
type FooterFormErrors = {
|
||||
name?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export function Footer() {
|
||||
const pathname = usePathname();
|
||||
const isContactPage = pathname?.startsWith("/contact");
|
||||
|
||||
// Form states
|
||||
const [formData, setFormData] = useState<FooterFormData>({
|
||||
name: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
message: "",
|
||||
});
|
||||
const [errors, setErrors] = useState<FooterFormErrors>({});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitSuccess, setSubmitSuccess] = useState(false);
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}));
|
||||
if (errors[name as keyof FooterFormErrors]) {
|
||||
setErrors((prev) => ({
|
||||
...prev,
|
||||
[name]: undefined,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const validateForm = (): boolean => {
|
||||
const tempErrors: FooterFormErrors = {};
|
||||
let isValid = true;
|
||||
|
||||
if (!formData.name.trim()) {
|
||||
tempErrors.name = "Name is required";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!formData.phone.trim()) {
|
||||
tempErrors.phone = "Phone is required";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!formData.email.trim()) {
|
||||
tempErrors.email = "Email is required";
|
||||
isValid = false;
|
||||
} else if (!emailRegex.test(formData.email)) {
|
||||
tempErrors.email = "Please enter a valid email address";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!formData.message.trim()) {
|
||||
tempErrors.message = "Message is required";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
setErrors(tempErrors);
|
||||
return isValid;
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!validateForm()) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
// Simulate API delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
setIsSubmitting(false);
|
||||
setSubmitSuccess(true);
|
||||
setFormData({ name: "", phone: "", email: "", message: "" });
|
||||
|
||||
// Hide success alert after 5 seconds
|
||||
setTimeout(() => {
|
||||
setSubmitSuccess(false);
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const brandCol = (
|
||||
<div className="footer-brand min-w-0 self-start">
|
||||
<Link href="/" className="mb-4 inline-block">
|
||||
<Image
|
||||
src="/logo-v2.png"
|
||||
alt="Nearle"
|
||||
width={220}
|
||||
height={36}
|
||||
style={{ width: "210px", height: "auto" }}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<p className="footer-desc mb-4 text-white/80">
|
||||
India's leading hyperlocal neighborhood network, empowering
|
||||
communities and verified local businesses within 2km.
|
||||
</p>
|
||||
|
||||
{/* Social Links */}
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="footer-social-link" aria-label="Share">
|
||||
<MaterialIcon icon="share" size={24} />
|
||||
</a>
|
||||
<a href="#" className="footer-social-link" aria-label="Website">
|
||||
<MaterialIcon icon="public" size={24} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<footer className="bg-[#E6D7EA] px-3 sm:px-4 md:px-5 lg:px-6 xl:px-8 pb-0 w-full mt-3 md:mt-4">
|
||||
<div className="mx-auto" style={{ maxWidth: "min(100% - 48px, 1520px)" }}>
|
||||
<div className="bg-[#120217] rounded-[1.5rem] md:rounded-[2rem] lg:rounded-[2.5rem] overflow-hidden border border-white/10 shadow-[0_18px_45px_rgba(20,0,30,0.28)]">
|
||||
{/* Top Helpdesk Bar */}
|
||||
<div className="bg-[#2A0838] border-b border-white/10 px-5 py-4 md:px-8 md:py-5 flex flex-col md:flex-row justify-between items-center gap-6">
|
||||
<div className="flex items-center gap-4 text-white">
|
||||
<div className="w-12 h-12 rounded-full bg-brand-accent text-brand-dark flex items-center justify-center shadow-lg shrink-0">
|
||||
<MaterialIcon icon="headset_mic" size={24} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-headline-md font-black text-white">
|
||||
24/7 Neighborhood Helpdesk
|
||||
</h4>
|
||||
<p className="text-sm font-semibold text-white/70 mt-0.5">
|
||||
Need immediate assistance with an order or local service?
|
||||
</p>
|
||||
<footer className="bg-[#E6D7EA] px-3 sm:px-4 md:px-6 lg:px-8 xl:px-10 2xl:px-12 pb-6 md:pb-8 lg:pb-10 w-full mt-4">
|
||||
<div className="mx-auto w-full max-w-[1920px]">
|
||||
<div className="section-card-dark p-8 md:p-12 lg:p-14 text-white relative">
|
||||
{/* Background ambient glowing details */}
|
||||
<div className="absolute right-[-10%] top-[-10%] w-[50%] h-[50%] rounded-full bg-brand-accent/5 blur-[120px] pointer-events-none" />
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-10 lg:gap-12 relative z-10 items-start text-left">
|
||||
{/* Col 1: Brand info */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<Link href="/" className="inline-block">
|
||||
<Image
|
||||
src="/logo-light.png"
|
||||
alt="Nearle"
|
||||
width={220}
|
||||
height={36}
|
||||
style={{ width: "160px", height: "auto" }}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<p className="text-sm leading-relaxed text-white/70">
|
||||
India's leading hyperlocal neighborhood network, empowering
|
||||
communities and verified local businesses within 2km.
|
||||
</p>
|
||||
{/* Social Links */}
|
||||
<div className="flex gap-3 mt-2">
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-[#E6D7EA] hover:text-[#17001F] transition-all duration-300" aria-label="Share">
|
||||
<MaterialIcon icon="share" size={20} />
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-[#E6D7EA] hover:text-[#17001F] transition-all duration-300" aria-label="Website">
|
||||
<MaterialIcon icon="public" size={20} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Col 2: Company Links */}
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-6">Company</h5>
|
||||
<ul className="flex flex-col gap-3">
|
||||
{COMPANY.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-sm text-white/70 hover:text-[#E6D7EA] hover:translate-x-1 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 3: Partnerships */}
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-6">Partnerships</h5>
|
||||
<ul className="flex flex-col gap-3">
|
||||
{PARTNERSHIPS.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-sm text-white/70 hover:text-[#E6D7EA] hover:translate-x-1 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 4: Support / Legal */}
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-6">Support & Legal</h5>
|
||||
<ul className="flex flex-col gap-3">
|
||||
{LEGAL.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-sm text-white/70 hover:text-[#E6D7EA] hover:translate-x-1 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 5: HQ Address & Helpdesk */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-4">Visit Nearle HQ</h5>
|
||||
<p className="text-xs leading-relaxed text-white/60">
|
||||
424, Diwan Bahadur Rd,<br />
|
||||
Opposite to Sri Krishna Sweets,<br />
|
||||
R.S. Puram, Coimbatore,<br />
|
||||
Tamil Nadu 641002
|
||||
</p>
|
||||
<a
|
||||
href="https://maps.google.com/?q=424,+Diwan+Bahadur+Rd,+Opposite+To+Sri+Krishna+Sweets,+R.S.+Puram,+Coimbatore,+Tamil+Nadu+641002"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-3 inline-flex items-center gap-1.5 px-3.5 py-1.5 rounded-xl border border-white/10 hover:border-[#E6D7EA]/50 text-white/80 hover:text-[#E6D7EA] text-xs font-bold transition-all duration-300"
|
||||
>
|
||||
<MaterialIcon icon="location_on" size={14} />
|
||||
<span>Get Directions</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-white/10 pt-4 flex flex-col gap-2">
|
||||
<p className="text-[10px] font-bold text-white/40 uppercase tracking-widest">Neighborhood Helpdesk</p>
|
||||
<a
|
||||
href="tel:+918049123456"
|
||||
className="flex items-center gap-2 text-white hover:text-[#E6D7EA] transition-all"
|
||||
>
|
||||
<MaterialIcon icon="phone" size={16} className="text-[#E6D7EA] shrink-0" />
|
||||
<span className="text-sm font-black tracking-tight">+91 80 4912 3456</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="tel:+918049123456"
|
||||
className="flex items-center gap-3 bg-brand-accent hover:bg-brand-accent-light text-brand-dark font-black px-6 py-3 rounded-full text-base shadow-lg transition-all duration-300 hover:-translate-y-0.5 shrink-0"
|
||||
>
|
||||
<MaterialIcon
|
||||
icon="phone"
|
||||
size={20}
|
||||
className="animate-pulse-subtle"
|
||||
/>
|
||||
<span>+91 80 4912 3456</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Main Footer Content */}
|
||||
<div className="px-5 pt-10 pb-8 md:px-8 md:pt-12 md:pb-10 lg:px-12 lg:pt-12 lg:pb-10 text-white">
|
||||
<div
|
||||
className={
|
||||
isContactPage
|
||||
? "grid grid-cols-1 sm:grid-cols-3 gap-8 lg:gap-10"
|
||||
: "grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(500px,560px)] gap-10 xl:gap-14 items-start"
|
||||
}
|
||||
>
|
||||
{isContactPage ? (
|
||||
<>
|
||||
{/* Brand Column */}
|
||||
{brandCol}
|
||||
|
||||
{/* Company Links */}
|
||||
<div className="footer-company min-w-0 self-start">
|
||||
<FooterCol title="Company" links={COMPANY} />
|
||||
</div>
|
||||
|
||||
{/* Partnerships Links */}
|
||||
<div className="footer-partnerships min-w-0 self-start">
|
||||
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col self-start w-full">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-8 lg:gap-10">
|
||||
{/* Brand Column */}
|
||||
{brandCol}
|
||||
|
||||
{/* Company Links */}
|
||||
<div className="footer-company min-w-0 self-start">
|
||||
<FooterCol title="Company" links={COMPANY} />
|
||||
</div>
|
||||
|
||||
{/* Partnerships Links */}
|
||||
<div className="footer-partnerships min-w-0 self-start">
|
||||
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* HQ Office Location & Directions block */}
|
||||
<div className="mt-8 border-t border-white/10 pt-7 max-w-[520px] text-left">
|
||||
<p className="text-[11px] font-black uppercase tracking-[0.18em] text-brand-accent">
|
||||
VISIT NEARLE HQ
|
||||
</p>
|
||||
|
||||
<h4 className="mt-2 font-display text-xl md:text-2xl font-black text-white">
|
||||
Meet the team behind your neighbourhood.
|
||||
</h4>
|
||||
|
||||
<p className="mt-3 text-sm leading-6 text-white/60">
|
||||
424, Diwan Bahadur Rd,
|
||||
<br />
|
||||
Opposite to Sri Krishna Sweets,
|
||||
<br />
|
||||
R.S. Puram, Coimbatore,
|
||||
<br />
|
||||
Tamil Nadu 641002
|
||||
</p>
|
||||
|
||||
<a
|
||||
href="https://maps.google.com/?q=424,+Diwan+Bahadur+Rd,+Opposite+To+Sri+Krishna+Sweets,+R.S.+Puram,+Coimbatore,+Tamil+Nadu+641002"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-4 inline-flex items-center gap-2 px-4 py-2 rounded-xl border border-white/15 hover:border-brand-accent/50 text-white hover:text-brand-accent text-xs md:text-sm font-black transition-all duration-300"
|
||||
>
|
||||
<MaterialIcon icon="location_on" size={16} />
|
||||
<span>Get Directions</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contact Form Card */}
|
||||
<div className="footer-contact-wrap w-full self-start">
|
||||
<div className="footer-contact-card bg-white text-brand-dark shadow-2xl border border-outline-variant/15 relative overflow-hidden w-full max-w-[540px] lg:ml-auto p-7 md:p-8 lg:p-9">
|
||||
{/* Background Glow Decors */}
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-primary/5 rounded-full blur-2xl" />
|
||||
<div className="absolute bottom-0 left-0 w-24 h-24 bg-secondary/5 rounded-full blur-2xl" />
|
||||
|
||||
<div className="relative z-10 text-center lg:text-left">
|
||||
<h3 className="footer-contact-title font-display text-2xl md:text-3xl font-black text-brand-dark tracking-tight">
|
||||
Send us a Message
|
||||
</h3>
|
||||
<p className="footer-contact-subtitle text-sm md:text-base mt-1 mb-5">
|
||||
We shall guide you through our Neighbourhood Experts.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-3">
|
||||
{submitSuccess && (
|
||||
<div className="p-3 bg-secondary/10 border border-secondary/20 text-secondary text-body-sm font-bold rounded-xl flex items-center justify-center gap-1.5 animate-bounce-subtle">
|
||||
<MaterialIcon icon="check_circle" size={16} />
|
||||
<span>Message sent successfully!</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="footer-form-row grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-name"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="footer-field-name"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Name..."
|
||||
className={`footer-input h-12 md:h-13 ${errors.name ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.name && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-phone"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Phone
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="footer-field-phone"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Phone..."
|
||||
className={`footer-input h-12 md:h-13 ${errors.phone ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.phone && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.phone}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-email"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Email Address
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="footer-field-email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Email Address..."
|
||||
className={`footer-input h-12 md:h-13 ${errors.email ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.email && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.email}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-message"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Message
|
||||
</label>
|
||||
<textarea
|
||||
id="footer-field-message"
|
||||
name="message"
|
||||
value={formData.message}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Message..."
|
||||
className={`footer-textarea min-h-[120px] md:min-h-[130px] ${errors.message ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.message && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.message}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="footer-submit-btn h-12 md:h-13"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<span className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||
<span>SUBMITTING...</span>
|
||||
</>
|
||||
) : (
|
||||
<span>SUBMIT</span>
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer Bottom Bar */}
|
||||
<div className="mt-8 border-t border-white/10 pt-5 text-xs text-white/45">
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
|
||||
<p>© {new Date().getFullYear()} Nearle. All rights reserved.</p>
|
||||
<div className="flex flex-col md:flex-row gap-2 md:gap-6 text-left">
|
||||
{LEGAL.map((link) => (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className="hover:text-[#e0c8f7] transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* Bottom Copyright Divider & Bar */}
|
||||
<div className="mt-12 pt-6 border-t border-white/10 relative z-10 flex flex-col sm:flex-row justify-between items-center gap-4 text-xs text-white/40">
|
||||
<p>© {new Date().getFullYear()} Nearle. All rights reserved.</p>
|
||||
<div className="flex flex-wrap gap-x-6 gap-y-2 justify-center">
|
||||
{LEGAL.map((link) => (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className="hover:text-[#E6D7EA] transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -421,28 +159,4 @@ export function Footer() {
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure default export is also available for Next.js app router client components if needed
|
||||
export default Footer;
|
||||
|
||||
function FooterCol({
|
||||
title,
|
||||
links,
|
||||
}: {
|
||||
title: string;
|
||||
links: { label: string; href: string }[];
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<h5 className="footer-column-title">{title}</h5>
|
||||
<ul className="footer-links-list">
|
||||
{links.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="footer-link inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
138
src/components/layout/HeroVisualCollage.tsx
Normal file
138
src/components/layout/HeroVisualCollage.tsx
Normal file
@@ -0,0 +1,138 @@
|
||||
import Image from "next/image";
|
||||
import { GlassInfoCard } from "../ui/GlassInfoCard";
|
||||
|
||||
type GlassCardItem = {
|
||||
text: string;
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
type HeroVisualCollageProps = {
|
||||
centerImage: string;
|
||||
leftImage?: string;
|
||||
rightImage?: string;
|
||||
glassCards: GlassCardItem[];
|
||||
isPhoneCenter?: boolean;
|
||||
};
|
||||
|
||||
export function HeroVisualCollage({
|
||||
centerImage,
|
||||
leftImage,
|
||||
rightImage,
|
||||
glassCards,
|
||||
isPhoneCenter = true,
|
||||
}: HeroVisualCollageProps) {
|
||||
return (
|
||||
<div className="relative w-full h-[380px] sm:h-[450px] lg:h-[500px] max-w-[540px] mx-auto flex items-center justify-center select-none">
|
||||
{/* Decorative backgrounds */}
|
||||
{/* 1. Soft purple circle */}
|
||||
<div className="absolute w-[240px] h-[240px] rounded-full bg-[#7C3AED]/10 blur-[60px] -z-10" />
|
||||
|
||||
{/* 2. SVG Dot grid */}
|
||||
<div className="absolute -top-4 -right-4 w-32 h-32 text-[#6330D6]/10 -z-10 opacity-20">
|
||||
<svg className="w-full h-full" fill="currentColor">
|
||||
<pattern id="collage-dots" x="0" y="0" width="16" height="16" patternUnits="userSpaceOnUse">
|
||||
<circle cx="2" cy="2" r="1.5" />
|
||||
</pattern>
|
||||
<rect width="100%" height="100%" fill="url(#collage-dots)" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* 3. Small x marks */}
|
||||
<div className="absolute top-12 left-6 text-[#6330D6]/15 font-display text-xl font-bold select-none pointer-events-none">✕</div>
|
||||
<div className="absolute bottom-16 right-8 text-[#6330D6]/15 font-display text-xl font-bold select-none pointer-events-none">✕</div>
|
||||
|
||||
{/* LEFT IMAGE PANEL (Hidden or compact on small mobile) */}
|
||||
{leftImage && (
|
||||
<div className="absolute left-2 sm:left-4 top-[15%] w-[100px] sm:w-[130px] h-[180px] sm:h-[220px] rounded-[18px] overflow-hidden border-2 border-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] z-10 transition-transform hover:scale-105 duration-300">
|
||||
<Image
|
||||
src={leftImage}
|
||||
alt="Collage left asset"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 640px) 100px, 130px"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* RIGHT IMAGE PANEL */}
|
||||
{rightImage && (
|
||||
<div className="absolute right-2 sm:right-4 bottom-[15%] w-[100px] sm:w-[130px] h-[180px] sm:h-[220px] rounded-[18px] overflow-hidden border-2 border-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] z-10 transition-transform hover:scale-105 duration-300">
|
||||
<Image
|
||||
src={rightImage}
|
||||
alt="Collage right asset"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 640px) 100px, 130px"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* CENTER COMPONENT */}
|
||||
<div className="relative z-20">
|
||||
{isPhoneCenter ? (
|
||||
/* Phone Frame Container */
|
||||
<div className="relative w-[180px] sm:w-[220px] h-[360px] sm:h-[440px] rounded-[36px] border-[5px] sm:border-[6px] border-white/95 shadow-[0_20px_50px_rgba(99,48,214,0.12)] bg-[#FAF8FC] overflow-hidden flex flex-col justify-center items-center">
|
||||
<Image
|
||||
src={centerImage}
|
||||
alt="Phone Mockup Screen"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 640px) 180px, 220px"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
/* Central Logo / Visual Panel */
|
||||
<div className="relative w-[180px] sm:w-[220px] h-[280px] sm:h-[340px] rounded-[24px] border-[5px] sm:border-[6px] border-white/95 shadow-[0_20px_40px_rgba(99,48,214,0.1)] bg-[#FAF8FC] overflow-hidden flex items-center justify-center p-6">
|
||||
<Image
|
||||
src={centerImage}
|
||||
alt="Central logo panel"
|
||||
width={160}
|
||||
height={160}
|
||||
className="object-contain max-h-[140px] w-auto animate-[pulse_6s_infinite]"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* FLOATING GLASS CARDS (Positioned Absolute, scaled down on mobile) */}
|
||||
{glassCards.length > 0 && (
|
||||
<div className="absolute inset-0 z-30 pointer-events-none">
|
||||
{/* Card 1: Top Right */}
|
||||
{glassCards[0] && (
|
||||
<div className="absolute right-0 sm:right-[5%] top-[10%] pointer-events-auto hover:translate-y-[-2px] transition-transform duration-200">
|
||||
<GlassInfoCard
|
||||
text={glassCards[0].text}
|
||||
icon={glassCards[0].icon}
|
||||
className="scale-90 sm:scale-100"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Card 2: Bottom Left */}
|
||||
{glassCards[1] && (
|
||||
<div className="absolute left-0 sm:left-[5%] bottom-[10%] pointer-events-auto hover:translate-y-[-2px] transition-transform duration-200">
|
||||
<GlassInfoCard
|
||||
text={glassCards[1].text}
|
||||
icon={glassCards[1].icon}
|
||||
className="scale-90 sm:scale-100"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Card 3: Mid Left/Right */}
|
||||
{glassCards[2] && (
|
||||
<div className="absolute left-[5%] top-[45%] pointer-events-auto hover:translate-y-[-2px] transition-transform duration-200">
|
||||
<GlassInfoCard
|
||||
text={glassCards[2].text}
|
||||
icon={glassCards[2].icon}
|
||||
className="scale-90 sm:scale-100"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -20,8 +20,8 @@ export function Navbar() {
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 right-0 z-50 w-full flex justify-center pointer-events-none">
|
||||
<div className="w-full max-w-[1440px] px-4 md:px-8 lg:px-12 pt-5 md:pt-6 pointer-events-auto relative">
|
||||
<nav className="w-full h-[68px] lg:h-[80px] rounded-[1.75rem] lg:rounded-[2rem] bg-gradient-to-r from-[#65108A] via-[#5A087B] to-[#3A044F] border border-white/10 shadow-[0_18px_40px_rgba(60,0,80,0.25)] backdrop-blur-md px-5 md:px-8 lg:px-10 flex items-center transition-all duration-300">
|
||||
<div className="w-full max-w-[1920px] px-4 md:px-6 lg:px-8 xl:px-10 2xl:px-12 pt-[18px] md:pt-[24px] pointer-events-auto relative">
|
||||
<nav className="w-full h-[68px] lg:h-[76px] rounded-full bg-white/88 border border-white/70 shadow-sm backdrop-blur-md px-5 md:px-8 lg:px-10 flex items-center transition-all duration-300">
|
||||
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_1fr] items-center w-full h-full">
|
||||
{/* Left: Brand */}
|
||||
<div className="flex items-center justify-start">
|
||||
@@ -30,7 +30,7 @@ export function Navbar() {
|
||||
className="flex items-center hover:scale-[1.02] transition-transform active:scale-95 duration-200"
|
||||
>
|
||||
<Image
|
||||
src="/logo-light.png"
|
||||
src="/logo.png"
|
||||
alt="Nearle"
|
||||
width={400}
|
||||
height={50}
|
||||
@@ -48,13 +48,13 @@ export function Navbar() {
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className={`relative py-2 text-[15px] font-medium leading-5 transition-all duration-200 whitespace-nowrap ${
|
||||
isActive ? "text-white" : "text-white/80 hover:text-white"
|
||||
className={`relative py-2 text-[15px] font-semibold leading-5 transition-all duration-200 whitespace-nowrap ${
|
||||
isActive ? "text-[#2A1234]" : "text-[#2A1234]/70 hover:text-[#2A1234]"
|
||||
} group`}
|
||||
>
|
||||
{link.label}
|
||||
<span
|
||||
className={`absolute bottom-[-6px] left-1/2 -translate-x-1/2 h-0.5 bg-white rounded-full transition-all duration-300 ${
|
||||
className={`absolute bottom-[-6px] left-1/2 -translate-x-1/2 h-0.5 bg-[#65149A] rounded-full transition-all duration-300 ${
|
||||
isActive
|
||||
? "w-5 opacity-100"
|
||||
: "w-0 opacity-0 group-hover:w-4 group-hover:opacity-60"
|
||||
@@ -69,14 +69,14 @@ export function Navbar() {
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<Link
|
||||
href="/#download"
|
||||
className="hidden md:inline-flex items-center justify-center bg-white text-[#4d046a] font-bold px-7 h-[46px] rounded-full text-[15px] hover:shadow-[0_8px_24px_rgba(255,255,255,0.2)] hover:scale-[1.03] active:scale-95 transition-all duration-300 whitespace-nowrap"
|
||||
className="hidden md:inline-flex items-center justify-center bg-[#65149A] text-white font-bold px-7 h-[46px] rounded-full text-[15px] hover:bg-[#7C3AED] hover:shadow-md hover:scale-[1.02] active:scale-95 transition-all duration-300 whitespace-nowrap"
|
||||
>
|
||||
Get App
|
||||
</Link>
|
||||
|
||||
{/* Mobile menu toggle */}
|
||||
<button
|
||||
className="md:hidden flex items-center justify-center w-10 h-10 rounded-full hover:bg-white/10 text-white transition-all active:scale-90 cursor-pointer"
|
||||
className="md:hidden flex items-center justify-center w-10 h-10 rounded-full hover:bg-[#2A1234]/5 text-[#2A1234] transition-all active:scale-90 cursor-pointer"
|
||||
onClick={() => setMobileOpen(!mobileOpen)}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
@@ -88,7 +88,7 @@ export function Navbar() {
|
||||
|
||||
{/* Mobile Drawer */}
|
||||
{mobileOpen && (
|
||||
<div className="absolute top-[calc(100%+12px)] left-4 right-4 z-40 bg-gradient-to-b from-[#5A087B] to-[#3A044F] border border-white/10 rounded-2xl shadow-[0_20px_40px_rgba(0,0,0,0.4)] backdrop-blur-md p-4 md:hidden">
|
||||
<div className="absolute top-[calc(100%+12px)] left-4 right-4 z-40 bg-white/95 border border-white/50 rounded-2xl shadow-[0_20px_40px_rgba(100,60,120,0.15)] backdrop-blur-md p-4 md:hidden">
|
||||
<div className="flex flex-col gap-2">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = pathname === link.href;
|
||||
@@ -98,14 +98,14 @@ export function Navbar() {
|
||||
href={link.href}
|
||||
className={`px-4 py-3 text-body-md font-bold rounded-xl transition-all duration-200 flex items-center justify-between ${
|
||||
isActive
|
||||
? "bg-white/10 text-white"
|
||||
: "text-white/85 hover:text-white hover:bg-white/5"
|
||||
? "bg-[#65149A]/10 text-[#65149A]"
|
||||
: "text-[#2A1234]/70 hover:text-[#2A1234] hover:bg-[#2A1234]/5"
|
||||
}`}
|
||||
onClick={() => setMobileOpen(false)}
|
||||
>
|
||||
{link.label}
|
||||
{isActive && (
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-white animate-pulse" />
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#65149A] animate-pulse" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
|
||||
147
src/components/layout/PremiumFooter.tsx
Normal file
147
src/components/layout/PremiumFooter.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const COMPANY = [
|
||||
{ label: "About Us", href: "/about" },
|
||||
{ label: "Careers", href: "#" },
|
||||
{ label: "Press & News", href: "#" },
|
||||
{ label: "Help Center", href: "#" },
|
||||
];
|
||||
|
||||
const PARTNERSHIPS = [
|
||||
{ label: "Merchant Partner", href: "/businesses" },
|
||||
{ label: "Delivery Partner", href: "#" },
|
||||
{ label: "Corporate Gifting", href: "#" },
|
||||
{ label: "Local Real Estate", href: "#" },
|
||||
];
|
||||
|
||||
const LEGAL = [
|
||||
{ label: "Privacy Policy", href: "#" },
|
||||
{ label: "Terms of Service", href: "#" },
|
||||
{ label: "Cookie Policy", href: "#" },
|
||||
{ label: "Sitemap", href: "#" },
|
||||
];
|
||||
|
||||
export function PremiumFooter() {
|
||||
return (
|
||||
<footer className="bg-gradient-to-br from-[#16001D] to-[#25002F] rounded-[1.5rem] md:rounded-[2rem] overflow-hidden text-white p-8 md:p-12 select-none mx-3 sm:mx-4 md:mx-6 lg:mx-8 mb-3 sm:mb-4 md:mb-6 shadow-[0_12px_40px_rgba(22,0,29,0.22)]">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8 items-start text-left">
|
||||
{/* Column 1: Brand & Description */}
|
||||
<div className="flex flex-col gap-4 lg:col-span-2 pr-0 lg:pr-8">
|
||||
<Link href="/" className="inline-block">
|
||||
<Image
|
||||
src="/logo-light.png"
|
||||
alt="Nearle"
|
||||
width={130}
|
||||
height={30}
|
||||
className="h-7 w-auto object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<p className="text-xs md:text-sm leading-relaxed text-white/70 max-w-sm">
|
||||
India's leading hyperlocal neighborhood network, empowering communities and verified local businesses within a 2km radius.
|
||||
</p>
|
||||
{/* Social Icons */}
|
||||
<div className="flex gap-2.5 mt-2">
|
||||
<a href="#" className="w-9 h-9 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-white hover:text-[#16001D] transition-all duration-300" aria-label="Share">
|
||||
<MaterialIcon icon="share" size={16} />
|
||||
</a>
|
||||
<a href="#" className="w-9 h-9 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-white hover:text-[#16001D] transition-all duration-300" aria-label="Website">
|
||||
<MaterialIcon icon="public" size={16} />
|
||||
</a>
|
||||
<a href="#" className="w-9 h-9 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-white hover:text-[#16001D] transition-all duration-300" aria-label="Help">
|
||||
<MaterialIcon icon="help" size={16} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Column 2: Company */}
|
||||
<div>
|
||||
<h5 className="text-xs font-black uppercase tracking-wider text-white/40 mb-4">Company</h5>
|
||||
<ul className="flex flex-col gap-2.5">
|
||||
{COMPANY.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-xs text-white/70 hover:text-white hover:translate-x-0.5 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column 3: Nearle */}
|
||||
<div>
|
||||
<h5 className="text-xs font-black uppercase tracking-wider text-white/40 mb-4">Nearle</h5>
|
||||
<ul className="flex flex-col gap-2.5">
|
||||
{PARTNERSHIPS.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-xs text-white/70 hover:text-white hover:translate-x-0.5 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column 4: Support */}
|
||||
<div>
|
||||
<h5 className="text-xs font-black uppercase tracking-wider text-white/40 mb-4">Support</h5>
|
||||
<ul className="flex flex-col gap-2.5">
|
||||
{LEGAL.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-xs text-white/70 hover:text-white hover:translate-x-0.5 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* HQ Address card at bottom-left and info */}
|
||||
<div className="mt-10 pt-8 border-t border-white/10 flex flex-col md:flex-row justify-between items-start md:items-center gap-6">
|
||||
{/* HQ Address Card */}
|
||||
<div className="bg-white/5 border border-white/10 rounded-2xl p-4 flex items-start gap-3.5 max-w-sm">
|
||||
<div className="w-8 h-8 rounded-lg bg-white/10 text-white flex items-center justify-center shrink-0 mt-0.5">
|
||||
<MaterialIcon icon="location_on" size={16} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h6 className="text-xs font-black text-white">Nearle HQ</h6>
|
||||
<p className="text-[11px] text-white/60 leading-normal mt-0.5">
|
||||
424, Diwan Bahadur Rd, Opp. Sri Krishna Sweets, R.S. Puram, Coimbatore, TN 641002
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Call center */}
|
||||
<div className="flex flex-col items-start md:items-end gap-1">
|
||||
<span className="text-[10px] font-black text-white/40 uppercase tracking-widest">Neighborhood Helpdesk</span>
|
||||
<a
|
||||
href="tel:+918049123456"
|
||||
className="flex items-center gap-2 text-white hover:text-[#6330D6] transition-colors"
|
||||
>
|
||||
<div className="w-7 h-7 rounded-full bg-[#6330D6] flex items-center justify-center">
|
||||
<MaterialIcon icon="phone" size={14} className="text-white" />
|
||||
</div>
|
||||
<span className="text-sm font-black tracking-tight">+91 80 4912 3456</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Copyright & legal links */}
|
||||
<div className="mt-8 pt-6 border-t border-white/5 flex flex-col sm:flex-row justify-between items-center gap-4 text-[11px] text-white/40 text-center sm:text-left">
|
||||
<p>© {new Date().getFullYear()} Nearle. All rights reserved.</p>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-1 justify-center">
|
||||
<Link href="#" className="hover:text-white transition-colors">Privacy Policy</Link>
|
||||
<span className="opacity-50">•</span>
|
||||
<Link href="#" className="hover:text-white transition-colors">Terms of Service</Link>
|
||||
<span className="opacity-50">•</span>
|
||||
<Link href="#" className="hover:text-white transition-colors">Help Center</Link>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
129
src/components/layout/PremiumNavbar.tsx
Normal file
129
src/components/layout/PremiumNavbar.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const NAV_LINKS = [
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Nearle for Business", href: "/businesses" },
|
||||
{ label: "Nearle for People", href: "/people" },
|
||||
{ label: "About", href: "/about" },
|
||||
{ label: "Contact", href: "/contact" },
|
||||
];
|
||||
|
||||
export function PremiumNavbar() {
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<header className="w-full bg-white border-b border-[#EEE7F4] px-6 md:px-10 h-16 md:h-20 flex items-center relative z-40 select-none">
|
||||
<div className="flex items-center justify-between w-full">
|
||||
{/* LOGO (LEFT) */}
|
||||
<Link
|
||||
href="/"
|
||||
className="flex items-center hover:scale-[1.02] transition-transform active:scale-95 duration-200"
|
||||
>
|
||||
<Image
|
||||
src="/logo.png"
|
||||
alt="Nearle"
|
||||
width={120}
|
||||
height={30}
|
||||
className="h-7 md:h-8 w-auto object-contain"
|
||||
priority
|
||||
/>
|
||||
</Link>
|
||||
|
||||
{/* LINKS (CENTER) */}
|
||||
<nav className="hidden md:flex items-center gap-6 lg:gap-8">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = pathname === link.href;
|
||||
return (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className={`relative py-1 text-sm font-bold transition-all duration-200 ${
|
||||
isActive ? "text-[#6330D6]" : "text-[#5E5866] hover:text-[#16001D]"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
{isActive && (
|
||||
<span className="absolute bottom-[-4px] left-0 right-0 h-0.5 bg-[#6330D6] rounded-full" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* ACTIONS (RIGHT) */}
|
||||
<div className="hidden md:flex items-center gap-3">
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-flex items-center justify-center border-2 border-[#6330D6]/20 text-[#6330D6] font-bold px-5 py-1.5 rounded-full text-xs hover:bg-[#6330D6]/5 active:scale-95 transition-all duration-200 whitespace-nowrap"
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
<Link
|
||||
href="/people#download-section"
|
||||
className="inline-flex items-center justify-center bg-[#6330D6] text-white font-bold px-5 py-2 rounded-full text-xs hover:bg-[#5225b8] hover:shadow-md hover:scale-[1.02] active:scale-95 transition-all duration-200 whitespace-nowrap"
|
||||
>
|
||||
Get App
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Mobile menu toggle */}
|
||||
<button
|
||||
className="md:hidden flex items-center justify-center w-10 h-10 rounded-full hover:bg-[#6330D6]/5 text-[#16001D] transition-all active:scale-90 cursor-pointer"
|
||||
onClick={() => setMobileOpen(!mobileOpen)}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<MaterialIcon icon={mobileOpen ? "close" : "menu"} size={22} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Drawer */}
|
||||
{mobileOpen && (
|
||||
<div className="absolute top-full left-0 right-0 z-50 bg-white border-b border-[#6330D6]/10 shadow-lg p-4 md:hidden animate-fade-in flex flex-col gap-2">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = pathname === link.href;
|
||||
return (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className={`px-4 py-2.5 text-sm font-bold rounded-xl transition-all duration-200 flex items-center justify-between ${
|
||||
isActive
|
||||
? "bg-[#6330D6]/10 text-[#6330D6]"
|
||||
: "text-[#5E5866] hover:text-[#16001D] hover:bg-[#6330D6]/5"
|
||||
}`}
|
||||
onClick={() => setMobileOpen(false)}
|
||||
>
|
||||
{link.label}
|
||||
{isActive && (
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#6330D6]" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
<div className="flex flex-col gap-2 pt-2 border-t border-[#6330D6]/5 mt-2">
|
||||
<Link
|
||||
href="#"
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className="flex items-center justify-center border-2 border-[#6330D6]/20 text-[#6330D6] font-bold py-2.5 rounded-xl text-sm"
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
<Link
|
||||
href="/people#download-section"
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className="flex items-center justify-center bg-[#6330D6] text-white font-bold py-2.5 rounded-xl text-sm"
|
||||
>
|
||||
Get App
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
43
src/components/layout/PremiumPageShell.tsx
Normal file
43
src/components/layout/PremiumPageShell.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import { PremiumNavbar } from "./PremiumNavbar";
|
||||
import { PremiumFooter } from "./PremiumFooter";
|
||||
|
||||
type PremiumPageShellProps = {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function PremiumPageShell({ children, className = "" }: PremiumPageShellProps) {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#E8DCF2] p-2 sm:p-3 md:p-4 lg:p-5 xl:p-6 2xl:p-8 font-body text-[#16001D] antialiased">
|
||||
<div className={`
|
||||
mx-auto
|
||||
w-full
|
||||
max-w-[1880px]
|
||||
overflow-hidden
|
||||
rounded-[1.5rem]
|
||||
sm:rounded-[2rem]
|
||||
md:rounded-[2.5rem]
|
||||
lg:rounded-[3rem]
|
||||
border
|
||||
border-white/80
|
||||
bg-white
|
||||
shadow-[0_20px_60px_rgba(93,57,128,0.16)]
|
||||
flex
|
||||
flex-col
|
||||
${className}
|
||||
`}>
|
||||
{/* Header/Navbar */}
|
||||
<PremiumNavbar />
|
||||
|
||||
{/* Page Content */}
|
||||
<main className="flex-1 w-full">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<PremiumFooter />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
45
src/components/ui/FeatureStatsRow.tsx
Normal file
45
src/components/ui/FeatureStatsRow.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { MaterialIcon } from "./MaterialIcon";
|
||||
|
||||
type FeatureStatsItem = {
|
||||
icon: string;
|
||||
title: string;
|
||||
desc?: string;
|
||||
};
|
||||
|
||||
type FeatureStatsRowProps = {
|
||||
items: FeatureStatsItem[];
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function FeatureStatsRow({ items, className = "" }: FeatureStatsRowProps) {
|
||||
return (
|
||||
<div className={`w-full py-6 md:py-8 ${className}`}>
|
||||
<div className="grid grid-cols-2 lg:flex lg:flex-row items-center justify-between gap-y-6 gap-x-4 lg:gap-0">
|
||||
{items.map((item, index) => (
|
||||
<div
|
||||
key={item.title}
|
||||
className={`flex items-center gap-3.5 lg:flex-1 px-3 lg:px-8 text-left ${
|
||||
index < items.length - 1
|
||||
? "lg:border-r lg:border-[#6330D6]/10"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div className="w-9 h-9 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon={item.icon} size={18} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<h4 className="text-sm md:text-base font-black text-[#16001D] leading-tight truncate">
|
||||
{item.title}
|
||||
</h4>
|
||||
{item.desc && (
|
||||
<p className="text-[11px] md:text-xs text-[#5E5866] font-semibold mt-0.5 leading-tight truncate">
|
||||
{item.desc}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
26
src/components/ui/GlassInfoCard.tsx
Normal file
26
src/components/ui/GlassInfoCard.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { MaterialIcon } from "./MaterialIcon";
|
||||
|
||||
type GlassInfoCardProps = {
|
||||
text: string;
|
||||
icon?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function GlassInfoCard({ text, icon, className = "" }: GlassInfoCardProps) {
|
||||
return (
|
||||
<div
|
||||
className={`bg-white/80 backdrop-blur-md border border-white/40 shadow-[0_8px_24px_rgba(99,48,214,0.08)] rounded-[16px] px-4 py-2.5 flex items-center gap-2.5 select-none ${className}`}
|
||||
>
|
||||
{icon ? (
|
||||
<div className="w-6 h-6 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon={icon} size={14} />
|
||||
</div>
|
||||
) : (
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-[#6330D6] shrink-0 animate-pulse" />
|
||||
)}
|
||||
<span className="text-sm font-extrabold text-[#16001D] whitespace-nowrap">
|
||||
{text}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user