update image in hero section
This commit is contained in:
BIN
public/about.png
Normal file
BIN
public/about.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
public/contect.png
Normal file
BIN
public/contect.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
public/nearle people.png
Normal file
BIN
public/nearle people.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
@@ -1,8 +1,13 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "About Us",
|
||||||
|
description: "Discover Nearle, India's first hyperlocal neighborhood living platform connecting residents with local convenience, grocery delivery, and home services.",
|
||||||
|
};
|
||||||
|
|
||||||
const STRATEGY_CARDS = [
|
const STRATEGY_CARDS = [
|
||||||
{
|
{
|
||||||
@@ -31,47 +36,24 @@ const COUNTERS = [
|
|||||||
{ count: "100+", label: "Active Neighborhoods", icon: "location_city" }
|
{ count: "100+", label: "Active Neighborhoods", icon: "location_city" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const TEAM = [
|
|
||||||
{
|
|
||||||
name: "Nellian Solliappan",
|
|
||||||
role: "Co-Founder & CEO",
|
|
||||||
initials: "NS",
|
|
||||||
color: "bg-primary text-white"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Fazul Ilahi",
|
|
||||||
role: "Founder & CTO",
|
|
||||||
initials: "FI",
|
|
||||||
color: "bg-secondary text-white"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Sagar",
|
|
||||||
role: "Co-Founder & COO",
|
|
||||||
initials: "S",
|
|
||||||
color: "bg-brand-accent text-brand-dark"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Prithvi",
|
|
||||||
role: "Investor",
|
|
||||||
initials: "P",
|
|
||||||
color: "bg-surface-container text-on-surface"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Sriram Sundararajan",
|
|
||||||
role: "Investor",
|
|
||||||
initials: "SS",
|
|
||||||
color: "bg-surface-container-highest text-brand-dark"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function AboutPage() {
|
export default function AboutPage() {
|
||||||
return (
|
return (
|
||||||
<div className="relative min-h-screen bg-background">
|
<div className="relative min-h-screen bg-background">
|
||||||
|
|
||||||
{/* ─── Hero Section ─── */}
|
{/* ─── Hero Section ─── */}
|
||||||
<section className="relative overflow-hidden bg-brand-dark px-6 md:px-12 lg:px-20 xl:px-24 pt-44 pb-48 text-center">
|
<section className="hero-section relative overflow-hidden bg-brand-dark px-6 md:px-12 lg:px-20 xl:px-24 pt-56 pb-72 text-center">
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_30%,rgba(108,14,128,0.25),transparent_40%)]" />
|
{/* Background Image with Overlay */}
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_70%,rgba(0,109,55,0.15),transparent_40%)]" />
|
<div className="absolute inset-0 z-0 select-none pointer-events-none">
|
||||||
|
<Image
|
||||||
|
src="/about.png"
|
||||||
|
alt="About Nearle Background"
|
||||||
|
fill
|
||||||
|
sizes="100vw"
|
||||||
|
className="object-cover"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-[#120217]/50" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="relative z-10 mx-auto max-w-container-max">
|
<div className="relative z-10 mx-auto max-w-container-max">
|
||||||
<p className="text-label-sm font-black uppercase tracking-[0.25em] text-brand-accent">
|
<p className="text-label-sm font-black uppercase tracking-[0.25em] text-brand-accent">
|
||||||
@@ -142,82 +124,6 @@ export default function AboutPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ─── Team Section ─── */}
|
|
||||||
<section className="mx-auto max-w-container-max px-6 md:px-12 lg:px-20 xl:px-24 py-28">
|
|
||||||
<div className="grid lg:grid-cols-12 gap-16 items-center">
|
|
||||||
|
|
||||||
{/* Left: About team content */}
|
|
||||||
<div className="lg:col-span-5">
|
|
||||||
<span className="text-label-sm font-black text-primary uppercase tracking-widest">
|
|
||||||
Who we are
|
|
||||||
</span>
|
|
||||||
<h2 className="font-display text-3xl font-black text-brand-dark mt-2 mb-6">
|
|
||||||
Team Nearle
|
|
||||||
</h2>
|
|
||||||
<p className="text-body-md text-on-surface-variant mb-6 leading-relaxed">
|
|
||||||
Nearle is built on the core concept of <strong>“Boost business by trust”</strong>. We assist local offline stores in successfully spreading their brand message to the neighborhood to open new revenue streams.
|
|
||||||
</p>
|
|
||||||
<p className="text-body-sm text-on-surface-variant/80 mb-8 leading-relaxed">
|
|
||||||
Our team combines technology skills, domain expertise, and operational focus to ensure the highest quality solution for our customers.
|
|
||||||
</p>
|
|
||||||
<Link
|
|
||||||
href="/contact"
|
|
||||||
className="bg-primary hover:bg-primary-container text-on-primary font-black px-8 py-4 rounded-xl text-label-md hover:shadow-lg active:scale-95 transition-all inline-flex items-center gap-2"
|
|
||||||
>
|
|
||||||
<MaterialIcon icon="mail" size={18} />
|
|
||||||
<span>Contact Team</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Right: Team Grid cards */}
|
|
||||||
<div className="lg:col-span-7 grid grid-cols-2 sm:grid-cols-3 gap-6">
|
|
||||||
{TEAM.map((t) => (
|
|
||||||
<div
|
|
||||||
key={t.name}
|
|
||||||
className="premium-card bg-white p-6 rounded-3xl border border-outline-variant/15 shadow-sm flex flex-col items-center text-center"
|
|
||||||
>
|
|
||||||
<div className={`w-16 h-16 rounded-full flex items-center justify-center font-display text-xl font-black mb-4 ${t.color}`}>
|
|
||||||
{t.initials}
|
|
||||||
</div>
|
|
||||||
<h4 className="font-display text-sm font-black text-brand-dark mb-1">
|
|
||||||
{t.name}
|
|
||||||
</h4>
|
|
||||||
<p className="text-[11px] font-bold text-on-surface-variant/65">
|
|
||||||
{t.role}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ─── Client Testimonial & Quote ─── */}
|
|
||||||
<section className="bg-brand-dark px-6 md:px-12 lg:px-20 xl:px-24 py-28 text-center text-white">
|
|
||||||
<div className="mx-auto max-w-4xl relative">
|
|
||||||
<span className="absolute -top-12 left-1/2 -translate-x-1/2 text-8xl font-black text-brand-accent/10 font-display">
|
|
||||||
“
|
|
||||||
</span>
|
|
||||||
<div className="relative z-10">
|
|
||||||
<h3 className="font-display text-xl md:text-2xl font-black text-brand-accent mb-6">
|
|
||||||
Partner Feedback
|
|
||||||
</h3>
|
|
||||||
<blockquote className="text-lg md:text-xl font-light italic leading-relaxed text-white/90 max-w-2xl mx-auto mb-8">
|
|
||||||
“Nearle has opened up immense opportunities for us to survive the competition, sustain in business, and gain our customers back.”
|
|
||||||
</blockquote>
|
|
||||||
<div className="flex flex-col items-center gap-2">
|
|
||||||
<div className="w-10 h-10 rounded-full bg-brand-accent text-brand-dark flex items-center justify-center font-display font-black text-xs">
|
|
||||||
DK
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-label-md font-black">Darshan K</p>
|
|
||||||
<p className="text-body-sm text-white/50">Erranderz Partner</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ─── Brand Building Banner ─── */}
|
{/* ─── Brand Building Banner ─── */}
|
||||||
<section className="mx-auto max-w-container-max px-6 md:px-12 lg:px-20 xl:px-24 py-28 text-center">
|
<section className="mx-auto max-w-container-max px-6 md:px-12 lg:px-20 xl:px-24 py-28 text-center">
|
||||||
<div className="bg-white rounded-[2.5rem] p-12 md:p-16 border border-outline-variant/15 shadow-xl max-w-4xl mx-auto">
|
<div className="bg-white rounded-[2.5rem] p-12 md:p-16 border border-outline-variant/15 shadow-xl max-w-4xl mx-auto">
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export default function BusinessesPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="relative min-h-screen bg-background">
|
<div className="relative min-h-screen bg-background">
|
||||||
{/* ─── Hero Section with Animated Rotator ─── */}
|
{/* ─── Hero Section with Animated Rotator ─── */}
|
||||||
<section className="relative overflow-hidden px-6 md:px-12 lg:px-20 xl:px-24 pt-44 pb-48 text-center">
|
<section className="hero-section relative overflow-hidden px-6 md:px-12 lg:px-20 xl:px-24 pt-56 pb-72 text-center">
|
||||||
{/* Background Image with Overlay */}
|
{/* Background Image with Overlay */}
|
||||||
<div className="absolute inset-0 z-0 select-none pointer-events-none">
|
<div className="absolute inset-0 z-0 select-none pointer-events-none">
|
||||||
<Image
|
<Image
|
||||||
@@ -112,7 +112,7 @@ export default function BusinessesPage() {
|
|||||||
<h1 className="mt-6 font-display text-4xl font-black text-white md:text-6xl tracking-tight leading-tight max-w-4xl mx-auto">
|
<h1 className="mt-6 font-display text-4xl font-black text-white md:text-6xl tracking-tight leading-tight max-w-4xl mx-auto">
|
||||||
<span>Power your business.</span>
|
<span>Power your business.</span>
|
||||||
<br />
|
<br />
|
||||||
<span className="relative inline-block text-brand-accent min-h-[1.2em] transition-all duration-500">
|
<span className="hero-rotator-text relative inline-flex text-brand-accent transition-all duration-500">
|
||||||
{ROTATOR_WORDS[wordIndex]}
|
{ROTATOR_WORDS[wordIndex]}
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -1,129 +1,34 @@
|
|||||||
"use client";
|
import React from "react";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
|
import { ContactForm } from "@/components/contact/ContactForm";
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
type FormData = {
|
export const metadata: Metadata = {
|
||||||
name: string;
|
title: "Contact Us",
|
||||||
email: string;
|
description: "Get in touch with Nearle's team. Reach out for support, merchant partnerships, delivery, or general hyperlocal neighborhood inquiries.",
|
||||||
message: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type FormErrors = {
|
|
||||||
name?: string;
|
|
||||||
email?: string;
|
|
||||||
message?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ContactPage() {
|
export default function ContactPage() {
|
||||||
const [formData, setFormData] = useState<FormData>({
|
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
message: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const [errors, setErrors] = useState<FormErrors>({});
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
||||||
const [showToast, setShowToast] = useState(false);
|
|
||||||
|
|
||||||
const handleInputChange = (
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
||||||
) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[name]: value,
|
|
||||||
}));
|
|
||||||
// Clear error for this field as the user types
|
|
||||||
if (errors[name as keyof FormErrors]) {
|
|
||||||
setErrors((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[name]: undefined,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateForm = (): boolean => {
|
|
||||||
const tempErrors: FormErrors = {};
|
|
||||||
let isValid = true;
|
|
||||||
|
|
||||||
if (!formData.name.trim()) {
|
|
||||||
tempErrors.name = "Name 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;
|
|
||||||
} else if (formData.message.trim().length < 10) {
|
|
||||||
tempErrors.message = "Message must be at least 10 characters long";
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setErrors(tempErrors);
|
|
||||||
return isValid;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (!validateForm()) return;
|
|
||||||
|
|
||||||
setIsSubmitting(true);
|
|
||||||
|
|
||||||
// Simulate API Request delay
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1200));
|
|
||||||
|
|
||||||
setIsSubmitting(false);
|
|
||||||
setShowToast(true);
|
|
||||||
setFormData({ name: "", email: "", message: "" });
|
|
||||||
|
|
||||||
// Auto-hide toast after 5 seconds
|
|
||||||
setTimeout(() => {
|
|
||||||
setShowToast(false);
|
|
||||||
}, 5000);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative min-h-screen bg-background">
|
<div className="relative min-h-screen bg-background">
|
||||||
{/* ─── Breadcrumbs & Hero Page Header ─── */}
|
{/* ─── Breadcrumbs & Hero Page Header ─── */}
|
||||||
<section className="relative overflow-hidden bg-brand-dark px-6 md:px-12 lg:px-20 xl:px-24 pt-36 pb-40 text-center">
|
<section className="hero-section relative overflow-hidden bg-brand-dark px-6 md:px-12 lg:px-20 xl:px-24 pt-36 pb-40 text-center">
|
||||||
{/* Background Decorative Gradients */}
|
{/* Background Image with Overlay */}
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_30%,rgba(108,14,128,0.25),transparent_40%)]" />
|
<div className="hero-background select-none pointer-events-none">
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_80%,rgba(203,157,248,0.12),transparent_50%)]" />
|
<Image
|
||||||
|
src="/contect.png"
|
||||||
<div className="relative z-10 mx-auto max-w-container-max">
|
alt="Contact Nearle Background"
|
||||||
{/* Breadcrumbs */}
|
fill
|
||||||
<nav className="flex justify-center mb-6">
|
sizes="100vw"
|
||||||
<ol className="inline-flex items-center space-x-1 md:space-x-2 text-body-sm font-bold text-white/50">
|
className="object-cover object-right"
|
||||||
<li className="inline-flex items-center">
|
priority
|
||||||
<Link
|
/>
|
||||||
href="/"
|
|
||||||
className="hover:text-brand-accent transition-colors flex items-center gap-1"
|
|
||||||
>
|
|
||||||
<MaterialIcon icon="home" size={14} />
|
|
||||||
Home
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<span className="mx-1 text-white/30">/</span>
|
|
||||||
<span className="text-brand-accent">Contact</span>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
|
<div className="hero-content relative z-10 mx-auto max-w-container-max">
|
||||||
|
{/* Header Title */}
|
||||||
<p className="text-label-sm font-black uppercase tracking-[0.2em] text-brand-accent">
|
<p className="text-label-sm font-black uppercase tracking-[0.2em] text-brand-accent">
|
||||||
Get in touch
|
Get in touch
|
||||||
</p>
|
</p>
|
||||||
@@ -147,12 +52,12 @@ export default function ContactPage() {
|
|||||||
</div>
|
</div>
|
||||||
<h3 className="font-display text-lg font-black text-brand-dark mb-2">Our Location</h3>
|
<h3 className="font-display text-lg font-black text-brand-dark mb-2">Our Location</h3>
|
||||||
<p className="text-body-sm text-on-surface-variant leading-relaxed">
|
<p className="text-body-sm text-on-surface-variant leading-relaxed">
|
||||||
Nearle HQ, 29 Avinashi Road,<br />
|
Nearle HQ, 424, Diwan Bahadur Rd,<br />
|
||||||
Coimbatore, Tamil Nadu,<br />
|
Opposite To Sri Krishna Sweets, R.S. Puram,<br />
|
||||||
641018, India
|
Coimbatore, Tamil Nadu 641002
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
href="https://maps.google.com/?q=Avinashi+Road,+Coimbatore,+Tamil+Nadu,+India"
|
href="https://maps.google.com/?q=424,+Diwan+Bahadur+Rd,+Opposite+To+Sri+Krishna+Sweets,+R.S.+Puram,+Coimbatore,+Tamil+Nadu+641002"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="mt-auto pt-4 text-label-sm text-primary hover:text-primary-container font-black flex items-center gap-1 group"
|
className="mt-auto pt-4 text-label-sm text-primary hover:text-primary-container font-black flex items-center gap-1 group"
|
||||||
@@ -233,7 +138,7 @@ export default function ContactPage() {
|
|||||||
<div className="relative bg-white rounded-3xl overflow-hidden shadow-xl border border-outline-variant/20 group h-[450px]">
|
<div className="relative bg-white rounded-3xl overflow-hidden shadow-xl border border-outline-variant/20 group h-[450px]">
|
||||||
<iframe
|
<iframe
|
||||||
title="Nearle Coimbatore Location Map"
|
title="Nearle Coimbatore Location Map"
|
||||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3916.2816999266157!2d76.9587!3d11.0168!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x3ba859af2f97b047%3A0x36b04859873d6e5a!2sAvinashi%20Rd%2C%20Coimbatore%2C%20Tamil%20Nadu!5e0!3m2!1sen!2sin!4v1719000000000!5m2!1sen!2sin"
|
src="https://maps.google.com/maps?q=424,+Diwan+Bahadur+Rd,+Opposite+To+Sri+Krishna+Sweets,+R.S.+Puram,+Coimbatore,+Tamil+Nadu+641002&t=&z=16&ie=UTF8&iwloc=&output=embed"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
style={{ border: 0 }}
|
style={{ border: 0 }}
|
||||||
@@ -248,7 +153,7 @@ export default function ContactPage() {
|
|||||||
<MaterialIcon icon="store" size={20} className="text-white" />
|
<MaterialIcon icon="store" size={20} className="text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-body-sm font-black text-brand-dark">Coimbatore Hub</h4>
|
<h4 className="text-body-sm font-black text-brand-dark">R.S. Puram Hub</h4>
|
||||||
<p className="text-[11px] text-on-surface-variant">Connecting local vendors & residents</p>
|
<p className="text-[11px] text-on-surface-variant">Connecting local vendors & residents</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -256,161 +161,10 @@ export default function ContactPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right: Message Form (7 Cols) */}
|
{/* Right: Message Form (7 Cols) */}
|
||||||
<div className="lg:col-span-7 bg-white rounded-3xl p-8 md:p-10 border border-outline-variant/25 shadow-xl relative overflow-hidden">
|
<ContactForm />
|
||||||
{/* Background Accent Mesh */}
|
|
||||||
<div className="absolute top-0 right-0 w-32 h-32 bg-primary/5 rounded-full blur-3xl" />
|
|
||||||
<div className="absolute bottom-0 left-0 w-32 h-32 bg-secondary/5 rounded-full blur-3xl" />
|
|
||||||
|
|
||||||
<div className="relative z-10">
|
|
||||||
<span className="text-label-sm font-black text-primary uppercase tracking-widest">
|
|
||||||
Write to us
|
|
||||||
</span>
|
|
||||||
<h2 className="font-display text-2xl md:text-3xl font-black text-brand-dark mt-2 mb-8">
|
|
||||||
Send Message
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
{/* Name field */}
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<label htmlFor="field-name" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
|
||||||
Your Name
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<span className="absolute inset-y-0 left-0 flex items-center pl-4 text-on-surface-variant/40">
|
|
||||||
<MaterialIcon icon="person" size={20} />
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="field-name"
|
|
||||||
name="name"
|
|
||||||
value={formData.name}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
placeholder="e.g. John Doe"
|
|
||||||
className={`w-full pl-11 pr-4 py-3.5 bg-surface rounded-xl border ${
|
|
||||||
errors.name ? "border-error" : "border-outline-variant/30"
|
|
||||||
} text-body-md text-on-surface placeholder:text-on-surface-variant/45 focus:outline-none focus:ring-2 ${
|
|
||||||
errors.name ? "focus:ring-error/20" : "focus:ring-primary/20"
|
|
||||||
} focus:border-primary transition-all`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{errors.name && (
|
|
||||||
<span className="text-body-sm text-error font-bold mt-1.5 flex items-center gap-1">
|
|
||||||
<MaterialIcon icon="error" size={14} />
|
|
||||||
{errors.name}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Email field */}
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<label htmlFor="field-email" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
|
||||||
Your Email
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<span className="absolute inset-y-0 left-0 flex items-center pl-4 text-on-surface-variant/40">
|
|
||||||
<MaterialIcon icon="email" size={20} />
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="field-email"
|
|
||||||
name="email"
|
|
||||||
value={formData.email}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
placeholder="e.g. john@example.com"
|
|
||||||
className={`w-full pl-11 pr-4 py-3.5 bg-surface rounded-xl border ${
|
|
||||||
errors.email ? "border-error" : "border-outline-variant/30"
|
|
||||||
} text-body-md text-on-surface placeholder:text-on-surface-variant/45 focus:outline-none focus:ring-2 ${
|
|
||||||
errors.email ? "focus:ring-error/20" : "focus:ring-primary/20"
|
|
||||||
} focus:border-primary transition-all`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{errors.email && (
|
|
||||||
<span className="text-body-sm text-error font-bold mt-1.5 flex items-center gap-1">
|
|
||||||
<MaterialIcon icon="error" size={14} />
|
|
||||||
{errors.email}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Message field */}
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<label htmlFor="field-message" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
|
||||||
Message
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<span className="absolute top-3.5 left-4 text-on-surface-variant/40">
|
|
||||||
<MaterialIcon icon="chat_bubble" size={20} />
|
|
||||||
</span>
|
|
||||||
<textarea
|
|
||||||
id="field-message"
|
|
||||||
name="message"
|
|
||||||
rows={5}
|
|
||||||
value={formData.message}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
placeholder="Describe your inquiry in detail (e.g. partnership options, tech support, etc.)"
|
|
||||||
className={`w-full pl-11 pr-4 py-3.5 bg-surface rounded-xl border ${
|
|
||||||
errors.message ? "border-error" : "border-outline-variant/30"
|
|
||||||
} text-body-md text-on-surface placeholder:text-on-surface-variant/45 focus:outline-none focus:ring-2 ${
|
|
||||||
errors.message ? "focus:ring-error/20" : "focus:ring-primary/20"
|
|
||||||
} focus:border-primary transition-all resize-none`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{errors.message && (
|
|
||||||
<span className="text-body-sm text-error font-bold mt-1.5 flex items-center gap-1">
|
|
||||||
<MaterialIcon icon="error" size={14} />
|
|
||||||
{errors.message}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Submit button */}
|
|
||||||
<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"
|
|
||||||
>
|
|
||||||
{isSubmitting ? (
|
|
||||||
<>
|
|
||||||
<span className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
|
||||||
<span>Sending Message...</span>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<MaterialIcon icon="send" size={18} />
|
|
||||||
<span>Submit Message</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ─── Success Toast Notification ─── */}
|
|
||||||
{showToast && (
|
|
||||||
<div className="fixed bottom-8 right-8 z-50 animate-bounce-subtle max-w-sm w-full bg-brand-dark-surface border border-brand-accent/30 rounded-2xl shadow-2xl p-4 flex gap-4 items-start">
|
|
||||||
<div className="w-10 h-10 rounded-xl bg-secondary text-white flex items-center justify-center shrink-0">
|
|
||||||
<MaterialIcon icon="check_circle" size={24} />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<h4 className="text-body-md font-black text-white">Message Sent!</h4>
|
|
||||||
<p className="text-body-sm text-white/70 mt-1 leading-normal">
|
|
||||||
Thank you for reaching out. We will get back to you within 24 hours.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => setShowToast(false)}
|
|
||||||
className="text-white/40 hover:text-white transition-colors cursor-pointer shrink-0"
|
|
||||||
aria-label="Close Toast"
|
|
||||||
>
|
|
||||||
<MaterialIcon icon="close" size={18} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
--spacing-gutter: 16px;
|
--spacing-gutter: 16px;
|
||||||
--spacing-margin-mobile: 16px;
|
--spacing-margin-mobile: 16px;
|
||||||
--spacing-margin-desktop: 32px;
|
--spacing-margin-desktop: 32px;
|
||||||
--spacing-container-max: 1280px;
|
--spacing-container-max: 1440px;
|
||||||
|
|
||||||
/* Fonts */
|
/* Fonts */
|
||||||
--font-display: "Jost", sans-serif;
|
--font-display: "Jost", sans-serif;
|
||||||
@@ -429,7 +429,7 @@ body {
|
|||||||
.hero-stage {
|
.hero-stage {
|
||||||
padding-left: clamp(72px, 7.5vw, 150px);
|
padding-left: clamp(72px, 7.5vw, 150px);
|
||||||
padding-right: clamp(32px, 4vw, 80px);
|
padding-right: clamp(32px, 4vw, 80px);
|
||||||
min-height: 600px;
|
min-height: 620px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-cards-wrapper {
|
.service-cards-wrapper {
|
||||||
@@ -549,3 +549,598 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ─── Footer Layout & Sizing System ─── */
|
||||||
|
.footer-container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1720px;
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: clamp(24px, 5%, 76px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns:
|
||||||
|
minmax(260px, 1.1fr)
|
||||||
|
minmax(170px, 0.8fr)
|
||||||
|
minmax(190px, 0.9fr)
|
||||||
|
minmax(460px, 1.45fr);
|
||||||
|
grid-template-areas:
|
||||||
|
"brand company partnerships form"
|
||||||
|
"brand legal legal form";
|
||||||
|
gap: 34px 48px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid-contact-page {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns:
|
||||||
|
minmax(260px, 1.1fr)
|
||||||
|
minmax(170px, 0.8fr)
|
||||||
|
minmax(190px, 0.9fr)
|
||||||
|
minmax(150px, 0.8fr);
|
||||||
|
grid-template-areas: "brand company partnerships legal";
|
||||||
|
gap: 34px 48px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid-contact-page .footer-legal {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1350px) {
|
||||||
|
.footer-grid {
|
||||||
|
grid-template-columns: minmax(240px, 1fr) repeat(2, minmax(160px, 0.8fr));
|
||||||
|
grid-template-areas:
|
||||||
|
"brand company partnerships"
|
||||||
|
"brand legal legal"
|
||||||
|
"form form form";
|
||||||
|
}
|
||||||
|
.footer-grid-contact-page {
|
||||||
|
grid-template-columns: minmax(240px, 1fr) repeat(2, minmax(160px, 0.8fr));
|
||||||
|
grid-template-areas:
|
||||||
|
"brand company partnerships"
|
||||||
|
"brand legal legal";
|
||||||
|
}
|
||||||
|
.footer-grid-contact-page .footer-legal {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-desc {
|
||||||
|
font-size: clamp(17px, 1.2vw, 19px);
|
||||||
|
line-height: 1.6;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
max-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-social-link {
|
||||||
|
width: 58px;
|
||||||
|
height: 58px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #ffffff;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-social-link:hover {
|
||||||
|
background: var(--brand-accent);
|
||||||
|
color: var(--brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-column-title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #E5E7EB;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link {
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link:hover {
|
||||||
|
color: var(--brand-accent);
|
||||||
|
transform: translateX(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contact Form Card styling */
|
||||||
|
.footer-brand {
|
||||||
|
grid-area: brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-company {
|
||||||
|
grid-area: company;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-partnerships {
|
||||||
|
grid-area: partnerships;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-legal {
|
||||||
|
grid-area: legal;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-wrap {
|
||||||
|
grid-area: form;
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-card {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 540px;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-card input,
|
||||||
|
.footer-contact-card textarea,
|
||||||
|
.footer-contact-card button {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-title {
|
||||||
|
font-size: clamp(30px, 2.2vw, 34px);
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-subtitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--on-surface-variant);
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
white-space: normal;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1440px) {
|
||||||
|
.footer-form-row {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--outline-variant);
|
||||||
|
color: var(--on-surface);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
min-height: 60px;
|
||||||
|
font-size: 16px;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-input:focus {
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 0 0 2px rgba(77, 4, 106, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-input.has-error {
|
||||||
|
border-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-input.has-error:focus {
|
||||||
|
box-shadow: 0 0 0 2px rgba(186, 26, 26, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-input::placeholder {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(77, 67, 79, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-textarea {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--outline-variant);
|
||||||
|
color: var(--on-surface);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 16px;
|
||||||
|
min-height: 130px;
|
||||||
|
font-size: 16px;
|
||||||
|
outline: none;
|
||||||
|
resize: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-textarea:focus {
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 0 0 2px rgba(77, 4, 106, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-textarea.has-error {
|
||||||
|
border-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-textarea.has-error:focus {
|
||||||
|
box-shadow: 0 0 0 2px rgba(186, 26, 26, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-textarea::placeholder {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(77, 67, 79, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-error-text {
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--error);
|
||||||
|
font-weight: 700;
|
||||||
|
margin-top: 4px;
|
||||||
|
padding-left: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--on-primary);
|
||||||
|
font-weight: 700;
|
||||||
|
min-height: 62px;
|
||||||
|
font-size: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-submit-btn:hover:not(:disabled) {
|
||||||
|
background: var(--primary-container);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-submit-btn:disabled {
|
||||||
|
background: rgba(77, 4, 106, 0.5);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-submit-btn:active:not(:disabled) {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom-text {
|
||||||
|
font-size: 15px;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helpdesk override for sizing constraints */
|
||||||
|
.helpdesk-subtitle {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(18, 2, 23, 0.8);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpdesk-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
background-color: var(--brand-dark);
|
||||||
|
color: var(--brand-accent);
|
||||||
|
font-weight: 900;
|
||||||
|
padding: 14px 32px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpdesk-btn:hover {
|
||||||
|
background-color: rgba(18, 2, 23, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.footer-grid,
|
||||||
|
.footer-grid-contact-page {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-brand-col {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-card-wrapper {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.footer-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-areas:
|
||||||
|
"brand"
|
||||||
|
"company"
|
||||||
|
"partnerships"
|
||||||
|
"legal"
|
||||||
|
"form";
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid-contact-page {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-areas:
|
||||||
|
"brand"
|
||||||
|
"company"
|
||||||
|
"partnerships"
|
||||||
|
"legal";
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact-card {
|
||||||
|
padding: 28px 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Footer Vertical Spacing & Height Alignment ─── */
|
||||||
|
.footer {
|
||||||
|
--helpdesk-height: 150px;
|
||||||
|
--helpdesk-overlap: 42px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-helpdesk-wrap {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-inline: clamp(24px, 5%, 76px);
|
||||||
|
margin-top: -42px;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-main {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-bottom: 56px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-divider {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto !important;
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 28px 0 34px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-spacer,
|
||||||
|
.footer-empty-space {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.footer-helpdesk-wrap {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Stable Subpage Hero Height to Prevent Layout Shift ─── */
|
||||||
|
.hero-section {
|
||||||
|
position: relative !important;
|
||||||
|
min-height: clamp(680px, 48vw, 820px) !important;
|
||||||
|
height: clamp(680px, 48vw, 820px) !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
align-items: center !important;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-section > div.relative {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-rotator-text {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 2.4em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Experience Bento Mosaic Grid Redesign ─── */
|
||||||
|
.experience-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
grid-auto-rows: 480px;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 26px;
|
||||||
|
min-height: 480px;
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card--wide {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card__image {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.7s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card:hover .experience-card__image {
|
||||||
|
transform: scale(1.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card__overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(18, 4, 28, 0.15) 0%,
|
||||||
|
rgba(18, 4, 28, 0.55) 48%,
|
||||||
|
rgba(18, 4, 28, 0.92) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card__content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: 100%;
|
||||||
|
padding: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card__badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 26px;
|
||||||
|
left: 26px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(238, 216, 255, 0.2);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card__icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 24px;
|
||||||
|
right: 24px;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(232, 202, 255, 0.22);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card h3 {
|
||||||
|
color: white;
|
||||||
|
font-size: clamp(24px, 2vw, 34px);
|
||||||
|
line-height: 1.1;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-card p {
|
||||||
|
color: rgba(255, 255, 255, 0.82);
|
||||||
|
max-width: 420px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.55;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.experience-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.experience-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-auto-rows: auto;
|
||||||
|
}
|
||||||
|
.experience-card {
|
||||||
|
min-height: 340px;
|
||||||
|
}
|
||||||
|
.experience-card--wide {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Hero Section Background & Overlay Styling ─── */
|
||||||
|
.hero-background {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-background img {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
object-fit: cover !important;
|
||||||
|
object-position: center right !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-background::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(18, 4, 28, 0.48);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
|
|
||||||
const ROTATOR_SLIDES = [
|
const ROTATOR_SLIDES = [
|
||||||
@@ -16,63 +17,81 @@ const OFFERINGS = [
|
|||||||
tag: "Join the #1 Neighbourhood App",
|
tag: "Join the #1 Neighbourhood App",
|
||||||
descr: "Enjoy the comfort of elegant living. Nearle is India's first hyper-local managed platform bringing all amenities and requirements directly to your fingertips.",
|
descr: "Enjoy the comfort of elegant living. Nearle is India's first hyper-local managed platform bringing all amenities and requirements directly to your fingertips.",
|
||||||
icon: "local_florist",
|
icon: "local_florist",
|
||||||
color: "from-purple-500/10 to-indigo-500/10 text-primary border-purple-100"
|
color: "from-purple-500/10 to-indigo-500/10 text-primary border-purple-100",
|
||||||
|
image: "/nearle people.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Awareness at a Touch",
|
title: "Awareness at a Touch",
|
||||||
tag: "Hot Deals",
|
tag: "Hot Deals",
|
||||||
descr: "Pick hot deals within your neighbourhood. Stay updated on localized sales, discounts, and flash promotions happening today.",
|
descr: "Pick hot deals within your neighbourhood. Stay updated on localized sales, discounts, and flash promotions happening today.",
|
||||||
icon: "local_activity",
|
icon: "local_activity",
|
||||||
color: "from-amber-500/10 to-orange-500/10 text-amber-700 border-amber-100"
|
color: "from-amber-500/10 to-orange-500/10 text-amber-700 border-amber-100",
|
||||||
|
image: "/images/app-mockup.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Best of Both Worlds",
|
title: "Best of Both Worlds",
|
||||||
tag: "Convenience & Speed",
|
tag: "Convenience & Speed",
|
||||||
descr: "Enjoy the ease of the World Wide Web, fulfilled entirely by trusted local businesses. Avoid traffic lights, parking hassles, and pollution.",
|
descr: "Enjoy the ease of the World Wide Web, fulfilled entirely by trusted local businesses. Avoid traffic lights, parking hassles, and pollution.",
|
||||||
icon: "travel_explore",
|
icon: "travel_explore",
|
||||||
color: "from-green-500/10 to-emerald-500/10 text-secondary border-green-100"
|
color: "from-green-500/10 to-emerald-500/10 text-secondary border-green-100",
|
||||||
|
image: "/images/slider-courier-mask.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Lifestyle Shopping",
|
title: "Lifestyle Shopping",
|
||||||
tag: "Exclusive Privileges",
|
tag: "Exclusive Privileges",
|
||||||
descr: "Enjoy safe, convenient shopping with custom pricing, resident promotions, and bulk order discounts negotiated for your community.",
|
descr: "Enjoy safe, convenient shopping with custom pricing, resident promotions, and bulk order discounts negotiated for your community.",
|
||||||
icon: "shopping_bag",
|
icon: "shopping_bag",
|
||||||
color: "from-rose-500/10 to-pink-500/10 text-rose-700 border-rose-100"
|
color: "from-rose-500/10 to-pink-500/10 text-rose-700 border-rose-100",
|
||||||
|
image: "/images/cat-pet-essentials.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Just a Click away",
|
title: "Just a Click away",
|
||||||
tag: "Instant Delivery",
|
tag: "Instant Delivery",
|
||||||
descr: "Order everything you need in your neighborhood with a single tap. A fast, organized last-mile delivery network ensures prompt fulfillment.",
|
descr: "Order everything you need in your neighborhood with a single tap. A fast, organized last-mile delivery network ensures prompt fulfillment.",
|
||||||
icon: "touch_app",
|
icon: "touch_app",
|
||||||
color: "from-sky-500/10 to-blue-500/10 text-sky-700 border-sky-100"
|
color: "from-sky-500/10 to-blue-500/10 text-sky-700 border-sky-100",
|
||||||
|
image: "/about.png",
|
||||||
|
isWide: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Amazingly Fresh",
|
title: "Amazingly Fresh",
|
||||||
tag: "Daily Essentials",
|
tag: "Daily Essentials",
|
||||||
descr: "Get your fresh fruits, farm-fresh vegetables, dairy, and grocery items delivered instantly from verified local green grocers.",
|
descr: "Get your fresh fruits, farm-fresh vegetables, dairy, and grocery items delivered instantly from verified local green grocers.",
|
||||||
icon: "eco",
|
icon: "eco",
|
||||||
color: "from-emerald-500/10 to-teal-500/10 text-emerald-700 border-emerald-100"
|
color: "from-emerald-500/10 to-teal-500/10 text-emerald-700 border-emerald-100",
|
||||||
|
image: "/images/cat-daily-essentials.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Restaurants & Takeaways",
|
title: "Restaurants & Takeaways",
|
||||||
tag: "Hot Food Nearby",
|
tag: "Hot Food Nearby",
|
||||||
descr: "Choose from the best local restaurants and neighborhood eateries close to your home. Hot food delivered with relevance and speed.",
|
descr: "Choose from the best local restaurants and neighborhood eateries close to your home. Hot food delivered with relevance and speed.",
|
||||||
icon: "restaurant",
|
icon: "restaurant",
|
||||||
color: "from-orange-500/10 to-red-500/10 text-orange-700 border-orange-100"
|
color: "from-orange-500/10 to-red-500/10 text-orange-700 border-orange-100",
|
||||||
|
image: "/images/cat-hot-food.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Never Before Experience",
|
title: "Never Before Experience",
|
||||||
tag: "Custom Services",
|
tag: "Custom Services",
|
||||||
descr: "Access custom-tailored local neighborhood services designed to integrate convenience directly into residential society living.",
|
descr: "Access custom-tailored local neighborhood services designed to integrate convenience directly into residential society living.",
|
||||||
icon: "stars",
|
icon: "stars",
|
||||||
color: "from-violet-500/10 to-purple-500/10 text-violet-700 border-violet-100"
|
color: "from-violet-500/10 to-purple-500/10 text-violet-700 border-violet-100",
|
||||||
|
image: "/images/cat-health-wellness.png",
|
||||||
|
isWide: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Home Services @ Ease",
|
title: "Home Services @ Ease",
|
||||||
tag: "Unified Local Partner",
|
tag: "Unified Local Partner",
|
||||||
descr: "Book certified local service providers at your convenience. From handymen to laundry, pet care to pharmacy delivery, all in one place.",
|
descr: "Book certified local service providers at your convenience. From handymen to laundry, pet care to pharmacy delivery, all in one place.",
|
||||||
icon: "construction",
|
icon: "construction",
|
||||||
color: "from-cyan-500/10 to-blue-500/10 text-cyan-700 border-cyan-100"
|
color: "from-cyan-500/10 to-blue-500/10 text-cyan-700 border-cyan-100",
|
||||||
|
image: "/images/cat-home-services.png",
|
||||||
|
isWide: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -97,11 +116,20 @@ export default function PeoplePage() {
|
|||||||
<div className="relative min-h-screen bg-background">
|
<div className="relative min-h-screen bg-background">
|
||||||
|
|
||||||
{/* ─── Hero Section ─── */}
|
{/* ─── Hero Section ─── */}
|
||||||
<section className="relative overflow-hidden bg-brand-dark px-6 md:px-12 lg:px-20 xl:px-24 pt-44 pb-48 text-center">
|
<section className="hero-section relative overflow-hidden px-6 md:px-12 lg:px-20 xl:px-24 pt-56 pb-72 text-center">
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_25%_25%,rgba(108,14,128,0.25),transparent_40%)]" />
|
{/* Background Image with Overlay */}
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_75%_75%,rgba(203,157,248,0.15),transparent_45%)]" />
|
<div className="hero-background select-none pointer-events-none">
|
||||||
|
<Image
|
||||||
|
src="/nearle people.png"
|
||||||
|
alt="Nearle People Background"
|
||||||
|
fill
|
||||||
|
sizes="100vw"
|
||||||
|
className="object-cover object-right"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="relative z-10 mx-auto max-w-container-max">
|
<div className="hero-content relative z-10 mx-auto max-w-container-max">
|
||||||
<p className="text-label-sm font-black uppercase tracking-[0.25em] text-brand-accent">
|
<p className="text-label-sm font-black uppercase tracking-[0.25em] text-brand-accent">
|
||||||
Nearle for People
|
Nearle for People
|
||||||
</p>
|
</p>
|
||||||
@@ -109,30 +137,15 @@ export default function PeoplePage() {
|
|||||||
<h1 className="mt-6 font-display text-4xl font-black text-white md:text-6xl tracking-tight leading-tight max-w-4xl mx-auto">
|
<h1 className="mt-6 font-display text-4xl font-black text-white md:text-6xl tracking-tight leading-tight max-w-4xl mx-auto">
|
||||||
<span>Redefining Local Living.</span>
|
<span>Redefining Local Living.</span>
|
||||||
<br />
|
<br />
|
||||||
<span className="relative inline-block text-brand-accent min-h-[1.2em] transition-all duration-500">
|
<span className="hero-rotator-text relative inline-flex text-brand-accent transition-all duration-500">
|
||||||
{ROTATOR_SLIDES[slideIndex]}
|
{ROTATOR_SLIDES[slideIndex]}
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="mx-auto mt-6 max-w-2xl text-body-lg text-white/70">
|
|
||||||
India's first hyper-local managed Neighbourhood Living Platform. Connect to verified stores and daily amenities around you instantly.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* Quick Action */}
|
|
||||||
<div className="mt-10">
|
|
||||||
<a
|
|
||||||
href="#download-section"
|
|
||||||
className="bg-brand-accent hover:bg-brand-accent-light text-brand-dark font-black px-10 py-4.5 rounded-xl text-label-md hover:shadow-xl transition-all duration-300 active:scale-95 inline-flex items-center gap-2"
|
|
||||||
>
|
|
||||||
<MaterialIcon icon="download" size={18} />
|
|
||||||
<span>Get the App Now</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* ─── 9 Core Offerings Bento Grid ─── */}
|
{/* ─── 9 Core Offerings Bento Grid ─── */}
|
||||||
<section className="mx-auto max-w-container-max px-6 md:px-12 lg:px-20 xl:px-24 py-28">
|
<section className="experience-section mx-auto max-w-container-max px-6 md:px-12 lg:px-20 xl:px-24 py-28">
|
||||||
<div className="text-center mb-16">
|
<div className="text-center mb-16">
|
||||||
<span className="text-label-sm font-black text-primary uppercase tracking-widest">
|
<span className="text-label-sm font-black text-primary uppercase tracking-widest">
|
||||||
What we offer
|
What we offer
|
||||||
@@ -145,27 +158,28 @@ export default function PeoplePage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="experience-grid">
|
||||||
{OFFERINGS.map((offering) => (
|
{OFFERINGS.map((offering) => (
|
||||||
<div
|
<article
|
||||||
key={offering.title}
|
key={offering.title}
|
||||||
className="premium-card bg-white rounded-3xl p-8 border border-outline-variant/15 shadow-md flex flex-col hover:border-primary/25 transition-all"
|
className="experience-card"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-6">
|
<Image
|
||||||
<span className="text-[10px] font-black uppercase tracking-wider text-secondary-container bg-secondary/15 text-secondary px-3 py-1 rounded-full">
|
src={offering.image}
|
||||||
{offering.tag}
|
alt={offering.title}
|
||||||
</span>
|
fill
|
||||||
<div className={`w-11 h-11 rounded-xl bg-gradient-to-br ${offering.color} flex items-center justify-center`}>
|
sizes="(max-width: 1023px) 100vw, 33vw"
|
||||||
<MaterialIcon icon={offering.icon} size={22} />
|
className="experience-card__image"
|
||||||
|
/>
|
||||||
|
<div className="experience-card__overlay" />
|
||||||
|
<div className="experience-card__content">
|
||||||
|
<div className="experience-card__icon">
|
||||||
|
<MaterialIcon icon={offering.icon} size={22} className="text-white" />
|
||||||
</div>
|
</div>
|
||||||
|
<h3>{offering.title}</h3>
|
||||||
|
<p>{offering.descr}</p>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-display text-lg font-black text-brand-dark mb-3">
|
</article>
|
||||||
{offering.title}
|
|
||||||
</h3>
|
|
||||||
<p className="text-body-sm text-on-surface-variant leading-relaxed">
|
|
||||||
{offering.descr}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
252
src/components/contact/ContactForm.tsx
Normal file
252
src/components/contact/ContactForm.tsx
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
|
|
||||||
|
type FormData = {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FormErrors = {
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ContactForm() {
|
||||||
|
const [formData, setFormData] = useState<FormData>({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [errors, setErrors] = useState<FormErrors>({});
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [showToast, setShowToast] = useState(false);
|
||||||
|
|
||||||
|
const handleInputChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||||
|
) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setFormData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
|
// Clear error for this field as the user types
|
||||||
|
if (errors[name as keyof FormErrors]) {
|
||||||
|
setErrors((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[name]: undefined,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateForm = (): boolean => {
|
||||||
|
const tempErrors: FormErrors = {};
|
||||||
|
let isValid = true;
|
||||||
|
|
||||||
|
if (!formData.name.trim()) {
|
||||||
|
tempErrors.name = "Name 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;
|
||||||
|
} else if (formData.message.trim().length < 10) {
|
||||||
|
tempErrors.message = "Message must be at least 10 characters long";
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(tempErrors);
|
||||||
|
return isValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!validateForm()) return;
|
||||||
|
|
||||||
|
setIsSubmitting(true);
|
||||||
|
|
||||||
|
// Simulate API Request delay
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1200));
|
||||||
|
|
||||||
|
setIsSubmitting(false);
|
||||||
|
setShowToast(true);
|
||||||
|
setFormData({ name: "", email: "", message: "" });
|
||||||
|
|
||||||
|
// Auto-hide toast after 5 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
setShowToast(false);
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="lg:col-span-7 bg-white rounded-3xl p-8 md:p-10 border border-outline-variant/25 shadow-xl relative overflow-hidden">
|
||||||
|
{/* Background Accent Mesh */}
|
||||||
|
<div className="absolute top-0 right-0 w-32 h-32 bg-primary/5 rounded-full blur-3xl" />
|
||||||
|
<div className="absolute bottom-0 left-0 w-32 h-32 bg-secondary/5 rounded-full blur-3xl" />
|
||||||
|
|
||||||
|
<div className="relative z-10">
|
||||||
|
<span className="text-label-sm font-black text-primary uppercase tracking-widest">
|
||||||
|
Write to us
|
||||||
|
</span>
|
||||||
|
<h2 className="font-display text-2xl md:text-3xl font-black text-brand-dark mt-2 mb-8">
|
||||||
|
Send Message
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
{/* Name field */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<label htmlFor="field-name" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
||||||
|
Your Name
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<span className="absolute inset-y-0 left-0 flex items-center pl-4 text-on-surface-variant/40">
|
||||||
|
<MaterialIcon icon="person" size={20} />
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="field-name"
|
||||||
|
name="name"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="e.g. John Doe"
|
||||||
|
className={`w-full pl-11 pr-4 py-3.5 bg-surface rounded-xl border ${
|
||||||
|
errors.name ? "border-error" : "border-outline-variant/30"
|
||||||
|
} text-body-md text-on-surface placeholder:text-on-surface-variant/45 focus:outline-none focus:ring-2 ${
|
||||||
|
errors.name ? "focus:ring-error/20" : "focus:ring-primary/20"
|
||||||
|
} focus:border-primary transition-all`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errors.name && (
|
||||||
|
<span className="text-body-sm text-error font-bold mt-1.5 flex items-center gap-1">
|
||||||
|
<MaterialIcon icon="error" size={14} />
|
||||||
|
{errors.name}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Email field */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<label htmlFor="field-email" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
||||||
|
Your Email
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<span className="absolute inset-y-0 left-0 flex items-center pl-4 text-on-surface-variant/40">
|
||||||
|
<MaterialIcon icon="email" size={20} />
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
id="field-email"
|
||||||
|
name="email"
|
||||||
|
value={formData.email}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="e.g. john@example.com"
|
||||||
|
className={`w-full pl-11 pr-4 py-3.5 bg-surface rounded-xl border ${
|
||||||
|
errors.email ? "border-error" : "border-outline-variant/30"
|
||||||
|
} text-body-md text-on-surface placeholder:text-on-surface-variant/45 focus:outline-none focus:ring-2 ${
|
||||||
|
errors.email ? "focus:ring-error/20" : "focus:ring-primary/20"
|
||||||
|
} focus:border-primary transition-all`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errors.email && (
|
||||||
|
<span className="text-body-sm text-error font-bold mt-1.5 flex items-center gap-1">
|
||||||
|
<MaterialIcon icon="error" size={14} />
|
||||||
|
{errors.email}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Message field */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<label htmlFor="field-message" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
||||||
|
Message
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<span className="absolute top-3.5 left-4 text-on-surface-variant/40">
|
||||||
|
<MaterialIcon icon="chat_bubble" size={20} />
|
||||||
|
</span>
|
||||||
|
<textarea
|
||||||
|
id="field-message"
|
||||||
|
name="message"
|
||||||
|
rows={5}
|
||||||
|
value={formData.message}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="Describe your inquiry in detail (e.g. partnership options, tech support, etc.)"
|
||||||
|
className={`w-full pl-11 pr-4 py-3.5 bg-surface rounded-xl border ${
|
||||||
|
errors.message ? "border-error" : "border-outline-variant/30"
|
||||||
|
} text-body-md text-on-surface placeholder:text-on-surface-variant/45 focus:outline-none focus:ring-2 ${
|
||||||
|
errors.message ? "focus:ring-error/20" : "focus:ring-primary/20"
|
||||||
|
} focus:border-primary transition-all resize-none`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errors.message && (
|
||||||
|
<span className="text-body-sm text-error font-bold mt-1.5 flex items-center gap-1">
|
||||||
|
<MaterialIcon icon="error" size={14} />
|
||||||
|
{errors.message}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Submit button */}
|
||||||
|
<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"
|
||||||
|
>
|
||||||
|
{isSubmitting ? (
|
||||||
|
<>
|
||||||
|
<span className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||||
|
<span>Sending Message...</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<MaterialIcon icon="send" size={18} />
|
||||||
|
<span>Submit Message</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ─── Success Toast Notification ─── */}
|
||||||
|
{showToast && (
|
||||||
|
<div className="fixed bottom-8 right-8 z-50 animate-bounce-subtle max-w-sm w-full bg-brand-dark-surface border border-brand-accent/30 rounded-2xl shadow-2xl p-4 flex gap-4 items-start">
|
||||||
|
<div className="w-10 h-10 rounded-xl bg-secondary text-white flex items-center justify-center shrink-0">
|
||||||
|
<MaterialIcon icon="check_circle" size={24} />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<h4 className="text-body-md font-black text-white">Message Sent!</h4>
|
||||||
|
<p className="text-body-sm text-white/70 mt-1 leading-normal">
|
||||||
|
Thank you for reaching out. We will get back to you within 24 hours.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowToast(false)}
|
||||||
|
className="text-white/40 hover:text-white transition-colors cursor-pointer shrink-0"
|
||||||
|
aria-label="Close Toast"
|
||||||
|
>
|
||||||
|
<MaterialIcon icon="close" size={18} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -116,7 +116,7 @@ export function Hero() {
|
|||||||
Express Services
|
Express Services
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<h1 className="text-5xl lg:text-[92px] lg:leading-[0.95] font-display font-black tracking-tight mb-8">
|
<h1 className="text-4xl sm:text-5xl lg:text-[64px] xl:text-[78px] 2xl:text-[92px] lg:leading-[0.95] font-display font-black tracking-tight mb-8">
|
||||||
Express
|
Express
|
||||||
<br />
|
<br />
|
||||||
<span className="text-brand-accent drop-shadow-md">
|
<span className="text-brand-accent drop-shadow-md">
|
||||||
|
|||||||
@@ -122,9 +122,9 @@ export function Footer() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="relative z-10 bg-brand-dark text-white border-t border-white/5 pt-24 pb-6 w-full mt-24">
|
<footer className="footer relative z-10 bg-brand-dark text-white border-t border-white/5 w-full mt-24">
|
||||||
{/* Overlapping Contact Helpdesk Card */}
|
{/* Overlapping Contact Helpdesk Card */}
|
||||||
<div className="absolute -top-20 md:-top-14 left-0 right-0 z-20 max-w-[1380px] mx-auto px-6 md:px-12 lg:px-20 xl:px-24">
|
<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="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="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">
|
<div className="w-12 h-12 rounded-full bg-brand-dark text-brand-accent flex items-center justify-center shadow-lg">
|
||||||
@@ -132,14 +132,14 @@ export function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-headline-md font-black">24/7 Neighborhood Helpdesk</h4>
|
<h4 className="text-headline-md font-black">24/7 Neighborhood Helpdesk</h4>
|
||||||
<p className="text-[11px] font-bold text-brand-dark/80 mt-0.5">
|
<p className="helpdesk-subtitle mt-0.5">
|
||||||
Need immediate assistance with an order or local service?
|
Need immediate assistance with an order or local service?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
href="tel:+918049123456"
|
href="tel:+918049123456"
|
||||||
className="flex items-center gap-3 bg-brand-dark hover:bg-brand-dark/90 text-brand-accent font-black px-8 py-3.5 rounded-full text-label-md shadow-2xl active:scale-95 duration-200 transition-all"
|
className="helpdesk-btn"
|
||||||
>
|
>
|
||||||
<MaterialIcon icon="phone" size={20} className="animate-pulse-subtle" />
|
<MaterialIcon icon="phone" size={20} className="animate-pulse-subtle" />
|
||||||
<span>+91 80 4912 3456</span>
|
<span>+91 80 4912 3456</span>
|
||||||
@@ -147,78 +147,80 @@ export function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-w-[1380px] mx-auto px-6 md:px-12 lg:px-20 xl:px-24">
|
<div className="footer-container">
|
||||||
|
{/* Main content wrapper */}
|
||||||
|
<div className="footer-main">
|
||||||
{/* Main content grid: aligned on the same top baseline */}
|
{/* Main content grid: aligned on the same top baseline */}
|
||||||
<div className={`grid grid-cols-1 md:grid-cols-2 lg:items-start gap-y-10 gap-x-6 lg:gap-x-12 mb-12 ${
|
<div className={`${
|
||||||
isContactPage
|
isContactPage
|
||||||
? "lg:grid-cols-[220px_170px_190px_150px]"
|
? "footer-grid-contact-page"
|
||||||
: "lg:grid-cols-[220px_170px_190px_150px_minmax(360px,480px)]"
|
: "footer-grid"
|
||||||
}`}>
|
}`}>
|
||||||
{/* Brand Column */}
|
{/* Brand Column */}
|
||||||
<div className="col-span-1 md:col-span-2 lg:col-span-1">
|
<div className="footer-brand">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="hover:scale-[1.02] transition-transform active:scale-95 duration-200 mb-4 inline-block"
|
className="mb-4 inline-block"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src="/logo-v2.png"
|
src="/logo-v2.png"
|
||||||
alt="Nearle"
|
alt="Nearle"
|
||||||
width={220}
|
width={220}
|
||||||
height={36}
|
height={36}
|
||||||
style={{ height: "auto" }}
|
style={{ width: "210px", height: "auto" }}
|
||||||
className="h-9 w-auto object-contain"
|
className="object-contain"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<p className="text-body-sm text-white/60 max-w-xs mb-4 leading-relaxed">
|
<p className="footer-desc mb-4">
|
||||||
India's leading hyperlocal neighborhood network, empowering communities and verified local businesses within 2km.
|
India's leading hyperlocal neighborhood network, empowering communities and verified local businesses within 2km.
|
||||||
</p>
|
</p>
|
||||||
{/* Social Links */}
|
{/* Social Links */}
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center hover:bg-brand-accent hover:text-brand-dark hover:scale-105 transition-all"
|
className="footer-social-link"
|
||||||
aria-label="Share"
|
aria-label="Share"
|
||||||
>
|
>
|
||||||
<MaterialIcon icon="share" size={18} />
|
<MaterialIcon icon="share" size={24} />
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center hover:bg-brand-accent hover:text-brand-dark hover:scale-105 transition-all"
|
className="footer-social-link"
|
||||||
aria-label="Website"
|
aria-label="Website"
|
||||||
>
|
>
|
||||||
<MaterialIcon icon="public" size={18} />
|
<MaterialIcon icon="public" size={24} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Company Links */}
|
{/* Company Links */}
|
||||||
<div className="col-span-1">
|
<div className="footer-company">
|
||||||
<FooterCol title="Company" links={COMPANY} />
|
<FooterCol title="Company" links={COMPANY} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Partnerships Links */}
|
{/* Partnerships Links */}
|
||||||
<div className="col-span-1">
|
<div className="footer-partnerships">
|
||||||
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
|
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Legal Links */}
|
{/* Legal Links */}
|
||||||
<div className="col-span-1">
|
<div className="footer-legal">
|
||||||
<FooterCol title="Legal" links={LEGAL} />
|
<FooterCol title="Legal" links={LEGAL} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Contact Form Card */}
|
{/* Contact Form Card */}
|
||||||
{!isContactPage && (
|
{!isContactPage && (
|
||||||
<div className="col-span-1 md:col-span-2 lg:col-span-1 bg-white text-brand-dark rounded-3xl p-5 md:p-6 shadow-2xl border border-outline-variant/15 relative overflow-hidden w-full lg:max-w-none lg:-translate-x-16 lg:translate-y-2">
|
<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 */}
|
{/* Background Glow Decors */}
|
||||||
<div className="absolute top-0 right-0 w-24 h-24 bg-primary/5 rounded-full blur-2xl" />
|
<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="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">
|
<div className="relative z-10 text-center lg:text-left">
|
||||||
<h3 className="text-xl font-display font-black text-brand-dark tracking-tight">
|
<h3 className="footer-contact-title font-display text-brand-dark tracking-tight">
|
||||||
Send us a Message
|
Send us a Message
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-[11px] text-on-surface-variant mt-1 mb-6">
|
<p className="footer-contact-subtitle">
|
||||||
We shall guide you through our Neighbourhood Experts.
|
We shall guide you through our Neighbourhood Experts.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -230,7 +232,7 @@ export function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 gap-4">
|
<div className="footer-form-row">
|
||||||
<div className="flex flex-col text-left">
|
<div className="flex flex-col text-left">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -238,13 +240,11 @@ export function Footer() {
|
|||||||
value={formData.name}
|
value={formData.name}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
placeholder="Your Name..."
|
placeholder="Your Name..."
|
||||||
className={`w-full bg-surface border ${
|
className={`footer-input ${errors.name ? "has-error" : ""}`}
|
||||||
errors.name ? "border-error focus:ring-error/20" : "border-outline-variant/30 focus:ring-primary/20"
|
|
||||||
} text-body-sm text-on-surface placeholder:text-on-surface-variant/45 rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:border-primary transition-all`}
|
|
||||||
/>
|
/>
|
||||||
{errors.name && (
|
{errors.name && (
|
||||||
<span className="text-[9px] text-error font-bold mt-1 pl-1 flex items-center gap-0.5">
|
<span className="footer-error-text">
|
||||||
<MaterialIcon icon="error" size={10} />
|
<MaterialIcon icon="error" size={16} />
|
||||||
{errors.name}
|
{errors.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -256,13 +256,11 @@ export function Footer() {
|
|||||||
value={formData.phone}
|
value={formData.phone}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
placeholder="Your Phone..."
|
placeholder="Your Phone..."
|
||||||
className={`w-full bg-surface border ${
|
className={`footer-input ${errors.phone ? "has-error" : ""}`}
|
||||||
errors.phone ? "border-error focus:ring-error/20" : "border-outline-variant/30 focus:ring-primary/20"
|
|
||||||
} text-body-sm text-on-surface placeholder:text-on-surface-variant/45 rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:border-primary transition-all`}
|
|
||||||
/>
|
/>
|
||||||
{errors.phone && (
|
{errors.phone && (
|
||||||
<span className="text-[9px] text-error font-bold mt-1 pl-1 flex items-center gap-0.5">
|
<span className="footer-error-text">
|
||||||
<MaterialIcon icon="error" size={10} />
|
<MaterialIcon icon="error" size={16} />
|
||||||
{errors.phone}
|
{errors.phone}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -276,13 +274,11 @@ export function Footer() {
|
|||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
placeholder="Your Email Address..."
|
placeholder="Your Email Address..."
|
||||||
className={`w-full bg-surface border ${
|
className={`footer-input ${errors.email ? "has-error" : ""}`}
|
||||||
errors.email ? "border-error focus:ring-error/20" : "border-outline-variant/30 focus:ring-primary/20"
|
|
||||||
} text-body-sm text-on-surface placeholder:text-on-surface-variant/45 rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:border-primary transition-all`}
|
|
||||||
/>
|
/>
|
||||||
{errors.email && (
|
{errors.email && (
|
||||||
<span className="text-[9px] text-error font-bold mt-1 pl-1 flex items-center gap-0.5">
|
<span className="footer-error-text">
|
||||||
<MaterialIcon icon="error" size={10} />
|
<MaterialIcon icon="error" size={16} />
|
||||||
{errors.email}
|
{errors.email}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -294,14 +290,11 @@ export function Footer() {
|
|||||||
value={formData.message}
|
value={formData.message}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
placeholder="Your Message..."
|
placeholder="Your Message..."
|
||||||
rows={3}
|
className={`footer-textarea ${errors.message ? "has-error" : ""}`}
|
||||||
className={`w-full bg-surface border ${
|
|
||||||
errors.message ? "border-error focus:ring-error/20" : "border-outline-variant/30 focus:ring-primary/20"
|
|
||||||
} text-body-sm text-on-surface placeholder:text-on-surface-variant/45 rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:border-primary transition-all resize-none`}
|
|
||||||
/>
|
/>
|
||||||
{errors.message && (
|
{errors.message && (
|
||||||
<span className="text-[9px] text-error font-bold mt-1 pl-1 flex items-center gap-0.5">
|
<span className="footer-error-text">
|
||||||
<MaterialIcon icon="error" size={10} />
|
<MaterialIcon icon="error" size={16} />
|
||||||
{errors.message}
|
{errors.message}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -310,11 +303,11 @@ export function Footer() {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="w-full bg-primary hover:bg-primary-container disabled:bg-primary/50 text-on-primary font-black px-6 py-3 rounded-xl text-label-md shadow-md active:scale-95 duration-200 transition-all flex items-center justify-center gap-2 cursor-pointer"
|
className="footer-submit-btn"
|
||||||
>
|
>
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<>
|
<>
|
||||||
<span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
<span className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||||
<span>SUBMITTING...</span>
|
<span>SUBMITTING...</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -324,15 +317,21 @@ export function Footer() {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Divider */}
|
||||||
|
<hr className="footer-divider" />
|
||||||
|
|
||||||
{/* Bottom Bar */}
|
{/* Bottom Bar */}
|
||||||
<div className="border-t border-white/10 pt-7 flex flex-col md:flex-row justify-between items-center gap-4">
|
<div className="footer-bottom">
|
||||||
<p className="text-body-sm text-white/40 lg:pl-20">
|
<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.
|
© {new Date().getFullYear()} Nearle. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2 text-white/40 text-body-sm">
|
<div className="flex items-center gap-2 footer-bottom-text">
|
||||||
<span>Designed for neighborhoods in</span>
|
<span>Designed for neighborhoods in</span>
|
||||||
<span className="flex items-center gap-1 font-bold text-white/80">
|
<span className="flex items-center gap-1 font-bold text-white/80">
|
||||||
India 🇮🇳
|
India 🇮🇳
|
||||||
@@ -340,10 +339,15 @@ export function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure default export is also available for Next.js app router client components if needed
|
||||||
|
export default Footer;
|
||||||
|
|
||||||
|
|
||||||
function FooterCol({
|
function FooterCol({
|
||||||
title,
|
title,
|
||||||
links,
|
links,
|
||||||
@@ -353,15 +357,15 @@ function FooterCol({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h5 className="text-label-sm font-black text-brand-accent uppercase tracking-widest mb-6">
|
<h5 className="footer-column-title">
|
||||||
{title}
|
{title}
|
||||||
</h5>
|
</h5>
|
||||||
<ul className="space-y-3">
|
<ul className="footer-links-list">
|
||||||
{links.map((l) => (
|
{links.map((l) => (
|
||||||
<li key={l.label}>
|
<li key={l.label}>
|
||||||
<Link
|
<Link
|
||||||
href={l.href}
|
href={l.href}
|
||||||
className="text-body-sm text-white/60 hover:text-brand-accent hover:translate-x-1.5 transition-all duration-300 inline-block"
|
className="footer-link inline-block"
|
||||||
>
|
>
|
||||||
{l.label}
|
{l.label}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Reference in New Issue
Block a user