feat(frontend): rebuild landing with parallax and carousel parity
This commit is contained in:
parent
10385d2e5d
commit
973ec59b69
2 changed files with 574 additions and 195 deletions
239
src/app.css
239
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<main class="public-main">
|
||||
<header class={`public-header ${scrolled() ? 'public-header-scrolled' : ''}`}>
|
||||
<div class="container nav-row">
|
||||
<A href="/"><img class="brand-logo" src="/nxtgauge-logo.png" alt="NXTGAUGE" /></A>
|
||||
const pagedPaths = createMemo(() => {
|
||||
const cards = filteredPaths();
|
||||
const per = cardsPerPage();
|
||||
const pages: PathCard[][] = [];
|
||||
for (let i = 0; i < cards.length; i += per) pages.push(cards.slice(i, i + per));
|
||||
return pages;
|
||||
});
|
||||
|
||||
<nav class="nav-links desktop-only">
|
||||
<A href="/">Home</A>
|
||||
<A href="/about">About Us</A>
|
||||
<A href="/contact">Contact Us</A>
|
||||
const activePathPage = createMemo(() => {
|
||||
const pages = pagedPaths();
|
||||
if (pages.length === 0) return 0;
|
||||
return pathPage() % pages.length;
|
||||
});
|
||||
|
||||
const pathCardsVisible = createMemo(() => {
|
||||
const pages = pagedPaths();
|
||||
if (pages.length === 0) return [];
|
||||
return pages[activePathPage()];
|
||||
});
|
||||
|
||||
const parallax = createMemo(() => ({
|
||||
mesh: Math.min(36, scrollY() * 0.1),
|
||||
ribbon: Math.min(52, scrollY() * 0.18),
|
||||
chips: Math.min(70, scrollY() * 0.23),
|
||||
}));
|
||||
|
||||
return (
|
||||
<main class="lp-main">
|
||||
<div class="lp-bg" aria-hidden="true">
|
||||
<div class="lp-dark-base" />
|
||||
<div class="lp-mesh" style={{ transform: `translate3d(0, ${parallax().mesh}px, 0)` }} />
|
||||
<div class="lp-ribbon" style={{ transform: `translate3d(0, ${parallax().ribbon}px, 0)` }} />
|
||||
<div class="lp-chips" style={{ transform: `translate3d(0, ${parallax().chips}px, 0)` }}>
|
||||
<For each={chipNodes}>
|
||||
{(chip) => (
|
||||
<span class={`lp-chip ${chip.cls}`} style={{ left: chip.left, top: chip.top }}>
|
||||
{chip.label}
|
||||
</span>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<div class="lp-noise" />
|
||||
</div>
|
||||
|
||||
<div class="lp-content">
|
||||
<header class={`public-header ${scrolled() ? 'public-header-scrolled' : ''}`}>
|
||||
<nav class="container nav-row">
|
||||
<A href="/"><img class="brand-logo" src="/nxtgauge-logo.png" alt="NXTGAUGE" /></A>
|
||||
|
||||
<div class="desktop-only nav-links">
|
||||
<A href="/">Home</A>
|
||||
<A href="/about">About Us</A>
|
||||
<A href="/help-center">Help Center</A>
|
||||
<A href="/contact">Contact Us</A>
|
||||
</div>
|
||||
|
||||
<div class="desktop-only nav-actions">
|
||||
<A class="btn" href="/auth/login">Login</A>
|
||||
<A class="btn primary" href="/auth/register">Sign Up</A>
|
||||
</div>
|
||||
|
||||
<button class="btn mobile-menu" onClick={() => setMobileOpen(!mobileOpen())}>Menu</button>
|
||||
</nav>
|
||||
|
||||
<div class="nav-actions desktop-only">
|
||||
<A class="btn" href="/onboarding?schemaId=professional_onboarding_v1">Login</A>
|
||||
<A class="btn primary" href="/onboarding?schemaId=customer_onboarding_v1">Sign Up</A>
|
||||
</div>
|
||||
|
||||
<button class="btn mobile-menu" onClick={() => setMobileOpen(!mobileOpen())}>Menu</button>
|
||||
</div>
|
||||
|
||||
<Show when={mobileOpen()}>
|
||||
<div class="mobile-nav container">
|
||||
<A href="/" onClick={() => setMobileOpen(false)}>Home</A>
|
||||
<A href="/about" onClick={() => setMobileOpen(false)}>About Us</A>
|
||||
<A href="/contact" onClick={() => setMobileOpen(false)}>Contact Us</A>
|
||||
</div>
|
||||
</Show>
|
||||
</header>
|
||||
|
||||
<section class="public-hero scene-dark">
|
||||
<div class="container hero-grid-2">
|
||||
<div>
|
||||
<h1 class="hero-title">Hire verified professionals. Post jobs. Get approvals in 24-48 hours.</h1>
|
||||
<p class="hero-copy">Nxtgauge connects customers, companies, job seekers, and professionals through a trusted approval workflow.</p>
|
||||
<div class="hero-actions">
|
||||
<A class="btn primary" href="/onboarding?schemaId=customer_onboarding_v1">Hire a Professional</A>
|
||||
<A class="btn ghost-dark" href="/onboarding?schemaId=jobseeker_onboarding_v1">Apply for Jobs</A>
|
||||
<Show when={mobileOpen()}>
|
||||
<div class="mobile-nav container">
|
||||
<A href="/" onClick={() => setMobileOpen(false)}>Home</A>
|
||||
<A href="/about" onClick={() => setMobileOpen(false)}>About Us</A>
|
||||
<A href="/help-center" onClick={() => setMobileOpen(false)}>Help Center</A>
|
||||
<A href="/contact" onClick={() => setMobileOpen(false)}>Contact Us</A>
|
||||
<A href="/auth/login" onClick={() => setMobileOpen(false)}>Login</A>
|
||||
<A href="/auth/register" onClick={() => setMobileOpen(false)}>Sign Up</A>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-stack">
|
||||
<article class="float-card">
|
||||
<h3>Customers</h3>
|
||||
<p>Post requirements with clear intent and receive verified responses.</p>
|
||||
</article>
|
||||
<article class="float-card">
|
||||
<h3>Professionals</h3>
|
||||
<p>Complete onboarding and verification, then discover relevant leads.</p>
|
||||
</article>
|
||||
<article class="float-card">
|
||||
<h3>Companies</h3>
|
||||
<p>Create approved job listings and track applications in one workflow.</p>
|
||||
</article>
|
||||
<article class="float-card">
|
||||
<h3>Job Seekers</h3>
|
||||
<p>Build profile, clear approvals, apply and track opportunities.</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Show>
|
||||
</header>
|
||||
|
||||
<section class="public-section scene-dark">
|
||||
<div class="container panel">
|
||||
<div class="section-head">
|
||||
<section class="public-hero scene-dark">
|
||||
<div class="container lp-hero-grid">
|
||||
<div>
|
||||
<h2>Choose Your Path</h2>
|
||||
<p>One account, multiple journeys. Pick your goal and get started.</p>
|
||||
<h1 class="lp-hero-title">Hire verified professionals. Post jobs. Get approvals in 24-48 hours.</h1>
|
||||
<p class="lp-hero-copy">
|
||||
Nxtgauge connects customers, companies, job seekers, and professionals through a trusted approval workflow.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<A class="btn primary" href="/onboarding?schemaId=customer_onboarding_v1">Hire a Professional</A>
|
||||
<A class="btn ghost-dark" href="/onboarding?schemaId=jobseeker_onboarding_v1">Apply for Jobs</A>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-row">
|
||||
<button class={`chip-btn ${filter() === 'all' ? 'active' : ''}`} onClick={() => setFilter('all')}>All Paths</button>
|
||||
<button class={`chip-btn ${filter() === 'customer' ? 'active' : ''}`} onClick={() => setFilter('customer')}>Customers</button>
|
||||
<button class={`chip-btn ${filter() === 'professional' ? 'active' : ''}`} onClick={() => setFilter('professional')}>Professionals</button>
|
||||
<button class={`chip-btn ${filter() === 'company' ? 'active' : ''}`} onClick={() => setFilter('company')}>Companies</button>
|
||||
<button class={`chip-btn ${filter() === 'jobseeker' ? 'active' : ''}`} onClick={() => setFilter('jobseeker')}>Job Seekers</button>
|
||||
<div class="lp-hero-slider">
|
||||
<For each={heroSlides}>
|
||||
{(slide, idx) => (
|
||||
<article class={`lp-float-card ${idx() === heroIdx() ? 'active' : ''}`}>
|
||||
<h3>{slide.title}</h3>
|
||||
<ul>
|
||||
<For each={slide.bullets}>{(b) => <li>{b}</li>}</For>
|
||||
</ul>
|
||||
<A class="btn" href={slide.href}>{slide.cta}</A>
|
||||
</article>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
<div class="path-grid">
|
||||
<For each={filteredCards()}>
|
||||
{(card) => (
|
||||
<article class="path-card">
|
||||
<img src={card.image} alt={card.title} />
|
||||
<div class="path-body">
|
||||
<span class="role-badge">{card.chip}</span>
|
||||
<h3>{card.title}</h3>
|
||||
<p>{card.description}</p>
|
||||
<A class="btn primary" href={card.href}>{card.button}</A>
|
||||
</div>
|
||||
</article>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="public-section scene-dark">
|
||||
<div class="container panel panel-dark">
|
||||
<h2 class="center">Why Nxtgauge</h2>
|
||||
<p class="center sub">Trust, approvals, and better matching in one flow.</p>
|
||||
<div class="benefit-grid">
|
||||
<For each={benefits}>{(item) => <article class="benefit-card"><h3>{item.title}</h3><p>{item.body}</p></article>}</For>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="choose-path" class="public-section scene-dark">
|
||||
<div class="container panel">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2>Choose Your Path</h2>
|
||||
<p class="sub">One account, multiple journeys. Pick your goal and get started.</p>
|
||||
</div>
|
||||
<div class="filter-row">
|
||||
<button class={`chip-btn ${filter() === 'all' ? 'active' : ''}`} onClick={() => { setFilter('all'); setPathPage(0); }}>All Paths</button>
|
||||
<button class={`chip-btn ${filter() === 'customer' ? 'active' : ''}`} onClick={() => { setFilter('customer'); setPathPage(0); }}>Customers</button>
|
||||
<button class={`chip-btn ${filter() === 'professional' ? 'active' : ''}`} onClick={() => { setFilter('professional'); setPathPage(0); }}>Professionals</button>
|
||||
<button class={`chip-btn ${filter() === 'company' ? 'active' : ''}`} onClick={() => { setFilter('company'); setPathPage(0); }}>Companies</button>
|
||||
<button class={`chip-btn ${filter() === 'job_seeker' ? 'active' : ''}`} onClick={() => { setFilter('job_seeker'); setPathPage(0); }}>Job Seekers</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="public-section scene-light">
|
||||
<div class="container panel panel-light">
|
||||
<h2 class="center">How It Works</h2>
|
||||
<p class="center sub">Clear journey, zero confusion.</p>
|
||||
<article class="flow-card">
|
||||
<img src={flows[flowIndex()].image} alt={flows[flowIndex()].label} />
|
||||
<div>
|
||||
<p class="eyebrow">{flows[flowIndex()].label}</p>
|
||||
<h3>{flows[flowIndex()].title}</h3>
|
||||
<p class="sub">{flows[flowIndex()].description}</p>
|
||||
<div class="step-list">
|
||||
<For each={flows[flowIndex()].steps}>
|
||||
{(step, idx) => (
|
||||
<div class={`step-item ${idx() === stepIndex() ? 'active' : ''}`}>
|
||||
<span>{idx() + 1}</span>
|
||||
<div>
|
||||
<h4>{step.title}</h4>
|
||||
<p>{step.description}</p>
|
||||
</div>
|
||||
<div class="lp-carousel-nav">
|
||||
<button class="btn" onClick={() => setPathPage((x) => Math.max(0, x - 1))}>←</button>
|
||||
<span class="note">Page {activePathPage() + 1} / {Math.max(1, pagedPaths().length)}</span>
|
||||
<button class="btn" onClick={() => setPathPage((x) => x + 1)}>→</button>
|
||||
</div>
|
||||
|
||||
<div class="path-grid">
|
||||
<For each={pathCardsVisible()}>
|
||||
{(card) => (
|
||||
<article class="path-card">
|
||||
<img src={card.image} alt={card.title} />
|
||||
<div class="path-body">
|
||||
<h3>{card.title}</h3>
|
||||
<p>{card.description}</p>
|
||||
<A class="btn primary" href={card.href}>{card.button}</A>
|
||||
</div>
|
||||
</article>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="why-nxtgauge" class="public-section scene-dark">
|
||||
<div class="container panel panel-dark lp-benefit-panel">
|
||||
<h2 class="center">Why Nxtgauge</h2>
|
||||
<p class="center sub">Trust, approvals, and better matching in one flow.</p>
|
||||
<article class="lp-benefit-hero">
|
||||
<h3>{benefits[benefitIdx()].title}</h3>
|
||||
<p>{benefits[benefitIdx()].body}</p>
|
||||
<div class="lp-benefit-dots">
|
||||
<For each={benefits}>
|
||||
{(_, idx) => (
|
||||
<button
|
||||
class={`lp-dot ${idx() === benefitIdx() ? 'active' : ''}`}
|
||||
onClick={() => setBenefitIdx(idx())}
|
||||
aria-label={`Benefit ${idx() + 1}`}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" onClick={() => { setFlowIndex((flowIndex() - 1 + flows.length) % flows.length); setStepIndex(0); }}>←</button>
|
||||
<button class="btn" onClick={() => { setFlowIndex((flowIndex() + 1) % flows.length); setStepIndex(0); }}>→</button>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="how-it-works" class="public-section scene-light">
|
||||
<div class="container panel panel-light">
|
||||
<h2 class="center">How it works</h2>
|
||||
<p class="center sub">Clear journey, zero confusion.</p>
|
||||
<article class="flow-card">
|
||||
<img src={flows[flowIndex()].image} alt={flows[flowIndex()].label} />
|
||||
<div>
|
||||
<p class="eyebrow">{flows[flowIndex()].label}</p>
|
||||
<h3>{flows[flowIndex()].title}</h3>
|
||||
<p class="sub">{flows[flowIndex()].description}</p>
|
||||
<div class="step-list">
|
||||
<For each={flows[flowIndex()].steps}>
|
||||
{(step, idx) => (
|
||||
<div class={`step-item ${idx() === flowStepIndex() ? 'active' : ''}`}>
|
||||
<span>{idx() + 1}</span>
|
||||
<div>
|
||||
<h4>{step.title}</h4>
|
||||
<p>{step.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" onClick={() => { setFlowIndex((flowIndex() - 1 + flows.length) % flows.length); setFlowStepIndex(0); }}>←</button>
|
||||
<button class="btn" onClick={() => { setFlowIndex((flowIndex() + 1) % flows.length); setFlowStepIndex(0); }}>→</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="faqs" class="public-section scene-dark">
|
||||
<div class="container panel panel-dark faq-wrap">
|
||||
<h2 class="center">Frequently asked questions</h2>
|
||||
<p class="center sub">Quick answers before you create your account.</p>
|
||||
<div class="faq-list">
|
||||
<For each={faqs}>
|
||||
{(item, idx) => (
|
||||
<article class={`faq-item ${openFaq() === idx() ? 'open' : ''}`}>
|
||||
<button class="faq-q" onClick={() => setOpenFaq(openFaq() === idx() ? -1 : idx())}>
|
||||
<span>{item.q}</span>
|
||||
<span>{openFaq() === idx() ? '−' : '+'}</span>
|
||||
</button>
|
||||
<Show when={openFaq() === idx()}>
|
||||
<p class="faq-a">{item.a}</p>
|
||||
</Show>
|
||||
</article>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="public-section scene-dark">
|
||||
<div class="container panel panel-dark faq-wrap">
|
||||
<h2 class="center">Frequently asked questions</h2>
|
||||
<p class="center sub">Quick answers before you create your account.</p>
|
||||
<div class="faq-list">
|
||||
<For each={faqs}>
|
||||
{(item, idx) => (
|
||||
<article class={`faq-item ${openFaq() === idx() ? 'open' : ''}`}>
|
||||
<button class="faq-q" onClick={() => setOpenFaq(openFaq() === idx() ? -1 : idx())}>
|
||||
<span>{item.q}</span>
|
||||
<span>{openFaq() === idx() ? '-' : '+'}</span>
|
||||
</button>
|
||||
<Show when={openFaq() === idx()}><p class="faq-a">{item.a}</p></Show>
|
||||
</article>
|
||||
)}
|
||||
</For>
|
||||
<section class="public-section scene-dark">
|
||||
<div class="container panel panel-dark cta-row">
|
||||
<div>
|
||||
<p class="eyebrow">Quick Actions</p>
|
||||
<h2>Ready to get started?</h2>
|
||||
<p class="sub">Pick your next action and continue with the correct role flow.</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<A class="btn primary" href="/onboarding?schemaId=customer_onboarding_v1">Hire a Professional</A>
|
||||
<A class="btn ghost-dark" href="/onboarding?schemaId=jobseeker_onboarding_v1">Apply for Jobs</A>
|
||||
<A class="btn ghost-dark" href="/onboarding?schemaId=company_onboarding_v1">Post a Job</A>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="public-section scene-dark">
|
||||
<div class="container panel panel-dark cta-row">
|
||||
<div>
|
||||
<p class="eyebrow">Quick Actions</p>
|
||||
<h2>Ready to get started?</h2>
|
||||
<p class="sub">Pick your next action and continue with the correct role flow.</p>
|
||||
<footer class="public-footer">
|
||||
<div class="container footer-row">
|
||||
<img class="brand-logo" src="/nxtgauge-logo.png" alt="NXTGAUGE" />
|
||||
<p>© {new Date().getFullYear()} Nxtgauge. All rights reserved.</p>
|
||||
<div class="footer-links">
|
||||
<A href="/about">About Us</A>
|
||||
<A href="/terms">Terms</A>
|
||||
<A href="/privacy">Privacy</A>
|
||||
<A href="/help-center">Help Center</A>
|
||||
<A href="/contact">Contact Us</A>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<A class="btn primary" href="/onboarding?schemaId=customer_onboarding_v1">Hire a Professional</A>
|
||||
<A class="btn ghost-dark" href="/onboarding?schemaId=jobseeker_onboarding_v1">Apply for Jobs</A>
|
||||
<A class="btn ghost-dark" href="/onboarding?schemaId=company_onboarding_v1">Post a Job</A>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="public-footer">
|
||||
<div class="container footer-row">
|
||||
<img class="brand-logo" src="/nxtgauge-logo.png" alt="NXTGAUGE" />
|
||||
<p>© {new Date().getFullYear()} Nxtgauge. All rights reserved.</p>
|
||||
<div class="footer-links">
|
||||
<A href="/about">About Us</A>
|
||||
<A href="/contact">Contact Us</A>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue