update layout

This commit is contained in:
2026-06-23 19:50:35 +05:30
parent 8ffc7809ce
commit 230be11899
14 changed files with 841 additions and 731 deletions

View File

@@ -43,7 +43,7 @@ type FooterFormErrors = {
export function Footer() {
const pathname = usePathname();
const isContactPage = pathname === "/contact";
const isContactPage = pathname?.startsWith("/contact");
// Form states
const [formData, setFormData] = useState<FooterFormData>({
@@ -121,229 +121,273 @@ export function Footer() {
}, 5000);
};
return (
<footer className="footer relative z-10 bg-brand-dark text-white border-t border-white/5 w-full mt-24">
{/* Overlapping Contact Helpdesk Card */}
<div className="footer-helpdesk-wrap">
<div className="bg-brand-accent p-6 md:p-8 rounded-[2.5rem] flex flex-col md:flex-row justify-between items-center gap-6 shadow-2xl border border-brand-accent/20">
<div className="flex items-center gap-4 text-brand-dark">
<div className="w-12 h-12 rounded-full bg-brand-dark text-brand-accent flex items-center justify-center shadow-lg">
<MaterialIcon icon="headset_mic" size={24} />
</div>
<div>
<h4 className="text-headline-md font-black">24/7 Neighborhood Helpdesk</h4>
<p className="helpdesk-subtitle mt-0.5">
Need immediate assistance with an order or local service?
</p>
</div>
</div>
<a
href="tel:+918049123456"
className="helpdesk-btn"
>
<MaterialIcon icon="phone" size={20} className="animate-pulse-subtle" />
<span>+91 80 4912 3456</span>
</a>
</div>
</div>
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&apos;s leading hyperlocal neighborhood network, empowering communities and verified local businesses within 2km.
</p>
<div className="footer-container">
{/* Main content wrapper */}
<div className="footer-main">
{/* Main content grid: aligned on the same top baseline */}
<div className={`${
isContactPage
? "footer-grid-contact-page"
: "footer-grid"
}`}>
{/* Brand Column */}
<div className="footer-brand">
<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">
India&apos;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>
{/* 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 py-8 md:py-12 lg:py-14 w-full mt-24">
<div className="mx-auto max-w-[1560px]">
<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>
</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>
{/* Company Links */}
<div className="footer-company">
<FooterCol title="Company" links={COMPANY} />
</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}
{/* Partnerships Links */}
<div className="footer-partnerships">
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
</div>
{/* Legal Links */}
<div className="footer-legal">
<FooterCol title="Legal" links={LEGAL} />
</div>
{/* Contact Form Card */}
{!isContactPage && (
<div className="footer-contact-wrap">
<div className="footer-contact-card bg-white text-brand-dark shadow-2xl border border-outline-variant/15 relative overflow-hidden">
{/* 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-2">
We shall guide you through our Neighbourhood Experts.
</p>
<form onSubmit={handleSubmit} className="space-y-4">
{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">
<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 ${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 ${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 ${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 ${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"
>
{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>
{/* 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>
)}
</div>
</div>
{/* Divider */}
<hr className="footer-divider" />
{/* Bottom Bar */}
<div className="footer-bottom">
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
<p className="footer-bottom-text">
© {new Date().getFullYear()} Nearle. All rights reserved.
</p>
<div className="flex items-center gap-2 footer-bottom-text">
<span>Designed for neighborhoods in</span>
<span className="flex items-center gap-1 font-bold text-white/80">
India 🇮🇳
</span>
</div>
</div>
</div>

View File

@@ -3,6 +3,7 @@
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 = [
@@ -15,78 +16,105 @@ const NAV_LINKS = [
export function Navbar() {
const [mobileOpen, setMobileOpen] = useState(false);
const pathname = usePathname();
return (
<nav className="sticky top-0 z-50 w-full bg-[#4d046a]/95 backdrop-blur-md border-b border-white/10 transition-all duration-300">
<div className="grid w-full grid-cols-[auto_auto] md:grid-cols-[auto_1fr_auto] items-center gap-4 md:gap-8 px-6 md:px-12 lg:px-20 xl:px-24 py-3">
{/* Left: Brand */}
<div className="flex items-center">
<Link
href="/"
className="flex items-center hover:scale-[1.02] transition-transform active:scale-95 duration-200"
>
<Image
src="/logo-light.png"
alt="Nearle"
width={400}
height={50}
style={{ height: "40px", width: "auto" }}
className="object-contain"
priority
/>
</Link>
</div>
<div className="hidden md:flex items-center justify-center gap-8 xl:gap-10">
{NAV_LINKS.map((link) => (
<Link
key={link.label}
href={link.href}
className="relative py-1 text-[15px] font-bold leading-5 text-white/80 hover:text-brand-accent transition-all duration-200 group whitespace-nowrap"
>
{link.label}
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-brand-accent transition-all duration-300 group-hover:w-full" />
</Link>
))}
</div>
{/* Right: Actions */}
<div className="flex items-center justify-end gap-3">
<Link
href="/#download"
className="hidden md:inline-flex bg-brand-accent hover:bg-brand-accent/90 text-brand-dark font-bold px-7 py-3 rounded-full text-label-md hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 active:translate-y-0 active:scale-95 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"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu"
>
<MaterialIcon icon={mobileOpen ? "close" : "menu"} size={22} />
</button>
</div>
</div>
{/* Mobile Drawer */}
{mobileOpen && (
<div className="md:hidden bg-[#4d046a] border-t border-white/10">
<div className="max-w-container-max mx-auto px-6 py-stack-md flex flex-col gap-2">
{NAV_LINKS.map((link) => (
<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="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">
<Link
key={link.label}
href={link.href}
className="px-3 py-2.5 text-body-md text-white/80 hover:text-brand-accent hover:bg-white/10 rounded-lg transition-colors"
onClick={() => setMobileOpen(false)}
href="/"
className="flex items-center hover:scale-[1.02] transition-transform active:scale-95 duration-200"
>
{link.label}
<Image
src="/logo-light.png"
alt="Nearle"
width={400}
height={50}
className="h-8 lg:h-9 w-auto object-contain"
priority
/>
</Link>
))}
</div>
{/* Center: Navigation Links */}
<div className="hidden md:flex items-center justify-center gap-6 lg:gap-8 xl:gap-10">
{NAV_LINKS.map((link) => {
const isActive = pathname === link.href;
return (
<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"
} 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 ${
isActive
? "w-5 opacity-100"
: "w-0 opacity-0 group-hover:w-4 group-hover:opacity-60"
}`}
/>
</Link>
);
})}
</div>
{/* Right: Actions */}
<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"
>
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"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu"
>
<MaterialIcon icon={mobileOpen ? "close" : "menu"} size={22} />
</button>
</div>
</div>
</div>
)}
</nav>
</nav>
{/* 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="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-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"
}`}
onClick={() => setMobileOpen(false)}
>
{link.label}
{isActive && (
<span className="w-1.5 h-1.5 rounded-full bg-white animate-pulse" />
)}
</Link>
);
})}
</div>
</div>
)}
</div>
</div>
);
}