animation fixed in section
This commit is contained in:
225
AGENTS.md
225
AGENTS.md
@@ -1,13 +1,216 @@
|
||||
# Nearle Project Guide
|
||||
|
||||
# This is NOT the Next.js you know
|
||||
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
|
||||
# STRICT PROJECT-WIDE EXECUTION RULES (TOKEN SAVER)
|
||||
Whenever you are assigned ANY task (bug fix, new feature, UI update, backend logic, etc.), you MUST follow these constraints strictly to prevent infinite loops and save compute resources:
|
||||
## Project
|
||||
|
||||
1. For frontend UI, layout, responsive, styling, or screenshot-reference tasks, you MAY start the Next.js local development server using `npm run dev`.
|
||||
2. For those frontend visual tasks, you MAY open and inspect `http://localhost:3000` locally.
|
||||
3. For those frontend visual tasks, you MAY capture local screenshots for before/after comparison.
|
||||
4. `npm run build` verifies compilation only. Do not claim a visual issue is fixed based only on build success.
|
||||
5. For visual tasks, inspect localhost before reporting completion.
|
||||
6. Provide the exact code fix, logic, or file modification directly based on your analysis of the provided files.
|
||||
7. For frontend UI, layout, responsive, styling, and screenshot-reference tasks, the agent must inspect localhost before reporting completion. Screenshots are required only for major layout changes, responsive/mobile changes, hero/footer changes, or when explicitly requested by the user. For small isolated CSS spacing fixes, screenshots are optional. The human developer gives final approval only.
|
||||
Nearle is a premium hyperlocal commerce platform connecting
|
||||
|
||||
- Customers
|
||||
- Local Merchants
|
||||
- Delivery Partners
|
||||
- Brands
|
||||
|
||||
The experience should feel:
|
||||
|
||||
- Premium
|
||||
- Modern
|
||||
- Minimal
|
||||
- Community-first
|
||||
- Human
|
||||
- Trustworthy
|
||||
|
||||
Avoid generic SaaS designs.
|
||||
|
||||
---
|
||||
|
||||
# Tech Stack
|
||||
|
||||
- Next.js 16 App Router
|
||||
- React
|
||||
- TypeScript
|
||||
- Tailwind CSS
|
||||
- MaterialIcon component
|
||||
|
||||
IMPORTANT
|
||||
|
||||
This project uses the latest Next.js version.
|
||||
|
||||
Before changing framework APIs, read
|
||||
|
||||
node_modules/next/dist/docs/
|
||||
|
||||
Follow the latest conventions.
|
||||
|
||||
---
|
||||
|
||||
# Design System
|
||||
|
||||
Preserve the existing Nearle identity.
|
||||
|
||||
Never change unless explicitly requested:
|
||||
|
||||
- Brand colors
|
||||
- Typography
|
||||
- Border radius
|
||||
- Layout hierarchy
|
||||
- Section order
|
||||
- Existing content
|
||||
- Existing illustrations
|
||||
|
||||
Always extend the current design instead of redesigning it.
|
||||
|
||||
---
|
||||
|
||||
# UI Rules
|
||||
|
||||
Always match existing Nearle pages.
|
||||
|
||||
Reuse:
|
||||
|
||||
- Hero layouts
|
||||
- CTA buttons
|
||||
- Card styles
|
||||
- Section spacing
|
||||
- Grid system
|
||||
- Shadows
|
||||
- Glass effects
|
||||
- Gradients
|
||||
|
||||
Avoid Bootstrap-style layouts.
|
||||
|
||||
---
|
||||
|
||||
# Motion Rules
|
||||
|
||||
Use:
|
||||
|
||||
- Framer Motion
|
||||
- CSS transitions
|
||||
|
||||
Avoid:
|
||||
|
||||
- Heavy GSAP
|
||||
- Layout animations
|
||||
- Flashy effects
|
||||
|
||||
Animation style:
|
||||
|
||||
- Apple
|
||||
- Linear
|
||||
- Stripe
|
||||
- Vercel
|
||||
|
||||
Use only:
|
||||
|
||||
- opacity
|
||||
- transform
|
||||
- scale
|
||||
- translate
|
||||
|
||||
Respect prefers-reduced-motion.
|
||||
|
||||
---
|
||||
|
||||
# Code Rules
|
||||
|
||||
Never rewrite files unnecessarily.
|
||||
|
||||
Only modify required code.
|
||||
|
||||
Preserve formatting.
|
||||
|
||||
Do not rename components unless necessary.
|
||||
|
||||
Reuse existing components before creating new ones.
|
||||
|
||||
Create reusable components when repeated more than twice.
|
||||
|
||||
---
|
||||
|
||||
# Performance
|
||||
|
||||
Maintain 60 FPS.
|
||||
|
||||
Avoid unnecessary re-renders.
|
||||
|
||||
Avoid layout shift.
|
||||
|
||||
Prefer GPU-friendly animations.
|
||||
|
||||
Optimize images.
|
||||
|
||||
---
|
||||
|
||||
# SEO
|
||||
|
||||
Every new page should include:
|
||||
|
||||
- Metadata
|
||||
- Title
|
||||
- Description
|
||||
- OpenGraph
|
||||
- Semantic HTML
|
||||
|
||||
---
|
||||
|
||||
# Content Rules
|
||||
|
||||
Write content specifically for Nearle.
|
||||
|
||||
Tone:
|
||||
|
||||
- Friendly
|
||||
- Premium
|
||||
- Community-first
|
||||
- Local
|
||||
- Trustworthy
|
||||
|
||||
Avoid AI-sounding or generic marketing copy.
|
||||
|
||||
Prefer real examples involving:
|
||||
|
||||
- neighbourhood stores
|
||||
- customers
|
||||
- delivery partners
|
||||
- local commerce
|
||||
- digital catalogues
|
||||
- QR ordering
|
||||
|
||||
---
|
||||
|
||||
# Execution Rules
|
||||
|
||||
Frontend Tasks
|
||||
|
||||
- You MAY run npm run dev.
|
||||
- Inspect localhost before reporting visual fixes.
|
||||
- Use screenshots only for major UI changes.
|
||||
|
||||
Build
|
||||
|
||||
- npm run build only verifies compilation.
|
||||
- Never claim visual fixes based only on build success.
|
||||
|
||||
---
|
||||
|
||||
# Workflow
|
||||
|
||||
Before editing
|
||||
|
||||
1. Read the target file.
|
||||
2. Understand existing implementation.
|
||||
3. Modify only the required code.
|
||||
4. Avoid unrelated refactoring.
|
||||
5. Keep code production ready.
|
||||
6. Return concise summaries.
|
||||
|
||||
---
|
||||
|
||||
# Response Rules
|
||||
|
||||
Do not explain obvious code.
|
||||
|
||||
Do not rewrite unchanged code.
|
||||
|
||||
Do not introduce unnecessary abstractions.
|
||||
|
||||
Focus only on the requested task.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 954 KiB After Width: | Height: | Size: 755 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 657 KiB After Width: | Height: | Size: 509 KiB |
@@ -3,8 +3,9 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import { AboutHero } from "@/components/heroes/AboutHero";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -48,93 +49,27 @@ const LOCAL_COUNTERS = [
|
||||
{ count: "Growing", label: "Neighbourhood Reach", icon: "location_city" }
|
||||
];
|
||||
|
||||
const HERO_STATS = [
|
||||
{ title: "2km Coverage", icon: "explore", desc: "Hyperlocal radius" },
|
||||
{ title: "Verified Local Stores", icon: "store", desc: "Growing local commerce" },
|
||||
{ title: "Happy Customers", icon: "mood", desc: "Neighbourhood community" },
|
||||
{ title: "Coimbatore & Beyond", icon: "location_city", desc: "Growing neighbourhood reach" }
|
||||
];
|
||||
|
||||
export default function AboutPage() {
|
||||
const collageCards = [
|
||||
{ text: "Local First", icon: "store" },
|
||||
{ text: "Trusted Network", icon: "verified" },
|
||||
{ text: "Connected Communities", icon: "groups" }
|
||||
];
|
||||
|
||||
return (
|
||||
<PremiumPageShell>
|
||||
{/* ─── Hero Section ─── */}
|
||||
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]">
|
||||
{/* TWO-COLUMN GRID */}
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Left Column: Copy & Actions */}
|
||||
<div className="flex flex-col text-left max-w-xl">
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit">
|
||||
About Nearle
|
||||
</span>
|
||||
|
||||
<h1 className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight">
|
||||
Built for Every
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Neighbourhood.</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed">
|
||||
Nearle is India's first hyper-local managed “Neighbourhood living platform” which brings all the amenities and requirements of residents to their fingertips.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto">
|
||||
<a
|
||||
href="#story-section"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
>
|
||||
Our Story
|
||||
</a>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
|
||||
>
|
||||
Join Our Journey
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Visual Collage */}
|
||||
<div className="w-full">
|
||||
<HeroVisualCollage
|
||||
centerImage="/nearlenewlogo.png"
|
||||
leftImage="/Nearle Business.png"
|
||||
rightImage="/nearle people.png"
|
||||
glassCards={collageCards}
|
||||
isPhoneCenter={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* BOTTOM HERO STATS */}
|
||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto">
|
||||
<FeatureStatsRow items={HERO_STATS} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<AboutHero />
|
||||
|
||||
{/* ─── Intro Description Block ─── */}
|
||||
<section id="story-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-white border-b border-[#6330D6]/10">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Our Platform
|
||||
</span>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-black text-[#16001D] mt-4 mb-4">
|
||||
Nearle Neighbourhood Commerce
|
||||
</h2>
|
||||
<p className="mx-auto max-w-3xl text-sm md:text-base text-[#5E5866] leading-relaxed font-semibold">
|
||||
We are redefining modern urban living by providing never before convenience. By linking local physical stores to an integrated digital framework, Nearle boosts merchant sales and delivers products instantly, fostering closer, cleaner, and faster local economies.
|
||||
</p>
|
||||
</section>
|
||||
<AnimatedSection>
|
||||
<section id="story-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-white border-b border-[#6330D6]/10">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Our Platform
|
||||
</span>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-black text-[#16001D] mt-4 mb-4">
|
||||
Nearle Neighbourhood Commerce
|
||||
</h2>
|
||||
<p className="mx-auto max-w-3xl text-sm md:text-base text-[#5E5866] leading-relaxed font-semibold">
|
||||
We are redefining modern urban living by providing never before convenience. By linking local physical stores to an integrated digital framework, Nearle boosts merchant sales and delivers products instantly, fostering closer, cleaner, and faster local economies.
|
||||
</p>
|
||||
</section>
|
||||
</AnimatedSection>
|
||||
|
||||
{/* ─── Strategy Cards (Mission, Vision, Why) ─── */}
|
||||
<section
|
||||
@@ -145,12 +80,12 @@ export default function AboutPage() {
|
||||
className="mx-auto w-[calc(100%-48px)] md:w-[calc(100%-64px)] xl:w-[calc(100%-96px)]"
|
||||
style={{ maxWidth: 1800 }}
|
||||
>
|
||||
<div
|
||||
<AnimatedGrid
|
||||
className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3"
|
||||
style={{ gap: "clamp(24px, 2.5vw, 36px)" }}
|
||||
>
|
||||
{STRATEGY_CARDS.map((card) => (
|
||||
<div
|
||||
<AnimatedCard
|
||||
key={card.title}
|
||||
className="bg-white border border-[#6330D6]/[0.10] shadow-[0_4px_28px_rgba(99,48,214,0.07)] flex flex-col overflow-hidden min-h-[480px] md:min-h-[520px] xl:min-h-[540px] 2xl:min-h-[560px]"
|
||||
style={{ borderRadius: 32 }}
|
||||
@@ -196,17 +131,17 @@ export default function AboutPage() {
|
||||
className={card.imgFit}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─── Global Stats counters ─── */}
|
||||
<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-white border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<AnimatedGrid className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{LOCAL_COUNTERS.map((c) => (
|
||||
<div key={c.label} className="flex flex-col items-center text-center">
|
||||
<AnimatedCard key={c.label} className="flex flex-col items-center text-center">
|
||||
<div className="w-12 h-12 rounded-full bg-[#6330D6]/5 text-[#6330D6] flex items-center justify-center mb-4">
|
||||
<MaterialIcon icon={c.icon} size={22} />
|
||||
</div>
|
||||
@@ -214,41 +149,43 @@ export default function AboutPage() {
|
||||
<p className="text-[10px] font-bold text-[#5E5866] mt-1.5 uppercase tracking-wider">
|
||||
{c.label}
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</section>
|
||||
|
||||
{/* ─── Brand Building Banner ─── */}
|
||||
<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">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<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
|
||||
</span>
|
||||
<h2 className="font-display text-3xl font-black text-[#16001D] mt-4 mb-4">
|
||||
Build Your Brand with Nearle
|
||||
</h2>
|
||||
<p className="text-xs md:text-sm text-[#5E5866] max-w-2xl mx-auto mb-8 leading-relaxed font-semibold">
|
||||
Delight your neighborhood with a personalized online experience. Unlock revenue opportunities and local marketing strategies that will take your business further.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
<Link
|
||||
href="/businesses"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-lg transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="bolt" size={18} />
|
||||
<span>Register Merchant</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/people"
|
||||
className="bg-white hover:bg-white/95 border border-[#6330D6]/10 text-[#16001D] font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="download" size={18} />
|
||||
<span>Explore Nearle</span>
|
||||
</Link>
|
||||
<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">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<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
|
||||
</span>
|
||||
<h2 className="font-display text-3xl font-black text-[#16001D] mt-4 mb-4">
|
||||
Build Your Brand with Nearle
|
||||
</h2>
|
||||
<p className="text-xs md:text-sm text-[#5E5866] max-w-2xl mx-auto mb-8 leading-relaxed font-semibold">
|
||||
Delight your neighborhood with a personalized online experience. Unlock revenue opportunities and local marketing strategies that will take your business further.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
<Link
|
||||
href="/businesses"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-lg transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="bolt" size={18} />
|
||||
<span>Register Merchant</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/people"
|
||||
className="bg-white hover:bg-white/95 border border-[#6330D6]/10 text-[#16001D] font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="download" size={18} />
|
||||
<span>Explore Nearle</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</AnimatedSection>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import { FAQAccordion } from "@/components/ui/FAQAccordion";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||
import { CTABanner } from "@/components/ui/CTABanner";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -215,21 +218,23 @@ export default function BrandsPage() {
|
||||
{/* ─── What We Offer ─── */}
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
What Nearle Offers Brands
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
The Full Stack of Neighbourhood Commerce
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
From your first store listing to city-wide distribution — Nearle builds the infrastructure so you can focus on your product.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
What Nearle Offers Brands
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
The Full Stack of Neighbourhood Commerce
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
From your first store listing to city-wide distribution — Nearle builds the infrastructure so you can focus on your product.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<AnimatedGrid className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{WHAT_WE_OFFER.map((item) => (
|
||||
<div
|
||||
<AnimatedCard
|
||||
key={item.title}
|
||||
className="rounded-[28px] border border-[#6330D6]/10 bg-[#FAF7FD] p-7 flex flex-col gap-4 hover:shadow-[0_10px_32px_rgba(22,0,29,0.09)] transition-shadow duration-300"
|
||||
>
|
||||
@@ -245,30 +250,32 @@ export default function BrandsPage() {
|
||||
<h3 className="text-base font-black text-[#16001D] leading-tight mb-2">{item.title}</h3>
|
||||
<p className="text-sm text-[#5E5866] leading-relaxed">{item.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─── Industries ─── */}
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10">
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||
Industries We Serve
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
Your Category Has a Place on Nearle
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Nearle's neighbourhood store network stocks a wide range of everyday product categories. If customers buy it daily, it belongs here.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10">
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||
Industries We Serve
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
Your Category Has a Place on Nearle
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Nearle's neighbourhood store network stocks a wide range of everyday product categories. If customers buy it daily, it belongs here.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-9 gap-4">
|
||||
<AnimatedGrid className="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-9 gap-4">
|
||||
{INDUSTRIES.map((industry) => (
|
||||
<div
|
||||
<AnimatedCard
|
||||
key={industry.label}
|
||||
className="flex flex-col items-center gap-2.5 p-4 rounded-2xl bg-white border border-[#6330D6]/8 hover:border-[#6330D6]/20 hover:shadow-md transition-all duration-200 cursor-default"
|
||||
>
|
||||
@@ -276,30 +283,32 @@ export default function BrandsPage() {
|
||||
<MaterialIcon icon={industry.icon} size={20} />
|
||||
</div>
|
||||
<span className="text-[10px] font-black text-[#16001D] text-center leading-tight">{industry.label}</span>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─── Partnership Process ─── */}
|
||||
<section id="partnership" className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
How It Works
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
The Partnership Process
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
From first conversation to city-wide brand presence in four structured steps.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
How It Works
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
The Partnership Process
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
From first conversation to city-wide brand presence in four structured steps.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
<AnimatedGrid className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
{PARTNERSHIP_STEPS.map((step) => (
|
||||
<article
|
||||
<AnimatedCard
|
||||
key={step.num}
|
||||
className="relative flex flex-col rounded-[28px] border border-[#6330D6]/10 bg-[#FAF7FD] p-7 shadow-[0_8px_32px_rgba(22,0,29,0.05)]"
|
||||
>
|
||||
@@ -313,9 +322,9 @@ export default function BrandsPage() {
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-sm text-[#5E5866] leading-relaxed">{step.desc}</p>
|
||||
</article>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -323,24 +332,26 @@ export default function BrandsPage() {
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[360px_1fr] gap-10 lg:gap-16 items-start">
|
||||
<div className="lg:sticky lg:top-28">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
FAQs
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Brand Partner Questions
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-6">
|
||||
What brand managers usually ask before starting their Nearle partnership.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 text-sm font-black text-[#6330D6] hover:text-[#5225b8] transition-colors"
|
||||
>
|
||||
<span>Talk to our sales team</span>
|
||||
<MaterialIcon icon="arrow_forward" size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="lg:sticky lg:top-28">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
FAQs
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Brand Partner Questions
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-6">
|
||||
What brand managers usually ask before starting their Nearle partnership.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 text-sm font-black text-[#6330D6] hover:text-[#5225b8] transition-colors"
|
||||
>
|
||||
<span>Talk to our sales team</span>
|
||||
<MaterialIcon icon="arrow_forward" size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<FAQAccordion items={FAQ_ITEMS} />
|
||||
</div>
|
||||
@@ -348,43 +359,17 @@ export default function BrandsPage() {
|
||||
</section>
|
||||
|
||||
{/* ─── CTA Banner ─── */}
|
||||
<section className="bg-white px-2 pt-2 pb-2 md:px-3 md:pt-3 md:pb-3 lg:px-4 lg:pt-4 lg:pb-4 xl:px-5 xl:pt-4 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<div className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#1A0322] via-[#2B0040] to-[#0A000D] text-white">
|
||||
<div className="px-6 py-12 md:px-10 md:py-14 lg:px-14 xl:py-12 text-center relative">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_30%,rgba(99,48,214,0.2),transparent_50%)] pointer-events-none" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_20%_70%,rgba(0,109,55,0.12),transparent_45%)] pointer-events-none" />
|
||||
<div className="relative z-10 max-w-2xl mx-auto">
|
||||
<span className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-white/15 text-white/70 text-xs font-black uppercase tracking-widest mb-6">
|
||||
<MaterialIcon icon="hub" size={14} />
|
||||
Brand Partnership
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl xl:text-5xl font-black mb-4 tracking-tight leading-tight">
|
||||
Ready to Grow in
|
||||
<br />Every Neighbourhood?
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-white/70 mb-8 leading-relaxed max-w-lg mx-auto">
|
||||
Let's talk about what a Nearle brand partnership looks like for your products. Our sales team will design a custom plan for your brand.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-3.5">
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-xl transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="forum" size={18} />
|
||||
<span>Talk to Sales</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-white/10 hover:bg-white/15 border border-white/20 text-white font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="mail" size={18} />
|
||||
<span>Send an Enquiry</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTABanner
|
||||
badge={{ icon: "hub", label: "Brand Partnership" }}
|
||||
heading={<>Ready to Grow in<br />Every Neighbourhood?</>}
|
||||
body="Let's talk about what a Nearle brand partnership looks like for your products. Our sales team will design a custom plan for your brand."
|
||||
primary={{ href: "/contact", icon: "forum", label: "Talk to Sales" }}
|
||||
secondary={{ href: "/contact", icon: "mail", label: "Send an Enquiry" }}
|
||||
decorations={[
|
||||
"circle at 70% 30%, rgba(99,48,214,0.2), transparent 50%",
|
||||
"circle at 20% 70%, rgba(0,109,55,0.12), transparent 45%",
|
||||
]}
|
||||
/>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import { BusinessFeaturesGrid } from "@/components/businesses/BusinessFeaturesGrid";
|
||||
import { BusinessHero } from "@/components/heroes/BusinessHero";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||
import { CTABanner } from "@/components/ui/CTABanner";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -15,12 +17,6 @@ export const metadata: Metadata = {
|
||||
};
|
||||
|
||||
|
||||
const HERO_BENEFITS = [
|
||||
{ title: "More Visibility Across Nearle", icon: "visibility", desc: "Get discovered by locals" },
|
||||
{ title: "Easy Order Management", icon: "assignment", desc: "Track and fulfill cleanly" },
|
||||
{ title: "Grow Repeat Customers", icon: "trending_up", desc: "Build neighborhood loyalty" },
|
||||
{ title: "Local Delivery Support", icon: "local_shipping", desc: "Deliver fast & verified" }
|
||||
];
|
||||
|
||||
function PhoneMapVisual() {
|
||||
return (
|
||||
@@ -96,102 +92,42 @@ function PhoneMapVisual() {
|
||||
}
|
||||
|
||||
export default function BusinessesPage() {
|
||||
const collageCards = [
|
||||
{ text: "Nearby Customers", icon: "people" },
|
||||
{ text: "Orders & Offers", icon: "local_offer" },
|
||||
{ text: "Local Delivery Support", icon: "local_shipping" }
|
||||
];
|
||||
|
||||
return (
|
||||
<PremiumPageShell>
|
||||
{/* ─── Hero Section ─── */}
|
||||
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]">
|
||||
{/* TWO-COLUMN GRID */}
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Left Column: Copy & Actions */}
|
||||
<div className="flex flex-col text-left max-w-xl">
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit">
|
||||
Nearle for Business
|
||||
</span>
|
||||
|
||||
<h1 className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight">
|
||||
Grow Your Local Business,
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Neighbourhood by Neighbourhood.</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed">
|
||||
Get discovered by nearby customers, manage orders, and build repeat business from one simple platform.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto">
|
||||
{/* TODO: Replace with real merchant onboarding URL once confirmed */}
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
>
|
||||
List Your Store
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
|
||||
>
|
||||
Explore Solutions
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Visual Collage */}
|
||||
<div className="w-full">
|
||||
<HeroVisualCollage
|
||||
centerImage="/nearlenewlogo.png"
|
||||
leftImage="/images/cat-daily-essentials.png"
|
||||
rightImage="/Nearle Business.png"
|
||||
glassCards={collageCards}
|
||||
isPhoneCenter={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* BOTTOM HERO BENEFITS */}
|
||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto">
|
||||
<FeatureStatsRow items={HERO_BENEFITS} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<BusinessHero />
|
||||
|
||||
{/* ─── Intro Highlight Banner ─── */}
|
||||
<section className="py-7 px-6 md:py-9 md:px-12 lg:px-16 xl:px-20 xl:py-8 2xl:px-24 flex flex-col lg:flex-row justify-between items-start lg:items-center gap-6 border-b border-[#6330D6]/10 bg-white">
|
||||
<div className="max-w-2xl text-left">
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3 py-1 rounded-full">
|
||||
Together, we grow
|
||||
</span>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-black text-[#16001D] mt-4 mb-3 leading-tight">
|
||||
Get set in minutes and delight the Neighborhood
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed">
|
||||
Nearle is built to help businesses like <strong className="text-[#6330D6]">Yours</strong> establish a local online presence and empower neighborhood customers to discover and interact with you directly.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-4 shrink-0">
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm shadow-md active:scale-95 transition-all flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="chat" size={18} />
|
||||
<span>Talk to an Expert</span>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
<AnimatedSection>
|
||||
<section className="py-7 px-6 md:py-9 md:px-12 lg:px-16 xl:px-20 xl:py-8 2xl:px-24 flex flex-col lg:flex-row justify-between items-start lg:items-center gap-6 border-b border-[#6330D6]/10 bg-white">
|
||||
<div className="max-w-2xl text-left">
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3 py-1 rounded-full">
|
||||
Together, we grow
|
||||
</span>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-black text-[#16001D] mt-4 mb-3 leading-tight">
|
||||
Get set in minutes and delight the Neighborhood
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed">
|
||||
Nearle is built to help businesses like <strong className="text-[#6330D6]">Yours</strong> establish a local online presence and empower neighborhood customers to discover and interact with you directly.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-4 shrink-0">
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm shadow-md active:scale-95 transition-all flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="chat" size={18} />
|
||||
<span>Talk to an Expert</span>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
</AnimatedSection>
|
||||
|
||||
{/* ─── Build Your Neighborhood Brand ─── */}
|
||||
<section className="py-10 md:py-14 lg:py-16 xl:py-12 border-b border-[#6330D6]/10 bg-white overflow-hidden">
|
||||
<div className="w-[calc(100%-32px)] lg:w-[calc(100%-64px)] max-w-[1800px] mx-auto">
|
||||
{/* Header */}
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 lg:mb-12 xl:mb-10">
|
||||
<span className="inline-flex items-center rounded-full bg-[#6330D6]/5 px-4 py-1.5 text-xs font-black uppercase tracking-widest text-[#6330D6]">
|
||||
How it works
|
||||
@@ -203,11 +139,12 @@ export default function BusinessesPage() {
|
||||
Three simple milestones to scale your retail reach from offline streets straight into neighborhood homes.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
{/* Cards grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-7">
|
||||
<AnimatedGrid className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-7">
|
||||
{/* Card 1 - Get Online */}
|
||||
<article className="relative flex min-h-[360px] md:min-h-[390px] lg:min-h-[420px] flex-col overflow-hidden rounded-[32px] border border-[rgba(99,48,214,0.12)] bg-white p-7 md:p-8 shadow-[0_18px_45px_rgba(22,0,29,0.08)]">
|
||||
<AnimatedCard className="relative flex min-h-[360px] md:min-h-[390px] lg:min-h-[420px] flex-col overflow-hidden rounded-[32px] border border-[rgba(99,48,214,0.12)] bg-white p-7 md:p-8 shadow-[0_18px_45px_rgba(22,0,29,0.08)]">
|
||||
<span className="absolute right-5 top-4 font-display text-6xl font-black leading-none text-[#6330D6]/[0.07] select-none">
|
||||
01
|
||||
</span>
|
||||
@@ -233,10 +170,10 @@ export default function BusinessesPage() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</AnimatedCard>
|
||||
|
||||
{/* Card 2 - Get Noticed */}
|
||||
<article className="relative flex min-h-[360px] md:min-h-[390px] lg:min-h-[420px] flex-col overflow-hidden rounded-[32px] border border-[rgba(99,48,214,0.12)] bg-white p-7 md:p-8 shadow-[0_18px_45px_rgba(22,0,29,0.08)]">
|
||||
<AnimatedCard className="relative flex min-h-[360px] md:min-h-[390px] lg:min-h-[420px] flex-col overflow-hidden rounded-[32px] border border-[rgba(99,48,214,0.12)] bg-white p-7 md:p-8 shadow-[0_18px_45px_rgba(22,0,29,0.08)]">
|
||||
<span className="absolute right-5 top-4 font-display text-6xl font-black leading-none text-[#6330D6]/[0.07] select-none">
|
||||
02
|
||||
</span>
|
||||
@@ -254,10 +191,10 @@ export default function BusinessesPage() {
|
||||
<div className="relative z-0 mt-auto h-[270px] lg:h-[290px] flex items-center justify-center">
|
||||
<PhoneMapVisual />
|
||||
</div>
|
||||
</article>
|
||||
</AnimatedCard>
|
||||
|
||||
{/* Card 3 - Get Simplified */}
|
||||
<article className="relative flex min-h-[360px] md:min-h-[390px] lg:min-h-[420px] flex-col overflow-hidden rounded-[32px] border border-[rgba(99,48,214,0.12)] bg-white p-7 md:p-8 shadow-[0_18px_45px_rgba(22,0,29,0.08)]">
|
||||
<AnimatedCard className="relative flex min-h-[360px] md:min-h-[390px] lg:min-h-[420px] flex-col overflow-hidden rounded-[32px] border border-[rgba(99,48,214,0.12)] bg-white p-7 md:p-8 shadow-[0_18px_45px_rgba(22,0,29,0.08)]">
|
||||
<span className="absolute right-5 top-4 font-display text-6xl font-black leading-none text-[#6330D6]/[0.07] select-none">
|
||||
03
|
||||
</span>
|
||||
@@ -290,8 +227,8 @@ export default function BusinessesPage() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -299,38 +236,15 @@ export default function BusinessesPage() {
|
||||
<BusinessFeaturesGrid />
|
||||
|
||||
{/* ─── Join/Download Call to Action ─── */}
|
||||
<section className="bg-white px-2 pt-2 pb-2 md:px-3 md:pt-3 md:pb-3 lg:px-4 lg:pt-4 lg:pb-4 xl:px-5 xl:pt-4 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<div className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#1A0322] to-[#0A000D] text-white">
|
||||
<div className="px-6 py-10 md:px-10 md:py-12 lg:px-14 lg:py-14 xl:py-12 text-center relative">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_20%,rgba(99,48,214,0.15),transparent_50%)] pointer-events-none" />
|
||||
<div className="relative z-10 max-w-2xl mx-auto">
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black mb-4 tracking-tight">
|
||||
Nearle is Essential for Business Growth
|
||||
</h2>
|
||||
<p className="text-xs md:text-sm text-white/70 mb-8 leading-relaxed max-w-lg mx-auto">
|
||||
Leverage the full potential of your neighborhood. Stand above the rest, increase customers, and scale your brand today.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-3.5">
|
||||
{/* TODO: Replace with real merchant onboarding URL once confirmed */}
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-xl transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="bolt" size={18} />
|
||||
<span>Register Interest</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-white/10 hover:bg-white/15 border border-white/20 text-white font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="phone" size={18} />
|
||||
<span>Contact Experts</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTABanner
|
||||
heading="Nearle is Essential for Business Growth"
|
||||
body="Leverage the full potential of your neighborhood. Stand above the rest, increase customers, and scale your brand today."
|
||||
primary={{ href: "/contact", icon: "bolt", label: "Register Interest" }}
|
||||
secondary={{ href: "/contact", icon: "phone", label: "Contact Experts" }}
|
||||
decorations={[
|
||||
"circle at 70% 20%, rgba(99,48,214,0.15), transparent 50%",
|
||||
]}
|
||||
/>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from "react";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { ContactForm } from "@/components/contact/ContactForm";
|
||||
import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { ContactHero } from "@/components/heroes/ContactHero";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -13,95 +14,10 @@ export default function ContactPage() {
|
||||
return (
|
||||
<PremiumPageShell>
|
||||
{/* ─── Contact Section ─── */}
|
||||
<section className="relative border-b border-[#6330D6]/10 px-4 py-10 md:px-6 md:py-12 lg:px-8 lg:py-14 xl:px-10 xl:py-16 2xl:px-12 2xl:py-20">
|
||||
|
||||
{/* Subtle Map Grid/Location decoration behind left content */}
|
||||
<div className="absolute left-[5%] top-[10%] w-[400px] h-[300px] opacity-[0.04] select-none pointer-events-none -z-10">
|
||||
<svg className="w-full h-full text-[#6330D6]" stroke="currentColor" fill="none" strokeWidth="1.5" viewBox="0 0 400 300">
|
||||
<path d="M0,50 L400,50 M0,130 L400,130 M0,210 L400,210 M80,0 L80,300 M200,0 L200,300 M320,0 L320,300" />
|
||||
<path d="M 80,130 C 120,90 160,170 200,130 C 240,90 280,170 320,130" strokeDasharray="3,3" />
|
||||
<circle cx="200" cy="130" r="4" fill="currentColor" />
|
||||
<circle cx="200" cy="130" r="14" strokeWidth="1" />
|
||||
<circle cx="80" cy="50" r="3" fill="currentColor" />
|
||||
<circle cx="320" cy="210" r="3" fill="currentColor" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* <div className="w-full mx-auto relative z-10"> */}
|
||||
<div className="relative z-10 mx-auto w-full max-w-[1520px]">
|
||||
<div className="grid grid-cols-1 items-start gap-10 lg:grid-cols-[1.2fr_0.8fr] lg:gap-12 xl:gap-16">
|
||||
|
||||
{/* Left Column — Contact Info */}
|
||||
<div className="w-full max-w-[760px] py-6 md:py-8 lg:py-10 relative z-10 text-[#16001D]">
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit">
|
||||
Contact Us
|
||||
</span>
|
||||
<h1 className="font-display text-4xl font-black leading-[1.05] text-[#16001D] md:text-5xl lg:text-[58px] xl:text-[64px] 2xl:text-[70px]">
|
||||
We’re Here to <br />
|
||||
<span className="text-[#6330D6]">Help You.</span>
|
||||
</h1>
|
||||
<p className="mt-6 max-w-[620px] text-sm font-bold leading-8 text-[#5E5866] md:text-base xl:text-lg">
|
||||
Whether you are a customer, local store owner, or delivery partner, our team is here to help you get started with Nearle.
|
||||
</p>
|
||||
|
||||
{/* Info Rows */}
|
||||
<div className="mt-8 border-t border-[#6330D6]/10">
|
||||
{/* Call Us */}
|
||||
<div className="flex gap-4 py-4.5 border-b border-[#6330D6]/10 items-center">
|
||||
<div className="w-10 h-10 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon="phone" size={18} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-[#16001D] text-sm font-black">Call Us</h4>
|
||||
<p className="text-[#5E5866] text-sm font-semibold mt-0.5">+91 909 206 8666</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Email Us */}
|
||||
<div className="flex gap-4 py-4.5 border-b border-[#6330D6]/10 items-center">
|
||||
<div className="w-10 h-10 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon="mail" size={18} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-[#16001D] text-sm font-black">Email Us</h4>
|
||||
<p className="text-[#5E5866] text-sm font-semibold mt-0.5">nearle@care.in</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Visit Us */}
|
||||
<div className="flex gap-4 py-4.5 border-b border-[#6330D6]/10 items-center">
|
||||
<div className="w-10 h-10 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon="location_on" size={18} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-[#16001D] text-sm font-black">Address </h4>
|
||||
<p className="text-[#5E5866] text-sm font-semibold mt-0.5">424, DB Rd, R.S. Puram, Coimbatore, TN 641002</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Helpdesk */}
|
||||
{/* <div className="flex gap-4 py-4.5 border-b border-[#6330D6]/10 items-center">
|
||||
<div className="w-10 h-10 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon="support_agent" size={18} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-[#16001D] text-sm font-black">Helpdesk</h4>
|
||||
<p className="text-[#5E5866] text-sm font-semibold mt-0.5">24/7 Phone Helpdesk Active</p>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Compact Form Card */}
|
||||
<div className="w-full max-w-[660px] justify-self-end pt-10 lg:pt-14 xl:pt-26">
|
||||
<ContactForm />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<ContactHero />
|
||||
|
||||
{/* ─── Map Section ─── */}
|
||||
<AnimatedSection>
|
||||
<section className="bg-[#FAF7FD] px-4 py-8 md:px-6 lg:px-8 xl:px-10 2xl:px-12">
|
||||
<div className="mx-auto w-full ">
|
||||
<div className="relative h-[420px] overflow-hidden rounded-2xl border border-[#6330D6]/10 shadow-[0_4px_24px_rgba(99,48,214,0.02)]">
|
||||
@@ -129,6 +45,7 @@ export default function ContactPage() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</AnimatedSection>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import { FAQAccordion } from "@/components/ui/FAQAccordion";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||
import { AnimatedTimeline } from "@/components/delivery/AnimatedTimeline";
|
||||
import { CTABanner } from "@/components/ui/CTABanner";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -252,21 +256,23 @@ export default function DeliveryPartnersPage() {
|
||||
{/* ─── Benefits Grid ─── */}
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Partner Benefits
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
More Than Just Delivery
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Nearle is designed around your life — not the other way around.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Partner Benefits
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
More Than Just Delivery
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Nearle is designed around your life — not the other way around.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
<AnimatedGrid className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
{BENEFITS.map((benefit) => (
|
||||
<div
|
||||
<AnimatedCard
|
||||
key={benefit.title}
|
||||
className="rounded-2xl border border-[#6330D6]/10 bg-[#FAF7FD] p-6 flex flex-col gap-4 hover:shadow-[0_8px_28px_rgba(22,0,29,0.08)] transition-shadow duration-300"
|
||||
>
|
||||
@@ -277,9 +283,9 @@ export default function DeliveryPartnersPage() {
|
||||
<h3 className="text-base font-black text-[#16001D] leading-tight">{benefit.title}</h3>
|
||||
<p className="mt-2 text-sm text-[#5E5866] leading-relaxed">{benefit.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -287,28 +293,30 @@ export default function DeliveryPartnersPage() {
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1.1fr_1fr] gap-10 lg:gap-16 items-center">
|
||||
<div>
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||
To Get Started
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
What You Need to Join
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-8 max-w-lg">
|
||||
No experience needed. If you have a vehicle, a smartphone, and a desire to earn — you're more than qualified.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-7 py-3.5 rounded-xl text-sm shadow-md transition-all duration-200 active:scale-95"
|
||||
>
|
||||
<MaterialIcon icon="how_to_reg" size={18} />
|
||||
<span>Apply Now</span>
|
||||
</Link>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div>
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||
To Get Started
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
What You Need to Join
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-8 max-w-lg">
|
||||
No experience needed. If you have a vehicle, a smartphone, and a desire to earn — you're more than qualified.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-7 py-3.5 rounded-xl text-sm shadow-md transition-all duration-200 active:scale-95"
|
||||
>
|
||||
<MaterialIcon icon="how_to_reg" size={18} />
|
||||
<span>Apply Now</span>
|
||||
</Link>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<AnimatedGrid className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{REQUIREMENTS.map((req) => (
|
||||
<div key={req.title} className="flex flex-col gap-3 p-5 rounded-2xl bg-white border border-[#6330D6]/10 shadow-[0_4px_18px_rgba(22,0,29,0.05)]">
|
||||
<AnimatedCard key={req.title} className="flex flex-col gap-3 p-5 rounded-2xl bg-white border border-[#6330D6]/10 shadow-[0_4px_18px_rgba(22,0,29,0.05)]">
|
||||
<div className="w-11 h-11 rounded-2xl bg-[#6330D6]/8 text-[#6330D6] flex items-center justify-center">
|
||||
<MaterialIcon icon={req.icon} size={22} />
|
||||
</div>
|
||||
@@ -316,9 +324,9 @@ export default function DeliveryPartnersPage() {
|
||||
<h4 className="text-sm font-black text-[#16001D]">{req.title}</h4>
|
||||
<p className="mt-1 text-xs text-[#5E5866] leading-relaxed">{req.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -326,41 +334,21 @@ export default function DeliveryPartnersPage() {
|
||||
{/* ─── How Delivery Works (Timeline) ─── */}
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Your Journey
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
From Sign-Up to First Earnings
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Most delivery partners are out earning within 3 days of applying.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative max-w-3xl mx-auto">
|
||||
{/* Vertical line */}
|
||||
<div className="absolute left-[22px] md:left-[26px] top-8 bottom-8 w-0.5 bg-gradient-to-b from-[#6330D6]/30 via-[#6330D6]/20 to-transparent hidden sm:block" />
|
||||
|
||||
<div className="space-y-6">
|
||||
{TIMELINE.map((item, index) => (
|
||||
<div key={item.step} className="relative flex gap-5 sm:gap-7">
|
||||
<div className="flex-shrink-0 w-11 h-11 md:w-12 md:h-12 rounded-full bg-[#6330D6] text-white flex items-center justify-center text-xs font-black shadow-[0_8px_20px_rgba(99,48,214,0.25)] relative z-10">
|
||||
{String(index + 1).padStart(2, "0")}
|
||||
</div>
|
||||
<div className="flex-1 pb-2 pt-1">
|
||||
<div className="flex items-center gap-3 mb-1.5">
|
||||
<h3 className="text-base font-black text-[#16001D] leading-tight">{item.title}</h3>
|
||||
<span className="px-2.5 py-0.5 rounded-full bg-[#6330D6]/8 text-[#6330D6] text-[10px] font-black uppercase tracking-wide shrink-0">
|
||||
{item.time}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-[#5E5866] leading-relaxed">{item.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Your Journey
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
From Sign-Up to First Earnings
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Most delivery partners are out earning within 3 days of applying.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedTimeline items={TIMELINE} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -416,24 +404,26 @@ export default function DeliveryPartnersPage() {
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[360px_1fr] gap-10 lg:gap-16 items-start">
|
||||
<div className="lg:sticky lg:top-28">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
FAQs
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Common Questions
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-6">
|
||||
Everything you want to know before joining the Nearle delivery network.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 text-sm font-black text-[#6330D6] hover:text-[#5225b8] transition-colors"
|
||||
>
|
||||
<span>Contact support</span>
|
||||
<MaterialIcon icon="arrow_forward" size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="lg:sticky lg:top-28">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
FAQs
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Common Questions
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-6">
|
||||
Everything you want to know before joining the Nearle delivery network.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 text-sm font-black text-[#6330D6] hover:text-[#5225b8] transition-colors"
|
||||
>
|
||||
<span>Contact support</span>
|
||||
<MaterialIcon icon="arrow_forward" size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<FAQAccordion items={FAQ_ITEMS} />
|
||||
</div>
|
||||
@@ -441,43 +431,17 @@ export default function DeliveryPartnersPage() {
|
||||
</section>
|
||||
|
||||
{/* ─── CTA Banner ─── */}
|
||||
<section className="bg-white px-2 pt-2 pb-2 md:px-3 md:pt-3 md:pb-3 lg:px-4 lg:pt-4 lg:pb-4 xl:px-5 xl:pt-4 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<div className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#1A0322] via-[#2B0040] to-[#0A000D] text-white">
|
||||
<div className="px-6 py-12 md:px-10 md:py-14 lg:px-14 xl:py-12 text-center relative">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_30%,rgba(0,109,55,0.15),transparent_50%)] pointer-events-none" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_70%,rgba(99,48,214,0.12),transparent_45%)] pointer-events-none" />
|
||||
<div className="relative z-10 max-w-2xl mx-auto">
|
||||
<span className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-white/15 text-white/70 text-xs font-black uppercase tracking-widest mb-6">
|
||||
<MaterialIcon icon="electric_scooter" size={14} />
|
||||
Start Earning Today
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl xl:text-5xl font-black mb-4 tracking-tight leading-tight">
|
||||
Join the Nearle
|
||||
<br />Delivery Network
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-white/70 mb-8 leading-relaxed max-w-lg mx-auto">
|
||||
Delivery partners in Coimbatore are already earning with Nearle. Sign up today and start delivering in your neighbourhood within days.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-3.5">
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-xl transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="how_to_reg" size={18} />
|
||||
<span>Apply Now</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-white/10 hover:bg-white/15 border border-white/20 text-white font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="phone" size={18} />
|
||||
<span>Talk to Us</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTABanner
|
||||
badge={{ icon: "electric_scooter", label: "Start Earning Today" }}
|
||||
heading={<>Join the Nearle<br />Delivery Network</>}
|
||||
body="Delivery partners in Coimbatore are already earning with Nearle. Sign up today and start delivering in your neighbourhood within days."
|
||||
primary={{ href: "/contact", icon: "how_to_reg", label: "Apply Now" }}
|
||||
secondary={{ href: "/contact", icon: "phone", label: "Talk to Us" }}
|
||||
decorations={[
|
||||
"circle at 30% 30%, rgba(0,109,55,0.15), transparent 50%",
|
||||
"circle at 70% 70%, rgba(99,48,214,0.12), transparent 45%",
|
||||
]}
|
||||
/>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import "./globals.css";
|
||||
import { MotionProvider } from "@/components/layout/MotionProvider";
|
||||
import { PremiumNavbar } from "@/components/layout/PremiumNavbar";
|
||||
import { PremiumFooter } from "@/components/layout/PremiumFooter";
|
||||
|
||||
const jost = { variable: "font-display" };
|
||||
const jostBody = { variable: "font-body" };
|
||||
@@ -70,6 +73,7 @@ export default function RootLayout({
|
||||
<html
|
||||
lang="en"
|
||||
className={`${jost.variable} ${jostBody.variable}`}
|
||||
data-scroll-behavior="smooth"
|
||||
suppressHydrationWarning
|
||||
>
|
||||
<head>
|
||||
@@ -86,7 +90,15 @@ export default function RootLayout({
|
||||
/>
|
||||
</head>
|
||||
<body className="bg-[#E8DCF2] text-on-surface font-body antialiased" suppressHydrationWarning>
|
||||
{children}
|
||||
<MotionProvider>
|
||||
<div className="min-h-screen bg-white font-body text-[#16001D] antialiased flex flex-col">
|
||||
<PremiumNavbar />
|
||||
<main className="w-full overflow-x-hidden bg-white">
|
||||
{children}
|
||||
</main>
|
||||
<PremiumFooter />
|
||||
</div>
|
||||
</MotionProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,9 @@ import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import { FAQAccordion } from "@/components/ui/FAQAccordion";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||
import { CTABanner } from "@/components/ui/CTABanner";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -226,21 +229,23 @@ export default function MerchantsPage() {
|
||||
{/* ─── Merchant Benefits Grid ─── */}
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
What You Get
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
Everything Your Store Needs to Grow
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Nearle gives your neighbourhood store the same tools that big online retailers have — without the complexity.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
What You Get
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
Everything Your Store Needs to Grow
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
Nearle gives your neighbourhood store the same tools that big online retailers have — without the complexity.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
<AnimatedGrid className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
{BENEFITS.map((benefit) => (
|
||||
<div
|
||||
<AnimatedCard
|
||||
key={benefit.title}
|
||||
className="rounded-2xl border border-[#6330D6]/10 bg-[#FAF7FD] p-5 flex flex-col gap-3 hover:shadow-[0_8px_28px_rgba(22,0,29,0.08)] transition-shadow duration-300"
|
||||
>
|
||||
@@ -251,30 +256,32 @@ export default function MerchantsPage() {
|
||||
<h3 className="text-base font-black text-[#16001D] leading-tight">{benefit.title}</h3>
|
||||
<p className="mt-1.5 text-xs md:text-sm text-[#5E5866] leading-relaxed">{benefit.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─── How It Works ─── */}
|
||||
<section id="how-it-works" className="py-10 md:py-14 xl:py-12 bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||
Simple Steps
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
Up and Running in 24 Hours
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
From registration to your first order, we've made the process as simple as possible.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-10 md:mb-12">
|
||||
<span className="text-xs text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1 rounded-full">
|
||||
Simple Steps
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-3 tracking-tight">
|
||||
Up and Running in 24 Hours
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] max-w-2xl mx-auto leading-relaxed">
|
||||
From registration to your first order, we've made the process as simple as possible.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
<AnimatedGrid className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
{HOW_STEPS.map((step) => (
|
||||
<article
|
||||
<AnimatedCard
|
||||
key={step.num}
|
||||
className="relative flex flex-col rounded-[28px] border border-[#6330D6]/10 bg-white p-7 shadow-[0_8px_32px_rgba(22,0,29,0.06)]"
|
||||
>
|
||||
@@ -288,9 +295,9 @@ export default function MerchantsPage() {
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-sm text-[#5E5866] leading-relaxed">{step.desc}</p>
|
||||
</article>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -298,37 +305,39 @@ export default function MerchantsPage() {
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10 overflow-hidden">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_1.1fr] gap-10 lg:gap-16 items-start">
|
||||
<div>
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Why Nearle
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Your Neighbourhood's
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Best Business Partner</span>
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-8 max-w-lg">
|
||||
Nearle isn't built like a big delivery platform that squeezes margins. We're built for neighbourhood stores like yours — where community and trust come first.
|
||||
</p>
|
||||
<AnimatedSection>
|
||||
<div>
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Why Nearle
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Your Neighbourhood's
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Best Business Partner</span>
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-8 max-w-lg">
|
||||
Nearle isn't built like a big delivery platform that squeezes margins. We're built for neighbourhood stores like yours — where community and trust come first.
|
||||
</p>
|
||||
|
||||
{/* Stats row */}
|
||||
<div className="grid grid-cols-3 gap-5">
|
||||
{[
|
||||
{ stat: "2km", label: "Hyperlocal Coverage" },
|
||||
{ stat: "24h", label: "Time to Go Live" },
|
||||
{ stat: "Fair", label: "Commission Model" },
|
||||
].map((s) => (
|
||||
<div key={s.label} className="text-center p-4 rounded-2xl bg-[#6330D6]/5 border border-[#6330D6]/8">
|
||||
<div className="text-2xl md:text-3xl font-display font-black text-[#6330D6]">{s.stat}</div>
|
||||
<div className="text-[10px] md:text-xs font-bold text-[#5E5866] mt-1 leading-tight">{s.label}</div>
|
||||
</div>
|
||||
))}
|
||||
{/* Stats row */}
|
||||
<div className="grid grid-cols-3 gap-5">
|
||||
{[
|
||||
{ stat: "2km", label: "Hyperlocal Coverage" },
|
||||
{ stat: "24h", label: "Time to Go Live" },
|
||||
{ stat: "Fair", label: "Commission Model" },
|
||||
].map((s) => (
|
||||
<div key={s.label} className="text-center p-4 rounded-2xl bg-[#6330D6]/5 border border-[#6330D6]/8">
|
||||
<div className="text-2xl md:text-3xl font-display font-black text-[#6330D6]">{s.stat}</div>
|
||||
<div className="text-[10px] md:text-xs font-bold text-[#5E5866] mt-1 leading-tight">{s.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<AnimatedGrid className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{WHY_REASONS.map((reason) => (
|
||||
<div key={reason.title} className="flex gap-3.5 p-4 rounded-2xl border border-[#6330D6]/8 bg-[#FAF7FD]">
|
||||
<AnimatedCard key={reason.title} className="flex gap-3.5 p-4 rounded-2xl border border-[#6330D6]/8 bg-[#FAF7FD]">
|
||||
<div className="w-10 h-10 shrink-0 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center">
|
||||
<MaterialIcon icon={reason.icon} size={20} />
|
||||
</div>
|
||||
@@ -336,9 +345,9 @@ export default function MerchantsPage() {
|
||||
<h4 className="text-sm font-black text-[#16001D] leading-tight">{reason.title}</h4>
|
||||
<p className="mt-1 text-xs text-[#5E5866] leading-relaxed">{reason.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -346,53 +355,55 @@ export default function MerchantsPage() {
|
||||
{/* ─── Success Story ─── */}
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="text-center mb-8">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Merchant Story
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 tracking-tight">
|
||||
Real Results from Real Stores
|
||||
</h2>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="text-center mb-8">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Merchant Story
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 tracking-tight">
|
||||
Real Results from Real Stores
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="relative overflow-hidden rounded-[2rem] bg-[linear-gradient(135deg,#ffffff_0%,#F4ECFA_100%)] border border-[#6330D6]/10 shadow-[0_18px_50px_rgba(22,0,29,0.08)] p-8 md:p-10 lg:p-12">
|
||||
<div className="pointer-events-none absolute -right-20 -top-20 h-64 w-64 rounded-full bg-[#6330D6]/5 blur-3xl" />
|
||||
<div className="relative z-10 grid grid-cols-1 lg:grid-cols-[1fr_1.5fr] gap-8 lg:gap-12 items-center">
|
||||
<div>
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-secondary/10 text-secondary text-xs font-black uppercase tracking-wider mb-5">
|
||||
<MaterialIcon icon="store" size={14} />
|
||||
Success Story
|
||||
</div>
|
||||
<blockquote className="text-xl md:text-2xl font-black text-[#16001D] leading-snug mb-6">
|
||||
“In three months, my daily orders doubled. Customers who used to call now just scan the QR and order. Even my evening rush feels calmer.”
|
||||
</blockquote>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-12 h-12 rounded-full bg-[#6330D6]/10 flex items-center justify-center">
|
||||
<MaterialIcon icon="person" size={22} className="text-[#6330D6]" />
|
||||
<div className="relative overflow-hidden rounded-[2rem] bg-[linear-gradient(135deg,#ffffff_0%,#F4ECFA_100%)] border border-[#6330D6]/10 shadow-[0_18px_50px_rgba(22,0,29,0.08)] p-8 md:p-10 lg:p-12">
|
||||
<div className="pointer-events-none absolute -right-20 -top-20 h-64 w-64 rounded-full bg-[#6330D6]/5 blur-3xl" />
|
||||
<div className="relative z-10 grid grid-cols-1 lg:grid-cols-[1fr_1.5fr] gap-8 lg:gap-12 items-center">
|
||||
<div>
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-secondary/10 text-secondary text-xs font-black uppercase tracking-wider mb-5">
|
||||
<MaterialIcon icon="store" size={14} />
|
||||
Success Story
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-black text-[#16001D]">Ramesh Kumar</div>
|
||||
<div className="text-xs text-[#5E5866] font-semibold">R.K. Provision Store, R.S. Puram, Coimbatore</div>
|
||||
<blockquote className="text-xl md:text-2xl font-black text-[#16001D] leading-snug mb-6">
|
||||
“In three months, my daily orders doubled. Customers who used to call now just scan the QR and order. Even my evening rush feels calmer.”
|
||||
</blockquote>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-12 h-12 rounded-full bg-[#6330D6]/10 flex items-center justify-center">
|
||||
<MaterialIcon icon="person" size={22} className="text-[#6330D6]" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-black text-[#16001D]">Ramesh Kumar</div>
|
||||
<div className="text-xs text-[#5E5866] font-semibold">R.K. Provision Store, R.S. Puram, Coimbatore</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{[
|
||||
{ value: "2.1×", label: "Daily Orders Growth", icon: "trending_up", color: "text-[#006D37]" },
|
||||
{ value: "340+", label: "Repeat Customers Built", icon: "people", color: "text-[#6330D6]" },
|
||||
{ value: "3 hrs", label: "Saved per Day on Calls", icon: "schedule", color: "text-[#006D37]" },
|
||||
{ value: "4.9 ★", label: "Average Store Rating", icon: "star", color: "text-amber-500" },
|
||||
].map((m) => (
|
||||
<div key={m.label} className="rounded-2xl bg-white border border-[#6330D6]/8 p-5 text-center shadow-sm">
|
||||
<MaterialIcon icon={m.icon} size={22} className={`${m.color} mx-auto`} />
|
||||
<div className={`text-2xl font-display font-black mt-2 ${m.color}`}>{m.value}</div>
|
||||
<div className="text-xs text-[#5E5866] font-semibold mt-1 leading-tight">{m.label}</div>
|
||||
</div>
|
||||
))}
|
||||
<AnimatedGrid className="grid grid-cols-2 gap-4">
|
||||
{[
|
||||
{ value: "2.1×", label: "Daily Orders Growth", icon: "trending_up", color: "text-[#006D37]" },
|
||||
{ value: "340+", label: "Repeat Customers Built", icon: "people", color: "text-[#6330D6]" },
|
||||
{ value: "3 hrs", label: "Saved per Day on Calls", icon: "schedule", color: "text-[#006D37]" },
|
||||
{ value: "4.9 ★", label: "Average Store Rating", icon: "star", color: "text-amber-500" },
|
||||
].map((m) => (
|
||||
<AnimatedCard key={m.label} className="rounded-2xl bg-white border border-[#6330D6]/8 p-5 text-center shadow-sm">
|
||||
<MaterialIcon icon={m.icon} size={22} className={`${m.color} mx-auto`} />
|
||||
<div className={`text-2xl font-display font-black mt-2 ${m.color}`}>{m.value}</div>
|
||||
<div className="text-xs text-[#5E5866] font-semibold mt-1 leading-tight">{m.label}</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</AnimatedGrid>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -400,24 +411,26 @@ export default function MerchantsPage() {
|
||||
<section className="py-10 md:py-14 xl:py-12 bg-white border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 xl:px-20 max-w-[1600px] mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[360px_1fr] gap-10 lg:gap-16 items-start">
|
||||
<div className="lg:sticky lg:top-28">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
FAQs
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Questions Merchants Ask
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-6">
|
||||
Everything you need to know before joining Nearle. Still have questions? Our team is a call away.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 text-sm font-black text-[#6330D6] hover:text-[#5225b8] transition-colors"
|
||||
>
|
||||
<span>Talk to our team</span>
|
||||
<MaterialIcon icon="arrow_forward" size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="lg:sticky lg:top-28">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
FAQs
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl font-black text-[#16001D] mt-4 mb-4 tracking-tight leading-tight">
|
||||
Questions Merchants Ask
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-[#5E5866] leading-relaxed mb-6">
|
||||
Everything you need to know before joining Nearle. Still have questions? Our team is a call away.
|
||||
</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 text-sm font-black text-[#6330D6] hover:text-[#5225b8] transition-colors"
|
||||
>
|
||||
<span>Talk to our team</span>
|
||||
<MaterialIcon icon="arrow_forward" size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<FAQAccordion items={FAQ_ITEMS} />
|
||||
</div>
|
||||
@@ -425,42 +438,18 @@ export default function MerchantsPage() {
|
||||
</section>
|
||||
|
||||
{/* ─── CTA Banner ─── */}
|
||||
<section className="bg-white px-2 pt-2 pb-2 md:px-3 md:pt-3 md:pb-3 lg:px-4 lg:pt-4 lg:pb-4 xl:px-5 xl:pt-4 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<div className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#1A0322] via-[#2B0040] to-[#0A000D] text-white">
|
||||
<div className="px-6 py-12 md:px-10 md:py-14 lg:px-14 xl:py-12 text-center relative">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_20%,rgba(99,48,214,0.18),transparent_50%)] pointer-events-none" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_80%,rgba(0,109,55,0.10),transparent_45%)] pointer-events-none" />
|
||||
<div className="relative z-10 max-w-2xl mx-auto">
|
||||
<span className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-white/15 text-white/70 text-xs font-black uppercase tracking-widest mb-6">
|
||||
<MaterialIcon icon="storefront" size={14} />
|
||||
Ready to Grow?
|
||||
</span>
|
||||
<h2 className="font-display text-3xl md:text-4xl xl:text-5xl font-black mb-4 tracking-tight leading-tight">
|
||||
Become a Merchant Partner
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-white/70 mb-8 leading-relaxed max-w-lg mx-auto">
|
||||
Join neighbourhood stores across Coimbatore already selling online with Nearle. Registration takes under 10 minutes.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-3.5">
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-xl transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="bolt" size={18} />
|
||||
<span>Register Your Store</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-white/10 hover:bg-white/15 border border-white/20 text-white font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon="phone" size={18} />
|
||||
<span>Talk to Our Team</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTABanner
|
||||
badge={{ icon: "storefront", label: "Ready to Grow?" }}
|
||||
heading="Become a Merchant Partner"
|
||||
body="Join neighbourhood stores across Coimbatore already selling online with Nearle. Registration takes under 10 minutes."
|
||||
primary={{ href: "/contact", icon: "bolt", label: "Register Your Store" }}
|
||||
secondary={{ href: "/contact", icon: "phone", label: "Talk to Our Team" }}
|
||||
decorations={[
|
||||
"circle at 70% 20%, rgba(99,48,214,0.18), transparent 50%",
|
||||
"circle at 30% 80%, rgba(0,109,55,0.10), transparent 45%",
|
||||
]}
|
||||
/>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { PremiumPageShell } from "@/components/layout/PremiumPageShell";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import { PeopleHero } from "@/components/heroes/PeopleHero";
|
||||
import { AnimatedSection } from "@/components/motion/AnimatedSection";
|
||||
import { AnimatedGrid, AnimatedCard } from "@/components/motion/AnimatedGrid";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -137,83 +138,15 @@ const APP_BENEFITS = [
|
||||
}
|
||||
];
|
||||
|
||||
const HERO_STATS = [
|
||||
{ title: "Verified Local Stores", icon: "store", desc: "Growing local commerce" },
|
||||
{ title: "2km Neighbourhood", icon: "location_on", desc: "Hyperlocal service radius" },
|
||||
{ title: "Happy Customers", icon: "mood", desc: "Growing neighbourhood community" },
|
||||
{ title: "Trusted Platform", icon: "star", desc: "Loved by local shoppers" }
|
||||
];
|
||||
|
||||
export default function PeoplePage() {
|
||||
const collageCards = [
|
||||
{ text: "Discover Nearby", icon: "explore" },
|
||||
{ text: "Save Favourites", icon: "favorite" },
|
||||
{ text: "Order Anytime", icon: "shopping_bag" }
|
||||
];
|
||||
|
||||
return (
|
||||
<PremiumPageShell>
|
||||
{/* ─── Hero Section ─── */}
|
||||
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]">
|
||||
{/* TWO-COLUMN GRID */}
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Left Column: Copy & Actions */}
|
||||
<div className="flex flex-col text-left max-w-xl">
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit">
|
||||
Nearle for People
|
||||
</span>
|
||||
|
||||
<h1 className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight">
|
||||
Your Neighbourhood,
|
||||
<br />
|
||||
Now in Your <span className="text-[#6330D6]">Pocket.</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed">
|
||||
Discover verified local stores, save your favorite merchants, and order everyday items with superfast local fulfillment.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto">
|
||||
<a
|
||||
href="#download-section"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
>
|
||||
Get the App
|
||||
</a>
|
||||
<Link
|
||||
href="/"
|
||||
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
|
||||
>
|
||||
Explore Stores
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Visual Collage */}
|
||||
<div className="w-full">
|
||||
<HeroVisualCollage
|
||||
centerImage="/images/app-mockup.png"
|
||||
leftImage="/images/cat-hot-food.png"
|
||||
rightImage="/images/cat-health-wellness.png"
|
||||
glassCards={collageCards}
|
||||
isPhoneCenter={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* BOTTOM HERO STATS */}
|
||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto">
|
||||
<FeatureStatsRow items={HERO_STATS} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<PeopleHero />
|
||||
|
||||
{/* ─── Bento Grid of Offerings ─── */}
|
||||
<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] border-b border-[#6330D6]/10">
|
||||
<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] border-b border-[#6330D6]/10">
|
||||
<div className="mb-10 xl:mb-8">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
What we offer
|
||||
@@ -250,25 +183,28 @@ export default function PeoplePage() {
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</AnimatedSection>
|
||||
|
||||
{/* ─── Localized Stats Block ─── */}
|
||||
<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-white border-b border-[#6330D6]/10">
|
||||
<div className="mb-10 xl:mb-8">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Nearle Network
|
||||
</span>
|
||||
<h2 className="font-display text-2xl font-black text-[#16001D] mt-4">
|
||||
The Neighbourhood App
|
||||
</h2>
|
||||
<p className="text-xs md:text-sm text-[#5E5866] mt-2">
|
||||
Bringing local stores to your doorstep instantly.
|
||||
</p>
|
||||
</div>
|
||||
<AnimatedSection>
|
||||
<div className="mb-10 xl:mb-8">
|
||||
<span className="text-xs text-[#6330D6] uppercase tracking-widest font-black bg-[#6330D6]/5 px-3.5 py-1 rounded-full">
|
||||
Nearle Network
|
||||
</span>
|
||||
<h2 className="font-display text-2xl font-black text-[#16001D] mt-4">
|
||||
The Neighbourhood App
|
||||
</h2>
|
||||
<p className="text-xs md:text-sm text-[#5E5866] mt-2">
|
||||
Bringing local stores to your doorstep instantly.
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<AnimatedGrid className="grid grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{LOCAL_STATS.map((s) => (
|
||||
<div
|
||||
<AnimatedCard
|
||||
key={s.label}
|
||||
className="bg-white rounded-2xl p-6 border border-[#6330D6]/10 shadow-[0_4px_16px_rgba(99,48,214,0.01)] flex flex-col items-center text-center group hover:scale-[1.01] transition-transform duration-200"
|
||||
>
|
||||
@@ -279,12 +215,13 @@ export default function PeoplePage() {
|
||||
<p className="text-[10px] font-bold text-[#5E5866] mt-1.5 uppercase tracking-wider">
|
||||
{s.label}
|
||||
</p>
|
||||
</div>
|
||||
</AnimatedCard>
|
||||
))}
|
||||
</div>
|
||||
</AnimatedGrid>
|
||||
</section>
|
||||
|
||||
{/* ─── Ready to Download Section ─── */}
|
||||
<AnimatedSection>
|
||||
<section className="bg-white px-2 pt-2 pb-2 md:px-3 md:pt-3 md:pb-3 lg:px-4 lg:pt-4 lg:pb-4 xl:px-5 xl:pt-4 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<section id="download-section" className="relative w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#16001D] to-[#25002F] p-8 text-center text-white md:p-10 lg:p-12 xl:p-10">
|
||||
{/* Subtle glow layers */}
|
||||
@@ -531,6 +468,7 @@ export default function PeoplePage() {
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</AnimatedSection>
|
||||
</PremiumPageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { fadeUp, scaleIn, staggerContainer, staggerSlow, viewport } from "@/lib/animations";
|
||||
|
||||
// ─── Feature SVG Illustrations ───────────────────────────────────────────────
|
||||
// Flat vector style · Nearle brand palette · no text inside SVGs
|
||||
@@ -428,46 +430,50 @@ export function BusinessFeaturesGrid() {
|
||||
>
|
||||
|
||||
{/* ── LEFT — clean text feature grid, no illustrations ── */}
|
||||
<div>
|
||||
{/* Badge */}
|
||||
<span className="inline-flex items-center rounded-full bg-[#6330D6]/[0.08] px-3.5 py-1 text-xs font-black uppercase tracking-widest text-[#6330D6]">
|
||||
Our features
|
||||
</span>
|
||||
<motion.div
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
{/* Badge + Heading */}
|
||||
<motion.div variants={fadeUp}>
|
||||
<span className="inline-flex items-center rounded-full bg-[#6330D6]/[0.08] px-3.5 py-1 text-xs font-black uppercase tracking-widest text-[#6330D6]">
|
||||
Our features
|
||||
</span>
|
||||
<h2
|
||||
className="font-display font-black text-[#16001D] mt-4"
|
||||
style={{
|
||||
fontSize: "clamp(36px, 3.4vw, 60px)",
|
||||
lineHeight: 1.08,
|
||||
letterSpacing: "-0.04em",
|
||||
maxWidth: 780,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
Move Your Business Forward
|
||||
</h2>
|
||||
<p
|
||||
className="text-[#5E5866]"
|
||||
style={{ fontSize: 18, lineHeight: 1.65, maxWidth: 760, marginTop: 16, marginBottom: 36 }}
|
||||
>
|
||||
Be a part of a community of like-minded people. Brand your business on Nearle and reach out to your neighborhood with ease.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Heading */}
|
||||
<h2
|
||||
className="font-display font-black text-[#16001D] mt-4"
|
||||
style={{
|
||||
fontSize: "clamp(36px, 3.4vw, 60px)",
|
||||
lineHeight: 1.08,
|
||||
letterSpacing: "-0.04em",
|
||||
maxWidth: 780,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
Move Your Business Forward
|
||||
</h2>
|
||||
|
||||
{/* Description */}
|
||||
<p
|
||||
className="text-[#5E5866]"
|
||||
style={{ fontSize: 18, lineHeight: 1.65, maxWidth: 760, marginTop: 16, marginBottom: 36 }}
|
||||
>
|
||||
Be a part of a community of like-minded people. Brand your business on Nearle and reach out to your neighborhood with ease.
|
||||
</p>
|
||||
|
||||
{/* Feature list – check + text only, no illustration columns */}
|
||||
<div
|
||||
{/* Feature list */}
|
||||
<motion.div
|
||||
className="grid grid-cols-1 md:grid-cols-2"
|
||||
style={{ columnGap: 48, rowGap: 32 }}
|
||||
variants={staggerSlow}
|
||||
>
|
||||
{FEATURES.map((feat) => (
|
||||
<div
|
||||
<motion.div
|
||||
key={feat.title}
|
||||
variants={fadeUp}
|
||||
className="grid items-start"
|
||||
style={{ gridTemplateColumns: "30px 1fr", columnGap: 16 }}
|
||||
>
|
||||
{/* Green check icon */}
|
||||
<div
|
||||
className="rounded-full bg-[#DCFCE7] flex items-center justify-center shrink-0"
|
||||
style={{ width: 30, height: 30, marginTop: 3 }}
|
||||
@@ -476,8 +482,6 @@ export function BusinessFeaturesGrid() {
|
||||
<path d="M3.5 8.5L6.5 11.5L12.5 5" stroke="#16A34A" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Title + description */}
|
||||
<div className="min-w-0">
|
||||
<h4
|
||||
className="font-display font-black text-[#16001D]"
|
||||
@@ -489,30 +493,33 @@ export function BusinessFeaturesGrid() {
|
||||
{feat.descr}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* ── RIGHT — 4 cards + illustration strip below ─────── */}
|
||||
<div className="self-start flex flex-col" style={{ gap: 28 }}>
|
||||
|
||||
{/* 2×2 feature benefit cards */}
|
||||
{/* ── RIGHT — 2×2 feature benefit cards ─────── */}
|
||||
<motion.div
|
||||
className="self-start flex flex-col"
|
||||
style={{ gap: 28 }}
|
||||
variants={staggerSlow}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
<div className="grid grid-cols-2" style={{ gap: 28 }}>
|
||||
{CARDS.map((card) => {
|
||||
const { CardIllus } = card;
|
||||
return (
|
||||
<div
|
||||
<motion.div
|
||||
key={card.title}
|
||||
variants={scaleIn}
|
||||
className={`relative flex flex-col overflow-hidden border border-[#6330D6]/10 shadow-[0_4px_28px_rgba(99,48,214,0.09)] ${card.bg}`}
|
||||
style={{ borderRadius: 34, padding: 28, minHeight: 330 }}
|
||||
>
|
||||
{/* Top icon */}
|
||||
<div className={`w-9 h-9 rounded-full flex items-center justify-center shrink-0 ${card.iconBg}`}>
|
||||
<MaterialIcon icon={card.iconName} size={18} />
|
||||
</div>
|
||||
|
||||
{/* Illustration */}
|
||||
<div
|
||||
className="flex-1 flex items-center justify-center overflow-hidden"
|
||||
style={{ margin: "8px 0" }}
|
||||
@@ -521,8 +528,6 @@ export function BusinessFeaturesGrid() {
|
||||
<CardIllus />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom label */}
|
||||
<div className="mt-auto shrink-0">
|
||||
<p
|
||||
className={`font-display font-black leading-none tracking-tight ${card.titleColor}`}
|
||||
@@ -537,13 +542,11 @@ export function BusinessFeaturesGrid() {
|
||||
{card.subtitle}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
// Stagger form contents after the card slides in from right (card enters at delay 0.25, duration 0.65 → visible ~t=0.7s)
|
||||
const formContentStagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.1, delayChildren: 0.75 } },
|
||||
};
|
||||
|
||||
const fieldVariant = {
|
||||
hidden: { opacity: 0, y: 14 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.45, ease: EASE } },
|
||||
};
|
||||
|
||||
const submitVariant = {
|
||||
hidden: { opacity: 0, y: 10, scale: 0.98 },
|
||||
visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.4, ease: EASE } },
|
||||
};
|
||||
|
||||
type FormData = {
|
||||
name: string;
|
||||
email: string;
|
||||
@@ -100,16 +119,21 @@ export function ContactForm() {
|
||||
<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-2xl" />
|
||||
|
||||
<div className="relative z-10">
|
||||
<span className="text-label-sm font-black text-primary uppercase tracking-widest">
|
||||
<motion.div
|
||||
className="relative z-10"
|
||||
variants={formContentStagger}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<motion.span variants={fieldVariant} className="text-label-sm font-black text-primary uppercase tracking-widest block">
|
||||
Write to us
|
||||
</span>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-black text-brand-dark mt-2 mb-8">
|
||||
</motion.span>
|
||||
<motion.h2 variants={fieldVariant} className="font-display text-2xl md:text-3xl font-black text-brand-dark mt-2 mb-8">
|
||||
Send Message
|
||||
</h2>
|
||||
</motion.h2>
|
||||
|
||||
<form onSubmit={handleSubmit} className="flex flex-col gap-5">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<motion.div variants={fieldVariant} className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
{/* Name field */}
|
||||
<div className="flex flex-col">
|
||||
<label htmlFor="field-name" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
||||
@@ -171,10 +195,10 @@ export function ContactForm() {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Message field */}
|
||||
<div className="flex flex-col">
|
||||
<motion.div variants={fieldVariant} className="flex flex-col">
|
||||
<label htmlFor="field-message" className="text-label-sm text-on-surface-variant font-bold mb-2">
|
||||
Message
|
||||
</label>
|
||||
@@ -202,28 +226,30 @@ export function ContactForm() {
|
||||
{errors.message}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Submit button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-[#6330D6] hover:bg-[#5225b8] disabled:bg-[#6330D6]/60 text-on-primary font-black px-8 py-4 rounded-xl text-label-md hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 active:translate-y-0 active:scale-[0.98] flex items-center justify-center gap-2 cursor-pointer"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<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>
|
||||
{/* Submit button — appears last */}
|
||||
<motion.div variants={submitVariant}>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-[#6330D6] hover:bg-[#5225b8] disabled:bg-[#6330D6]/60 text-on-primary font-black px-8 py-4 rounded-xl text-label-md hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 active:translate-y-0 active:scale-[0.98] flex items-center justify-center gap-2 cursor-pointer"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<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>
|
||||
</motion.div>
|
||||
</form>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* ─── Success Toast Notification ─── */}
|
||||
|
||||
71
src/components/delivery/AnimatedTimeline.tsx
Normal file
71
src/components/delivery/AnimatedTimeline.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
type TimelineItem = {
|
||||
step: string;
|
||||
title: string;
|
||||
desc: string;
|
||||
time: string;
|
||||
};
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
const containerVariant = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.1, delayChildren: 0.15 } },
|
||||
};
|
||||
|
||||
const itemVariant = {
|
||||
hidden: { opacity: 0, x: -24 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.55, ease: EASE } },
|
||||
};
|
||||
|
||||
const connectorVariant = {
|
||||
hidden: { scaleY: 0 },
|
||||
visible: { scaleY: 1, transition: { duration: 0.9, ease: EASE } },
|
||||
};
|
||||
|
||||
export function AnimatedTimeline({ items }: { items: TimelineItem[] }) {
|
||||
return (
|
||||
<div className="relative max-w-3xl mx-auto">
|
||||
{/* Vertical connector line — animated scaleY from origin-top */}
|
||||
<motion.div
|
||||
className="absolute left-[22px] md:left-[26px] top-8 bottom-8 w-0.5 bg-gradient-to-b from-[#6330D6]/30 via-[#6330D6]/20 to-transparent hidden sm:block origin-top"
|
||||
variants={connectorVariant}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, amount: 0.1 }}
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
className="space-y-6"
|
||||
variants={containerVariant}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, amount: 0.1 }}
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<motion.div
|
||||
key={item.step}
|
||||
className="relative flex gap-5 sm:gap-7"
|
||||
variants={itemVariant}
|
||||
>
|
||||
<div className="flex-shrink-0 w-11 h-11 md:w-12 md:h-12 rounded-full bg-[#6330D6] text-white flex items-center justify-center text-xs font-black shadow-[0_8px_20px_rgba(99,48,214,0.25)] relative z-10">
|
||||
{String(index + 1).padStart(2, "0")}
|
||||
</div>
|
||||
<div className="flex-1 pb-2 pt-1">
|
||||
<div className="flex items-center gap-3 mb-1.5">
|
||||
<h3 className="text-base font-black text-[#16001D] leading-tight">{item.title}</h3>
|
||||
<span className="px-2.5 py-0.5 rounded-full bg-[#6330D6]/8 text-[#6330D6] text-[10px] font-black uppercase tracking-wide shrink-0">
|
||||
{item.time}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-[#5E5866] leading-relaxed">{item.desc}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
150
src/components/heroes/AboutHero.tsx
Normal file
150
src/components/heroes/AboutHero.tsx
Normal file
@@ -0,0 +1,150 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { motion } from "framer-motion";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import type { Variants } from "framer-motion";
|
||||
import {
|
||||
fadeInSlow,
|
||||
fadeUp,
|
||||
staggerSlow,
|
||||
viewport,
|
||||
} from "@/lib/animations";
|
||||
|
||||
const HERO_STATS = [
|
||||
{ title: "2km Coverage", icon: "explore", desc: "Hyperlocal radius" },
|
||||
{ title: "Verified Local Stores", icon: "store", desc: "Growing local commerce" },
|
||||
{ title: "Happy Customers", icon: "mood", desc: "Neighbourhood community" },
|
||||
{ title: "Coimbatore & Beyond", icon: "location_city", desc: "Growing neighbourhood reach" },
|
||||
];
|
||||
|
||||
const COLLAGE_CARDS = [
|
||||
{ text: "Local First", icon: "store" },
|
||||
{ text: "Trusted Network", icon: "verified" },
|
||||
{ text: "Connected Communities", icon: "groups" },
|
||||
];
|
||||
|
||||
// Choreography: deliberate, slow-stagger sequence — thoughtful and purposeful
|
||||
// badge fades in (opacity only) → h1 sweeps from left → p fades up → CTAs fade up
|
||||
// The collage scales up softly, reinforcing the "built carefully" feeling
|
||||
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 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] },
|
||||
},
|
||||
};
|
||||
const ctaVariant = fadeUp;
|
||||
|
||||
const collageVariant = {
|
||||
hidden: { opacity: 0, scale: 0.92 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
transition: { duration: 0.95, ease: [0.22, 1, 0.36, 1] as [number, number, number, number], delay: 0.2 },
|
||||
},
|
||||
};
|
||||
|
||||
// Trust-feeling card variant: no spring bounce, deliberate easing
|
||||
const trustCardVariant: Variants = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export function AboutHero() {
|
||||
return (
|
||||
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]">
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Left Column: slow, deliberate stagger — thoughtful pacing */}
|
||||
<motion.div
|
||||
className="flex flex-col text-left max-w-xl"
|
||||
variants={staggerSlow}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<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-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit"
|
||||
>
|
||||
About Nearle
|
||||
</motion.span>
|
||||
|
||||
<motion.h1
|
||||
variants={titleVariant}
|
||||
className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight"
|
||||
>
|
||||
Built for Every
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Neighbourhood.</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={descVariant}
|
||||
className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed"
|
||||
>
|
||||
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.div
|
||||
variants={ctaVariant}
|
||||
className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto"
|
||||
>
|
||||
<a
|
||||
href="#story-section"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
>
|
||||
Our Story
|
||||
</a>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
|
||||
>
|
||||
Join Our Journey
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: soft scale-up — gentle and community-first */}
|
||||
<motion.div
|
||||
className="w-full"
|
||||
variants={collageVariant}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<HeroVisualCollage
|
||||
centerImage="/nearlenewlogo.png"
|
||||
leftImage="/Nearle Business.png"
|
||||
rightImage="/nearle people.png"
|
||||
glassCards={COLLAGE_CARDS}
|
||||
isPhoneCenter={false}
|
||||
cardVariant={trustCardVariant}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto">
|
||||
<FeatureStatsRow items={HERO_STATS} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
123
src/components/heroes/BusinessHero.tsx
Normal file
123
src/components/heroes/BusinessHero.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { motion } from "framer-motion";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import {
|
||||
slideInLeftSubtle,
|
||||
fadeUp,
|
||||
fadeIn,
|
||||
scaleIn,
|
||||
staggerContainer,
|
||||
viewport,
|
||||
} from "@/lib/animations";
|
||||
|
||||
const HERO_BENEFITS = [
|
||||
{ title: "More Visibility Across Nearle", icon: "visibility", desc: "Get discovered by locals" },
|
||||
{ title: "Easy Order Management", icon: "assignment", desc: "Track and fulfill cleanly" },
|
||||
{ title: "Grow Repeat Customers", icon: "trending_up", desc: "Build neighborhood loyalty" },
|
||||
{ title: "Local Delivery Support", icon: "local_shipping", desc: "Deliver fast & verified" },
|
||||
];
|
||||
|
||||
const COLLAGE_CARDS = [
|
||||
{ text: "Nearby Customers", icon: "people" },
|
||||
{ text: "Orders & Offers", icon: "local_offer" },
|
||||
{ text: "Local Delivery Support", icon: "local_shipping" },
|
||||
];
|
||||
|
||||
// Choreography: badge slides left → title fades up → description fades in (opacity only) → CTAs scale in
|
||||
const badgeVariant = slideInLeftSubtle;
|
||||
const titleVariant = {
|
||||
hidden: { opacity: 0, y: 28 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.55, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
const descVariant = fadeIn;
|
||||
const ctaVariant = scaleIn;
|
||||
|
||||
export function BusinessHero() {
|
||||
return (
|
||||
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]">
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Left Column: animated with unique stagger */}
|
||||
<motion.div
|
||||
className="flex flex-col text-left max-w-xl"
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<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-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit"
|
||||
>
|
||||
Nearle for Business
|
||||
</motion.span>
|
||||
|
||||
<motion.h1
|
||||
variants={titleVariant}
|
||||
className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight"
|
||||
>
|
||||
Grow Your Local Business,
|
||||
<br />
|
||||
<span className="text-[#6330D6]">Neighbourhood by Neighbourhood.</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={descVariant}
|
||||
className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed"
|
||||
>
|
||||
Get discovered by nearby customers, manage orders, and build repeat business from one simple platform.
|
||||
</motion.p>
|
||||
|
||||
<motion.div
|
||||
variants={ctaVariant}
|
||||
className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto"
|
||||
>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
>
|
||||
List Your Store
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
|
||||
>
|
||||
Explore Solutions
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: subtle fade-in — HeroVisualCollage internal animations choreograph each element */}
|
||||
<motion.div
|
||||
className="w-full"
|
||||
variants={fadeIn}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.2 }}
|
||||
>
|
||||
<HeroVisualCollage
|
||||
centerImage="/nearlenewlogo.png"
|
||||
leftImage="/images/cat-daily-essentials.png"
|
||||
rightImage="/Nearle Business.png"
|
||||
glassCards={COLLAGE_CARDS}
|
||||
isPhoneCenter={false}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto">
|
||||
<FeatureStatsRow items={HERO_BENEFITS} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
139
src/components/heroes/ContactHero.tsx
Normal file
139
src/components/heroes/ContactHero.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { ContactForm } from "@/components/contact/ContactForm";
|
||||
import { fadeUp, fadeUpStrong, slideInRight, staggerContainer, viewport } from "@/lib/animations";
|
||||
|
||||
const CONTACT_INFO = [
|
||||
{
|
||||
icon: "phone",
|
||||
label: "Call Us",
|
||||
value: "+91 909 206 8666",
|
||||
},
|
||||
{
|
||||
icon: "mail",
|
||||
label: "Email Us",
|
||||
value: "nearle@care.in",
|
||||
},
|
||||
{
|
||||
icon: "location_on",
|
||||
label: "Address",
|
||||
value: "424, DB Rd, R.S. Puram, Coimbatore, TN 641002",
|
||||
},
|
||||
];
|
||||
|
||||
// Choreography: professional, clear sequence
|
||||
// Left column — each info row staggers in from left; h1 has strong upward entry
|
||||
// Form card slides in from right with slight delay
|
||||
// Info rows use a tighter stagger to feel organised and systematic
|
||||
const infoRowVariant = {
|
||||
hidden: { opacity: 0, x: -18 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.45, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
const formVariant = {
|
||||
hidden: { opacity: 0, x: 40 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.65, ease: [0.22, 1, 0.36, 1] as [number, number, number, number], delay: 0.25 },
|
||||
},
|
||||
};
|
||||
|
||||
const infoStagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.08 } },
|
||||
};
|
||||
|
||||
export function ContactHero() {
|
||||
return (
|
||||
<section className="relative border-b border-[#6330D6]/10 px-4 py-10 md:px-6 md:py-12 lg:px-8 lg:py-14 xl:px-10 xl:py-16 2xl:px-12 2xl:py-20">
|
||||
|
||||
{/* Decorative map grid — not animated so it stays subtle */}
|
||||
<div className="absolute left-[5%] top-[10%] w-[400px] h-[300px] opacity-[0.04] select-none pointer-events-none -z-10">
|
||||
<svg className="w-full h-full text-[#6330D6]" stroke="currentColor" fill="none" strokeWidth="1.5" viewBox="0 0 400 300">
|
||||
<path d="M0,50 L400,50 M0,130 L400,130 M0,210 L400,210 M80,0 L80,300 M200,0 L200,300 M320,0 L320,300" />
|
||||
<path d="M 80,130 C 120,90 160,170 200,130 C 240,90 280,170 320,130" strokeDasharray="3,3" />
|
||||
<circle cx="200" cy="130" r="4" fill="currentColor" />
|
||||
<circle cx="200" cy="130" r="14" strokeWidth="1" />
|
||||
<circle cx="80" cy="50" r="3" fill="currentColor" />
|
||||
<circle cx="320" cy="210" r="3" fill="currentColor" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 mx-auto w-full max-w-[1520px]">
|
||||
<div className="grid grid-cols-1 items-start gap-10 lg:grid-cols-[1.2fr_0.8fr] lg:gap-12 xl:gap-16">
|
||||
|
||||
{/* Left Column — Contact Info: sequential stagger from top */}
|
||||
<motion.div
|
||||
className="w-full max-w-[760px] py-6 md:py-8 lg:py-10 relative z-10 text-[#16001D]"
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit"
|
||||
>
|
||||
Contact Us
|
||||
</motion.span>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUpStrong}
|
||||
className="font-display text-4xl font-black leading-[1.05] text-[#16001D] md:text-5xl lg:text-[58px] xl:text-[64px] 2xl:text-[70px]"
|
||||
>
|
||||
We're Here to <br />
|
||||
<span className="text-[#6330D6]">Help You.</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
className="mt-6 max-w-[620px] text-sm font-bold leading-8 text-[#5E5866] md:text-base xl:text-lg"
|
||||
>
|
||||
Whether you are a customer, local store owner, or delivery partner, our team is here to help you get started with Nearle.
|
||||
</motion.p>
|
||||
|
||||
{/* Info rows: each row staggers in from left */}
|
||||
<motion.div
|
||||
className="mt-8 border-t border-[#6330D6]/10"
|
||||
variants={infoStagger}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
{CONTACT_INFO.map((item) => (
|
||||
<motion.div
|
||||
key={item.label}
|
||||
variants={infoRowVariant}
|
||||
className="flex gap-4 py-4.5 border-b border-[#6330D6]/10 items-center"
|
||||
>
|
||||
<div className="w-10 h-10 rounded-full bg-[#6330D6]/10 text-[#6330D6] flex items-center justify-center shrink-0">
|
||||
<MaterialIcon icon={item.icon} size={18} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-[#16001D] text-sm font-black">{item.label}</h4>
|
||||
<p className="text-[#5E5866] text-sm font-semibold mt-0.5">{item.value}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: form slides in from right */}
|
||||
<motion.div
|
||||
className="w-full max-w-[660px] justify-self-end pt-10 lg:pt-14 xl:pt-26"
|
||||
variants={formVariant}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<ContactForm />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
117
src/components/heroes/PeopleHero.tsx
Normal file
117
src/components/heroes/PeopleHero.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { motion } from "framer-motion";
|
||||
import { HeroVisualCollage } from "@/components/layout/HeroVisualCollage";
|
||||
import { FeatureStatsRow } from "@/components/ui/FeatureStatsRow";
|
||||
import {
|
||||
scaleInSpring,
|
||||
fadeUpStrong,
|
||||
fadeUp,
|
||||
slideInLeftSubtle,
|
||||
fadeIn,
|
||||
staggerFast,
|
||||
} from "@/lib/animations";
|
||||
|
||||
const HERO_STATS = [
|
||||
{ title: "Verified Local Stores", icon: "store", desc: "Growing local commerce" },
|
||||
{ title: "2km Neighbourhood", icon: "location_on", desc: "Hyperlocal service radius" },
|
||||
{ title: "Happy Customers", icon: "mood", desc: "Growing neighbourhood community" },
|
||||
{ title: "Trusted Platform", icon: "star", desc: "Loved by local shoppers" },
|
||||
];
|
||||
|
||||
const COLLAGE_CARDS = [
|
||||
{ text: "Discover Nearby", icon: "explore" },
|
||||
{ text: "Save Favourites", icon: "favorite" },
|
||||
{ text: "Order Anytime", icon: "shopping_bag" },
|
||||
];
|
||||
|
||||
// Choreography: badge bounces in (spring) → h1 strong fade-up → p subtle up → CTAs slide from left
|
||||
// Fast stagger (0.07) gives a snappy, energetic feel — phone/fast/mobile-first vibe
|
||||
const badgeVariant = scaleInSpring;
|
||||
const titleVariant = fadeUpStrong;
|
||||
const descVariant = fadeUp;
|
||||
const ctaVariant = slideInLeftSubtle;
|
||||
|
||||
export function PeopleHero() {
|
||||
return (
|
||||
<section className="w-full flex flex-col pt-6 md:pt-10 select-none bg-gradient-to-br from-white via-[#FEFCFF] to-[#F4ECFA]">
|
||||
<div className="border-b border-[#6330D6]/10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[45%_55%] items-center gap-10 lg:gap-6 px-6 md:px-12 lg:px-16 pb-12 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Left Column: snappy fast-stagger sequence */}
|
||||
<motion.div
|
||||
className="flex flex-col text-left max-w-xl"
|
||||
variants={staggerFast}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
<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-[#6330D6]/10 text-[#6330D6] uppercase mb-6 w-fit"
|
||||
>
|
||||
Nearle for People
|
||||
</motion.span>
|
||||
|
||||
<motion.h1
|
||||
variants={titleVariant}
|
||||
className="font-display text-4xl sm:text-5xl lg:text-[48px] xl:text-[54px] font-black text-[#16001D] leading-[1.1] tracking-tight"
|
||||
>
|
||||
Your Neighbourhood,
|
||||
<br />
|
||||
Now in Your <span className="text-[#6330D6]">Pocket.</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
variants={descVariant}
|
||||
className="text-sm md:text-base text-[#5E5866] font-bold mt-6 leading-relaxed"
|
||||
>
|
||||
Discover verified local stores, save your favorite merchants, and order everyday items with superfast local fulfillment.
|
||||
</motion.p>
|
||||
|
||||
<motion.div
|
||||
variants={ctaVariant}
|
||||
className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto"
|
||||
>
|
||||
<a
|
||||
href="#download-section"
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
>
|
||||
Get the App
|
||||
</a>
|
||||
<Link
|
||||
href="/"
|
||||
className="border-2 border-[#6330D6]/20 hover:border-[#6330D6]/40 text-[#6330D6] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6330D6]/5 active:scale-[0.98]"
|
||||
>
|
||||
Explore Stores
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column: subtle fade — HeroVisualCollage's internal animations handle phone, images, badges individually */}
|
||||
<motion.div
|
||||
className="w-full"
|
||||
variants={fadeIn}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.15 }}
|
||||
>
|
||||
<HeroVisualCollage
|
||||
centerImage="/images/app-mockup.png"
|
||||
leftImage="/images/cat-hot-food.png"
|
||||
rightImage="/images/cat-health-wellness.png"
|
||||
glassCards={COLLAGE_CARDS}
|
||||
isPhoneCenter={true}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#FAF7FD] border-b border-[#6330D6]/10">
|
||||
<div className="px-6 md:px-12 lg:px-16 max-w-[1600px] mx-auto">
|
||||
<FeatureStatsRow items={HERO_STATS} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -69,8 +69,16 @@ export function BusinessSection() {
|
||||
<section className="section bg-white w-full overflow-hidden">
|
||||
<div className="mx-auto w-full max-w-[2200px] px-2 md:px-4 lg:px-5 xl:px-6">
|
||||
<div className="relative overflow-hidden rounded-[2rem] bg-[linear-gradient(135deg,#ffffff_0%,#fbf7ff_50%,#ede4f5_100%)] border border-primary/10 shadow-[0_24px_70px_rgba(22,0,29,0.08)] p-5 md:p-8 lg:p-10">
|
||||
<div className="pointer-events-none absolute -left-16 top-24 h-64 w-64 rounded-full bg-primary/5 blur-3xl" />
|
||||
<div className="pointer-events-none absolute -right-20 bottom-10 h-64 w-64 rounded-full bg-secondary/5 blur-3xl" />
|
||||
<motion.div
|
||||
className="pointer-events-none absolute -left-16 top-24 h-64 w-64 rounded-full bg-primary/5 blur-3xl"
|
||||
animate={{ y: [0, -16, 0] }}
|
||||
transition={{ duration: 13, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
<motion.div
|
||||
className="pointer-events-none absolute -right-20 bottom-10 h-64 w-64 rounded-full bg-secondary/5 blur-3xl"
|
||||
animate={{ y: [0, 14, 0] }}
|
||||
transition={{ duration: 11, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
|
||||
<div className="relative grid gap-6 grid-cols-1 md:gap-7
|
||||
xl:grid-cols-[420px_1fr] xl:gap-8 xl:items-start">
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import {
|
||||
fadeUp,
|
||||
slideInRight,
|
||||
staggerContainer,
|
||||
viewport,
|
||||
} from "@/lib/animations";
|
||||
import { viewport } from "@/lib/animations";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
const PROOF_ITEMS = [
|
||||
{ label: "Verified", text: "Local Stores", icon: "store" },
|
||||
@@ -18,16 +15,86 @@ const PROOF_ITEMS = [
|
||||
{ label: "Trusted", text: "Local Platform", icon: "star" },
|
||||
];
|
||||
|
||||
// Left column: badge → line1 mask-reveal → line2 mask-reveal → desc → primary CTA → secondary CTA
|
||||
const heroStagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.12, delayChildren: 0.05 } },
|
||||
};
|
||||
|
||||
const badgeVariant = {
|
||||
hidden: { opacity: 0, y: 10, scale: 0.95 },
|
||||
visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.38, ease: EASE } },
|
||||
};
|
||||
|
||||
// Lines stagger internally
|
||||
const lineStagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.09 } },
|
||||
};
|
||||
|
||||
// True mask reveal: text slides up from below a clipping parent
|
||||
const lineReveal = {
|
||||
hidden: { y: "110%" },
|
||||
visible: { y: 0, transition: { duration: 0.72, ease: EASE } },
|
||||
};
|
||||
|
||||
const descVariant = {
|
||||
hidden: { opacity: 0, y: 18 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.55, ease: EASE } },
|
||||
};
|
||||
|
||||
const primaryCtaVariant = {
|
||||
hidden: { opacity: 0, y: 14, scale: 0.97 },
|
||||
visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.45, ease: EASE } },
|
||||
};
|
||||
|
||||
const secondaryCtaVariant = {
|
||||
hidden: { opacity: 0, x: -14 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.4, ease: EASE } },
|
||||
};
|
||||
|
||||
// Right column: each element enters independently
|
||||
const imgFromLeft = {
|
||||
hidden: { opacity: 0, x: -36 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.65, ease: EASE } },
|
||||
};
|
||||
|
||||
const centerCardReveal = {
|
||||
hidden: { opacity: 0, scale: 0.86, y: 24 },
|
||||
visible: { opacity: 1, scale: 1, y: 0, transition: { duration: 0.75, ease: EASE } },
|
||||
};
|
||||
|
||||
const imgFromRight = {
|
||||
hidden: { opacity: 0, x: 36 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.65, ease: EASE } },
|
||||
};
|
||||
|
||||
const statStagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.08 } },
|
||||
};
|
||||
|
||||
const statItem = {
|
||||
hidden: { opacity: 0, y: 14 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.45, ease: EASE } },
|
||||
};
|
||||
|
||||
export function Hero() {
|
||||
const reducedMotion = useReducedMotion();
|
||||
|
||||
return (
|
||||
<section className="relative overflow-hidden bg-gradient-to-b from-[#FAF8FC] to-[#FFFFFF] select-none w-full">
|
||||
{/* ─── DECORATIONS (BEHIND CONTENT) ─── */}
|
||||
|
||||
{/* 1. Large pale lavender partial circle (top-left) */}
|
||||
<div className="hidden md:block absolute top-[-100px] left-[-100px] w-[350px] h-[350px] rounded-full border-[1.5px] border-[#6D28D9]/15 bg-[#6D28D9]/5 opacity-[0.55] z-0 pointer-events-none" />
|
||||
<motion.div
|
||||
className="hidden md:block absolute top-[-100px] left-[-100px] w-[350px] h-[350px] rounded-full border-[1.5px] border-[#6D28D9]/15 bg-[#6D28D9]/5 opacity-[0.55] z-0 pointer-events-none"
|
||||
animate={{ y: [0, -14, 0] }}
|
||||
transition={{ duration: 14, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
|
||||
{/* 2. Purple solid circle (center-right around collage) */}
|
||||
<div className="hidden lg:block absolute right-[22%] top-[38%] w-[84px] h-[84px] rounded-full bg-[#6D28D9] z-0 shadow-[0_8px_32px_rgba(109,40,217,0.3)] pointer-events-none animate-pulse" />
|
||||
<div className="hidden lg:block absolute right-[22%] top-[38%] w-[84px] h-[84px] rounded-full bg-[#6D28D9] z-0 shadow-[0_8px_32px_rgba(109,40,217,0.3)] pointer-events-none motion-safe:animate-pulse" />
|
||||
|
||||
{/* 3. Striped purple circle (lower-middle collage area) */}
|
||||
<div
|
||||
@@ -53,7 +120,11 @@ export function Hero() {
|
||||
<div className="absolute bottom-[14%] right-[5%] text-[#6D28D9]/25 font-bold text-xl pointer-events-none select-none z-0">✕</div>
|
||||
|
||||
{/* 6. Large partial purple circle (bottom-right corner) */}
|
||||
<div className="absolute bottom-[-100px] right-[-100px] w-[200px] h-[200px] rounded-full bg-[#7C3AED]/80 z-0 pointer-events-none" />
|
||||
<motion.div
|
||||
className="absolute bottom-[-100px] right-[-100px] w-[200px] h-[200px] rounded-full bg-[#7C3AED]/80 z-0 pointer-events-none"
|
||||
animate={{ y: [0, 12, 0] }}
|
||||
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
|
||||
{/* ─── TWO-COLUMN CONTENT GRID ─── */}
|
||||
<div className="page-container relative grid min-h-[650px] grid-cols-1 lg:grid-cols-[0.92fr_1.08fr] items-center py-16 md:py-20 lg:py-24 z-10 gap-12 lg:gap-6">
|
||||
@@ -61,64 +132,84 @@ export function Hero() {
|
||||
{/* LEFT COLUMN: Editorial Typography & Copy */}
|
||||
<motion.div
|
||||
className="flex flex-col text-left max-w-xl z-20 relative"
|
||||
variants={staggerContainer}
|
||||
variants={heroStagger}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
{/* Badge */}
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
variants={badgeVariant}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-black tracking-widest bg-[#6D28D9]/10 text-[#6D28D9] uppercase mb-6 w-fit"
|
||||
>
|
||||
Welcome to Nearle
|
||||
</motion.span>
|
||||
|
||||
<motion.h1
|
||||
variants={fadeUp}
|
||||
className="font-display text-4xl sm:text-5xl lg:text-[68px] xl:text-[76px] font-black text-[#16001D] leading-[0.95] tracking-[-0.05em]"
|
||||
>
|
||||
Everything Local.
|
||||
<br />
|
||||
Everything <span className="text-[#6D28D9]">Near.</span>
|
||||
</motion.h1>
|
||||
{/* H1: line-by-line mask reveal */}
|
||||
<motion.div variants={lineStagger} className="font-display text-4xl sm:text-5xl lg:text-[68px] xl:text-[76px] font-black text-[#16001D] tracking-[-0.05em]">
|
||||
<div className="overflow-hidden pb-1">
|
||||
<motion.div variants={lineReveal} className="leading-[0.95]">
|
||||
Everything Local.
|
||||
</motion.div>
|
||||
</div>
|
||||
<div className="overflow-hidden pb-1">
|
||||
<motion.div variants={lineReveal} className="leading-[0.95]">
|
||||
Everything <span className="text-[#6D28D9]">Near.</span>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Description */}
|
||||
<motion.p
|
||||
variants={fadeUp}
|
||||
variants={descVariant}
|
||||
className="max-w-[480px] text-base md:text-lg text-[#6D6172] leading-relaxed font-bold mt-6"
|
||||
>
|
||||
Discover verified local stores, exclusive offers, fast delivery, and a better way to shop within your neighbourhood.
|
||||
</motion.p>
|
||||
|
||||
<motion.div
|
||||
variants={fadeUp}
|
||||
className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto"
|
||||
>
|
||||
<Link
|
||||
href="/people"
|
||||
className="bg-[#6D28D9] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-all duration-200 active:scale-[0.98]"
|
||||
{/* CTAs: primary scales in, secondary slides from left */}
|
||||
<div className="flex flex-col sm:flex-row gap-3.5 mt-8 w-full sm:w-auto">
|
||||
<motion.div
|
||||
variants={primaryCtaVariant}
|
||||
whileHover={{ scale: 1.03, transition: { duration: 0.2, ease: EASE } }}
|
||||
whileTap={{ scale: 0.97, transition: { duration: 0.1 } }}
|
||||
>
|
||||
Explore Stores
|
||||
</Link>
|
||||
<Link
|
||||
href="/people#download-section"
|
||||
className="border-2 border-[#6D28D9]/20 hover:border-[#6D28D9]/40 text-[#6D28D9] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-all duration-200 hover:bg-[#6D28D9]/5 active:scale-[0.98]"
|
||||
<Link
|
||||
href="/people"
|
||||
className="bg-[#6D28D9] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center shadow-md hover:shadow-lg transition-colors duration-200 block"
|
||||
>
|
||||
Explore Stores
|
||||
</Link>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
variants={secondaryCtaVariant}
|
||||
whileHover={{ scale: 1.03, transition: { duration: 0.2, ease: EASE } }}
|
||||
whileTap={{ scale: 0.97, transition: { duration: 0.1 } }}
|
||||
>
|
||||
Get the App
|
||||
</Link>
|
||||
</motion.div>
|
||||
<Link
|
||||
href="/people#download-section"
|
||||
className="border-2 border-[#6D28D9]/20 hover:border-[#6D28D9]/40 text-[#6D28D9] font-black px-8 py-3.5 rounded-xl text-sm md:text-base text-center transition-colors duration-200 hover:bg-[#6D28D9]/5 block"
|
||||
>
|
||||
Get the App
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* RIGHT COLUMN: Creative Overlapping Strips Collage */}
|
||||
<motion.div
|
||||
className="w-full z-20"
|
||||
variants={slideInRight}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
{/* RIGHT COLUMN: Individual image + center card animations */}
|
||||
<div className="w-full z-20">
|
||||
|
||||
{/* DESKTOP LAYOUT (lg and above) */}
|
||||
<div className="hidden lg:block relative h-[500px] lg:h-[560px] w-full">
|
||||
{/* left image: absolute left-[10%] top-[20%] w-[170px] h-[360px] */}
|
||||
<div className="absolute left-[10%] top-[20%] w-[170px] h-[360px] rounded-[1.5rem] overflow-hidden shadow-lg border-2 border-white z-10 transition-transform duration-300 hover:scale-[1.02]">
|
||||
|
||||
{/* Left image: slides in from left */}
|
||||
<motion.div
|
||||
className="absolute left-[10%] top-[20%] w-[170px] h-[360px] rounded-[1.5rem] overflow-hidden shadow-lg border-2 border-white z-10"
|
||||
variants={imgFromLeft}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.3 }}
|
||||
whileHover={{ scale: 1.02, transition: { duration: 0.25, ease: EASE } }}
|
||||
>
|
||||
<Image
|
||||
src="/images/cat-daily-essentials.png"
|
||||
alt="Local grocery products"
|
||||
@@ -126,37 +217,63 @@ export function Hero() {
|
||||
className="object-cover"
|
||||
sizes="170px"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* middle image: central logo panel absolute left-[38%] top-[8%] */}
|
||||
<div className="absolute left-[38%] top-[8%] z-20 transition-transform duration-300 hover:scale-[1.02]">
|
||||
<div className="relative w-[180px] sm:w-[220px] h-[280px] sm:h-[340px] rounded-[24px] border-[5px] sm:border-[6px] border-white/95 shadow-[0_20px_40px_rgba(99,48,214,0.1)] bg-[#FAF8FC] overflow-hidden flex items-center justify-center p-6">
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
alt="Central logo panel"
|
||||
width={160}
|
||||
height={160}
|
||||
className="object-contain max-h-[140px] w-auto animate-[pulse_6s_infinite]"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* Center card: scales up from below, then gently bobs */}
|
||||
<motion.div
|
||||
className="absolute left-[38%] top-[8%] z-20"
|
||||
variants={centerCardReveal}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.15 }}
|
||||
>
|
||||
<motion.div
|
||||
animate={!reducedMotion ? { y: [0, -10, 0] } : {}}
|
||||
transition={{ delay: 0.9, duration: 4, repeat: Infinity, ease: "easeInOut" }}
|
||||
whileHover={{ scale: 1.02, transition: { duration: 0.25, ease: EASE } }}
|
||||
>
|
||||
<div className="relative w-[180px] sm:w-[220px] h-[280px] sm:h-[340px] rounded-[24px] border-[5px] sm:border-[6px] border-white/95 shadow-[0_20px_40px_rgba(99,48,214,0.1)] bg-[#FAF8FC] overflow-hidden flex items-center justify-center p-6">
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
alt="Central logo panel"
|
||||
width={160}
|
||||
height={160}
|
||||
className="object-contain max-h-[140px] w-auto motion-safe:animate-[pulse_6s_infinite]"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* right image: absolute right-[2%] top-[18%] w-[180px] h-[390px] */}
|
||||
<div className="absolute right-[2%] top-[18%] w-[180px] h-[390px] rounded-[1.5rem] overflow-hidden shadow-lg border-2 border-white z-10 transition-transform duration-300 hover:scale-[1.02]">
|
||||
{/* Right image: slides in from right */}
|
||||
<motion.div
|
||||
className="absolute right-[2%] top-[18%] w-[180px] h-[390px] rounded-[1.5rem] overflow-hidden shadow-lg border-2 border-white z-10"
|
||||
variants={imgFromRight}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.42 }}
|
||||
whileHover={{ scale: 1.02, transition: { duration: 0.25, ease: EASE } }}
|
||||
>
|
||||
<Image
|
||||
src="/nearle people.png"
|
||||
alt="Local customer shopping"
|
||||
fill
|
||||
priority
|
||||
className="object-cover"
|
||||
sizes="180px"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* MOBILE/TABLET COLLAGE (below lg) */}
|
||||
<div className="lg:hidden flex items-center justify-center gap-2 mt-2 w-full relative h-[280px]">
|
||||
<div className="relative w-[95px] h-[200px] rounded-2xl overflow-hidden border border-white shadow-md z-10">
|
||||
<motion.div
|
||||
className="relative w-[95px] h-[200px] rounded-2xl overflow-hidden border border-white shadow-md z-10"
|
||||
variants={imgFromLeft}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.28 }}
|
||||
>
|
||||
<Image
|
||||
src="/images/cat-daily-essentials.png"
|
||||
alt="Grocery products"
|
||||
@@ -164,18 +281,37 @@ export function Hero() {
|
||||
className="object-cover"
|
||||
sizes="95px"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative w-[115px] h-[240px] rounded-2xl border-4 border-white shadow-lg bg-[#FAF8FC] overflow-hidden flex items-center justify-center p-3 -mx-5 z-20">
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
alt="Central logo panel"
|
||||
width={100}
|
||||
height={100}
|
||||
className="object-contain max-h-[90px] w-auto animate-[pulse_6s_infinite]"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<div className="relative w-[105px] h-[220px] rounded-2xl overflow-hidden border border-white shadow-md z-10">
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="relative w-[115px] h-[240px] rounded-2xl border-4 border-white shadow-lg bg-[#FAF8FC] overflow-hidden flex items-center justify-center p-3 -mx-5 z-20"
|
||||
variants={centerCardReveal}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.15 }}
|
||||
>
|
||||
<motion.div
|
||||
animate={!reducedMotion ? { y: [0, -6, 0] } : {}}
|
||||
transition={{ delay: 0.85, duration: 3.5, repeat: Infinity, ease: "easeInOut" }}
|
||||
>
|
||||
<Image
|
||||
src="/nearlenewlogo.png"
|
||||
alt="Central logo panel"
|
||||
width={100}
|
||||
height={100}
|
||||
className="object-contain max-h-[90px] w-auto motion-safe:animate-[pulse_6s_infinite]"
|
||||
priority
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="relative w-[105px] h-[220px] rounded-2xl overflow-hidden border border-white shadow-md z-10"
|
||||
variants={imgFromRight}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
transition={{ delay: 0.36 }}
|
||||
>
|
||||
<Image
|
||||
src="/nearle people.png"
|
||||
alt="Customer"
|
||||
@@ -183,10 +319,10 @@ export function Hero() {
|
||||
className="object-cover"
|
||||
sizes="105px"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -194,14 +330,13 @@ export function Hero() {
|
||||
<div className="border-t border-[#EEE7F4]/80 bg-white">
|
||||
<motion.div
|
||||
className="page-container py-8 grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-4 relative z-20"
|
||||
variants={staggerContainer}
|
||||
variants={statStagger}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
{PROOF_ITEMS.map((item, idx) => (
|
||||
<motion.div key={item.label} variants={fadeUp} className="flex items-center gap-4 text-left md:justify-center relative">
|
||||
{/* Subtle vertical separator for desktop, except for the first item */}
|
||||
<motion.div key={item.label} variants={statItem} className="flex items-center gap-4 text-left md:justify-center relative">
|
||||
{idx > 0 && (
|
||||
<div className="hidden md:block absolute left-0 top-1/2 -translate-y-1/2 w-[1px] h-10 bg-[#EEE7F4]" />
|
||||
)}
|
||||
|
||||
@@ -256,10 +256,14 @@ export function HowItWorks() {
|
||||
<span className="font-black text-primary">Yours</span>{" "}
|
||||
establish a local online presence and empower neighbourhood customers to discover and interact with you directly.
|
||||
</p>
|
||||
<button className="mt-8 inline-flex w-full items-center justify-center gap-2 rounded-full bg-primary px-8 py-4 text-base font-black text-white shadow-[0_16px_30px_rgba(101,20,154,0.22)] transition-transform duration-200 hover:-translate-y-0.5 sm:w-auto">
|
||||
<motion.button
|
||||
className="mt-8 inline-flex w-full items-center justify-center gap-2 rounded-full bg-primary px-8 py-4 text-base font-black text-white shadow-[0_16px_30px_rgba(101,20,154,0.22)] sm:w-auto"
|
||||
whileHover={{ y: -2, scale: 1.02, transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] } }}
|
||||
whileTap={{ scale: 0.97, transition: { duration: 0.1 } }}
|
||||
>
|
||||
<MaterialIcon icon="forum" size={20} />
|
||||
Talk to an Expert
|
||||
</button>
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
|
||||
@@ -6,7 +6,7 @@ import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { fadeUp, fadeIn, staggerContainer, viewport } from "@/lib/animations";
|
||||
|
||||
const MotionLink = motion(Link);
|
||||
const MotionLink = motion.create(Link);
|
||||
|
||||
const CATEGORIES = [
|
||||
{
|
||||
@@ -106,6 +106,8 @@ export function ServiceCategories() {
|
||||
href="/people"
|
||||
variants={fadeIn}
|
||||
className="bg-white rounded-[2rem] border border-outline-variant/10 shadow-lg overflow-hidden premium-card flex flex-col group h-full cursor-pointer"
|
||||
whileHover={{ y: -4, scale: 1.02, transition: { duration: 0.22, ease: [0.22, 1, 0.36, 1] } }}
|
||||
whileTap={{ scale: 0.98, transition: { duration: 0.1 } }}
|
||||
>
|
||||
{/* Image Container */}
|
||||
<div className="relative aspect-[4/3] w-full overflow-hidden bg-surface-container/30">
|
||||
|
||||
@@ -17,8 +17,16 @@ export function StoreQRSection() {
|
||||
<div className="w-full">
|
||||
<div id="download" className="w-full bg-gradient-to-br from-[#1A0322] to-[#0A000D] rounded-3xl md:rounded-[2rem] overflow-hidden text-white relative flex items-center py-12 md:py-16 px-6 md:px-12 lg:px-16 xl:px-20 border border-white/10 shadow-[0_20px_50px_rgba(20,0,30,0.22)]">
|
||||
{/* Background ambient glowing details */}
|
||||
<div className="absolute right-[-10%] top-[-10%] w-[50%] h-[50%] rounded-full bg-brand-accent/5 blur-[120px] pointer-events-none" />
|
||||
<div className="absolute left-[-10%] bottom-[-10%] w-[50%] h-[50%] rounded-full bg-primary/10 blur-[120px] pointer-events-none" />
|
||||
<motion.div
|
||||
className="absolute right-[-10%] top-[-10%] w-[50%] h-[50%] rounded-full bg-brand-accent/5 blur-[120px] pointer-events-none"
|
||||
animate={{ y: [0, -18, 0] }}
|
||||
transition={{ duration: 14, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute left-[-10%] bottom-[-10%] w-[50%] h-[50%] rounded-full bg-primary/10 blur-[120px] pointer-events-none"
|
||||
animate={{ y: [0, 16, 0] }}
|
||||
transition={{ duration: 11, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
|
||||
<div className="w-full relative z-10">
|
||||
|
||||
@@ -124,7 +132,7 @@ export function StoreQRSection() {
|
||||
</div>
|
||||
|
||||
<span className="inline-flex items-center gap-1.5 px-3.5 py-1.5 rounded-full text-[10px] font-black tracking-wider uppercase bg-primary/5 text-primary leading-none">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-pulse" />
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-primary motion-safe:animate-pulse" />
|
||||
Scan to Shop
|
||||
</span>
|
||||
</motion.div>
|
||||
@@ -189,7 +197,7 @@ export function StoreQRSection() {
|
||||
</div>
|
||||
|
||||
<span className="inline-flex items-center gap-1.5 px-3.5 py-1.5 rounded-full text-[10px] font-black tracking-wider uppercase bg-primary/5 text-primary">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-pulse" />
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-primary motion-safe:animate-pulse" />
|
||||
Scan to Shop
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
@@ -81,7 +81,7 @@ export function WhyNearle() {
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Cards Grid — fadeIn preserves .premium-card:hover CSS transform */}
|
||||
{/* Cards Grid */}
|
||||
<motion.div
|
||||
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5 lg:gap-7"
|
||||
variants={staggerContainer}
|
||||
@@ -93,7 +93,9 @@ export function WhyNearle() {
|
||||
<motion.div
|
||||
key={card.title}
|
||||
variants={fadeIn}
|
||||
className="premium-card bg-white rounded-3xl p-5 md:p-6 border border-outline-variant/15 shadow-lg flex flex-col h-full hover:scale-[1.02] transition-transform duration-300"
|
||||
className="premium-card bg-white rounded-3xl p-5 md:p-6 border border-outline-variant/15 shadow-lg flex flex-col h-full"
|
||||
whileHover={{ y: -4, scale: 1.02, transition: { duration: 0.22, ease: [0.22, 1, 0.36, 1] } }}
|
||||
whileTap={{ scale: 0.98, transition: { duration: 0.1 } }}
|
||||
>
|
||||
<div className={`w-14 h-14 rounded-2xl flex items-center justify-center border mb-5 shrink-0 ${card.color}`}>
|
||||
<MaterialIcon icon={card.icon} size={27} />
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { GlassInfoCard } from "../ui/GlassInfoCard";
|
||||
import { scaleIn, staggerContainer, viewport } from "@/lib/animations";
|
||||
import type { Variants } from "framer-motion";
|
||||
|
||||
type GlassCardItem = {
|
||||
text: string;
|
||||
@@ -12,6 +17,40 @@ type HeroVisualCollageProps = {
|
||||
rightImage?: string;
|
||||
glassCards: GlassCardItem[];
|
||||
isPhoneCenter?: boolean;
|
||||
cardVariant?: Variants;
|
||||
};
|
||||
|
||||
const leftPanelVariant: Variants = {
|
||||
hidden: { opacity: 0, x: -28 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
const rightPanelVariant: Variants = {
|
||||
hidden: { opacity: 0, x: 28 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
const glasscardVariant: Variants = {
|
||||
hidden: { opacity: 0, scale: 0.88, y: 8 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
y: 0,
|
||||
transition: { type: "spring", stiffness: 260, damping: 22 },
|
||||
},
|
||||
};
|
||||
|
||||
const glassCardStagger: Variants = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.1, delayChildren: 0.3 } },
|
||||
};
|
||||
|
||||
export function HeroVisualCollage({
|
||||
@@ -20,14 +59,14 @@ export function HeroVisualCollage({
|
||||
rightImage,
|
||||
glassCards,
|
||||
isPhoneCenter = true,
|
||||
cardVariant,
|
||||
}: HeroVisualCollageProps) {
|
||||
const activeCardVariant = cardVariant ?? glasscardVariant;
|
||||
return (
|
||||
<div className="relative w-full h-[380px] sm:h-[450px] lg:h-[500px] max-w-[540px] mx-auto flex items-center justify-center select-none">
|
||||
{/* Decorative backgrounds */}
|
||||
{/* 1. Soft purple circle */}
|
||||
<div className="absolute w-[240px] h-[240px] rounded-full bg-[#7C3AED]/10 blur-[60px] -z-10" />
|
||||
|
||||
{/* 2. SVG Dot grid */}
|
||||
<div className="absolute -top-4 -right-4 w-32 h-32 text-[#6330D6]/10 -z-10 opacity-20">
|
||||
<svg className="w-full h-full" fill="currentColor">
|
||||
<pattern id="collage-dots" x="0" y="0" width="16" height="16" patternUnits="userSpaceOnUse">
|
||||
@@ -37,13 +76,19 @@ export function HeroVisualCollage({
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* 3. Small x marks */}
|
||||
<div className="absolute top-12 left-6 text-[#6330D6]/15 font-display text-xl font-bold select-none pointer-events-none">✕</div>
|
||||
<div className="absolute bottom-16 right-8 text-[#6330D6]/15 font-display text-xl font-bold select-none pointer-events-none">✕</div>
|
||||
|
||||
{/* LEFT IMAGE PANEL (Hidden or compact on small mobile) */}
|
||||
{/* LEFT IMAGE PANEL */}
|
||||
{leftImage && (
|
||||
<div className="absolute left-2 sm:left-4 top-[15%] w-[100px] sm:w-[130px] h-[180px] sm:h-[220px] rounded-[18px] overflow-hidden border-2 border-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] z-10 transition-transform hover:scale-105 duration-300">
|
||||
<motion.div
|
||||
className="absolute left-2 sm:left-4 top-[15%] w-[100px] sm:w-[130px] h-[180px] sm:h-[220px] rounded-[18px] overflow-hidden border-2 border-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] z-10"
|
||||
variants={leftPanelVariant}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
whileHover={{ scale: 1.04, transition: { duration: 0.25, ease: [0.22, 1, 0.36, 1] } }}
|
||||
>
|
||||
<Image
|
||||
src={leftImage}
|
||||
alt="Collage left asset"
|
||||
@@ -51,12 +96,19 @@ export function HeroVisualCollage({
|
||||
className="object-cover"
|
||||
sizes="(max-width: 640px) 100px, 130px"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* RIGHT IMAGE PANEL */}
|
||||
{rightImage && (
|
||||
<div className="absolute right-2 sm:right-4 bottom-[15%] w-[100px] sm:w-[130px] h-[180px] sm:h-[220px] rounded-[18px] overflow-hidden border-2 border-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] z-10 transition-transform hover:scale-105 duration-300">
|
||||
<motion.div
|
||||
className="absolute right-2 sm:right-4 bottom-[15%] w-[100px] sm:w-[130px] h-[180px] sm:h-[220px] rounded-[18px] overflow-hidden border-2 border-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] z-10"
|
||||
variants={rightPanelVariant}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
whileHover={{ scale: 1.04, transition: { duration: 0.25, ease: [0.22, 1, 0.36, 1] } }}
|
||||
>
|
||||
<Image
|
||||
src={rightImage}
|
||||
alt="Collage right asset"
|
||||
@@ -64,13 +116,18 @@ export function HeroVisualCollage({
|
||||
className="object-cover"
|
||||
sizes="(max-width: 640px) 100px, 130px"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* CENTER COMPONENT */}
|
||||
<div className="relative z-20">
|
||||
<motion.div
|
||||
className="relative z-20"
|
||||
variants={scaleIn}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
{isPhoneCenter ? (
|
||||
/* Phone Frame Container */
|
||||
<div className="relative w-[180px] sm:w-[220px] h-[360px] sm:h-[440px] rounded-[36px] border-[5px] sm:border-[6px] border-white/95 shadow-[0_20px_50px_rgba(99,48,214,0.12)] bg-[#FAF8FC] overflow-hidden flex flex-col justify-center items-center">
|
||||
<Image
|
||||
src={centerImage}
|
||||
@@ -82,56 +139,70 @@ export function HeroVisualCollage({
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
/* Central Logo / Visual Panel */
|
||||
<div className="relative w-[180px] sm:w-[220px] h-[280px] sm:h-[340px] rounded-[24px] border-[5px] sm:border-[6px] border-white/95 shadow-[0_20px_40px_rgba(99,48,214,0.1)] bg-[#FAF8FC] overflow-hidden flex items-center justify-center p-6">
|
||||
<Image
|
||||
src={centerImage}
|
||||
alt="Central logo panel"
|
||||
width={160}
|
||||
height={160}
|
||||
className="object-contain max-h-[140px] w-auto animate-[pulse_6s_infinite]"
|
||||
className="object-contain max-h-[140px] w-auto motion-safe:animate-[pulse_6s_infinite]"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* FLOATING GLASS CARDS (Positioned Absolute, scaled down on mobile) */}
|
||||
{/* FLOATING GLASS CARDS — stagger in after center */}
|
||||
{glassCards.length > 0 && (
|
||||
<div className="absolute inset-0 z-30 pointer-events-none">
|
||||
{/* Card 1: Top Right */}
|
||||
<motion.div
|
||||
className="absolute inset-0 z-30 pointer-events-none"
|
||||
variants={glassCardStagger}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
{glassCards[0] && (
|
||||
<div className="absolute right-0 sm:right-[5%] top-[10%] pointer-events-auto hover:translate-y-[-2px] transition-transform duration-200">
|
||||
<motion.div
|
||||
variants={activeCardVariant}
|
||||
className="absolute right-0 sm:right-[5%] top-[10%] pointer-events-auto"
|
||||
whileHover={{ y: -2, transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] } }}
|
||||
>
|
||||
<GlassInfoCard
|
||||
text={glassCards[0].text}
|
||||
icon={glassCards[0].icon}
|
||||
className="scale-90 sm:scale-100"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Card 2: Bottom Left */}
|
||||
{glassCards[1] && (
|
||||
<div className="absolute left-0 sm:left-[5%] bottom-[10%] pointer-events-auto hover:translate-y-[-2px] transition-transform duration-200">
|
||||
<motion.div
|
||||
variants={activeCardVariant}
|
||||
className="absolute left-0 sm:left-[5%] bottom-[10%] pointer-events-auto"
|
||||
whileHover={{ y: -2, transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] } }}
|
||||
>
|
||||
<GlassInfoCard
|
||||
text={glassCards[1].text}
|
||||
icon={glassCards[1].icon}
|
||||
className="scale-90 sm:scale-100"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Card 3: Mid Left/Right */}
|
||||
{glassCards[2] && (
|
||||
<div className="absolute left-[5%] top-[45%] pointer-events-auto hover:translate-y-[-2px] transition-transform duration-200">
|
||||
<motion.div
|
||||
variants={activeCardVariant}
|
||||
className="absolute left-[5%] top-[45%] pointer-events-auto"
|
||||
whileHover={{ y: -2, transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] } }}
|
||||
>
|
||||
<GlassInfoCard
|
||||
text={glassCards[2].text}
|
||||
icon={glassCards[2].icon}
|
||||
className="scale-90 sm:scale-100"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const NAV_LINKS = [
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Nearle for Business", href: "/businesses" },
|
||||
{ label: "Nearle for People", href: "/people" },
|
||||
{ label: "About", href: "/about" },
|
||||
{ label: "Contact", href: "/contact" },
|
||||
];
|
||||
|
||||
export function Navbar() {
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 right-0 z-50 w-full flex justify-center pointer-events-none">
|
||||
<div className="w-full max-w-[1920px] px-4 md:px-6 lg:px-8 xl:px-10 2xl:px-12 pt-[18px] md:pt-[24px] pointer-events-auto relative">
|
||||
<nav className="w-full h-[68px] lg:h-[76px] rounded-full bg-[rgba(61,45,143,0.88)] border border-white/20 shadow-sm backdrop-blur-md px-5 md:px-8 lg:px-10 flex items-center transition-all duration-300">
|
||||
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_1fr] items-center w-full h-full">
|
||||
{/* Left: Brand */}
|
||||
<div className="flex items-center justify-start">
|
||||
<Link
|
||||
href="/"
|
||||
className="flex items-center hover:scale-[1.02] transition-transform active:scale-95 duration-200"
|
||||
>
|
||||
<Image
|
||||
src="/logo-light.png"
|
||||
alt="Nearle"
|
||||
width={400}
|
||||
height={50}
|
||||
className="h-8 lg:h-9 w-auto object-contain"
|
||||
priority
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Center: Navigation Links */}
|
||||
<div className="hidden md:flex items-center justify-center gap-6 lg:gap-8 xl:gap-10">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = pathname === link.href;
|
||||
return (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className={`relative py-2 text-[15px] font-semibold leading-5 transition-all duration-200 whitespace-nowrap ${
|
||||
isActive ? "text-white" : "text-white/75 hover:text-white"
|
||||
} group`}
|
||||
>
|
||||
{link.label}
|
||||
<span
|
||||
className={`absolute bottom-[-6px] left-1/2 -translate-x-1/2 h-0.5 bg-white rounded-full transition-all duration-300 ${
|
||||
isActive
|
||||
? "w-5 opacity-100"
|
||||
: "w-0 opacity-0 group-hover:w-4 group-hover:opacity-60"
|
||||
}`}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Right: Actions */}
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<Link
|
||||
href="/#download"
|
||||
className="hidden md:inline-flex items-center justify-center bg-white text-[rgba(61,45,143,0.88)] font-bold px-7 h-[46px] rounded-full text-[15px] hover:bg-white/90 hover:shadow-md hover:scale-[1.02] active:scale-95 transition-all duration-300 whitespace-nowrap"
|
||||
>
|
||||
Get App
|
||||
</Link>
|
||||
|
||||
{/* Mobile menu toggle */}
|
||||
<button
|
||||
className="md:hidden flex items-center justify-center w-10 h-10 rounded-full hover:bg-white/10 text-white transition-all active:scale-90 cursor-pointer"
|
||||
onClick={() => setMobileOpen(!mobileOpen)}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<MaterialIcon icon={mobileOpen ? "close" : "menu"} size={22} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Mobile Drawer */}
|
||||
{mobileOpen && (
|
||||
<div className="absolute top-[calc(100%+12px)] left-4 right-4 z-40 bg-[rgba(61,45,143,0.95)] border border-white/20 rounded-2xl shadow-[0_20px_40px_rgba(100,60,120,0.15)] backdrop-blur-md p-4 md:hidden">
|
||||
<div className="flex flex-col gap-2">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = pathname === link.href;
|
||||
return (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className={`px-4 py-3 text-body-md font-bold rounded-xl transition-all duration-200 flex items-center justify-between ${
|
||||
isActive
|
||||
? "bg-white/10 text-white"
|
||||
: "text-white/70 hover:text-white hover:bg-white/5"
|
||||
}`}
|
||||
onClick={() => setMobileOpen(false)}
|
||||
>
|
||||
{link.label}
|
||||
{isActive && (
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-white animate-pulse" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { FaFacebookF, FaInstagram, FaLinkedinIn } from "react-icons/fa";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { fadeUp, fadeIn, staggerContainer, staggerSlow, viewport } from "@/lib/animations";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
const COMPANY = [
|
||||
{ label: "About Us", href: "/about" },
|
||||
{ label: "Careers", href: "#" },
|
||||
// { label: "Press & News", href: "#" },
|
||||
{ label: "Help Center", href: "#" },
|
||||
];
|
||||
|
||||
@@ -17,26 +20,87 @@ const PARTNERSHIPS = [
|
||||
{ label: "Merchant Partner", href: "/merchants" },
|
||||
{ label: "Delivery Partner", href: "/delivery-partners" },
|
||||
{ label: "Direct to Customer Brands", href: "/brands" },
|
||||
// { label: "Local Real Estate", href: "#" },
|
||||
];
|
||||
|
||||
const LEGAL = [
|
||||
{ label: "Privacy Policy", href: "/privacy" },
|
||||
{ label: "Terms of Service", href: "/terms" },
|
||||
{ label: "Cookie Policy", href: "/cookies" },
|
||||
// { label: "Sitemap", href: "#" },
|
||||
];
|
||||
|
||||
const socialButtonClass =
|
||||
"flex h-10 w-10 items-center justify-center rounded-full border border-white/10 bg-white/5 text-white transition-all duration-300 xl:h-[54px] xl:w-[54px]";
|
||||
"flex h-10 w-10 items-center justify-center rounded-full border border-white/10 bg-white/5 text-white transition-[background-color] duration-300 xl:h-[54px] xl:w-[54px]";
|
||||
|
||||
const linkColumnVariant = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.5, ease: EASE },
|
||||
},
|
||||
};
|
||||
|
||||
const footerReveal = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.6, ease: EASE },
|
||||
},
|
||||
};
|
||||
|
||||
// Renders an animated link list used in all three footer link columns
|
||||
function FooterLinkList({ links }: { links: { label: string; href: string }[] }) {
|
||||
return (
|
||||
<ul className="flex flex-col gap-4 xl:gap-5">
|
||||
{links.map((link) => (
|
||||
<li key={link.label}>
|
||||
<motion.span
|
||||
className="relative inline-block"
|
||||
initial="rest"
|
||||
whileHover="hover"
|
||||
animate="rest"
|
||||
>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="text-sm leading-normal text-white/70 transition-colors duration-200 hover:text-white md:text-base xl:text-[17px]"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
{/* Underline grows from left on hover */}
|
||||
<motion.span
|
||||
className="absolute -bottom-0.5 left-0 right-0 h-px rounded-full bg-white/50"
|
||||
style={{ originX: 0 }}
|
||||
variants={{ rest: { scaleX: 0 }, hover: { scaleX: 1 } }}
|
||||
transition={{ duration: 0.2, ease: EASE }}
|
||||
/>
|
||||
</motion.span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export function PremiumFooter() {
|
||||
return (
|
||||
<section className="bg-white px-2 pb-2 md:px-3 md:pb-3 lg:px-4 lg:pb-4 xl:px-5 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<footer className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#16001D] to-[#25002F] text-white shadow-[0_-12px_40px_rgba(22,0,29,0.12)]">
|
||||
{/* Footer reveal: the whole footer fades up as it enters the viewport */}
|
||||
<motion.footer
|
||||
className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#16001D] to-[#25002F] text-white shadow-[0_-12px_40px_rgba(22,0,29,0.12)]"
|
||||
variants={footerReveal}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
<div className="flex flex-col px-6 pb-8 pt-10 md:px-8 md:pb-8 md:pt-12 xl:px-16 xl:pb-8 xl:pt-12 2xl:px-20 2xl:pt-10 2xl:pb-8">
|
||||
<div className="grid w-full grid-cols-1 items-start gap-10 text-left md:grid-cols-2 md:gap-x-12 md:gap-y-12 lg:grid-cols-[1.6fr_1fr_1fr_1fr] lg:gap-10 xl:gap-14">
|
||||
<div className="flex flex-col gap-5">
|
||||
|
||||
{/* Main grid: columns stagger in via parent footer variant propagation */}
|
||||
<motion.div
|
||||
className="grid w-full grid-cols-1 items-start gap-10 text-left md:grid-cols-2 md:gap-x-12 md:gap-y-12 lg:grid-cols-[1.6fr_1fr_1fr_1fr] lg:gap-10 xl:gap-14"
|
||||
variants={staggerSlow}
|
||||
>
|
||||
{/* Brand column */}
|
||||
<motion.div variants={fadeUp} className="flex flex-col gap-5">
|
||||
<Link href="/" className="inline-block w-fit">
|
||||
<Image
|
||||
src="/logo-light.png"
|
||||
@@ -52,100 +116,81 @@ export function PremiumFooter() {
|
||||
communities and verified local businesses within a 2km radius.
|
||||
</p>
|
||||
|
||||
{/* Social icons with scale spring on hover */}
|
||||
<div className="mt-1 flex gap-3 xl:mt-2 xl:gap-4">
|
||||
<a
|
||||
<motion.a
|
||||
href="https://www.facebook.com/nearledigital"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Facebook"
|
||||
className={`${socialButtonClass} hover:bg-[#1877F2]`}
|
||||
whileHover={{ scale: 1.12 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
transition={{ type: "spring", stiffness: 400, damping: 17 }}
|
||||
>
|
||||
<FaFacebookF size={20} />
|
||||
</a>
|
||||
</motion.a>
|
||||
|
||||
<a
|
||||
<motion.a
|
||||
href="https://www.instagram.com/nearledigital/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Instagram"
|
||||
className={`${socialButtonClass} hover:bg-[#E4405F]`}
|
||||
whileHover={{ scale: 1.12 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
transition={{ type: "spring", stiffness: 400, damping: 17 }}
|
||||
>
|
||||
<FaInstagram size={21} />
|
||||
</a>
|
||||
</motion.a>
|
||||
|
||||
<a
|
||||
<motion.a
|
||||
href="https://www.linkedin.com/company/nearledigital/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="LinkedIn"
|
||||
className={`${socialButtonClass} hover:bg-[#0A66C2]`}
|
||||
whileHover={{ scale: 1.12 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
transition={{ type: "spring", stiffness: 400, damping: 17 }}
|
||||
>
|
||||
<FaLinkedinIn size={20} />
|
||||
</a>
|
||||
</motion.a>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
{/* Company links */}
|
||||
<motion.div variants={linkColumnVariant} className="flex flex-col">
|
||||
<h5 className="mb-5 text-xs font-extrabold uppercase tracking-wider text-white/40 md:text-sm xl:mb-7 xl:text-[17px]">
|
||||
Company
|
||||
</h5>
|
||||
<FooterLinkList links={COMPANY} />
|
||||
</motion.div>
|
||||
|
||||
<ul className="flex flex-col gap-4 xl:gap-5">
|
||||
{COMPANY.map((link) => (
|
||||
<li key={link.label}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="inline-block text-sm leading-normal text-white/70 transition-all hover:translate-x-0.5 hover:text-white md:text-base xl:text-[17px]"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
{/* Nearle links */}
|
||||
<motion.div variants={linkColumnVariant} className="flex flex-col">
|
||||
<h5 className="mb-5 text-xs font-extrabold uppercase tracking-wider text-white/40 md:text-sm xl:mb-7 xl:text-[17px]">
|
||||
Nearle
|
||||
</h5>
|
||||
<FooterLinkList links={PARTNERSHIPS} />
|
||||
</motion.div>
|
||||
|
||||
<ul className="flex flex-col gap-4 xl:gap-5">
|
||||
{PARTNERSHIPS.map((link) => (
|
||||
<li key={link.label}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="inline-block text-sm leading-normal text-white/70 transition-all hover:translate-x-0.5 hover:text-white md:text-base xl:text-[17px]"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
{/* Support links */}
|
||||
<motion.div variants={linkColumnVariant} className="flex flex-col">
|
||||
<h5 className="mb-5 text-xs font-extrabold uppercase tracking-wider text-white/40 md:text-sm xl:mb-7 xl:text-[17px]">
|
||||
Support
|
||||
</h5>
|
||||
|
||||
<ul className="flex flex-col gap-4 xl:gap-5">
|
||||
{LEGAL.map((link) => (
|
||||
<li key={link.label}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="inline-block text-sm leading-normal text-white/70 transition-all hover:translate-x-0.5 hover:text-white md:text-base xl:text-[17px]"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<FooterLinkList links={LEGAL} />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<div className="my-8 w-full border-t border-white/10 xl:my-10" />
|
||||
|
||||
<div className="flex w-full flex-col items-center justify-between gap-8 md:flex-row xl:gap-12">
|
||||
{/* Bottom row */}
|
||||
<motion.div
|
||||
className="flex w-full flex-col items-center justify-between gap-8 md:flex-row xl:gap-12"
|
||||
variants={fadeUp}
|
||||
>
|
||||
<div className="flex min-h-[120px] w-full max-w-[560px] items-start gap-3 rounded-2xl border border-white/10 bg-white/5 p-4 md:w-auto md:p-5 xl:min-h-[130px] xl:gap-4 xl:p-6">
|
||||
<div className="mt-0.5 flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-white/10 text-white xl:h-[58px] xl:w-[58px] xl:rounded-2xl">
|
||||
<MaterialIcon icon="location_on" size={20} />
|
||||
@@ -155,7 +200,6 @@ export function PremiumFooter() {
|
||||
<h6 className="text-sm font-black text-white md:text-base xl:text-lg">
|
||||
Nearle
|
||||
</h6>
|
||||
|
||||
<p className="mt-0.5 text-xs leading-normal text-white/60 md:text-sm xl:mt-1 xl:text-base">
|
||||
424, Diwan Bahadur Rd, Opp. Sri Krishna Sweets, R.S. Puram,
|
||||
Coimbatore, TN 641002
|
||||
@@ -181,11 +225,15 @@ export function PremiumFooter() {
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="mb-4 mt-8 w-full border-t border-white/5 xl:mb-6 xl:mt-10" />
|
||||
|
||||
<div className="flex w-full flex-col items-center justify-between gap-4 text-[13px] text-white/40 md:flex-row md:text-[14px] xl:text-[15px]">
|
||||
{/* Copyright bar */}
|
||||
<motion.div
|
||||
className="flex w-full flex-col items-center justify-between gap-4 text-[13px] text-white/40 md:flex-row md:text-[14px] xl:text-[15px]"
|
||||
variants={fadeIn}
|
||||
>
|
||||
<p className="text-center md:text-left">
|
||||
© {new Date().getFullYear()} Nearle. All rights reserved.
|
||||
</p>
|
||||
@@ -203,9 +251,9 @@ export function PremiumFooter() {
|
||||
Help Center
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</footer>
|
||||
</motion.footer>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import {
|
||||
motion,
|
||||
AnimatePresence,
|
||||
useScroll,
|
||||
useMotionValueEvent,
|
||||
} from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
const NAV_LINKS = [
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Nearle for Business", href: "/businesses" },
|
||||
@@ -14,9 +22,44 @@ const NAV_LINKS = [
|
||||
{ label: "Contact", href: "/contact" },
|
||||
];
|
||||
|
||||
const mobileMenuVariants = {
|
||||
hidden: { opacity: 0, height: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
height: "auto",
|
||||
transition: { duration: 0.3, ease: EASE },
|
||||
},
|
||||
exit: {
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
transition: { duration: 0.2, ease: "easeIn" as const },
|
||||
},
|
||||
};
|
||||
|
||||
const mobileStagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.04, delayChildren: 0.06 } },
|
||||
};
|
||||
|
||||
const mobileItemVariants = {
|
||||
hidden: { opacity: 0, x: -10 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.22, ease: EASE } },
|
||||
};
|
||||
|
||||
export function PremiumNavbar() {
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const pathname = usePathname();
|
||||
const { scrollY } = useScroll();
|
||||
|
||||
useMotionValueEvent(scrollY, "change", (y) => {
|
||||
setScrolled(y > 20);
|
||||
});
|
||||
|
||||
// Close mobile menu whenever the route changes (navbar no longer remounts on navigation)
|
||||
useEffect(() => {
|
||||
setMobileOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
const isActiveLink = (href: string) => {
|
||||
if (href === "/") return pathname === "/";
|
||||
@@ -24,10 +67,18 @@ export function PremiumNavbar() {
|
||||
};
|
||||
|
||||
return (
|
||||
// <header className="sticky top-0 z-50 w-full border-b border-white/10 bg-[#3D2D8F]/90 text-white backdrop-blur-xl">
|
||||
<header className="sticky top-0 z-50 w-full bg-[#83429f] border-b border-white/10 text-white">
|
||||
<motion.header
|
||||
className={`sticky top-0 z-50 w-full text-white transition-[background-color,box-shadow,backdrop-filter] duration-300 ${
|
||||
scrolled
|
||||
? "bg-[#83429f]/82 backdrop-blur-lg shadow-[0_6px_32px_rgba(0,0,0,0.35)] border-b border-white/15"
|
||||
: "bg-[#83429f] border-b border-white/10"
|
||||
}`}
|
||||
initial={{ opacity: 0, y: -8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.4, ease: EASE }}
|
||||
>
|
||||
<div className="relative mx-auto flex h-16 w-full max-w-[1600px] items-center px-6 md:h-20 md:px-10 xl:px-16">
|
||||
{/* Logo - Left */}
|
||||
{/* Logo */}
|
||||
<Link
|
||||
href="/"
|
||||
className="flex shrink-0 items-center transition-transform duration-200 hover:scale-[1.02] active:scale-95"
|
||||
@@ -43,38 +94,55 @@ export function PremiumNavbar() {
|
||||
/>
|
||||
</Link>
|
||||
|
||||
{/* Desktop Navigation - Center */}
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="absolute left-1/2 hidden -translate-x-1/2 items-center gap-6 lg:flex lg:gap-8 xl:gap-10">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = isActiveLink(link.href);
|
||||
|
||||
return (
|
||||
<Link
|
||||
<motion.div
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className={`relative whitespace-nowrap py-2 text-sm font-bold transition-colors duration-200 ${
|
||||
isActive
|
||||
? "text-white"
|
||||
: "text-white/70 hover:text-white"
|
||||
}`}
|
||||
className="relative py-2"
|
||||
initial="rest"
|
||||
whileHover="hover"
|
||||
animate="rest"
|
||||
>
|
||||
{link.label}
|
||||
|
||||
<span
|
||||
className={`absolute bottom-0 left-1/2 h-0.5 -translate-x-1/2 rounded-full bg-white transition-all duration-300 ${
|
||||
isActive ? "w-full" : "w-0"
|
||||
<Link
|
||||
href={link.href}
|
||||
className={`whitespace-nowrap text-sm font-bold transition-colors duration-200 ${
|
||||
isActive ? "text-white" : "text-white/70 hover:text-white"
|
||||
}`}
|
||||
/>
|
||||
</Link>
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
|
||||
{/* Active underline: layoutId lets it slide between links on navigation */}
|
||||
{isActive && (
|
||||
<motion.span
|
||||
layoutId="activeNavUnderline"
|
||||
className="absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-white"
|
||||
transition={{ duration: 0.3, ease: EASE }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Hover underline: grows from left on inactive links */}
|
||||
{!isActive && (
|
||||
<motion.span
|
||||
className="absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-white/40"
|
||||
style={{ originX: 0 }}
|
||||
variants={{ rest: { scaleX: 0 }, hover: { scaleX: 1 } }}
|
||||
transition={{ duration: 0.2, ease: EASE }}
|
||||
/>
|
||||
)}
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* Mobile Toggle - Right */}
|
||||
{/* Mobile Toggle */}
|
||||
<button
|
||||
type="button"
|
||||
className="ml-auto flex h-10 w-10 items-center justify-center rounded-full text-white transition-all duration-200 hover:bg-white/10 active:scale-90 lg:hidden"
|
||||
onClick={() => setMobileOpen((value) => !value)}
|
||||
onClick={() => setMobileOpen((v) => !v)}
|
||||
aria-label={mobileOpen ? "Close menu" : "Open menu"}
|
||||
aria-expanded={mobileOpen}
|
||||
>
|
||||
@@ -82,39 +150,48 @@ export function PremiumNavbar() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
<div
|
||||
className={`overflow-hidden border-t border-white/10 bg-[#30226F]/98 backdrop-blur-xl transition-all duration-300 lg:hidden ${
|
||||
mobileOpen
|
||||
? "max-h-[500px] opacity-100"
|
||||
: "pointer-events-none max-h-0 opacity-0"
|
||||
}`}
|
||||
>
|
||||
<nav className="mx-auto flex w-full max-w-[1600px] flex-col gap-1 px-6 py-5 md:px-10">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = isActiveLink(link.href);
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className={`flex items-center justify-between rounded-xl px-4 py-3 text-sm font-bold transition-all duration-200 ${
|
||||
isActive
|
||||
? "bg-white/15 text-white"
|
||||
: "text-white/70 hover:bg-white/10 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
|
||||
{isActive && (
|
||||
<span className="h-2 w-2 rounded-full bg-white" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
{/* Mobile Menu with enter/exit animation */}
|
||||
<AnimatePresence>
|
||||
{mobileOpen && (
|
||||
<motion.div
|
||||
key="mobile-menu"
|
||||
variants={mobileMenuVariants}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
className="overflow-hidden border-t border-white/10 bg-[#30226F]/98 backdrop-blur-xl lg:hidden"
|
||||
>
|
||||
<motion.nav
|
||||
className="mx-auto flex w-full max-w-[1600px] flex-col gap-1 px-6 py-5 md:px-10"
|
||||
variants={mobileStagger}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
>
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = isActiveLink(link.href);
|
||||
return (
|
||||
<motion.div key={link.label} variants={mobileItemVariants}>
|
||||
<Link
|
||||
href={link.href}
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className={`flex items-center justify-between rounded-xl px-4 py-3 text-sm font-bold transition-all duration-200 ${
|
||||
isActive
|
||||
? "bg-white/15 text-white"
|
||||
: "text-white/70 hover:bg-white/10 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
{isActive && (
|
||||
<span className="h-2 w-2 rounded-full bg-white" />
|
||||
)}
|
||||
</Link>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</motion.nav>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</motion.header>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,12 @@
|
||||
import React from "react";
|
||||
import { PremiumNavbar } from "./PremiumNavbar";
|
||||
import { PremiumFooter } from "./PremiumFooter";
|
||||
import { MotionProvider } from "./MotionProvider";
|
||||
|
||||
type PremiumPageShellProps = {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function PremiumPageShell({ children, className = "" }: PremiumPageShellProps) {
|
||||
return (
|
||||
<MotionProvider>
|
||||
<div className={`min-h-screen bg-white font-body text-[#16001D] antialiased flex flex-col ${className}`}>
|
||||
{/* Header/Navbar */}
|
||||
<PremiumNavbar />
|
||||
|
||||
{/* Page Content */}
|
||||
<main className="w-full overflow-x-hidden bg-white">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
<PremiumFooter />
|
||||
</div>
|
||||
</MotionProvider>
|
||||
);
|
||||
// Navbar, footer, and MotionProvider are rendered in the root layout (app/layout.tsx)
|
||||
// and persist across all navigations. This component is kept for call-site compatibility.
|
||||
export function PremiumPageShell({ children }: PremiumPageShellProps) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
42
src/components/motion/AnimatedGrid.tsx
Normal file
42
src/components/motion/AnimatedGrid.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import type { ReactNode, CSSProperties } from "react";
|
||||
import { cardReveal, staggerCards, viewport20 } from "@/lib/animations";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
|
||||
export function AnimatedGrid({ children, className, style }: Props) {
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
style={style}
|
||||
variants={staggerCards}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport20}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
export function AnimatedCard({ children, className, style }: Props) {
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
style={style}
|
||||
variants={cardReveal}
|
||||
whileHover={{ y: -4, transition: { duration: 0.22, ease: EASE } }}
|
||||
whileTap={{ scale: 0.97, transition: { duration: 0.1 } }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
50
src/components/motion/AnimatedSection.tsx
Normal file
50
src/components/motion/AnimatedSection.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import type { ReactNode } from "react";
|
||||
import { fadeUp, staggerContainer, viewport } from "@/lib/animations";
|
||||
import type { Variants } from "framer-motion";
|
||||
|
||||
const VARIANTS: Record<string, Variants> = {
|
||||
fadeUp,
|
||||
stagger: staggerContainer,
|
||||
};
|
||||
|
||||
type AnimatedSectionProps = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
variant?: "fadeUp" | "stagger";
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
export function AnimatedSection({
|
||||
children,
|
||||
className = "",
|
||||
variant = "fadeUp",
|
||||
delay = 0,
|
||||
}: AnimatedSectionProps) {
|
||||
const chosen = VARIANTS[variant] ?? fadeUp;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const withDelay: Variants = {
|
||||
hidden: chosen.hidden as any,
|
||||
visible: {
|
||||
...(chosen.visible as any),
|
||||
transition: {
|
||||
...((chosen.visible as any)?.transition ?? {}),
|
||||
delay,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
variants={withDelay}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
102
src/components/ui/CTABanner.tsx
Normal file
102
src/components/ui/CTABanner.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
const VP = { once: true, amount: 0.25 } as const;
|
||||
|
||||
const stagger = {
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: 0.13 } },
|
||||
};
|
||||
const textReveal = {
|
||||
hidden: { opacity: 0, y: 18 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.52, ease: EASE } },
|
||||
};
|
||||
const buttonReveal = {
|
||||
hidden: { opacity: 0, y: 12 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.42, ease: EASE } },
|
||||
};
|
||||
const decorReveal = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: { opacity: 1, transition: { duration: 1.1, delay: 0.38 } },
|
||||
};
|
||||
|
||||
type CTABannerProps = {
|
||||
badge?: { icon: string; label: string };
|
||||
heading: React.ReactNode;
|
||||
body: string;
|
||||
primary: { href: string; icon: string; label: string };
|
||||
secondary: { href: string; icon: string; label: string };
|
||||
decorations?: string[];
|
||||
};
|
||||
|
||||
export function CTABanner({ badge, heading, body, primary, secondary, decorations }: CTABannerProps) {
|
||||
return (
|
||||
<section className="bg-white px-2 pt-2 pb-2 md:px-3 md:pt-3 md:pb-3 lg:px-4 lg:pt-4 lg:pb-4 xl:px-5 xl:pt-4 xl:pb-4 2xl:px-6 2xl:pb-5">
|
||||
<motion.div
|
||||
className="w-full overflow-hidden rounded-[28px] bg-gradient-to-br from-[#1A0322] via-[#2B0040] to-[#0A000D] text-white"
|
||||
variants={stagger}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={VP}
|
||||
>
|
||||
<div className="px-6 py-12 md:px-10 md:py-14 lg:px-14 xl:py-12 text-center relative">
|
||||
{decorations?.map((grad, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="absolute inset-0 pointer-events-none"
|
||||
style={{ background: `radial-gradient(${grad})` }}
|
||||
variants={decorReveal}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div className="relative z-10 max-w-2xl mx-auto">
|
||||
{badge && (
|
||||
<motion.span
|
||||
className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-white/15 text-white/70 text-xs font-black uppercase tracking-widest mb-6"
|
||||
variants={textReveal}
|
||||
>
|
||||
<MaterialIcon icon={badge.icon} size={14} />
|
||||
{badge.label}
|
||||
</motion.span>
|
||||
)}
|
||||
|
||||
<motion.h2
|
||||
className="font-display text-3xl md:text-4xl xl:text-5xl font-black mb-4 tracking-tight leading-tight"
|
||||
variants={textReveal}
|
||||
>
|
||||
{heading}
|
||||
</motion.h2>
|
||||
|
||||
<motion.p
|
||||
className="text-sm md:text-base text-white/70 mb-8 leading-relaxed max-w-lg mx-auto"
|
||||
variants={textReveal}
|
||||
>
|
||||
{body}
|
||||
</motion.p>
|
||||
|
||||
<motion.div className="flex flex-wrap justify-center gap-3.5" variants={buttonReveal}>
|
||||
<Link
|
||||
href={primary.href}
|
||||
className="bg-[#6330D6] hover:bg-[#5225b8] text-white font-black px-8 py-3.5 rounded-xl text-sm hover:shadow-xl transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon={primary.icon} size={18} />
|
||||
<span>{primary.label}</span>
|
||||
</Link>
|
||||
<Link
|
||||
href={secondary.href}
|
||||
className="bg-white/10 hover:bg-white/15 border border-white/20 text-white font-black px-8 py-3.5 rounded-xl text-sm transition-all duration-200 active:scale-95 flex items-center gap-2"
|
||||
>
|
||||
<MaterialIcon icon={secondary.icon} size={18} />
|
||||
<span>{secondary.label}</span>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { MaterialIcon } from "./MaterialIcon";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
export type FAQItem = {
|
||||
question: string;
|
||||
answer: string;
|
||||
@@ -31,25 +34,30 @@ export function FAQAccordion({ items }: FAQAccordionProps) {
|
||||
<span className="text-sm md:text-base font-black text-[#16001D] leading-snug">
|
||||
{item.question}
|
||||
</span>
|
||||
<div
|
||||
className={`flex-shrink-0 w-8 h-8 rounded-full bg-[#6330D6]/8 flex items-center justify-center text-[#6330D6] transition-transform duration-300 ${
|
||||
openIndex === index ? "rotate-180" : ""
|
||||
}`}
|
||||
<motion.div
|
||||
className="flex-shrink-0 w-8 h-8 rounded-full bg-[#6330D6]/8 flex items-center justify-center text-[#6330D6]"
|
||||
animate={{ rotate: openIndex === index ? 180 : 0 }}
|
||||
transition={{ duration: 0.3, ease: EASE }}
|
||||
>
|
||||
<MaterialIcon icon="expand_more" size={20} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</button>
|
||||
<div
|
||||
className={`overflow-hidden transition-all duration-300 ease-in-out ${
|
||||
openIndex === index
|
||||
? "max-h-[500px] opacity-100"
|
||||
: "max-h-0 opacity-0"
|
||||
}`}
|
||||
>
|
||||
<p className="px-6 pb-5 text-sm md:text-base text-[#5E5866] leading-relaxed border-t border-[#6330D6]/5 pt-4">
|
||||
{item.answer}
|
||||
</p>
|
||||
</div>
|
||||
<AnimatePresence initial={false}>
|
||||
{openIndex === index && (
|
||||
<motion.div
|
||||
key="content"
|
||||
initial={{ height: 0, opacity: 0 }}
|
||||
animate={{ height: "auto", opacity: 1 }}
|
||||
exit={{ height: 0, opacity: 0 }}
|
||||
transition={{ duration: 0.3, ease: EASE }}
|
||||
style={{ overflow: "hidden" }}
|
||||
>
|
||||
<p className="px-6 pb-5 text-sm md:text-base text-[#5E5866] leading-relaxed border-t border-[#6330D6]/5 pt-4">
|
||||
{item.answer}
|
||||
</p>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { MaterialIcon } from "./MaterialIcon";
|
||||
import { fadeUp, staggerContainer, viewport } from "@/lib/animations";
|
||||
|
||||
type FeatureStatsItem = {
|
||||
icon: string;
|
||||
@@ -13,11 +17,18 @@ type FeatureStatsRowProps = {
|
||||
|
||||
export function FeatureStatsRow({ items, className = "" }: FeatureStatsRowProps) {
|
||||
return (
|
||||
<div className={`w-full py-6 md:py-8 ${className}`}>
|
||||
<motion.div
|
||||
className={`w-full py-6 md:py-8 ${className}`}
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
>
|
||||
<div className="grid grid-cols-2 lg:flex lg:flex-row items-center justify-between gap-y-6 gap-x-4 lg:gap-0">
|
||||
{items.map((item, index) => (
|
||||
<div
|
||||
<motion.div
|
||||
key={item.title}
|
||||
variants={fadeUp}
|
||||
className={`flex items-center gap-3.5 lg:flex-1 px-3 lg:px-8 text-left ${
|
||||
index < items.length - 1
|
||||
? "lg:border-r lg:border-[#6330D6]/10"
|
||||
@@ -37,9 +48,9 @@ export function FeatureStatsRow({ items, className = "" }: FeatureStatsRowProps)
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function GlassInfoCard({ text, icon, className = "" }: GlassInfoCardProps
|
||||
<MaterialIcon icon={icon} size={14} />
|
||||
</div>
|
||||
) : (
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-[#6330D6] shrink-0 animate-pulse" />
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-[#6330D6] shrink-0 motion-safe:animate-pulse" />
|
||||
)}
|
||||
<span className="text-sm font-extrabold text-[#16001D] whitespace-nowrap">
|
||||
{text}
|
||||
|
||||
@@ -5,7 +5,7 @@ export const fadeUp: Variants = {
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },
|
||||
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -19,12 +19,38 @@ export const fadeIn: Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
export const fadeInSlow: Variants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.7, ease: "easeOut" },
|
||||
},
|
||||
};
|
||||
|
||||
export const fadeUpStrong: Variants = {
|
||||
hidden: { opacity: 0, y: 36 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.65, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export const scaleIn: Variants = {
|
||||
hidden: { opacity: 0, scale: 0.95 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },
|
||||
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export const scaleInSpring: Variants = {
|
||||
hidden: { opacity: 0, scale: 0.88 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
transition: { type: "spring", stiffness: 280, damping: 20 },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -33,7 +59,16 @@ export const slideInLeft: Variants = {
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] },
|
||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export const slideInLeftSubtle: Variants = {
|
||||
hidden: { opacity: 0, x: -20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -42,7 +77,7 @@ export const slideInRight: Variants = {
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] },
|
||||
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -53,4 +88,55 @@ export const staggerContainer: Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
export const staggerFast: Variants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
transition: { staggerChildren: 0.07 },
|
||||
},
|
||||
};
|
||||
|
||||
export const staggerSlow: Variants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
transition: { staggerChildren: 0.13 },
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport = { once: true, margin: "-60px" } as const;
|
||||
export const viewportEarly = { once: true, margin: "-20px" } as const;
|
||||
export const viewport20 = { once: true, amount: 0.2 } as const;
|
||||
|
||||
export const revealUp: Variants = {
|
||||
hidden: { opacity: 0, y: 30 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.65, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export const cardReveal: Variants = {
|
||||
hidden: { opacity: 0, y: 20, scale: 0.98 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
transition: { duration: 0.55, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export const imageReveal: Variants = {
|
||||
hidden: { opacity: 0, scale: 0.97 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
export const staggerCards: Variants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
transition: { staggerChildren: 0.08 },
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user