Initial commit
This commit is contained in:
17
src/app/about/page.tsx
Normal file
17
src/app/about/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
17
src/app/businesses/page.tsx
Normal file
17
src/app/businesses/page.tsx
Normal 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
17
src/app/contact/page.tsx
Normal 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
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
537
src/app/globals.css
Normal 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
103
src/app/layout.tsx
Normal 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
17
src/app/page.tsx
Normal 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
17
src/app/people/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
159
src/components/home/AppPromo.tsx
Normal file
159
src/components/home/AppPromo.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
162
src/components/home/BusinessSection.tsx
Normal file
162
src/components/home/BusinessSection.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
252
src/components/home/Hero.tsx
Normal file
252
src/components/home/Hero.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
129
src/components/home/HyperlocalFeatures.tsx
Normal file
129
src/components/home/HyperlocalFeatures.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
148
src/components/home/ServiceCategories.tsx
Normal file
148
src/components/home/ServiceCategories.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
146
src/components/layout/Footer.tsx
Normal file
146
src/components/layout/Footer.tsx
Normal 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'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>
|
||||
);
|
||||
}
|
||||
93
src/components/layout/Navbar.tsx
Normal file
93
src/components/layout/Navbar.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
25
src/components/ui/MaterialIcon.tsx
Normal file
25
src/components/ui/MaterialIcon.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user