update about section

This commit is contained in:
2026-06-30 18:19:05 +05:30
parent 61ab517a21
commit f3f74cf47c
8 changed files with 182 additions and 55 deletions

View File

@@ -0,0 +1,25 @@
"use client";
import Image from "next/image";
import { motion, useReducedMotion } from "framer-motion";
export function FloatingDelivery() {
const shouldReduce = useReducedMotion();
return (
<motion.div
className="pointer-events-none select-none absolute right-[4%] xl:right-[8%] top-1/2 -translate-y-1/2 hidden lg:block w-[180px] xl:w-[220px] z-0"
animate={shouldReduce ? undefined : { y: [0, -8, 0] }}
transition={{ duration: 6, ease: "easeInOut", repeat: Infinity }}
>
<Image
src="/images/nearle-redesign/delivery-doorstep.webp"
alt=""
width={220}
height={220}
className="w-full h-auto object-contain opacity-80"
aria-hidden="true"
/>
</motion.div>
);
}

View File

@@ -1,12 +1,11 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { motion } from "framer-motion";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
import {
fadeInSlow,
staggerSlow,
} from "@/lib/animations";
import { fadeUp, fadeUpStrong, staggerContainer } from "@/lib/animations";
const HERO_STATS = [
{ title: "2km Coverage", icon: "explore", desc: "Hyperlocal radius" },
@@ -15,28 +14,31 @@ const HERO_STATS = [
{ title: "Coimbatore & Beyond", icon: "location_city", desc: "Growing neighbourhood reach" },
];
const badgeVariant = fadeInSlow;
const titleVariant = {
hidden: { opacity: 0, x: -30 },
visible: {
opacity: 1,
x: 0,
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
},
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
const badgeVariant = {
hidden: { opacity: 0, y: 10, scale: 0.95 },
visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.38, ease: EASE } },
};
const titleVariant = {
hidden: { opacity: 0, y: 28 },
visible: { opacity: 1, y: 0, transition: { duration: 0.65, ease: EASE } },
};
const descVariant = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
},
hidden: { opacity: 0, y: 18 },
visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: EASE } },
};
export function AboutHero() {
return (
<section className="w-full flex flex-col select-none bg-white">
{/* ─── Hero Banner ─── */}
<div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
{/* Background image — scooter anchored to the right */}
<Image
src="/about.png"
alt=""
@@ -46,45 +48,76 @@ export function AboutHero() {
priority
aria-hidden="true"
/>
{/* Gradient overlay — dark-purple toned to preserve the purple scene and protect white text */}
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(23,5,31,0.72)_0%,rgba(23,5,31,0.52)_30%,rgba(23,5,31,0.22)_62%,rgba(23,5,31,0.06)_100%)] md:bg-[radial-gradient(ellipse_72%_88%_at_50%_42%,rgba(23,5,31,0.65)_0%,rgba(23,5,31,0.42)_38%,rgba(23,5,31,0.16)_65%,rgba(23,5,31,0.02)_100%)]" />
{/* Content */}
<div className="relative z-10 flex min-h-[560px] items-center justify-center px-6 pt-20 pb-10 sm:min-h-[580px] sm:px-8 sm:pt-24 md:min-h-[610px] md:px-12 md:py-20 lg:min-h-[650px] lg:px-16 lg:py-24 xl:min-h-[680px] max-w-[1600px] mx-auto">
<motion.div
className="flex flex-col items-center text-center w-full max-w-[780px] relative z-20"
variants={staggerSlow}
variants={staggerContainer}
initial="hidden"
animate="visible"
>
{/* Badge */}
<motion.span
variants={badgeVariant}
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-white/15 backdrop-blur-[8px] border border-white/20 text-white uppercase mb-6 w-fit [text-shadow:0_2px_6px_rgba(0,0,0,0.35),0_8px_24px_rgba(0,0,0,0.25)]"
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-white/15 backdrop-blur-[8px] border border-white/20 text-white uppercase mb-6 w-fit"
>
About Nearle
</motion.span>
{/* Heading */}
<motion.h1
variants={titleVariant}
className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-white leading-[1.1] tracking-tight [text-shadow:0_2px_6px_rgba(0,0,0,0.35),0_8px_24px_rgba(0,0,0,0.25)]"
>
Built for Every
<br />
<span className="text-white">Neighbourhood.</span>
<span className="text-[#C4B5FD]">Neighbourhood.</span>
</motion.h1>
{/* Description */}
<motion.p
variants={descVariant}
className="text-sm md:text-base font-bold mt-6 leading-[1.75] text-white/96 [text-shadow:0_1px_4px_rgba(0,0,0,0.45)]"
className="mt-6 max-w-[560px] text-sm font-semibold leading-[1.75] text-white/85 md:text-base [text-shadow:0_1px_4px_rgba(0,0,0,0.45)]"
>
Nearle is India&apos;s first hyper-local managed &ldquo;Neighbourhood living platform&rdquo; which brings all the amenities and requirements of residents to their fingertips.
</motion.p>
{/* CTA Buttons */}
<motion.div
variants={descVariant}
className="mt-8 flex flex-wrap justify-center gap-3"
>
<Link
href="/businesses"
className="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full bg-white px-7 py-3.5 text-base font-black text-[#6330D6] shadow-sm transition-all duration-200 hover:bg-white/90 hover:shadow-lg hover:-translate-y-0.5 active:translate-y-0 active:scale-95"
>
Partner with Nearle
<MaterialIcon icon="arrow_forward" size={18} />
</Link>
<Link
href="/people"
className="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full border border-white/30 bg-white/10 px-7 py-3.5 text-base font-black text-white backdrop-blur-[6px] transition-all duration-200 hover:bg-white/18 hover:border-white/45 hover:-translate-y-0.5 active:translate-y-0 active:scale-95"
>
Explore Nearle
</Link>
</motion.div>
</motion.div>
</div>
</div>
{/* ─── Stats Row ─── */}
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
<div className="px-6 sm:px-10 max-w-[1600px] mx-auto">
<FeatureStatsRow items={HERO_STATS} />
</div>
</div>
</section>
);
}

View File

@@ -162,7 +162,8 @@ export function BusinessSection() {
<motion.article
key={feature.title}
variants={fadeUp}
className="merchant-feature-card flex min-w-0 flex-col overflow-hidden rounded-[1.5rem] border border-primary/10 bg-white shadow-[0_4px_24px_rgba(22,0,29,0.07)]"
whileHover={{ y: -6, transition: { duration: 0.22, ease: [0.22, 1, 0.36, 1] } }}
className="merchant-feature-card flex min-w-0 flex-col overflow-hidden rounded-[1.5rem] border border-primary/10 bg-white shadow-[0_4px_24px_rgba(22,0,29,0.07)] hover:shadow-[0_16px_40px_rgba(22,0,29,0.12)] hover:border-primary/20 transition-[box-shadow,border-color] duration-[250ms]"
>
<div className="p-5">
<div className="flex items-start gap-3">
@@ -244,7 +245,7 @@ export function BusinessSection() {
</div>
<div>
<div className="text-sm font-black text-brand-dark">{b.title}</div>
<div className="mt-0.5 text-xs leading-relaxed text-on-surface-variant">{b.desc}</div>
<div className="mt-0.5 text-sm leading-relaxed text-on-surface-variant">{b.desc}</div>
</div>
</motion.div>
))}

View File

@@ -2,7 +2,7 @@
import { Fragment } from "react";
import Image from "next/image";
import { motion } from "framer-motion";
import { motion, useReducedMotion } from "framer-motion";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
import { viewport } from "@/lib/animations";
@@ -53,18 +53,27 @@ const statItem = {
};
export function Hero() {
const shouldReduce = useReducedMotion();
return (
<section className="bg-white select-none w-full">
<div className="relative overflow-hidden bg-[#FAF8FC]">
<Image
src="/images/home1.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 z-0 h-full w-full object-cover object-[62%_center] md:object-[58%_center] xl:object-center"
priority
aria-hidden="true"
/>
<motion.div
className="absolute inset-0 z-0"
initial={{ scale: 1 }}
animate={shouldReduce ? undefined : { scale: 1.06 }}
transition={{ duration: 28, ease: "linear", repeat: Infinity, repeatType: "reverse" }}
>
<Image
src="/images/home1.png"
alt=""
fill
sizes="100vw"
className="absolute inset-0 h-full w-full object-cover object-[62%_center] md:object-[58%_center] xl:object-center"
priority
aria-hidden="true"
/>
</motion.div>
<div className="absolute inset-0 z-[1] bg-[linear-gradient(180deg,rgba(250,248,252,0.85)_0%,rgba(250,248,252,0.68)_28%,rgba(250,248,252,0.38)_58%,rgba(250,248,252,0.10)_100%)] md:bg-[radial-gradient(ellipse_72%_88%_at_50%_42%,rgba(250,248,252,0.72)_0%,rgba(250,248,252,0.50)_38%,rgba(250,248,252,0.18)_65%,rgba(250,248,252,0.04)_100%)]" />
<div className="page-container relative z-10 flex min-h-[560px] items-center justify-center px-6 pt-20 pb-10 sm:min-h-[580px] sm:px-8 sm:pt-24 md:min-h-[610px] md:py-20 lg:min-h-[650px] lg:py-24 xl:min-h-[680px]">

View File

@@ -328,7 +328,8 @@ export function HowItWorks() {
<motion.article
key={step.num}
variants={fadeUp}
className="relative flex min-h-[380px] min-w-0 flex-col overflow-hidden rounded-3xl border border-primary/10 bg-white p-7 shadow-[0_18px_45px_rgba(22,0,29,0.08)] md:min-h-[420px] lg:min-h-[460px] xl:min-h-[420px] lg:p-8"
whileHover={{ y: -6, transition: { duration: 0.22, ease: [0.22, 1, 0.36, 1] } }}
className="relative flex min-h-[380px] min-w-0 flex-col overflow-hidden rounded-3xl border border-primary/10 bg-white p-7 shadow-[0_18px_45px_rgba(22,0,29,0.08)] hover:shadow-[0_24px_60px_rgba(22,0,29,0.14)] hover:border-primary/20 transition-[box-shadow,border-color] duration-[250ms] md:min-h-[420px] lg:min-h-[460px] xl:min-h-[420px] lg:p-8"
>
<span className="absolute right-5 top-4 font-display text-6xl font-black leading-none text-primary/[0.07]">
{step.num}

View File

@@ -3,6 +3,7 @@
import Image from "next/image";
import { motion } from "framer-motion";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
import { siteContent } from "@/config/site-content";
import { fadeUp, scaleIn, slideInRight, staggerContainer, viewport } from "@/lib/animations";
const FLOW_STEPS = [
@@ -11,6 +12,10 @@ const FLOW_STEPS = [
{ label: "Order Anytime", icon: "shopping_bag" },
];
// TODO: Replace fallback hrefs once the app is confirmed live on both stores.
const APP_STORE_URL = siteContent.app.iosUrl || "about:blank#todo-app-store-url";
const GOOGLE_PLAY_URL = siteContent.app.androidUrl || "about:blank#todo-google-play-url";
export function StoreQRSection() {
return (
<section className="mb-2 bg-white w-full px-2 pt-2 md:mb-3 md:px-3 md:pt-3 lg:mb-4 lg:px-4 lg:pt-4 xl:mb-4 xl:px-5 xl:pt-4 2xl:mb-4 2xl:px-6">
@@ -71,9 +76,14 @@ export function StoreQRSection() {
))}
</div>
{/* TODO: Replace with real app store URLs once app is confirmed live (siteContent.app.iosUrl / androidUrl) */}
<div className="flex flex-wrap gap-4">
<div className="h-[60px] border border-white/20 rounded-2xl bg-white/10 text-white/60 px-8 py-2 flex items-center gap-3.5 shrink-0 cursor-not-allowed select-none">
<a
href={APP_STORE_URL}
target="_blank"
rel="noopener noreferrer"
aria-label="Download Nearle on the App Store"
className="h-[60px] border border-white/20 rounded-2xl bg-white/10 text-white/60 px-8 py-2 flex items-center gap-3.5 shrink-0 cursor-pointer select-none hover:bg-white/[0.16] transition-all duration-300 active:scale-[0.98]"
>
<svg viewBox="0 0 24 24" className="w-7 h-7 shrink-0 fill-current opacity-60" fill="currentColor">
<path d="M17.537 12.625c-.023-2.949 2.398-4.37 2.506-4.44-1.364-2.008-3.48-2.282-4.227-2.307-1.79-.186-3.504 1.064-4.413 1.064-.918 0-2.323-1.04-3.827-1.01-1.963.028-3.788 1.146-4.796 2.91-2.06 3.587-.526 8.9 1.466 11.808.98 1.428 2.147 3.035 3.685 2.975 1.47-.059 2.03-.964 3.807-.964 1.767 0 2.266.964 3.818.932 1.58-.03 2.58-1.453 3.536-2.89 1.116-1.628 1.57-3.21 1.596-3.29-.035-.016-3.057-1.18-3.087-4.678l.036-.002zM14.87 4.058c.821-.99 1.375-2.361 1.223-3.733-1.184.05-2.618.784-3.47 1.77-.762.875-1.43 2.28-1.25 3.623 1.327.102 2.673-.668 3.497-1.66z" />
</svg>
@@ -85,9 +95,15 @@ export function StoreQRSection() {
Available on
</div>
</div>
</div>
</a>
<div className="h-[60px] border border-white/20 rounded-2xl bg-white/10 text-white/60 px-8 py-2 flex items-center gap-3.5 shrink-0 cursor-not-allowed select-none">
<a
href={GOOGLE_PLAY_URL}
target="_blank"
rel="noopener noreferrer"
aria-label="Download Nearle on Google Play"
className="h-[60px] border border-white/20 rounded-2xl bg-white/10 text-white/60 px-8 py-2 flex items-center gap-3.5 shrink-0 cursor-pointer select-none hover:bg-white/[0.16] transition-all duration-300 active:scale-[0.98]"
>
<svg viewBox="0 0 24 24" className="w-7 h-7 shrink-0 fill-current opacity-60" fill="currentColor">
<path d="M3.609 1.814L13.414 12 3.609 22.186c-.244-.178-.395-.466-.395-.786V2.6c0-.32.151-.608.395-.786zM14.244 12.83l2.705 2.688-4.073 2.276-4.073 2.276L14.244 12.83zm1-1.66l2.838-2.8 4.153 2.336c.464.26.464.688 0 .948l-4.153 2.336-2.838-2.82zM8.803 4.93l4.073 2.276 4.073 2.276-2.705 2.688L8.803 4.93z" />
</svg>
@@ -99,7 +115,7 @@ export function StoreQRSection() {
Available on
</div>
</div>
</div>
</a>
</div>
</motion.div>
@@ -238,9 +254,14 @@ export function StoreQRSection() {
/>
</motion.div>
{/* 5. App store buttons — TODO: replace with real URLs once app is live */}
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<div className="h-14 w-60 sm:w-auto border border-white/20 rounded-2xl bg-white/10 text-white/60 px-6 py-2 flex items-center justify-center gap-3 cursor-not-allowed select-none">
<a
href={APP_STORE_URL}
target="_blank"
rel="noopener noreferrer"
aria-label="Download Nearle on the App Store"
className="h-14 w-60 sm:w-auto border border-white/20 rounded-2xl bg-white/10 text-white/60 px-6 py-2 flex items-center justify-center gap-3 cursor-pointer select-none hover:bg-white/[0.16] transition-all duration-300 active:scale-[0.98]"
>
<svg viewBox="0 0 24 24" className="w-6 h-6 shrink-0 fill-current opacity-60" fill="currentColor">
<path d="M17.537 12.625c-.023-2.949 2.398-4.37 2.506-4.44-1.364-2.008-3.48-2.282-4.227-2.307-1.79-.186-3.504 1.064-4.413 1.064-.918 0-2.323-1.04-3.827-1.01-1.963.028-3.788 1.146-4.796 2.91-2.06 3.587-.526 8.9 1.466 11.808.98 1.428 2.147 3.035 3.685 2.975 1.47-.059 2.03-.964 3.807-.964 1.767 0 2.266.964 3.818.932 1.58-.03 2.58-1.453 3.536-2.89 1.116-1.628 1.57-3.21 1.596-3.29-.035-.016-3.057-1.18-3.087-4.678l.036-.002zM14.87 4.058c.821-.99 1.375-2.361 1.223-3.733-1.184.05-2.618.784-3.47 1.77-.762.875-1.43 2.28-1.25 3.623 1.327.102 2.673-.668 3.497-1.66z" />
</svg>
@@ -252,9 +273,15 @@ export function StoreQRSection() {
Available on
</div>
</div>
</div>
</a>
<div className="h-14 w-60 sm:w-auto border border-white/20 rounded-2xl bg-white/10 text-white/60 px-6 py-2 flex items-center justify-center gap-3 cursor-not-allowed select-none">
<a
href={GOOGLE_PLAY_URL}
target="_blank"
rel="noopener noreferrer"
aria-label="Download Nearle on Google Play"
className="h-14 w-60 sm:w-auto border border-white/20 rounded-2xl bg-white/10 text-white/60 px-6 py-2 flex items-center justify-center gap-3 cursor-pointer select-none hover:bg-white/[0.16] transition-all duration-300 active:scale-[0.98]"
>
<svg viewBox="0 0 24 24" className="w-6 h-6 shrink-0 fill-current opacity-60" fill="currentColor">
<path d="M3.609 1.814L13.414 12 3.609 22.186c-.244-.178-.395-.466-.395-.786V2.6c0-.32.151-.608.395-.786zM14.244 12.83l2.705 2.688-4.073 2.276-4.073 2.276L14.244 12.83zm1-1.66l2.838-2.8 4.153 2.336c.464.26.464.688 0 .948l-4.153 2.336-2.838-2.82zM8.803 4.93l4.073 2.276 4.073 2.276-2.705 2.688L8.803 4.93z" />
</svg>
@@ -266,7 +293,7 @@ export function StoreQRSection() {
Available on
</div>
</div>
</div>
</a>
</div>
</div>