Initial commit

This commit is contained in:
2026-06-20 15:41:55 +05:30
commit 2778527442
163 changed files with 72703 additions and 0 deletions

17
src/app/about/page.tsx Normal file
View File

@@ -0,0 +1,17 @@
export default function AboutPage() {
return (
<section className="min-h-[70vh] bg-surface px-margin-mobile md:px-margin-desktop py-24">
<div className="mx-auto max-w-container-max text-center">
<p className="text-label-sm font-black uppercase tracking-widest text-primary">
About
</p>
<h1 className="mt-4 font-display text-4xl font-black text-brand-dark md:text-6xl">
Built for local communities.
</h1>
<p className="mx-auto mt-6 max-w-2xl text-body-lg text-on-surface-variant">
Nearle connects people with verified neighborhood businesses through a fast, reliable hyperlocal commerce network.
</p>
</div>
</section>
);
}

View File

@@ -0,0 +1,17 @@
export default function BusinessesPage() {
return (
<section className="min-h-[70vh] bg-surface px-margin-mobile md:px-margin-desktop py-24">
<div className="mx-auto max-w-container-max text-center">
<p className="text-label-sm font-black uppercase tracking-widest text-primary">
Nearle for Business
</p>
<h1 className="mt-4 font-display text-4xl font-black text-brand-dark md:text-6xl">
Grow with neighborhood delivery.
</h1>
<p className="mx-auto mt-6 max-w-2xl text-body-lg text-on-surface-variant">
Partner with Nearle to reach nearby customers, manage local demand, and deliver faster within your neighborhood.
</p>
</div>
</section>
);
}

17
src/app/contact/page.tsx Normal file
View File

@@ -0,0 +1,17 @@
export default function ContactPage() {
return (
<section className="min-h-[70vh] bg-surface px-margin-mobile md:px-margin-desktop py-24">
<div className="mx-auto max-w-container-max text-center">
<p className="text-label-sm font-black uppercase tracking-widest text-primary">
Contact
</p>
<h1 className="mt-4 font-display text-4xl font-black text-brand-dark md:text-6xl">
Talk to the Nearle team.
</h1>
<p className="mx-auto mt-6 max-w-2xl text-body-lg text-on-surface-variant">
Reach out for partnerships, support, business onboarding, or neighborhood launch enquiries.
</p>
</div>
</section>
);
}

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

537
src/app/globals.css Normal file
View File

@@ -0,0 +1,537 @@
@import "tailwindcss";
/* ─── Design Tokens (Material Design 3 inspired) ─── */
:root {
--surface: #f9f9fc;
--surface-dim: #dadadc;
--surface-bright: #f9f9fc;
--surface-container-lowest: #ffffff;
--surface-container-low: #f3f3f6;
--surface-container: #eeeef0;
--surface-container-high: #e8e8ea;
--surface-container-highest: #e2e2e5;
--on-surface: #1a1c1e;
--on-surface-variant: #4d434f;
--inverse-surface: #2f3133;
--inverse-on-surface: #f0f0f3;
--outline: #7f7381;
--outline-variant: #d0c2d1;
--surface-tint: #83429f;
--primary: #4d046a;
--on-primary: #ffffff;
--primary-container: #662582;
--on-primary-container: #de96f9;
--inverse-primary: #ebb2ff;
--secondary: #006d37;
--on-secondary: #ffffff;
--secondary-container: #7bf8a1;
--on-secondary-container: #007239;
--tertiary: #745b00;
--on-tertiary: #ffffff;
--tertiary-container: #cda72b;
--on-tertiary-container: #4f3d00;
--error: #ba1a1a;
--on-error: #ffffff;
--error-container: #ffdad6;
--on-error-container: #93000a;
--primary-fixed: #f8d8ff;
--primary-fixed-dim: #ebb2ff;
--on-primary-fixed: #320047;
--on-primary-fixed-variant: #692885;
--secondary-fixed: #7efba4;
--secondary-fixed-dim: #61de8a;
--on-secondary-fixed: #00210c;
--on-secondary-fixed-variant: #005228;
--tertiary-fixed: #ffe08b;
--tertiary-fixed-dim: #ebc246;
--on-tertiary-fixed: #241a00;
--on-tertiary-fixed-variant: #584400;
--background: #f9f9fc;
--on-background: #1a1c1e;
--surface-variant: #e2e2e5;
--brand-dark: #120217;
--brand-dark-surface: #1e0627;
--brand-accent: #fca311;
--brand-accent-light: #ffe08b;
--brand-cream: #faf8f5;
}
/* ─── Tailwind v4 Theme ─── */
@theme inline {
/* Colors */
--color-surface: var(--surface);
--color-surface-dim: var(--surface-dim);
--color-surface-bright: var(--surface-bright);
--color-surface-container-lowest: var(--surface-container-lowest);
--color-surface-container-low: var(--surface-container-low);
--color-surface-container: var(--surface-container);
--color-surface-container-high: var(--surface-container-high);
--color-surface-container-highest: var(--surface-container-highest);
--color-on-surface: var(--on-surface);
--color-on-surface-variant: var(--on-surface-variant);
--color-inverse-surface: var(--inverse-surface);
--color-inverse-on-surface: var(--inverse-on-surface);
--color-outline: var(--outline);
--color-outline-variant: var(--outline-variant);
--color-surface-tint: var(--surface-tint);
--color-primary: var(--primary);
--color-on-primary: var(--on-primary);
--color-primary-container: var(--primary-container);
--color-on-primary-container: var(--on-primary-container);
--color-inverse-primary: var(--inverse-primary);
--color-secondary: var(--secondary);
--color-on-secondary: var(--on-secondary);
--color-secondary-container: var(--secondary-container);
--color-on-secondary-container: var(--on-secondary-container);
--color-tertiary: var(--tertiary);
--color-on-tertiary: var(--on-tertiary);
--color-tertiary-container: var(--tertiary-container);
--color-on-tertiary-container: var(--on-tertiary-container);
--color-error: var(--error);
--color-on-error: var(--on-error);
--color-error-container: var(--error-container);
--color-on-error-container: var(--on-error-container);
--color-primary-fixed: var(--primary-fixed);
--color-primary-fixed-dim: var(--primary-fixed-dim);
--color-on-primary-fixed: var(--on-primary-fixed);
--color-on-primary-fixed-variant: var(--on-primary-fixed-variant);
--color-secondary-fixed: var(--secondary-fixed);
--color-secondary-fixed-dim: var(--secondary-fixed-dim);
--color-on-secondary-fixed: var(--on-secondary-fixed);
--color-on-secondary-fixed-variant: var(--on-secondary-fixed-variant);
--color-tertiary-fixed: var(--tertiary-fixed);
--color-tertiary-fixed-dim: var(--tertiary-fixed-dim);
--color-on-tertiary-fixed: var(--on-tertiary-fixed);
--color-on-tertiary-fixed-variant: var(--on-tertiary-fixed-variant);
--color-background: var(--background);
--color-on-background: var(--on-background);
--color-surface-variant: var(--surface-variant);
--color-brand-dark: var(--brand-dark);
--color-brand-dark-surface: var(--brand-dark-surface);
--color-brand-accent: var(--brand-accent);
--color-brand-accent-light: var(--brand-accent-light);
--color-brand-cream: var(--brand-cream);
/* Spacing */
--spacing-stack-xs: 4px;
--spacing-stack-sm: 8px;
--spacing-stack-md: 16px;
--spacing-stack-lg: 24px;
--spacing-gutter: 16px;
--spacing-margin-mobile: 16px;
--spacing-margin-desktop: 32px;
--spacing-container-max: 1280px;
/* Fonts */
--font-display: "Hanken Grotesk", sans-serif;
--font-body: "Inter", sans-serif;
/* Border radius */
--radius-sm: 0.25rem;
--radius-DEFAULT: 0.5rem;
--radius-md: 0.75rem;
--radius-lg: 1rem;
--radius-xl: 1.5rem;
--radius-2xl: 2rem;
--radius-full: 9999px;
}
/* ─── Base Styles ─── */
html {
scroll-behavior: smooth;
}
body {
background: var(--background);
color: var(--on-surface);
font-family: var(--font-body);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
::selection {
background: var(--primary-container);
color: var(--on-primary-container);
}
/* ─── Typography Utility Classes ─── */
.text-display {
font-family: var(--font-display);
font-size: 48px;
font-weight: 800;
line-height: 56px;
letter-spacing: -0.02em;
}
.text-headline-lg {
font-family: var(--font-display);
font-size: 32px;
font-weight: 700;
line-height: 40px;
letter-spacing: -0.01em;
}
.text-headline-lg-mobile {
font-family: var(--font-display);
font-size: 24px;
font-weight: 700;
line-height: 32px;
}
.text-headline-md {
font-family: var(--font-display);
font-size: 20px;
font-weight: 600;
line-height: 28px;
}
.text-body-lg {
font-family: var(--font-body);
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
.text-body-md {
font-family: var(--font-body);
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.text-body-sm {
font-family: var(--font-body);
font-size: 12px;
font-weight: 400;
line-height: 16px;
}
.text-label-md {
font-family: var(--font-body);
font-size: 14px;
font-weight: 600;
line-height: 20px;
letter-spacing: 0.01em;
}
.text-label-sm {
font-family: var(--font-body);
font-size: 11px;
font-weight: 700;
line-height: 16px;
letter-spacing: 0.03em;
}
/* ─── Component Utilities ─── */
.bento-card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.bento-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
}
/* Material Symbols config */
.material-symbols-outlined {
font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 24;
}
/* ─── Responsive Typography ─── */
@media (max-width: 768px) {
.text-display {
font-size: 36px;
line-height: 44px;
}
.text-headline-lg {
font-size: 24px;
line-height: 32px;
}
}
/* ─── Premium Custom Animations & Utilities ─── */
@keyframes float {
0%, 100% {
transform: translateY(0px) rotate(0deg);
}
50% {
transform: translateY(-8px) rotate(1deg);
}
}
.animate-float {
animation: float 4s ease-in-out infinite;
}
@keyframes pulse-subtle {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.9;
transform: scale(1.02);
}
}
.animate-pulse-subtle {
animation: pulse-subtle 3s ease-in-out infinite;
}
/* Smooth Curved Clip Paths */
.curved-bottom-sm {
clip-path: ellipse(120% 100% at 50% 0%);
}
.curved-bottom-lg {
clip-path: ellipse(150% 100% at 50% 0%);
}
.curved-top-lg {
clip-path: ellipse(150% 100% at 50% 100%);
}
/* Glassmorphism */
.glass-panel {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.glass-panel-dark {
background: rgba(30, 6, 39, 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.05);
}
/* Card hover states */
.premium-card {
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.premium-card:hover {
transform: translateY(-6px) scale(1.01);
box-shadow: 0 20px 35px -10px rgba(18, 2, 23, 0.15);
}
.premium-card-dark {
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.premium-card-dark:hover {
transform: translateY(-6px) scale(1.01);
box-shadow: 0 20px 35px -10px rgba(0, 0, 0, 0.5);
border-color: var(--brand-accent);
}
/* Hero-only clipped background layers */
@media (min-width: 768px) {
.hero {
position: relative;
min-height: 760px;
overflow: visible;
background: #ffffff;
}
.hero-dark-panel {
position: absolute;
inset: 0;
width: 100%;
background:
radial-gradient(circle at 62% 48%, rgba(108, 14, 128, 0.7), transparent 36%),
radial-gradient(circle at 25% 38%, rgba(55, 0, 74, 0.62), transparent 34%),
linear-gradient(135deg, #09000e 0%, #17001f 42%, #2c0038 70%, #0b0010 100%);
clip-path: polygon(0 0, 94% 0, 56% 100%, 0 100%);
overflow: hidden;
}
.hero-dark-panel::after {
content: "";
position: absolute;
inset: 0;
background:
radial-gradient(circle at 68% 56%, rgba(222, 150, 249, 0.22), transparent 26%),
linear-gradient(90deg, rgba(5, 0, 8, 0.34), transparent 48%, rgba(5, 0, 8, 0.12));
opacity: 0.9;
pointer-events: none;
z-index: 2;
}
.hero-bike {
position: absolute;
z-index: 3;
width: clamp(560px, 44vw, 760px);
aspect-ratio: 1080 / 867;
right: clamp(40px, 5vw, 100px);
bottom: 70px;
pointer-events: none;
filter: none;
animation: hero-bike-enter 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.hero-bike img {
animation: hero-bike-float 5.5s ease-in-out 900ms infinite;
}
.hero-map-layer {
position: absolute;
width: 86%;
left: 2%;
top: -1%;
height: 610px;
opacity: 0.72;
z-index: 1;
mix-blend-mode: screen;
animation: hero-map-drift 18s ease-in-out infinite alternate;
}
.hero-map-layer img {
filter: sepia(1) saturate(4.6) hue-rotate(230deg) brightness(0.9) contrast(1.35)
drop-shadow(0 0 22px rgba(189, 52, 254, 0.34));
opacity: 0.95;
}
.hero-content {
position: relative;
z-index: 4;
width: min(610px, 48vw);
padding-top: 94px;
animation: hero-copy-enter 760ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.hero-stage {
padding-left: clamp(72px, 7.5vw, 150px);
padding-right: clamp(32px, 4vw, 80px);
min-height: 740px;
}
.hero-cards {
padding-left: clamp(72px, 7.5vw, 150px);
padding-right: clamp(72px, 7.5vw, 150px);
}
}
@media (min-width: 768px) and (max-width: 1099px) {
.hero {
min-height: 720px;
}
.hero-dark-panel {
width: 82%;
clip-path: polygon(0 0, 100% 0, 58% 100%, 0 100%);
}
.hero-bike {
width: 500px;
right: -72px;
bottom: 86px;
opacity: 0.92;
}
.hero-content {
width: min(440px, 58vw);
}
}
@media (max-width: 767px) {
.hero {
position: relative;
background: #120018;
padding-bottom: 120px;
overflow: visible;
}
.hero-dark-panel {
position: absolute;
inset: 0;
background: #120018;
overflow: hidden;
z-index: 0;
}
.hero-map-layer {
position: absolute;
width: 120%;
left: -10%;
top: 5%;
height: 380px; /* Explicit height on mobile */
opacity: 0.3;
z-index: 1;
mix-blend-mode: screen;
}
.hero-map-layer img {
filter: sepia(1) saturate(4) hue-rotate(230deg) brightness(0.76) contrast(1.18);
opacity: 0.7;
}
.hero-content {
position: relative;
z-index: 3;
width: 100%;
padding-top: 60px;
padding-bottom: 24px;
}
.hero-bike {
position: relative;
z-index: 5;
width: 95%;
max-width: 450px;
margin: 20px auto 0 auto;
pointer-events: none;
filter: none; /* No filter tint */
}
}
/* Animated Route SVG Lines */
@keyframes stroke-dash {
to {
stroke-dashoffset: -20;
}
}
.animate-route {
animation: stroke-dash 2s linear infinite;
}
@keyframes hero-copy-enter {
from {
opacity: 0;
transform: translateY(18px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes hero-bike-enter {
from {
opacity: 0;
transform: translateX(34px) scale(0.98);
}
to {
opacity: 1;
transform: translateX(0) scale(1);
}
}
@keyframes hero-bike-float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
@keyframes hero-map-drift {
from {
transform: translate3d(0, 0, 0) scale(1);
}
to {
transform: translate3d(18px, -8px, 0) scale(1.03);
}
}

103
src/app/layout.tsx Normal file
View File

@@ -0,0 +1,103 @@
import type { Metadata, Viewport } from "next";
import { Hanken_Grotesk, Inter } from "next/font/google";
import "./globals.css";
import { Navbar } from "@/components/layout/Navbar";
import { Footer } from "@/components/layout/Footer";
const hankenGrotesk = Hanken_Grotesk({
subsets: ["latin"],
weight: ["600", "700", "800"],
variable: "--font-display",
display: "swap",
});
const inter = Inter({
subsets: ["latin"],
weight: ["400", "600", "700"],
variable: "--font-body",
display: "swap",
});
export const metadata: Metadata = {
metadataBase: new URL("https://nearle.in"),
title: {
default: "Nearle — Your Neighborhood, Delivered",
template: "%s | Nearle",
},
description:
"Hyper-local essentials, hot meals, and professional services from verified businesses within your 2km radius. India's #1 neighborhood commerce platform.",
keywords: [
"hyperlocal",
"neighborhood delivery",
"Coimbatore",
"local grocery",
"Nearle",
"home services",
"India delivery",
"neighborhood commerce",
],
openGraph: {
title: "Nearle — Your Neighborhood, Delivered",
description:
"Hyper-local essentials, hot meals, and professional services from verified businesses within your 2km radius.",
url: "https://nearle.in",
siteName: "Nearle",
locale: "en_IN",
type: "website",
images: [
{
url: "/logo.png",
width: 512,
height: 512,
alt: "Nearle logo",
},
],
},
twitter: {
card: "summary",
title: "Nearle — Your Neighborhood, Delivered",
description:
"India's hyperlocal neighborhood commerce platform",
images: ["/logo.png"],
},
alternates: { canonical: "/" },
icons: {
icon: "/favicon.ico",
shortcut: "/favicon.ico",
apple: "/apple-icon.png",
},
robots: { index: true, follow: true },
};
export const viewport: Viewport = {
themeColor: "#4d046a",
width: "device-width",
initialScale: 1,
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html
lang="en"
className={`${hankenGrotesk.variable} ${inter.variable}`}
suppressHydrationWarning
>
<head>
{/* Material Symbols Outlined */}
<link
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
rel="stylesheet"
/>
</head>
<body className="bg-background text-on-surface font-body antialiased" suppressHydrationWarning>
<Navbar />
<main>{children}</main>
<Footer />
</body>
</html>
);
}

17
src/app/page.tsx Normal file
View File

@@ -0,0 +1,17 @@
import { Hero } from "@/components/home/Hero";
import { ServiceCategories } from "@/components/home/ServiceCategories";
import { HyperlocalFeatures } from "@/components/home/HyperlocalFeatures";
import { BusinessSection } from "@/components/home/BusinessSection";
import { AppPromo } from "@/components/home/AppPromo";
export default function HomePage() {
return (
<>
<Hero />
<ServiceCategories />
<HyperlocalFeatures />
<BusinessSection />
<AppPromo />
</>
);
}

17
src/app/people/page.tsx Normal file
View File

@@ -0,0 +1,17 @@
export default function PeoplePage() {
return (
<section className="min-h-[70vh] bg-surface px-margin-mobile md:px-margin-desktop py-24">
<div className="mx-auto max-w-container-max text-center">
<p className="text-label-sm font-black uppercase tracking-widest text-primary">
Nearle for People
</p>
<h1 className="mt-4 font-display text-4xl font-black text-brand-dark md:text-6xl">
Everything nearby, delivered.
</h1>
<p className="mx-auto mt-6 max-w-2xl text-body-lg text-on-surface-variant">
Discover groceries, meals, essentials, and services from trusted local partners around you.
</p>
</div>
</section>
);
}

View File

@@ -0,0 +1,159 @@
import Image from "next/image";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
const FEATURES = [
{
title: "Eco-Friendly Routing",
desc: "Our routing software matches you to stores within 2km to minimize delivery times and energy.",
icon: "near_me",
},
{
title: "Live Courier Tracking",
desc: "See your neighborhood runner on a live map as they collect your essentials and ride to your gate.",
icon: "map",
},
{
title: "Secure Digital Payments",
desc: "Enjoy quick checkouts via UPI, credit/debit cards, and integrated wallet coins with cashbacks.",
icon: "payments",
},
];
export function AppPromo() {
return (
<section
id="download"
className="py-24 px-margin-mobile md:px-margin-desktop bg-brand-cream overflow-hidden border-t border-outline-variant/10"
>
<div className="max-w-container-max mx-auto relative">
{/* Background Dot pattern */}
<div
className="absolute inset-0 opacity-[0.03] pointer-events-none"
style={{
backgroundImage: "radial-gradient(#120217 2px, transparent 2px)",
backgroundSize: "24px 24px",
}}
/>
<div className="grid md:grid-cols-12 gap-12 items-center relative z-10">
{/* Left Column: Typography, benefits, download actions (7 cols) */}
<div className="md:col-span-7">
<span className="text-label-sm text-primary uppercase tracking-widest font-black bg-primary/5 px-3.5 py-1.5 rounded-full border border-primary/10">
Download Nearle Mobile
</span>
<h2 className="text-display text-brand-dark mt-6 mb-6 leading-[1.1] tracking-tight">
Get More With Our <br />
<span className="text-primary font-black">Mobile Application</span>
</h2>
<p className="text-body-lg text-on-surface-variant mb-10 max-w-lg leading-relaxed">
Experience the fastest way to order groceries, hot food, and emergency home maintenance. Download the app today for live updates and community coins.
</p>
{/* Benefit Bullets */}
<div className="space-y-6 mb-10">
{FEATURES.map((item) => (
<div key={item.title} className="flex gap-4">
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-brand-accent/20 flex items-center justify-center">
<MaterialIcon icon={item.icon} size={18} className="text-brand-dark" />
</div>
<div>
<h4 className="text-label-md font-bold text-brand-dark">{item.title}</h4>
<p className="text-body-md text-on-surface-variant mt-0.5 leading-relaxed">
{item.desc}
</p>
</div>
</div>
))}
</div>
{/* Store Badges */}
<div className="flex flex-wrap gap-4 mt-8">
<a
href="https://apps.apple.com"
target="_blank"
rel="noopener noreferrer"
className="h-14 border border-brand-dark/20 rounded-2xl hover:bg-brand-dark hover:text-white transition-all duration-300 px-6 py-2 flex items-center gap-3 group hover:-translate-y-1 hover:shadow-lg bg-white"
>
<svg viewBox="0 0 24 24" className="w-6 h-6 shrink-0 fill-current text-brand-dark group-hover:text-white transition-colors" fill="currentColor">
<path d="M17.537 12.625c-.023-2.949 2.398-4.37 2.506-4.44-1.364-2.008-3.48-2.282-4.227-2.307-1.79-.186-3.504 1.064-4.413 1.064-.918 0-2.323-1.04-3.827-1.01-1.963.028-3.788 1.146-4.796 2.91-2.06 3.587-.526 8.9 1.466 11.808.98 1.428 2.147 3.035 3.685 2.975 1.47-.059 2.03-.964 3.807-.964 1.767 0 2.266.964 3.818.932 1.58-.03 2.58-1.453 3.536-2.89 1.116-1.628 1.57-3.21 1.596-3.29-.035-.016-3.057-1.18-3.087-4.678l.036-.002zM14.87 4.058c.821-.99 1.375-2.361 1.223-3.733-1.184.05-2.618.784-3.47 1.77-.762.875-1.43 2.28-1.25 3.623 1.327.102 2.673-.668 3.497-1.66z" />
</svg>
<div className="text-left leading-tight">
<div className="text-[9px] opacity-75 font-semibold tracking-wider uppercase">
Download on the
</div>
<div className="text-headline-md font-black -mt-0.5">
App Store
</div>
</div>
</a>
<a
href="https://play.google.com/store/apps/details?id=com.nearle.gear"
target="_blank"
rel="noopener noreferrer"
className="h-14 border border-brand-dark/20 rounded-2xl hover:bg-brand-dark hover:text-white transition-all duration-300 px-6 py-2 flex items-center gap-3 group hover:-translate-y-1 hover:shadow-lg bg-white"
>
<svg viewBox="0 0 24 24" className="w-6 h-6 shrink-0 fill-current text-brand-dark group-hover:text-white transition-colors" fill="currentColor">
<path d="M3.609 1.814L13.414 12 3.609 22.186c-.244-.178-.395-.466-.395-.786V2.6c0-.32.151-.608.395-.786zM14.244 12.83l2.705 2.688-4.073 2.276-4.073 2.276L14.244 12.83zm1-1.66l2.838-2.8 4.153 2.336c.464.26.464.688 0 .948l-4.153 2.336-2.838-2.82zM8.803 4.93l4.073 2.276 4.073 2.276-2.705 2.688L8.803 4.93z" />
</svg>
<div className="text-left leading-tight">
<div className="text-[9px] opacity-75 font-semibold tracking-wider uppercase">
GET IT ON
</div>
<div className="text-headline-md font-black -mt-0.5">
Google Play
</div>
</div>
</a>
</div>
</div>
{/* Right Column: Phone Mockup showcase (5 cols) */}
<div className="md:col-span-5 flex justify-center md:justify-end relative">
{/* Background glowing circle */}
<div className="absolute w-80 h-80 bg-brand-accent/10 rounded-full blur-2xl pointer-events-none -right-10 top-10" />
<div className="relative w-full max-w-[270px] animate-float">
{/* iPhone style phone container */}
<div className="bg-[#120217] w-full aspect-[9/18.5] rounded-[3rem] border-[6px] border-brand-dark-surface shadow-2xl relative overflow-hidden ring-4 ring-outline-variant/15">
{/* Speaker notch */}
<div className="absolute top-2.5 left-1/2 -translate-x-1/2 w-24 h-4 bg-black rounded-full z-20 flex items-center justify-center">
<div className="w-12 h-1 bg-zinc-800 rounded-full" />
</div>
<Image
src="/images/app-mockup.png"
alt="Nearle mobile app interface showing neighborhood services"
width={360}
height={760}
className="w-full h-full object-cover"
/>
</div>
{/* Overlapping alert bubble */}
<div className="absolute -left-10 top-1/4 bg-white/95 backdrop-blur-md p-4 rounded-2xl shadow-2xl border border-outline-variant/20 hidden lg:block hover:scale-105 transition-transform duration-300">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-full bg-secondary-fixed flex items-center justify-center">
<MaterialIcon
icon="check_circle"
size={18}
className="text-secondary"
/>
</div>
<div>
<p className="text-label-md font-black text-brand-dark">Order Dispatched</p>
<p className="text-[10px] text-on-surface-variant font-medium">Runner is arriving in 4 mins</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,162 @@
import Image from "next/image";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
const FEATURES = [
{
title: "Direct Customer Relationship",
desc: "Build long-term direct ties with nearby families. Own your neighborhood presence.",
},
{
title: "Managed Instant Delivery Fleet",
desc: "We supply professional, verified moped couriers. Focus on your business, not hiring drivers.",
},
{
title: "Neighborhood Demand Trends",
desc: "Use Nearle's analytic insights to track demand, optimize your stock, and launch promos.",
},
];
const STATS = [
{
value: "40%+",
label: "Average Revenue Rise",
icon: "trending_up",
style: "bg-primary text-white",
},
{
value: "12k+",
label: "Daily Neighborhood Orders",
icon: "shopping_bag",
style: "bg-brand-accent text-brand-dark",
},
{
value: "5k+",
label: "Verified Retail Partners",
icon: "storefront",
style: "bg-[#faf8f5] border border-outline-variant/20 text-primary",
},
{
value: "24/7",
label: "Partner Helpdesk Support",
icon: "support_agent",
style: "bg-[#de96f9]/20 text-primary border border-primary/10",
},
];
export function BusinessSection() {
return (
<section className="py-24 px-margin-mobile md:px-margin-desktop bg-white">
<div className="max-w-container-max mx-auto">
{/* Merchant Section Grid */}
<div className="grid lg:grid-cols-12 gap-16 items-center">
{/* Left Column: Feature copywriting (7 cols) */}
<div className="lg:col-span-7">
<span className="text-label-sm text-secondary uppercase tracking-widest font-black bg-secondary/5 px-3.5 py-1.5 rounded-full border border-secondary/15">
Merchant Partnerships
</span>
<h2 className="text-display text-brand-dark mt-6 mb-6 leading-tight">
Grow your local brand in the <span className="text-secondary">Neighborhood.</span>
</h2>
<p className="text-body-lg text-on-surface-variant mb-12 max-w-xl leading-relaxed">
Unlock delivery, loyalty programs, and localized promotions. Join over 5,000 neighborhood partners who are digitizing their community sales channels.
</p>
<div className="space-y-8 mb-12">
{FEATURES.map((feat) => (
<div key={feat.title} className="flex gap-4 group">
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-secondary/10 border border-secondary/20 flex items-center justify-center group-hover:bg-secondary group-hover:text-white transition-all duration-300">
<MaterialIcon
icon="check"
size={18}
className="text-secondary group-hover:text-white transition-colors"
/>
</div>
<div>
<h4 className="text-headline-md font-black text-brand-dark group-hover:text-primary transition-colors">
{feat.title}
</h4>
<p className="text-body-md text-on-surface-variant mt-1.5 leading-relaxed">
{feat.desc}
</p>
</div>
</div>
))}
</div>
<button className="bg-primary hover:bg-primary-container text-white font-black px-10 py-4 rounded-full text-label-md hover:shadow-xl hover:-translate-y-0.5 active:translate-y-0 active:scale-95 transition-all duration-200 cursor-pointer">
Register as Merchant Partner
</button>
</div>
{/* Right Column: Premium Bento Stats Grid (5 cols) */}
<div className="lg:col-span-5 grid grid-cols-2 gap-6">
{STATS.map((stat, idx) => (
<div
key={stat.value}
className={`p-6 rounded-[2rem] flex flex-col justify-between aspect-square hover:-translate-y-2 hover:shadow-xl transition-all duration-300 ${stat.style} ${idx % 2 === 1 ? "translate-y-6 md:translate-y-8" : ""}`}
>
<div className="w-10 h-10 rounded-full bg-white/20 flex items-center justify-center">
<MaterialIcon icon={stat.icon} size={22} />
</div>
<div>
<p className="text-4xl font-display font-black tracking-tight">
{stat.value}
</p>
<p className="text-label-sm font-semibold mt-1 opacity-90 leading-tight">
{stat.label}
</p>
</div>
</div>
))}
</div>
</div>
{/* CURVED PROMO BANNER: Inspired by GoMoto Hottest Pizza Banner */}
<div className="mt-32 relative overflow-hidden bg-brand-accent rounded-[3.5rem] p-8 md:p-16 flex flex-col md:flex-row justify-between items-center gap-12 border border-brand-accent/20 shadow-2xl">
{/* Decorative background vectors */}
<div className="absolute right-0 top-0 w-[400px] h-[400px] bg-white/10 rounded-full blur-3xl pointer-events-none" />
<div className="absolute left-10 bottom-0 w-[200px] h-[200px] bg-brand-dark/5 rounded-full blur-2xl pointer-events-none" />
{/* Left copy column */}
<div className="md:w-3/5 z-10 text-brand-dark">
<span className="text-[10px] font-black uppercase tracking-widest bg-brand-dark/15 px-3.5 py-1.5 rounded-full">
Piping Hot & Fresh
</span>
<h3 className="text-display mt-6 mb-4 leading-[1.1] font-black">
Always the Hottest Meals <br />& Freshest Groceries.
</h3>
<p className="text-body-lg text-brand-dark/80 mb-8 max-w-md font-semibold leading-relaxed">
Our advanced insulation packs guarantee your hot food stays steaming, and frozen goods stay completely frozen until handed to you.
</p>
<a
href="#"
className="bg-brand-dark hover:bg-brand-dark/90 text-white font-black px-8 py-3.5 rounded-full text-label-md hover:shadow-2xl transition-all hover:-translate-y-0.5 active:translate-y-0 active:scale-95 duration-200 inline-block shadow-md"
>
Order Meals Now
</a>
</div>
{/* Right visual column */}
<div className="md:w-2/5 relative flex justify-center items-center">
{/* Soft background shape */}
<div className="absolute w-[260px] h-[260px] bg-brand-dark/10 rounded-full pointer-events-none scale-110" />
<div className="relative w-full max-w-[280px] aspect-square rounded-[2rem] overflow-hidden border-4 border-white shadow-2xl rotate-3 hover:rotate-0 transition-transform duration-500">
<Image
src="/images/cat-hot-food.png"
alt="Hot meals from Nearle local kitchen partners"
width={400}
height={400}
className="w-full h-full object-cover scale-105"
/>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,252 @@
import Image from "next/image";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
const QUICK_LINKS = [
{
name: "Hot Meals",
icon: "fastfood",
label: "Quick & tasty",
},
{
name: "Daily Groceries",
icon: "shopping_basket",
label: "Fresh & On-Time",
},
{
name: "Health & Care",
icon: "medical_services",
label: "Essential & Trusted",
},
{
name: "More Services",
icon: "grid_view",
label: "Explore More",
},
];
export function Hero() {
return (
<div className="hero">
{/* ─── Base Dark Background Panel (Clipped diagonally) ─── */}
<div className="hero-dark-panel select-none pointer-events-none">
{/* Flat Dotted World Map Layer */}
<div className="hero-map-layer select-none mix-blend-screen">
<Image
src="/images/slider-glob.png"
alt="Dotted World Map"
fill
sizes="(max-width: 768px) 100vw, 75vw"
className="object-contain object-left"
priority
/>
{/* Animated Route Lines & Glowing Location Nodes */}
<svg
className="absolute inset-0 w-full h-full opacity-85 pointer-events-none"
viewBox="0 0 1000 800"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<filter id="heroRouteGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
{/* Glowing nodes */}
<circle cx="150" cy="180" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="150" cy="180" r="2.5" className="fill-white" />
<circle cx="350" cy="110" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="350" cy="110" r="2.5" className="fill-white" />
<circle cx="280" cy="300" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="280" cy="300" r="2.5" className="fill-white" />
<circle cx="480" cy="220" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="480" cy="220" r="2.5" className="fill-white" />
<circle cx="650" cy="165" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="650" cy="165" r="2.5" className="fill-white" />
<circle cx="780" cy="250" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="780" cy="250" r="2.5" className="fill-white" />
<circle cx="580" cy="140" r="8" className="fill-[#bd34fe] opacity-70 animate-pulse" filter="url(#heroRouteGlow)" />
<circle cx="580" cy="140" r="2.5" className="fill-white" />
{/* Arc dashed lines with moving stroke-dash animation */}
<path
d="M150,180 Q250,120 350,110"
fill="none"
stroke="#c02cff"
strokeWidth="2"
strokeDasharray="6,6"
className="animate-route opacity-70"
filter="url(#heroRouteGlow)"
/>
<path
d="M150,180 Q200,240 280,300"
fill="none"
stroke="#c02cff"
strokeWidth="2"
strokeDasharray="6,6"
className="animate-route opacity-70"
filter="url(#heroRouteGlow)"
/>
<path
d="M350,110 Q420,165 480,220"
fill="none"
stroke="#c02cff"
strokeWidth="2"
strokeDasharray="6,6"
className="animate-route opacity-70"
filter="url(#heroRouteGlow)"
/>
<path
d="M280,300 Q380,250 480,220"
fill="none"
stroke="#c02cff"
strokeWidth="2"
strokeDasharray="6,6"
className="animate-route opacity-70"
filter="url(#heroRouteGlow)"
/>
<path
d="M480,220 Q520,180 580,140 Q630,120 650,165"
fill="none"
stroke="#c02cff"
strokeWidth="2"
strokeDasharray="6,6"
className="animate-route opacity-70"
filter="url(#heroRouteGlow)"
/>
<path
d="M480,220 Q620,250 780,250"
fill="none"
stroke="#c02cff"
strokeWidth="2"
strokeDasharray="6,6"
className="animate-route opacity-70"
filter="url(#heroRouteGlow)"
/>
</svg>
</div>
{/* Soft purple radial glow behind the bike near the diagonal edge (clipped) */}
<div className="absolute right-0 top-1/4 z-0 h-[60%] w-[45%] rounded-full bg-primary/45 blur-[120px] opacity-50 pointer-events-none" />
</div>
{/* ─── Main Content Wrapper ─── */}
<div className="hero-stage relative w-full flex flex-col z-10 md:justify-center md:items-start">
{/* Left Column: Text & Search Content */}
<div className="hero-content text-white select-none">
<span className="inline-block text-label-sm text-brand-accent font-black tracking-widest uppercase mb-4 bg-brand-accent/10 px-4 py-1.5 rounded-full border border-brand-accent/20">
Express Services
</span>
<h1 className="text-5xl lg:text-[82px] font-display font-black leading-[0.98] tracking-tight mb-7">
Express
<br />
<span className="text-brand-accent drop-shadow-md">Neighborhood</span>
</h1>
<p className="text-body-lg md:text-[20px] md:leading-8 text-white/80 mb-11 leading-relaxed max-w-2xl">
Get groceries, hot meals, daily essentials, and local professional services delivered from trusted partners within <span className="text-brand-accent font-bold">25-30 minutes</span>.
</p>
{/* Search Input Bar */}
<div className="flex flex-col gap-4">
<div className="flex items-center bg-white p-2 rounded-full shadow-2xl border border-white/10 focus-within:ring-4 focus-within:ring-brand-accent/30 transition-all duration-300 max-w-[620px]">
<MaterialIcon
icon="location_on"
size={22}
className="ml-4 text-brand-accent animate-pulse-subtle"
/>
<input
type="text"
placeholder="Enter your neighbourhood or delivery location..."
className="w-full border-none focus:ring-0 focus:outline-none text-body-md text-on-surface font-semibold placeholder-on-surface-variant/50 px-3 py-2 bg-transparent"
/>
<button className="bg-brand-accent hover:bg-brand-accent/90 text-brand-dark font-black px-6 py-3 rounded-full text-label-sm hover:shadow-lg transition-all active:scale-95 duration-200 whitespace-nowrap cursor-pointer">
Find Shops
</button>
</div>
{/* Popular tags below */}
<div className="flex gap-3 items-center flex-wrap px-4 mt-2">
<span className="text-label-sm text-white/40 uppercase tracking-widest font-black text-[10px]">
Popular:
</span>
{["Fresh Produce", "African Bakery", "Pet Care"].map((tag) => (
<a
key={tag}
href="#"
className="text-label-sm text-brand-accent-light hover:text-brand-accent transition-colors font-bold"
>
{tag}
</a>
))}
</div>
</div>
</div>
{/* Right Column: Dominant Purple Scooter Rider (Overlapping) */}
<div className="hero-bike select-none pointer-events-none">
<div className="relative w-full h-full flex items-end">
<Image
src="/images/slider-courier-mask-purple-v4.png"
alt="Nearle Delivery Courier"
fill
sizes="(max-width: 768px) 95vw, 48vw"
className="object-contain object-bottom drop-shadow-2xl"
priority
/>
</div>
</div>
</div>
{/* Overlapping Quick Category Links (Anchored at the bottom edge) */}
<div className="hero-cards absolute bottom-0 left-0 right-0 transform translate-y-[50%] z-20">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{QUICK_LINKS.map((item) => (
<div
key={item.name}
className="flex items-center gap-4 bg-white p-5 rounded-2xl border border-outline-variant/15 shadow-xl hover:shadow-2xl premium-card cursor-pointer group"
>
<div className="flex-shrink-0 w-12 h-12 rounded-full bg-brand-accent/10 flex items-center justify-center group-hover:bg-brand-accent/20 transition-colors">
<MaterialIcon
icon={item.icon}
size={24}
className="text-brand-accent"
/>
</div>
<div className="flex-grow">
<h3 className="text-label-md font-extrabold text-brand-dark group-hover:text-primary transition-colors">
{item.name}
</h3>
<p className="text-[11px] text-on-surface-variant font-medium mt-0.5 leading-tight">
{item.label}
</p>
</div>
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-surface-container flex items-center justify-center opacity-0 group-hover:opacity-100 group-hover:translate-x-1 transition-all duration-300">
<MaterialIcon
icon="arrow_forward"
size={16}
className="text-primary"
/>
</div>
</div>
))}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,129 @@
import Image from "next/image";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
const FEATURES = [
{
title: "Verified Community Partners",
icon: "verified_user",
desc: "Every merchant on Nearle is manually verified for food hygiene, service quality, and local licensing.",
},
{
title: "Eco-Friendly 2KM Logistics",
icon: "electric_moped",
desc: "By capping deliveries at 2km, we run a fast, eco-friendly moped fleet that reduces emissions and saves fuel.",
},
{
title: "Exclusive Society Discounting",
icon: "local_activity",
desc: "We coordinate with housing societies to negotiate collective discount rates and free scheduled delivery runs.",
},
];
export function HyperlocalFeatures() {
return (
<section className="py-20 bg-surface-container-low border-y border-outline-variant/10 relative overflow-hidden">
{/* Background soft blur */}
<div className="absolute -left-20 top-1/3 w-80 h-80 bg-primary/5 rounded-full blur-3xl pointer-events-none" />
<div className="max-w-container-max mx-auto px-margin-mobile md:px-margin-desktop">
<div className="grid lg:grid-cols-12 gap-12 items-center">
{/* Left Column: Visual Storytelling (5 cols) */}
<div className="lg:col-span-5 relative">
<div className="relative aspect-[4/5] w-full max-w-[420px] mx-auto rounded-[3rem] overflow-hidden border-4 border-white shadow-2xl">
<Image
src="/images/cat-daily-essentials.png"
alt="Fresh groceries and goods delivered at home"
width={500}
height={600}
className="w-full h-full object-cover group-hover:scale-102 transition-transform duration-500"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-transparent to-transparent" />
{/* Floating Badge */}
<div className="absolute bottom-6 left-6 right-6 bg-white/95 backdrop-blur-md p-5 rounded-2xl border border-outline-variant/20 shadow-xl">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-brand-accent/20 flex items-center justify-center">
<MaterialIcon icon="eco" className="text-brand-accent" size={22} />
</div>
<div>
<h4 className="text-label-md font-black text-brand-dark">100% Eco-Friendly</h4>
<p className="text-[11px] text-on-surface-variant font-semibold mt-0.5">Reducing neighbor carbon footprint</p>
</div>
</div>
</div>
</div>
{/* Background Decorative Circle */}
<div className="absolute -bottom-8 -right-8 w-32 h-32 bg-brand-accent/10 rounded-full blur-xl pointer-events-none" />
</div>
{/* Right Column: Dark Feature Panel (7 cols) */}
<div className="lg:col-span-7">
<div className="bg-brand-dark text-white p-8 md:p-16 rounded-[3rem] shadow-2xl relative overflow-hidden border border-white/5">
{/* Internal vector decor */}
<div className="absolute right-0 top-0 w-64 h-64 bg-brand-accent/5 rounded-full blur-3xl pointer-events-none" />
<div className="absolute -left-16 -bottom-16 w-48 h-48 bg-primary/10 rounded-full blur-2xl pointer-events-none" />
<div className="relative z-10">
<span className="text-label-sm text-brand-accent uppercase tracking-widest font-black bg-brand-accent/10 px-3.5 py-1.5 rounded-full border border-brand-accent/20">
Care & Quality
</span>
<h3 className="text-display mt-6 mb-8 leading-tight tracking-tight">
Relax at Home,<br />
<span className="text-brand-accent font-black">We Care.</span>
</h3>
<p className="text-body-lg text-white/70 mb-10 max-w-lg leading-relaxed">
Nearle connects you to local, trusted neighborhood shops, bringing you the best essentials while taking care of the logistics and safety standards.
</p>
{/* Features List */}
<div className="space-y-8">
{FEATURES.map((item) => (
<div key={item.title} className="flex gap-5 group">
<div className="flex-shrink-0 w-12 h-12 rounded-full bg-brand-accent/15 border border-brand-accent/30 flex items-center justify-center group-hover:bg-brand-accent group-hover:text-brand-dark transition-colors duration-300">
<MaterialIcon
icon={item.icon}
className="text-brand-accent group-hover:text-brand-dark transition-colors"
size={22}
/>
</div>
<div>
<h4 className="text-headline-md font-black text-white group-hover:text-brand-accent transition-colors">
{item.title}
</h4>
<p className="text-body-md text-white/60 mt-1 leading-relaxed">
{item.desc}
</p>
</div>
</div>
))}
</div>
{/* Onboarding Call to Action */}
<div className="mt-12 flex flex-wrap gap-4 items-center">
<a
href="#download"
className="bg-brand-accent hover:bg-brand-accent/90 text-brand-dark font-black px-8 py-3.5 rounded-full text-label-md hover:shadow-lg hover:-translate-y-0.5 active:translate-y-0 active:scale-95 transition-all duration-200"
>
Get Nearle App
</a>
<a
href="#"
className="text-white hover:text-brand-accent font-bold text-label-md flex items-center gap-1 group py-2"
>
Partner Code of Ethics
<MaterialIcon icon="arrow_forward" size={16} className="transition-transform group-hover:translate-x-1" />
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,148 @@
import Image from "next/image";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
const CATEGORIES = [
{
name: "Hot Food",
image: "/images/cat-hot-food.png",
tag: "Popular",
tagStyle: "bg-brand-accent text-brand-dark",
desc: "Fresh meals, bakes & street favorites",
stats: "★ 4.8 (250+ kitchens)",
cta: "Order Now",
},
{
name: "Daily Essentials",
image: "/images/cat-daily-essentials.png",
tag: "15 Mins",
tagStyle: "bg-secondary text-white",
desc: "Groceries, fresh fruits & veggies",
stats: "★ 4.9 (180+ stores)",
cta: "Shop Fresh",
},
{
name: "Health & Wellness",
image: "/images/cat-health-wellness.png",
tag: "24/7 Delivery",
tagStyle: "bg-primary text-white",
desc: "Medicines & daily health supplies",
stats: "★ 4.7 (95+ pharmacies)",
cta: "Order Meds",
},
{
name: "Home Services",
image: "/images/cat-home-services.png",
tag: "Verified Professionals",
tagStyle: "bg-blue-600 text-white",
desc: "Electricians, cleaning & repairs",
stats: "★ 4.9 (340+ experts)",
cta: "Book Service",
},
{
name: "Pet Essentials",
image: "/images/cat-pet-essentials.png",
tag: "Express",
tagStyle: "bg-orange-500 text-white",
desc: "Pet food, toys & grooming care",
stats: "★ 4.8 (60+ partners)",
cta: "Shop Pet",
},
{
name: "More Services",
image: null,
tag: "Hyperlocal",
tagStyle: "bg-surface-variant text-on-surface",
desc: "Laundry, car wash, tailoring & more",
stats: "★ 5.0 (500+ services)",
cta: "Explore All",
},
];
export function ServiceCategories() {
return (
<section className="bg-background pt-28 pb-16 px-margin-mobile md:px-margin-desktop">
<div className="max-w-container-max mx-auto">
{/* Header Section */}
<div className="flex flex-col md:flex-row justify-between items-start md:items-end mb-12 gap-4">
<div>
<span className="text-label-sm text-primary uppercase tracking-widest font-black bg-primary/5 px-3 py-1 rounded-full">
Neighborhood Offerings
</span>
<h2 className="text-display text-brand-dark mt-3 leading-tight">
Popular Services <span className="text-primary font-normal">Near You</span>
</h2>
<p className="text-body-lg text-on-surface-variant mt-2 max-w-xl">
From fresh groceries to emergency services, everything in your 2km radius delivered instantly.
</p>
</div>
<a
href="#"
className="text-primary text-label-md font-black flex items-center gap-1 hover:gap-2 transition-all group"
>
View All Categories
<MaterialIcon icon="arrow_forward" size={18} className="transition-transform group-hover:translate-x-1" />
</a>
</div>
{/* Categories Premium Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{CATEGORIES.map((cat) => (
<div
key={cat.name}
className="bg-white rounded-[2rem] border border-outline-variant/10 shadow-lg overflow-hidden premium-card flex flex-col group h-full"
>
{/* Image Container */}
<div className="relative aspect-[4/3] w-full overflow-hidden bg-surface-container/30">
{cat.image ? (
<Image
src={cat.image}
alt={cat.name}
width={400}
height={300}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-primary/10 to-brand-accent/15 flex flex-col items-center justify-center text-primary">
<div className="w-16 h-16 rounded-full bg-white/80 shadow-md flex items-center justify-center animate-pulse-subtle">
<MaterialIcon icon="grid_view" size={32} />
</div>
</div>
)}
{/* Overlaid Badge */}
<div className={`absolute top-4 left-4 text-[10px] font-black uppercase tracking-wider px-3.5 py-1.5 rounded-full shadow-md z-10 ${cat.tagStyle}`}>
{cat.tag}
</div>
</div>
{/* Card Body */}
<div className="p-6 flex flex-col flex-grow">
<div className="flex items-center justify-between mb-2">
<h3 className="text-headline-md font-black text-brand-dark group-hover:text-primary transition-colors">
{cat.name}
</h3>
<span className="text-[11px] font-bold text-on-surface-variant bg-surface-container px-2.5 py-1 rounded-full">
{cat.stats}
</span>
</div>
<p className="text-body-md text-on-surface-variant mb-6 flex-grow leading-relaxed">
{cat.desc}
</p>
{/* Interactive Action Button */}
<div className="flex items-center justify-between pt-4 border-t border-dashed border-outline-variant/25">
<span className="text-label-sm text-primary font-black uppercase tracking-wider group-hover:underline">
{cat.cta}
</span>
<div className="w-10 h-10 rounded-full bg-brand-dark text-white flex items-center justify-center group-hover:bg-brand-accent group-hover:text-brand-dark transition-colors duration-300 shadow-md">
<MaterialIcon icon="chevron_right" size={20} className="font-bold" />
</div>
</div>
</div>
</div>
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,146 @@
import Link from "next/link";
import Image from "next/image";
import { MaterialIcon } from "@/components/ui/MaterialIcon";
const COMPANY = [
{ label: "About Us", href: "/about" },
{ label: "Careers", href: "#" },
{ label: "Press & News", href: "#" },
{ label: "Help Center", href: "#" },
];
const PARTNERSHIPS = [
{ label: "Merchant Partner", href: "/businesses" },
{ label: "Delivery Partner", href: "#" },
{ label: "Corporate Gifting", href: "#" },
{ label: "Local Real Estate", href: "#" },
];
const LEGAL = [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "Cookie Policy", href: "#" },
{ label: "Sitemap", href: "#" },
];
export function Footer() {
return (
<footer className="relative bg-brand-dark text-white border-t border-white/5 pt-28 pb-12 w-full mt-24">
{/* Overlapping Contact Helpdesk Card */}
<div className="absolute top-0 left-0 right-0 transform -translate-y-1/2 z-20 max-w-container-max mx-auto px-margin-mobile md:px-margin-desktop">
<div className="bg-brand-accent p-6 md:p-8 rounded-[2.5rem] flex flex-col md:flex-row justify-between items-center gap-6 shadow-2xl border border-brand-accent/20">
<div className="flex items-center gap-4 text-brand-dark">
<div className="w-12 h-12 rounded-full bg-brand-dark text-brand-accent flex items-center justify-center shadow-lg">
<MaterialIcon icon="headset_mic" size={24} />
</div>
<div>
<h4 className="text-headline-md font-black">24/7 Neighborhood Helpdesk</h4>
<p className="text-[11px] font-bold text-brand-dark/80 mt-0.5">
Need immediate assistance with an order or local service?
</p>
</div>
</div>
<a
href="tel:+918049123456"
className="flex items-center gap-3 bg-brand-dark hover:bg-brand-dark/90 text-brand-accent font-black px-8 py-3.5 rounded-full text-label-md shadow-2xl active:scale-95 duration-200 transition-all"
>
<MaterialIcon icon="phone" size={20} className="animate-pulse-subtle" />
<span>+91 80 4912 3456</span>
</a>
</div>
</div>
<div className="max-w-container-max mx-auto px-margin-mobile md:px-margin-desktop">
{/* Footer Link Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-gutter mb-16 pt-4">
{/* Brand Column */}
<div className="col-span-2 md:col-span-1">
<Link
href="/"
className="hover:scale-[1.02] transition-transform active:scale-95 duration-200 mb-6 inline-block"
>
<Image
src="/logo-v2.png"
alt="Nearle"
width={140}
height={23}
style={{ height: "auto" }}
className="h-7 w-auto object-contain"
/>
</Link>
<p className="text-body-sm text-white/60 max-w-xs mb-8 leading-relaxed">
India&apos;s leading hyperlocal neighborhood network, empowering communities and verified local businesses within 2km.
</p>
{/* Social Links */}
<div className="flex gap-4">
<a
href="#"
className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center hover:bg-brand-accent hover:text-brand-dark hover:scale-105 transition-all"
aria-label="Share"
>
<MaterialIcon icon="share" size={18} />
</a>
<a
href="#"
className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center hover:bg-brand-accent hover:text-brand-dark hover:scale-105 transition-all"
aria-label="Website"
>
<MaterialIcon icon="public" size={18} />
</a>
</div>
</div>
{/* Company Links */}
<FooterCol title="Company" links={COMPANY} />
{/* Partnerships Links */}
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
{/* Legal Links */}
<FooterCol title="Legal" links={LEGAL} />
</div>
{/* Bottom Bar */}
<div className="border-t border-white/10 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
<p className="text-body-sm text-white/40">
© {new Date().getFullYear()} Nearle. All rights reserved.
</p>
<div className="flex items-center gap-2 text-white/40 text-body-sm">
<span>Designed for neighborhoods in</span>
<span className="flex items-center gap-1 font-bold text-white/80">
India 🇮🇳
</span>
</div>
</div>
</div>
</footer>
);
}
function FooterCol({
title,
links,
}: {
title: string;
links: { label: string; href: string }[];
}) {
return (
<div>
<h5 className="text-label-sm font-black text-brand-accent uppercase tracking-widest mb-6">
{title}
</h5>
<ul className="space-y-3">
{links.map((l) => (
<li key={l.label}>
<Link
href={l.href}
className="text-body-sm text-white/60 hover:text-brand-accent hover:translate-x-1.5 transition-all duration-300 inline-block"
>
{l.label}
</Link>
</li>
))}
</ul>
</div>
);
}

View File

@@ -0,0 +1,93 @@
"use client";
import Link from "next/link";
import Image from "next/image";
import { useState } from "react";
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);
return (
<nav className="sticky top-0 z-50 w-full bg-white/95 backdrop-blur-md border-b border-outline-variant/20 transition-all duration-300">
<div className="grid w-full grid-cols-[auto_auto] md:grid-cols-[auto_1fr_auto] items-center gap-4 md:gap-8 px-margin-mobile md:px-16 xl:px-24 py-3">
{/* Left: Brand */}
<div className="flex items-center">
<Link
href="/"
className="flex items-center hover:scale-[1.02] transition-transform active:scale-95 duration-200"
>
<Image
src="/logo-purple-v2.png"
alt="Nearle"
width={140}
height={23}
style={{ height: "auto" }}
className="h-7 w-auto object-contain"
priority
/>
</Link>
</div>
{/* Center: Navigation */}
<div className="hidden md:flex items-center justify-center gap-8 xl:gap-10">
{NAV_LINKS.map((link) => (
<Link
key={link.label}
href={link.href}
className="relative py-1 text-[15px] font-bold leading-5 text-on-surface-variant hover:text-primary transition-all duration-200 group whitespace-nowrap"
>
{link.label}
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-primary transition-all duration-300 group-hover:w-full" />
</Link>
))}
</div>
{/* Right: Actions */}
<div className="flex items-center justify-end gap-3">
<Link
href="/#download"
className="hidden md:inline-flex bg-primary hover:bg-primary-container text-on-primary font-bold px-7 py-3 rounded-full text-label-md hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 active:translate-y-0 active:scale-95 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-surface-container transition-all active:scale-90 cursor-pointer"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu"
>
<MaterialIcon icon={mobileOpen ? "close" : "menu"} size={22} />
</button>
</div>
</div>
{/* Mobile Drawer */}
{mobileOpen && (
<div className="md:hidden bg-surface-container-lowest border-t border-outline-variant">
<div className="max-w-container-max mx-auto px-margin-mobile py-stack-md flex flex-col gap-2">
{NAV_LINKS.map((link) => (
<Link
key={link.label}
href={link.href}
className="px-3 py-2.5 text-body-md text-on-surface-variant hover:text-primary hover:bg-surface-container-low rounded-lg transition-colors"
onClick={() => setMobileOpen(false)}
>
{link.label}
</Link>
))}
</div>
</div>
)}
</nav>
);
}

View File

@@ -0,0 +1,25 @@
type MaterialIconProps = {
icon: string;
size?: number;
fill?: boolean;
className?: string;
};
export function MaterialIcon({
icon,
size = 24,
fill = false,
className = "",
}: MaterialIconProps) {
return (
<span
className={`material-symbols-outlined ${className}`}
style={{
fontSize: size,
fontVariationSettings: `'FILL' ${fill ? 1 : 0}, 'wght' 400, 'GRAD' 0, 'opsz' ${size}`,
}}
>
{icon}
</span>
);
}