diff --git a/desktop_screenshot.png b/desktop_screenshot.png index 277f8f8..bce2f86 100644 Binary files a/desktop_screenshot.png and b/desktop_screenshot.png differ diff --git a/mobile_screenshot.png b/mobile_screenshot.png index 908e01c..a5891bd 100644 Binary files a/mobile_screenshot.png and b/mobile_screenshot.png differ diff --git a/package-lock.json b/package-lock.json index 713b672..ccc0331 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "nearle-new", "version": "0.1.0", "dependencies": { + "framer-motion": "^12.42.0", "jsdom": "^29.1.1", "next": "16.2.9", "puppeteer-core": "^24.43.1", @@ -4306,6 +4307,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/framer-motion": { + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.0.tgz", + "integrity": "sha512-wp7EJnfWaaEScVygKv3e20udoRz+LbtxScsuTkakAxfXmt+ReC6WyPW2nINRAGvd+hG9odwcjBLyOTPjH5pBRA==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.0", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5811,6 +5839,21 @@ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "license": "MIT" }, + "node_modules/motion-dom": { + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.0.tgz", + "integrity": "sha512-M63h4n8R+quJdNhBwuLlgxM+OLYa9+I/T2pzDRboB9fLXRdbou+Gw7Zury+SkpaCyACP1JHSjHgZ1EgTkBr30w==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 8e5224c..6f5a8df 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "eslint" }, "dependencies": { + "framer-motion": "^12.42.0", "jsdom": "^29.1.1", "next": "16.2.9", "puppeteer-core": "^24.43.1", diff --git a/src/app/brands/page.tsx b/src/app/brands/page.tsx index 0ba8dd0..2ae5722 100644 --- a/src/app/brands/page.tsx +++ b/src/app/brands/page.tsx @@ -262,7 +262,7 @@ export default function BrandsPage() { Your Category Has a Place on Nearle

- Nearle's neighbourhood store network stocks a wide range of everyday product categories. If customers buy it daily, it belongs here. + Nearle's neighbourhood store network stocks a wide range of everyday product categories. If customers buy it daily, it belongs here.

diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index 79dd44b..6f66bfe 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -64,7 +64,7 @@ export default function ContactPage() {

Email Us

-

support@nearle.in • partners@nearle.in

+

nearle@care.in

@@ -74,13 +74,13 @@ export default function ContactPage() {
-

Visit Us

+

Address

424, DB Rd, R.S. Puram, Coimbatore, TN 641002

{/* Helpdesk */} -
+ {/*
@@ -88,7 +88,7 @@ export default function ContactPage() {

Helpdesk

24/7 Phone Helpdesk Active

-
+ */} diff --git a/src/app/delivery-partners/page.tsx b/src/app/delivery-partners/page.tsx index 4d5b416..400cd2b 100644 --- a/src/app/delivery-partners/page.tsx +++ b/src/app/delivery-partners/page.tsx @@ -365,7 +365,7 @@ export default function DeliveryPartnersPage() { {/* ─── Earnings Illustration ─── */} -
+ {/*
@@ -410,7 +410,7 @@ export default function DeliveryPartnersPage() { Estimates include base delivery fees only. Peak-hour surge pricing, performance bonuses, and festive incentives are additional. Earnings vary by zone.

-
+
*/} {/* ─── FAQ ─── */}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 1955e21..dc39cc4 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -79,6 +79,7 @@ export default function RootLayout({ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet" /> + {/* eslint-disable-next-line @next/next/no-page-custom-font */}
- {/* - * Grid layout: - * mobile (<768px) : 1 col — text → cards (1/row) → success story [via CSS order] - * tablet (768–1279px) : 1 col — text → success story → cards 2×2 [via CSS order] - * desktop (≥1280px) : 2 col — [left: text + success story] | [right: cards 2×2] - */}
- {/* ── 1. Left text content (always col-1 row-1) ── */} -
+ {/* ── 1. Left text content ── */} + {/* Badge */}
@@ -133,20 +137,23 @@ export function BusinessSection() {
-
+
- {/* ── 2. Feature cards — 2×2 grid (right col on desktop) ── - mobile : order-2 → appears after text, before success story - tablet : order-3 → appears after text + success story - desktop : explicit col-2, row-span-2 - */} -
+ grid grid-cols-1 gap-4 md:grid-cols-2" + variants={staggerContainer} + initial="hidden" + whileInView="visible" + viewport={viewport} + > {FEATURES.map((feature) => ( -
@@ -174,20 +181,22 @@ export function BusinessSection() { className="block h-auto w-full object-cover" />
-
+ ))} -
+ - {/* ── 3. Success story ── - mobile : order-3 → appears after feature cards - tablet : order-2 → appears after text, before cards - desktop : explicit col-1, row-2 (below text in left column) - */} -
+ grid grid-cols-[100px_minmax(0,1fr)]" + variants={scaleIn} + initial="hidden" + whileInView="visible" + viewport={viewport} + >
-
+
{/* ── Benefits strip ── */} -
+
{BENEFITS.map((b) => ( -
+
@@ -223,10 +238,10 @@ export function BusinessSection() {
{b.title}
{b.desc}
-
+
))}
-
+
diff --git a/src/components/home/Hero.tsx b/src/components/home/Hero.tsx index 634de28..9366122 100644 --- a/src/components/home/Hero.tsx +++ b/src/components/home/Hero.tsx @@ -1,6 +1,15 @@ +"use client"; + import Link from "next/link"; import Image from "next/image"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { + fadeUp, + slideInRight, + staggerContainer, + viewport, +} from "@/lib/animations"; const PROOF_ITEMS = [ { label: "Verified", text: "Local Stores", icon: "store" }, @@ -13,7 +22,7 @@ export function Hero() { return (
{/* ─── DECORATIONS (BEHIND CONTENT) ─── */} - + {/* 1. Large pale lavender partial circle (top-left) */}
@@ -21,10 +30,10 @@ export function Hero() {
{/* 3. Striped purple circle (lower-middle collage area) */} -
@@ -48,24 +57,41 @@ export function Hero() { {/* ─── TWO-COLUMN CONTENT GRID ─── */}
- - {/* LEFT COLUMN: Editorial Typography & Copy */} -
- - Welcome to Nearle - -

+ {/* LEFT COLUMN: Editorial Typography & Copy */} + + + Welcome to Nearle + + + Everything Local.
Everything Near. -

+ -

+ Discover verified local stores, exclusive offers, fast delivery, and a better way to shop within your neighbourhood. -

+ -
+ Get the App -
-
+ + {/* RIGHT COLUMN: Creative Overlapping Strips Collage */} -
- + + {/* DESKTOP LAYOUT (lg and above) */}
{/* left image: absolute left-[10%] top-[20%] w-[170px] h-[360px] */}
- Local grocery products @@ -113,10 +144,10 @@ export function Hero() { {/* right image: absolute right-[2%] top-[18%] w-[180px] h-[390px] */}
- Local customer shopping @@ -126,44 +157,50 @@ export function Hero() { {/* MOBILE/TABLET COLLAGE (below lg) */}
- Grocery products
- Central logo panel
- Customer
-
+
{/* ─── BOTTOM PROOF STATS ROW ─── */}
-
+ {PROOF_ITEMS.map((item, idx) => ( -
+ {/* Subtle vertical separator for desktop, except for the first item */} {idx > 0 && (
@@ -179,9 +216,9 @@ export function Hero() { {item.text}
-
+ ))} -
+
diff --git a/src/components/home/HowItWorks.tsx b/src/components/home/HowItWorks.tsx index 92d3629..175976e 100644 --- a/src/components/home/HowItWorks.tsx +++ b/src/components/home/HowItWorks.tsx @@ -1,5 +1,16 @@ +"use client"; + import Image from "next/image"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { + fadeUp, + scaleIn, + staggerContainer, + slideInLeft, + slideInRight, + viewport, +} from "@/lib/animations"; const STEPS = [ { @@ -174,7 +185,6 @@ function PhoneMapVisual() { function StepVisual({ type }: { type: string }) { if (type === "store") { - // Inset box gives the storefront image breathing room on all sides return (
@@ -198,7 +208,6 @@ function StepVisual({ type }: { type: string }) { ); } - // Bag: chips on the left, image on the right – keep bag from overflowing right edge return (
@@ -227,7 +236,13 @@ export function HowItWorks() { {/* HERO AREA */}
-
+ Together, We Grow @@ -245,9 +260,15 @@ export function HowItWorks() { Talk to an Expert -
+ -
+
-
+
@@ -274,7 +295,13 @@ export function HowItWorks() { {/* CARDS SECTION */}
-
+ How It Works @@ -284,12 +311,19 @@ export function HowItWorks() {

Three simple milestones to scale your retail reach from offline streets straight into neighbourhood homes.

-
+ -
+ {STEPS.map((step) => ( -
@@ -309,9 +343,9 @@ export function HowItWorks() {
-
+ ))} -
+
); diff --git a/src/components/home/HyperlocalFeatures.tsx b/src/components/home/HyperlocalFeatures.tsx index 8ab674a..ae2ca92 100644 --- a/src/components/home/HyperlocalFeatures.tsx +++ b/src/components/home/HyperlocalFeatures.tsx @@ -1,6 +1,10 @@ +"use client"; + import Image from "next/image"; import Link from "next/link"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { fadeUp, slideInLeft, staggerContainer, viewport } from "@/lib/animations"; const FEATURES = [ { @@ -33,11 +37,17 @@ export function HyperlocalFeatures() {
{/* Inner container */} -
+
- + {/* Left Column: Visual Storytelling */} -
+
-
+
{/* Right Column: Feature Panel directly on page background */}
- + Community & Trust - - -

+ + + Built Around Your
Neighbourhood -

+ -

+ Nearle brings the convenience of an app to the stores you already know and trust, making it easy to support local shops. -

+ {/* Features List with vertical connector line */} -
- + {/* Vertical connector line */}
- + {FEATURES.map((item) => ( -
- + + {/* Icon circle */}
- +

{item.title} @@ -178,15 +211,21 @@ export function HyperlocalFeatures() { {item.desc}

-
+ ))} -
+
{/* Divider Line above CTA Area */}
{/* Onboarding Call to Action */} -
+ -
+
diff --git a/src/components/home/ServiceCategories.tsx b/src/components/home/ServiceCategories.tsx index 38d9c76..1adacd8 100644 --- a/src/components/home/ServiceCategories.tsx +++ b/src/components/home/ServiceCategories.tsx @@ -1,6 +1,12 @@ +"use client"; + import Image from "next/image"; import Link from "next/link"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { fadeUp, fadeIn, staggerContainer, viewport } from "@/lib/animations"; + +const MotionLink = motion(Link); const CATEGORIES = [ { @@ -58,7 +64,13 @@ export function ServiceCategories() {
{/* Header Section */} -
+
Neighbourhood Offerings @@ -77,14 +89,22 @@ export function ServiceCategories() { View All Categories -
+
{/* Categories Premium Grid */} -
+ {/* fadeIn (opacity only) preserves .premium-card:hover CSS transform */} + {CATEGORIES.map((cat) => ( - {/* Image Container */} @@ -132,11 +152,10 @@ export function ServiceCategories() {
- + ))} -
+
); } - diff --git a/src/components/home/StoreQRSection.tsx b/src/components/home/StoreQRSection.tsx index d515490..0906b5f 100644 --- a/src/components/home/StoreQRSection.tsx +++ b/src/components/home/StoreQRSection.tsx @@ -1,5 +1,9 @@ +"use client"; + import Image from "next/image"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { fadeUp, scaleIn, slideInRight, staggerContainer, viewport } from "@/lib/animations"; const FLOW_STEPS = [ { label: "Scan QR", icon: "qr_code_scanner" }, @@ -17,12 +21,18 @@ export function StoreQRSection() {
- + {/* ─── DESKTOP LAYOUT (lg and above) ─── */}
- + {/* Left Column: Heading, flow steps, download buttons */} -
+ Instant Connections & App @@ -83,12 +93,21 @@ export function StoreQRSection() {
-
+ {/* Right Column: Visual components (QR Sticker & Phone Mockup) */} -
+ {/* Small supporting visual: QR Sticker (Secondary) */} -
+

Order Online

Store QR

@@ -108,10 +127,13 @@ export function StoreQRSection() { Scan to Shop -
+
{/* Primary large visual: Phone Mockup (Significantly Larger) */} -
+ Nearle mobile app interface -
- - -
+
+
{/* ─── MOBILE & TABLET LAYOUT (below lg) ─── */}
{/* 1. Heading and description */} -
+ Instant Connections & App @@ -138,10 +163,16 @@ export function StoreQRSection() {

Scan Nearle QRs to instantly save local stores, and order from them anytime in one convenient app.

-
+ {/* 2. QR Sticker */} -
+

Order Online

Store QR

@@ -161,7 +192,7 @@ export function StoreQRSection() { Scan to Shop -
+
{/* 3. Scan → Save → Order steps */}
@@ -183,7 +214,13 @@ export function StoreQRSection() {
{/* 4. Phone Mockup */} -
+ Nearle mobile app interface -
+ {/* 5. App store buttons — TODO: replace with real URLs once app is live */}
diff --git a/src/components/home/WhyNearle.tsx b/src/components/home/WhyNearle.tsx index b376f22..1b6327c 100644 --- a/src/components/home/WhyNearle.tsx +++ b/src/components/home/WhyNearle.tsx @@ -1,5 +1,9 @@ +"use client"; + import Image from "next/image"; +import { motion } from "framer-motion"; import { MaterialIcon } from "@/components/ui/MaterialIcon"; +import { fadeUp, fadeIn, staggerContainer, viewport } from "@/lib/animations"; const CARDS = [ { @@ -41,7 +45,13 @@ export function WhyNearle() {
{/* Header Section */} -
+
Nearle brings the convenience of an app to the stores you already know and trust.

-
+
- {/* Cards Grid */} -
+ {/* Cards Grid — fadeIn preserves .premium-card:hover CSS transform */} + {CARDS.map((card) => ( -
@@ -96,11 +113,10 @@ export function WhyNearle() { className="object-cover" />
-
+
))} -
+
); } - diff --git a/src/components/layout/MotionProvider.tsx b/src/components/layout/MotionProvider.tsx new file mode 100644 index 0000000..d19bebe --- /dev/null +++ b/src/components/layout/MotionProvider.tsx @@ -0,0 +1,8 @@ +"use client"; + +import { MotionConfig } from "framer-motion"; +import React from "react"; + +export function MotionProvider({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/src/components/layout/PremiumPageShell.tsx b/src/components/layout/PremiumPageShell.tsx index bdc7b76..07214e5 100644 --- a/src/components/layout/PremiumPageShell.tsx +++ b/src/components/layout/PremiumPageShell.tsx @@ -1,6 +1,7 @@ import React from "react"; import { PremiumNavbar } from "./PremiumNavbar"; import { PremiumFooter } from "./PremiumFooter"; +import { MotionProvider } from "./MotionProvider"; type PremiumPageShellProps = { children: React.ReactNode; @@ -9,16 +10,18 @@ type PremiumPageShellProps = { export function PremiumPageShell({ children, className = "" }: PremiumPageShellProps) { return ( -
- {/* Header/Navbar */} - + +
+ {/* Header/Navbar */} + - {/* Page Content */} -
- {children} -
+ {/* Page Content */} +
+ {children} +
- -
+ +
+ ); } diff --git a/src/lib/animations/index.ts b/src/lib/animations/index.ts new file mode 100644 index 0000000..e234312 --- /dev/null +++ b/src/lib/animations/index.ts @@ -0,0 +1,56 @@ +import type { Variants } from "framer-motion"; + +export const fadeUp: Variants = { + hidden: { opacity: 0, y: 24 }, + visible: { + opacity: 1, + y: 0, + transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] }, + }, +}; + +// Use for elements with CSS transform-based hover effects (e.g. .premium-card:hover) +// to avoid inline-style override of CSS hover transforms. +export const fadeIn: Variants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { duration: 0.45, ease: "easeOut" }, + }, +}; + +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] }, + }, +}; + +export const slideInLeft: Variants = { + hidden: { opacity: 0, x: -40 }, + visible: { + opacity: 1, + x: 0, + transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] }, + }, +}; + +export const slideInRight: Variants = { + hidden: { opacity: 0, x: 40 }, + visible: { + opacity: 1, + x: 0, + transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] }, + }, +}; + +export const staggerContainer: Variants = { + hidden: {}, + visible: { + transition: { staggerChildren: 0.09 }, + }, +}; + +export const viewport = { once: true, margin: "-60px" } as const; diff --git a/take_screenshot.js b/take_screenshot.js index 8e81a28..b141913 100644 --- a/take_screenshot.js +++ b/take_screenshot.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ const puppeteer = require('puppeteer-core'); const path = require('path');