update about section
This commit is contained in:
@@ -6,6 +6,7 @@ import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
|||||||
import { AboutHero } from "@/components/heroes/AboutHero";
|
import { AboutHero } from "@/components/heroes/AboutHero";
|
||||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||||
|
import { FloatingDelivery } from "@/components/about/FloatingDelivery";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -156,8 +157,9 @@ export default function AboutPage() {
|
|||||||
|
|
||||||
{/* ─── Brand Building Banner ─── */}
|
{/* ─── Brand Building Banner ─── */}
|
||||||
<AnimatedSection>
|
<AnimatedSection>
|
||||||
<section className="py-10 md:py-14 xl:py-10 px-6 md:px-12 lg:px-16 xl:px-20 2xl:px-24 text-center bg-[#FAF7FD] mb-2 md:mb-3 xl:mb-4">
|
<section className="relative overflow-hidden py-10 md:py-14 xl:py-10 px-6 md:px-12 lg:px-16 xl:px-20 2xl:px-24 text-center bg-[#FAF7FD] mb-2 md:mb-3 xl:mb-4">
|
||||||
<div className="max-w-4xl mx-auto">
|
<FloatingDelivery />
|
||||||
|
<div className="max-w-4xl mx-auto relative z-10">
|
||||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||||
Don't miss the opportunity
|
Don't miss the opportunity
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
|||||||
import { PeopleHero } from "@/components/heroes/PeopleHero";
|
import { PeopleHero } from "@/components/heroes/PeopleHero";
|
||||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||||
|
import { siteContent } from "@/config/site-content";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -138,6 +139,10 @@ const APP_BENEFITS = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 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 default function PeoplePage() {
|
export default function PeoplePage() {
|
||||||
return (
|
return (
|
||||||
<PremiumPageShell>
|
<PremiumPageShell>
|
||||||
@@ -248,20 +253,32 @@ export default function PeoplePage() {
|
|||||||
|
|
||||||
<div className="flex flex-col gap-2 mt-8">
|
<div className="flex flex-col gap-2 mt-8">
|
||||||
<div className="flex flex-wrap gap-4">
|
<div className="flex flex-wrap gap-4">
|
||||||
<div className="group h-14 w-44 rounded-xl border border-white/10 px-4 py-2 flex items-center gap-3 bg-white/[0.06] backdrop-blur-md text-white hover:bg-white/[0.12] transition-all duration-300 shadow-md">
|
<a
|
||||||
|
href={APP_STORE_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="Download Nearle on the App Store"
|
||||||
|
className="group h-14 w-44 rounded-xl border border-white/10 px-4 py-2 flex items-center gap-3 bg-white/[0.06] backdrop-blur-md text-white hover:bg-white/[0.12] transition-all duration-300 shadow-md cursor-pointer active:scale-[0.98]"
|
||||||
|
>
|
||||||
<MaterialIcon icon="phone_iphone" size={24} className="text-brand-accent group-hover:scale-110 transition-transform" />
|
<MaterialIcon icon="phone_iphone" size={24} className="text-brand-accent group-hover:scale-110 transition-transform" />
|
||||||
<div className="text-left leading-tight">
|
<div className="text-left leading-tight">
|
||||||
<div className="text-[9px] uppercase font-black text-brand-accent/70">Available on</div>
|
<div className="text-[9px] uppercase font-black text-brand-accent/70">Available on</div>
|
||||||
<div className="text-sm font-black text-white">App Store</div>
|
<div className="text-sm font-black text-white">App Store</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
<div className="group h-14 w-44 rounded-xl border border-white/10 px-4 py-2 flex items-center gap-3 bg-white/[0.06] backdrop-blur-md text-white hover:bg-white/[0.12] transition-all duration-300 shadow-md">
|
<a
|
||||||
|
href={GOOGLE_PLAY_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="Download Nearle on Google Play"
|
||||||
|
className="group h-14 w-44 rounded-xl border border-white/10 px-4 py-2 flex items-center gap-3 bg-white/[0.06] backdrop-blur-md text-white hover:bg-white/[0.12] transition-all duration-300 shadow-md cursor-pointer active:scale-[0.98]"
|
||||||
|
>
|
||||||
<MaterialIcon icon="play_arrow" size={24} className="text-brand-accent group-hover:scale-110 transition-transform" />
|
<MaterialIcon icon="play_arrow" size={24} className="text-brand-accent group-hover:scale-110 transition-transform" />
|
||||||
<div className="text-left leading-tight">
|
<div className="text-left leading-tight">
|
||||||
<div className="text-[9px] uppercase font-black text-brand-accent/70">Available on</div>
|
<div className="text-[9px] uppercase font-black text-brand-accent/70">Available on</div>
|
||||||
<div className="text-sm font-black text-white">Google Play</div>
|
<div className="text-sm font-black text-white">Google Play</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -450,20 +467,32 @@ export default function PeoplePage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-3 mt-8 w-full max-w-[320px] justify-center">
|
<div className="flex flex-col sm:flex-row gap-3 mt-8 w-full max-w-[320px] justify-center">
|
||||||
<div className="h-12 w-full rounded-xl border border-white/10 px-4 py-2 flex items-center justify-center gap-3 bg-white/[0.06] text-white">
|
<a
|
||||||
|
href={APP_STORE_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="Download Nearle on the App Store"
|
||||||
|
className="h-12 w-full rounded-xl border border-white/10 px-4 py-2 flex items-center justify-center gap-3 bg-white/[0.06] text-white hover:bg-white/[0.12] transition-all duration-300 cursor-pointer active:scale-[0.98]"
|
||||||
|
>
|
||||||
<MaterialIcon icon="phone_iphone" size={18} className="text-brand-accent" />
|
<MaterialIcon icon="phone_iphone" size={18} className="text-brand-accent" />
|
||||||
<div className="text-left leading-none">
|
<div className="text-left leading-none">
|
||||||
<div className="text-[7.5px] uppercase font-black text-brand-accent/70">Available on</div>
|
<div className="text-[7.5px] uppercase font-black text-brand-accent/70">Available on</div>
|
||||||
<div className="text-xs font-black text-white">App Store</div>
|
<div className="text-xs font-black text-white">App Store</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
<div className="h-12 w-full rounded-xl border border-white/10 px-4 py-2 flex items-center justify-center gap-3 bg-white/[0.06] text-white">
|
<a
|
||||||
|
href={GOOGLE_PLAY_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="Download Nearle on Google Play"
|
||||||
|
className="h-12 w-full rounded-xl border border-white/10 px-4 py-2 flex items-center justify-center gap-3 bg-white/[0.06] text-white hover:bg-white/[0.12] transition-all duration-300 cursor-pointer active:scale-[0.98]"
|
||||||
|
>
|
||||||
<MaterialIcon icon="play_arrow" size={18} className="text-brand-accent" />
|
<MaterialIcon icon="play_arrow" size={18} className="text-brand-accent" />
|
||||||
<div className="text-left leading-none">
|
<div className="text-left leading-none">
|
||||||
<div className="text-[7.5px] uppercase font-black text-brand-accent/70">Available on</div>
|
<div className="text-[7.5px] uppercase font-black text-brand-accent/70">Available on</div>
|
||||||
<div className="text-xs font-black text-white">Google Play</div>
|
<div className="text-xs font-black text-white">Google Play</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
25
src/components/about/FloatingDelivery.tsx
Normal file
25
src/components/about/FloatingDelivery.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||||
import {
|
import { fadeUp, fadeUpStrong, staggerContainer } from "@/lib/animations";
|
||||||
fadeInSlow,
|
|
||||||
staggerSlow,
|
|
||||||
} from "@/lib/animations";
|
|
||||||
|
|
||||||
const HERO_STATS = [
|
const HERO_STATS = [
|
||||||
{ title: "2km Coverage", icon: "explore", desc: "Hyperlocal radius" },
|
{ 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" },
|
{ title: "Coimbatore & Beyond", icon: "location_city", desc: "Growing neighbourhood reach" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const badgeVariant = fadeInSlow;
|
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||||
const titleVariant = {
|
|
||||||
hidden: { opacity: 0, x: -30 },
|
const badgeVariant = {
|
||||||
visible: {
|
hidden: { opacity: 0, y: 10, scale: 0.95 },
|
||||||
opacity: 1,
|
visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.38, ease: EASE } },
|
||||||
x: 0,
|
|
||||||
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const titleVariant = {
|
||||||
|
hidden: { opacity: 0, y: 28 },
|
||||||
|
visible: { opacity: 1, y: 0, transition: { duration: 0.65, ease: EASE } },
|
||||||
|
};
|
||||||
|
|
||||||
const descVariant = {
|
const descVariant = {
|
||||||
hidden: { opacity: 0, y: 20 },
|
hidden: { opacity: 0, y: 18 },
|
||||||
visible: {
|
visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: EASE } },
|
||||||
opacity: 1,
|
|
||||||
y: 0,
|
|
||||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AboutHero() {
|
export function AboutHero() {
|
||||||
return (
|
return (
|
||||||
<section className="w-full flex flex-col select-none bg-white">
|
<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]">
|
<div className="relative overflow-hidden border-b border-[#6330D6]/10 bg-[#FAF8FC]">
|
||||||
|
|
||||||
|
{/* Background image — scooter anchored to the right */}
|
||||||
<Image
|
<Image
|
||||||
src="/about.png"
|
src="/about.png"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -46,45 +48,76 @@ export function AboutHero() {
|
|||||||
priority
|
priority
|
||||||
aria-hidden="true"
|
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">
|
<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
|
<motion.div
|
||||||
className="flex flex-col items-center text-center w-full max-w-[780px] relative z-20"
|
className="flex flex-col items-center text-center w-full max-w-[780px] relative z-20"
|
||||||
variants={staggerSlow}
|
variants={staggerContainer}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate="visible"
|
animate="visible"
|
||||||
>
|
>
|
||||||
|
{/* Badge */}
|
||||||
<motion.span
|
<motion.span
|
||||||
variants={badgeVariant}
|
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
|
About Nearle
|
||||||
</motion.span>
|
</motion.span>
|
||||||
|
|
||||||
|
{/* Heading */}
|
||||||
<motion.h1
|
<motion.h1
|
||||||
variants={titleVariant}
|
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)]"
|
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
|
Built for Every
|
||||||
<br />
|
<br />
|
||||||
<span className="text-white">Neighbourhood.</span>
|
<span className="text-[#C4B5FD]">Neighbourhood.</span>
|
||||||
</motion.h1>
|
</motion.h1>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
<motion.p
|
<motion.p
|
||||||
variants={descVariant}
|
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's first hyper-local managed “Neighbourhood living platform” which brings all the amenities and requirements of residents to their fingertips.
|
Nearle is India's first hyper-local managed “Neighbourhood living platform” which brings all the amenities and requirements of residents to their fingertips.
|
||||||
</motion.p>
|
</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>
|
</motion.div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* ─── Stats Row ─── */}
|
||||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||||
<div className="px-6 sm:px-10 max-w-[1600px] mx-auto">
|
<div className="px-6 sm:px-10 max-w-[1600px] mx-auto">
|
||||||
<FeatureStatsRow items={HERO_STATS} />
|
<FeatureStatsRow items={HERO_STATS} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,8 @@ export function BusinessSection() {
|
|||||||
<motion.article
|
<motion.article
|
||||||
key={feature.title}
|
key={feature.title}
|
||||||
variants={fadeUp}
|
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="p-5">
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
@@ -244,7 +245,7 @@ export function BusinessSection() {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-black text-brand-dark">{b.title}</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>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { motion } from "framer-motion";
|
import { motion, useReducedMotion } from "framer-motion";
|
||||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
import { viewport } from "@/lib/animations";
|
import { viewport } from "@/lib/animations";
|
||||||
|
|
||||||
@@ -53,18 +53,27 @@ const statItem = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function Hero() {
|
export function Hero() {
|
||||||
|
const shouldReduce = useReducedMotion();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="bg-white select-none w-full">
|
<section className="bg-white select-none w-full">
|
||||||
<div className="relative overflow-hidden bg-[#FAF8FC]">
|
<div className="relative overflow-hidden bg-[#FAF8FC]">
|
||||||
<Image
|
<motion.div
|
||||||
src="/images/home1.png"
|
className="absolute inset-0 z-0"
|
||||||
alt=""
|
initial={{ scale: 1 }}
|
||||||
fill
|
animate={shouldReduce ? undefined : { scale: 1.06 }}
|
||||||
sizes="100vw"
|
transition={{ duration: 28, ease: "linear", repeat: Infinity, repeatType: "reverse" }}
|
||||||
className="absolute inset-0 z-0 h-full w-full object-cover object-[62%_center] md:object-[58%_center] xl:object-center"
|
>
|
||||||
priority
|
<Image
|
||||||
aria-hidden="true"
|
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="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]">
|
<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]">
|
||||||
|
|||||||
@@ -328,7 +328,8 @@ export function HowItWorks() {
|
|||||||
<motion.article
|
<motion.article
|
||||||
key={step.num}
|
key={step.num}
|
||||||
variants={fadeUp}
|
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]">
|
<span className="absolute right-5 top-4 font-display text-6xl font-black leading-none text-primary/[0.07]">
|
||||||
{step.num}
|
{step.num}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||||
|
import { siteContent } from "@/config/site-content";
|
||||||
import { fadeUp, scaleIn, slideInRight, staggerContainer, viewport } from "@/lib/animations";
|
import { fadeUp, scaleIn, slideInRight, staggerContainer, viewport } from "@/lib/animations";
|
||||||
|
|
||||||
const FLOW_STEPS = [
|
const FLOW_STEPS = [
|
||||||
@@ -11,6 +12,10 @@ const FLOW_STEPS = [
|
|||||||
{ label: "Order Anytime", icon: "shopping_bag" },
|
{ 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() {
|
export function StoreQRSection() {
|
||||||
return (
|
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">
|
<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>
|
</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="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">
|
<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" />
|
<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>
|
</svg>
|
||||||
@@ -85,9 +95,15 @@ export function StoreQRSection() {
|
|||||||
Available on
|
Available on
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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" />
|
<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>
|
</svg>
|
||||||
@@ -99,7 +115,7 @@ export function StoreQRSection() {
|
|||||||
Available on
|
Available on
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
@@ -238,9 +254,14 @@ export function StoreQRSection() {
|
|||||||
/>
|
/>
|
||||||
</motion.div>
|
</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="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">
|
<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" />
|
<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>
|
</svg>
|
||||||
@@ -252,9 +273,15 @@ export function StoreQRSection() {
|
|||||||
Available on
|
Available on
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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" />
|
<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>
|
</svg>
|
||||||
@@ -266,7 +293,7 @@ export function StoreQRSection() {
|
|||||||
Available on
|
Available on
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user