From 973ec59b69f1e4c19e0ff75623f535f8d5ab87d1 Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Date: Tue, 17 Mar 2026 00:32:44 +0100 Subject: [PATCH] feat(frontend): rebuild landing with parallax and carousel parity --- src/app.css | 239 ++++++++++++++ src/components/PublicLanding.tsx | 530 +++++++++++++++++++------------ 2 files changed, 574 insertions(+), 195 deletions(-) diff --git a/src/app.css b/src/app.css index 9665707..254c500 100644 --- a/src/app.css +++ b/src/app.css @@ -812,3 +812,242 @@ body { .glass-dark .subtitle { color: rgba(255, 255, 255, 0.82); } + +/* Landing Parity Layer */ +.lp-main { + position: relative; + min-height: 100vh; + overflow-x: clip; +} + +.lp-bg { + pointer-events: none; + position: fixed; + inset: 0; + z-index: 0; +} + +.lp-dark-base { + position: absolute; + inset: 0; + background: + radial-gradient(110% 85% at 6% 0%, rgba(253, 98, 22, 0.2), transparent 56%), + radial-gradient(90% 70% at 96% 10%, rgba(253, 98, 22, 0.16), transparent 58%), + linear-gradient(180deg, #100b2f 0%, #0b0824 58%, #07051a 100%); +} + +.lp-mesh { + position: absolute; + inset: -12% -12%; + background: + radial-gradient(42% 36% at 14% 26%, rgba(2, 6, 23, 0.46), transparent 76%), + radial-gradient(34% 30% at 82% 14%, rgba(253, 98, 22, 0.2), transparent 74%), + radial-gradient(40% 32% at 66% 80%, rgba(2, 6, 23, 0.4), transparent 74%); + opacity: 0.58; +} + +.lp-ribbon { + position: absolute; + inset: -18% -6%; + background: linear-gradient(120deg, transparent 35%, rgba(253, 98, 22, 0.18) 55%, transparent 74%); + filter: blur(14px); + opacity: 0.38; +} + +.lp-noise { + position: absolute; + inset: 0; + opacity: 0.05; + background-image: radial-gradient(circle at 1px 1px, rgba(255, 255, 255, 0.38) 1px, transparent 0); + background-size: 4px 4px; + mix-blend-mode: soft-light; +} + +.lp-chips { + position: absolute; + inset: 0; +} + +.lp-chip { + position: absolute; + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 44px; + height: 44px; + border-radius: 999px; + border: 1px solid rgba(253, 98, 22, 0.46); + background: rgba(255, 255, 255, 0.14); + color: #fd6216; + font-size: 12px; + font-weight: 700; + backdrop-filter: blur(14px); + box-shadow: + 0 18px 36px -22px rgba(2, 6, 23, 0.8), + 0 0 0 1px rgba(253, 98, 22, 0.46) inset; + opacity: 0.52; +} + +.lp-chip-slow { + animation: lp-float-slow 8s ease-in-out infinite; +} + +.lp-chip-mid { + animation: lp-float-mid 6.4s ease-in-out infinite; +} + +.lp-chip-fast { + animation: lp-float-fast 5.6s ease-in-out infinite; +} + +.lp-content { + position: relative; + z-index: 10; +} + +.lp-hero-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + align-items: center; +} + +.lp-hero-title { + margin: 0; + color: #fff; + font-size: clamp(34px, 5vw, 56px); + line-height: 1.08; + font-weight: 800; +} + +.lp-hero-copy { + margin-top: 14px; + color: rgba(255, 255, 255, 0.8); + font-size: 17px; + line-height: 1.6; +} + +.lp-hero-slider { + position: relative; + min-height: 370px; +} + +.lp-float-card { + position: absolute; + inset: 0; + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.18); + background: linear-gradient(145deg, rgba(16, 11, 47, 0.72), rgba(16, 11, 47, 0.5)); + padding: 18px; + color: #fff; + backdrop-filter: blur(18px); + opacity: 0; + transform: translateY(14px) scale(0.98); + transition: all 380ms ease; +} + +.lp-float-card.active { + opacity: 1; + transform: translateY(0) scale(1); +} + +.lp-float-card h3 { + margin: 0; + font-size: 22px; +} + +.lp-float-card ul { + margin: 10px 0 16px; + padding-left: 18px; + color: rgba(255, 255, 255, 0.86); + line-height: 1.6; +} + +.lp-carousel-nav { + margin-top: 10px; + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; +} + +.lp-benefit-panel { + max-width: 980px; +} + +.lp-benefit-hero { + margin-top: 14px; + border: 1px solid rgba(255, 255, 255, 0.24); + border-radius: 18px; + padding: 16px; + background: rgba(255, 255, 255, 0.08); +} + +.lp-benefit-hero h3 { + margin: 0; + font-size: 28px; +} + +.lp-benefit-hero p { + margin-top: 8px; + color: rgba(255, 255, 255, 0.88); +} + +.lp-benefit-dots { + margin-top: 12px; + display: flex; + gap: 6px; +} + +.lp-dot { + width: 10px; + height: 10px; + border: 0; + border-radius: 999px; + background: rgba(255, 255, 255, 0.34); + cursor: pointer; +} + +.lp-dot.active { + background: #fd6216; +} + +@keyframes lp-float-slow { + 0%, + 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-7px); + } +} + +@keyframes lp-float-mid { + 0%, + 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-10px); + } +} + +@keyframes lp-float-fast { + 0%, + 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-12px); + } +} + +@media (max-width: 980px) { + .lp-hero-grid { + grid-template-columns: 1fr; + } + + .lp-hero-slider { + min-height: 340px; + } +} diff --git a/src/components/PublicLanding.tsx b/src/components/PublicLanding.tsx index 2d6d4ae..392f5d0 100644 --- a/src/components/PublicLanding.tsx +++ b/src/components/PublicLanding.tsx @@ -1,22 +1,57 @@ import { A } from '@solidjs/router'; import { createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'; -type RoleCard = { +type PathCard = { title: string; description: string; button: string; href: string; image: string; - chip: string; + audience: 'customer' | 'professional' | 'company' | 'job_seeker'; }; -const roleCards: RoleCard[] = [ +type Flow = { + label: string; + title: string; + description: string; + image: string; + steps: Array<{ title: string; description: string }>; +}; + +const heroSlides = [ + { + title: 'Customers', + bullets: ['Post requirements with clear intent', 'Receive verified responses after review'], + href: '/onboarding?schemaId=customer_onboarding_v1', + cta: 'Hire a Professional', + }, + { + title: 'Professionals', + bullets: ['Complete role onboarding and verification', 'Discover leads with focused matching'], + href: '/onboarding?schemaId=professional_onboarding_v1', + cta: 'Join as Professional', + }, + { + title: 'Companies', + bullets: ['Create approved job listings', 'Track applications in one workflow'], + href: '/onboarding?schemaId=company_onboarding_v1', + cta: 'Post a Job', + }, + { + title: 'Job Seekers', + bullets: ['Build profile and clear approvals', 'Apply and monitor opportunities'], + href: '/onboarding?schemaId=jobseeker_onboarding_v1', + cta: 'Apply for Jobs', + }, +] as const; + +const pathCards: PathCard[] = [ { title: 'Post a Job', description: 'Create verified job openings and find the right talent faster.', button: 'Start as Company', href: '/onboarding?schemaId=company_onboarding_v1', - chip: 'Company', + audience: 'company', image: 'https://images.unsplash.com/photo-1484480974693-6ca0a78fb36b?q=80&w=800&auto=format&fit=crop', }, { @@ -24,7 +59,7 @@ const roleCards: RoleCard[] = [ description: 'Build your profile and apply to approved opportunities quickly.', button: 'Start as Job Seeker', href: '/onboarding?schemaId=jobseeker_onboarding_v1', - chip: 'Job Seeker', + audience: 'job_seeker', image: 'https://images.unsplash.com/photo-1586281380349-632531db7ed4?q=80&w=800&auto=format&fit=crop', }, { @@ -32,7 +67,7 @@ const roleCards: RoleCard[] = [ description: 'Post your requirement and discover trusted specialists.', button: 'Start as Customer', href: '/onboarding?schemaId=customer_onboarding_v1', - chip: 'Customer', + audience: 'customer', image: 'https://images.unsplash.com/photo-1450101499163-c8848c66ca85?q=80&w=800&auto=format&fit=crop', }, { @@ -40,7 +75,7 @@ const roleCards: RoleCard[] = [ description: 'Build products and grow with verified client demand.', button: 'Join Developer', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Developer', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1498050108023-c5249f4df085?q=80&w=800&auto=format&fit=crop', }, { @@ -48,7 +83,7 @@ const roleCards: RoleCard[] = [ description: 'Capture events and campaigns with trusted bookings.', button: 'Join Photographer', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Photographer', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1516035069371-29a1b244cc32?q=80&w=800&auto=format&fit=crop', }, { @@ -56,7 +91,7 @@ const roleCards: RoleCard[] = [ description: 'Offer styling services with profile-based trust signals.', button: 'Join Makeup Artist', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Makeup%20Artist', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1522335789203-aabd1fc54bc9?q=80&w=800&auto=format&fit=crop', }, { @@ -64,7 +99,7 @@ const roleCards: RoleCard[] = [ description: 'Teach learners and build your reputation with verified profiles.', button: 'Join Tutor', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Tutor', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1497633762265-9d179a990aa6?q=80&w=800&auto=format&fit=crop', }, { @@ -72,7 +107,7 @@ const roleCards: RoleCard[] = [ description: 'Create compelling edits and work with quality clients.', button: 'Join Video Editor', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Video%20Editor', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1574717024653-61fd2cf4d44d?q=80&w=800&auto=format&fit=crop', }, { @@ -80,7 +115,7 @@ const roleCards: RoleCard[] = [ description: 'Design brand-ready visuals and collaborate with growing businesses.', button: 'Join Graphic Designer', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Graphic%20Designer', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1558655146-d09347e92766?q=80&w=800&auto=format&fit=crop', }, { @@ -88,7 +123,7 @@ const roleCards: RoleCard[] = [ description: 'Plan campaigns and scale audience growth for clients.', button: 'Join Social Manager', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Social%20Media%20Manager', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1611162618071-b39a2ec055fb?q=80&w=800&auto=format&fit=crop', }, { @@ -96,7 +131,7 @@ const roleCards: RoleCard[] = [ description: 'Coach clients with structured plans and trusted profiles.', button: 'Join Trainer', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Fitness%20Trainer', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1517836357463-d25dfeac3438?q=80&w=800&auto=format&fit=crop', }, { @@ -104,7 +139,7 @@ const roleCards: RoleCard[] = [ description: 'Showcase event-ready menus to customers and companies.', button: 'Join Catering', href: '/onboarding?schemaId=professional_onboarding_v1&profession=Catering%20Services', - chip: 'Professional', + audience: 'professional', image: 'https://images.unsplash.com/photo-1555244162-803834f70033?q=80&w=800&auto=format&fit=crop', }, ]; @@ -116,9 +151,9 @@ const benefits = [ { title: 'Focused discovery with filters', body: 'Search and filter tools keep opportunity discovery focused.' }, { title: 'Controlled contact visibility', body: 'Sensitive contact flow remains controlled by role and workflow.' }, { title: 'Notifications & updates', body: 'Track approvals, responses, applications, and key updates.' }, -]; +] as const; -const flows = [ +const flows: Flow[] = [ { label: 'Customers', title: 'Need to solution, with verified trust in the middle', @@ -190,225 +225,330 @@ const faqs = [ q: 'Do I need to choose my role during signup?', a: 'No. You can sign up once and continue with the role flow that fits you best.', }, -]; +] as const; + +const chipNodes = [ + { label: '', left: '3%', top: '14%', cls: 'lp-chip-slow' }, + { label: 'Cam', left: '95%', top: '20%', cls: 'lp-chip-mid' }, + { label: 'Job', left: '5%', top: '78%', cls: 'lp-chip-fast' }, + { label: 'Pro', left: '92%', top: '74%', cls: 'lp-chip-slow' }, + { label: 'AI', left: '48%', top: '7%', cls: 'lp-chip-mid' }, +] as const; export default function PublicLanding() { const [scrolled, setScrolled] = createSignal(false); const [mobileOpen, setMobileOpen] = createSignal(false); - const [filter, setFilter] = createSignal<'all' | 'customer' | 'professional' | 'company' | 'jobseeker'>('all'); + const [scrollY, setScrollY] = createSignal(0); + const [heroIdx, setHeroIdx] = createSignal(0); + const [filter, setFilter] = createSignal<'all' | 'customer' | 'professional' | 'company' | 'job_seeker'>('all'); + const [pathPage, setPathPage] = createSignal(0); + const [cardsPerPage, setCardsPerPage] = createSignal(3); + const [benefitIdx, setBenefitIdx] = createSignal(0); const [flowIndex, setFlowIndex] = createSignal(0); - const [stepIndex, setStepIndex] = createSignal(0); + const [flowStepIndex, setFlowStepIndex] = createSignal(0); const [openFaq, setOpenFaq] = createSignal(0); onMount(() => { - const onScroll = () => setScrolled(window.scrollY > 10); - onScroll(); - window.addEventListener('scroll', onScroll, { passive: true }); + const onScroll = () => { + setScrolled(window.scrollY > 10); + setScrollY(window.scrollY || 0); + }; - const timer = window.setInterval(() => { - setStepIndex((prev) => { - const active = flows[flowIndex()]; - if (prev + 1 < active.steps.length) return prev + 1; + const syncCardsPerPage = () => { + const w = window.innerWidth; + if (w < 640) { + setCardsPerPage(1); + return; + } + if (w < 1024) { + setCardsPerPage(2); + return; + } + setCardsPerPage(3); + }; + + onScroll(); + syncCardsPerPage(); + window.addEventListener('scroll', onScroll, { passive: true }); + window.addEventListener('resize', syncCardsPerPage); + + const heroTimer = window.setInterval(() => setHeroIdx((x) => (x + 1) % heroSlides.length), 3500); + const pathTimer = window.setInterval(() => setPathPage((x) => x + 1), 4200); + const benefitTimer = window.setInterval(() => setBenefitIdx((x) => (x + 1) % benefits.length), 4200); + const flowTimer = window.setInterval(() => { + const active = flows[flowIndex()]; + setFlowStepIndex((prev) => { + const next = prev + 1; + if (next < active.steps.length) return next; setFlowIndex((f) => (f + 1) % flows.length); return 0; }); - }, 3200); + }, 3000); onCleanup(() => { window.removeEventListener('scroll', onScroll); - window.clearInterval(timer); + window.removeEventListener('resize', syncCardsPerPage); + window.clearInterval(heroTimer); + window.clearInterval(pathTimer); + window.clearInterval(benefitTimer); + window.clearInterval(flowTimer); }); }); - const filteredCards = createMemo(() => { - const active = filter(); - if (active === 'all') return roleCards; - if (active === 'customer') return roleCards.filter((x) => x.chip === 'Customer'); - if (active === 'professional') return roleCards.filter((x) => x.chip === 'Professional'); - if (active === 'company') return roleCards.filter((x) => x.chip === 'Company'); - return roleCards.filter((x) => x.chip === 'Job Seeker'); + const filteredPaths = createMemo(() => { + const value = filter(); + if (value === 'all') return pathCards; + return pathCards.filter((card) => card.audience === value); }); - return ( -
-
-
- -
-
-
-

Hire verified professionals. Post jobs. Get approvals in 24-48 hours.

-

Nxtgauge connects customers, companies, job seekers, and professionals through a trusted approval workflow.

- -
-
-

Customers

-

Post requirements with clear intent and receive verified responses.

-
-
-

Professionals

-

Complete onboarding and verification, then discover relevant leads.

-
-
-

Companies

-

Create approved job listings and track applications in one workflow.

-
-
-

Job Seekers

-

Build profile, clear approvals, apply and track opportunities.

-
-
-
-
+ + -
-
-
+
+
-

Choose Your Path

-

One account, multiple journeys. Pick your goal and get started.

+

Hire verified professionals. Post jobs. Get approvals in 24-48 hours.

+

+ Nxtgauge connects customers, companies, job seekers, and professionals through a trusted approval workflow. +

+
-
- - - - - +
+ + {(slide, idx) => ( + + )} +
-
- - {(card) => ( -
- {card.title} -
- {card.chip} -

{card.title}

-

{card.description}

- {card.button} -
-
- )} -
-
-
-
+
-
-
-

Why Nxtgauge

-

Trust, approvals, and better matching in one flow.

-
- {(item) =>

{item.title}

{item.body}

}
-
-
-
+
+
+
+
+

Choose Your Path

+

One account, multiple journeys. Pick your goal and get started.

+
+
+ + + + + +
+
-
-
-

How It Works

-

Clear journey, zero confusion.

-
- {flows[flowIndex()].label} -
-

{flows[flowIndex()].label}

-

{flows[flowIndex()].title}

-

{flows[flowIndex()].description}

-
- - {(step, idx) => ( -
- {idx() + 1} -
-

{step.title}

-

{step.description}

-
+ + +
+ + {(card) => ( + + )} + +
+
+
+ +
+
+

Why Nxtgauge

+

Trust, approvals, and better matching in one flow.

+
+

{benefits[benefitIdx()].title}

+

{benefits[benefitIdx()].body}

+
+ + {(_, idx) => ( +
-
- - +
+
+
+ +
+
+

How it works

+

Clear journey, zero confusion.

+
+ {flows[flowIndex()].label} +
+

{flows[flowIndex()].label}

+

{flows[flowIndex()].title}

+

{flows[flowIndex()].description}

+
+ + {(step, idx) => ( +
+ {idx() + 1} +
+

{step.title}

+

{step.description}

+
+
+ )} +
+
+
+ + +
+
+
+
+ +
+
+

Frequently asked questions

+

Quick answers before you create your account.

+
+ + {(item, idx) => ( +
+ + +

{item.a}

+
+
+ )} +
- -
-
+
+
-
-
-

Frequently asked questions

-

Quick answers before you create your account.

-
- - {(item, idx) => ( -
- -

{item.a}

-
- )} -
+
+
+
+

Quick Actions

+

Ready to get started?

+

Pick your next action and continue with the correct role flow.

+
+
-
-
+ -
-
-
-

Quick Actions

-

Ready to get started?

-

Pick your next action and continue with the correct role flow.

+
-
- - + +
); }