fix(frontend): add hero tilt animation and stronger landing parity
This commit is contained in:
parent
973ec59b69
commit
e3b857a767
2 changed files with 29 additions and 2 deletions
|
|
@ -930,6 +930,8 @@ body {
|
||||||
.lp-hero-slider {
|
.lp-hero-slider {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 370px;
|
min-height: 370px;
|
||||||
|
transition: transform 260ms ease;
|
||||||
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lp-float-card {
|
.lp-float-card {
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,8 @@ export default function PublicLanding() {
|
||||||
const [scrolled, setScrolled] = createSignal(false);
|
const [scrolled, setScrolled] = createSignal(false);
|
||||||
const [mobileOpen, setMobileOpen] = createSignal(false);
|
const [mobileOpen, setMobileOpen] = createSignal(false);
|
||||||
const [scrollY, setScrollY] = createSignal(0);
|
const [scrollY, setScrollY] = createSignal(0);
|
||||||
|
const [reduceMotion, setReduceMotion] = createSignal(false);
|
||||||
|
const [heroTilt, setHeroTilt] = createSignal({ x: 0, y: 0 });
|
||||||
const [heroIdx, setHeroIdx] = createSignal(0);
|
const [heroIdx, setHeroIdx] = createSignal(0);
|
||||||
const [filter, setFilter] = createSignal<'all' | 'customer' | 'professional' | 'company' | 'job_seeker'>('all');
|
const [filter, setFilter] = createSignal<'all' | 'customer' | 'professional' | 'company' | 'job_seeker'>('all');
|
||||||
const [pathPage, setPathPage] = createSignal(0);
|
const [pathPage, setPathPage] = createSignal(0);
|
||||||
|
|
@ -249,6 +251,10 @@ export default function PublicLanding() {
|
||||||
const [openFaq, setOpenFaq] = createSignal(0);
|
const [openFaq, setOpenFaq] = createSignal(0);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
const media = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||||
|
const syncMotion = () => setReduceMotion(media.matches);
|
||||||
|
syncMotion();
|
||||||
|
|
||||||
const onScroll = () => {
|
const onScroll = () => {
|
||||||
setScrolled(window.scrollY > 10);
|
setScrolled(window.scrollY > 10);
|
||||||
setScrollY(window.scrollY || 0);
|
setScrollY(window.scrollY || 0);
|
||||||
|
|
@ -271,6 +277,7 @@ export default function PublicLanding() {
|
||||||
syncCardsPerPage();
|
syncCardsPerPage();
|
||||||
window.addEventListener('scroll', onScroll, { passive: true });
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
window.addEventListener('resize', syncCardsPerPage);
|
window.addEventListener('resize', syncCardsPerPage);
|
||||||
|
media.addEventListener('change', syncMotion);
|
||||||
|
|
||||||
const heroTimer = window.setInterval(() => setHeroIdx((x) => (x + 1) % heroSlides.length), 3500);
|
const heroTimer = window.setInterval(() => setHeroIdx((x) => (x + 1) % heroSlides.length), 3500);
|
||||||
const pathTimer = window.setInterval(() => setPathPage((x) => x + 1), 4200);
|
const pathTimer = window.setInterval(() => setPathPage((x) => x + 1), 4200);
|
||||||
|
|
@ -288,6 +295,7 @@ export default function PublicLanding() {
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
window.removeEventListener('scroll', onScroll);
|
window.removeEventListener('scroll', onScroll);
|
||||||
window.removeEventListener('resize', syncCardsPerPage);
|
window.removeEventListener('resize', syncCardsPerPage);
|
||||||
|
media.removeEventListener('change', syncMotion);
|
||||||
window.clearInterval(heroTimer);
|
window.clearInterval(heroTimer);
|
||||||
window.clearInterval(pathTimer);
|
window.clearInterval(pathTimer);
|
||||||
window.clearInterval(benefitTimer);
|
window.clearInterval(benefitTimer);
|
||||||
|
|
@ -377,7 +385,17 @@ export default function PublicLanding() {
|
||||||
</Show>
|
</Show>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="public-hero scene-dark">
|
<section
|
||||||
|
class="public-hero scene-dark"
|
||||||
|
onMouseMove={(event) => {
|
||||||
|
if (reduceMotion()) return;
|
||||||
|
const rect = event.currentTarget.getBoundingClientRect();
|
||||||
|
const px = (event.clientX - rect.left) / rect.width - 0.5;
|
||||||
|
const py = (event.clientY - rect.top) / rect.height - 0.5;
|
||||||
|
setHeroTilt({ x: px * 14, y: py * 12 });
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setHeroTilt({ x: 0, y: 0 })}
|
||||||
|
>
|
||||||
<div class="container lp-hero-grid">
|
<div class="container lp-hero-grid">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="lp-hero-title">Hire verified professionals. Post jobs. Get approvals in 24-48 hours.</h1>
|
<h1 class="lp-hero-title">Hire verified professionals. Post jobs. Get approvals in 24-48 hours.</h1>
|
||||||
|
|
@ -389,7 +407,14 @@ export default function PublicLanding() {
|
||||||
<A class="btn ghost-dark" href="/onboarding?schemaId=jobseeker_onboarding_v1">Apply for Jobs</A>
|
<A class="btn ghost-dark" href="/onboarding?schemaId=jobseeker_onboarding_v1">Apply for Jobs</A>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="lp-hero-slider">
|
<div
|
||||||
|
class="lp-hero-slider"
|
||||||
|
style={{
|
||||||
|
transform: reduceMotion()
|
||||||
|
? 'none'
|
||||||
|
: `translate3d(${heroTilt().x}px, ${heroTilt().y}px, 0)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<For each={heroSlides}>
|
<For each={heroSlides}>
|
||||||
{(slide, idx) => (
|
{(slide, idx) => (
|
||||||
<article class={`lp-float-card ${idx() === heroIdx() ? 'active' : ''}`}>
|
<article class={`lp-float-card ${idx() === heroIdx() ? 'active' : ''}`}>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue