diff --git a/src/app.css b/src/app.css index 254c500..64a9455 100644 --- a/src/app.css +++ b/src/app.css @@ -930,6 +930,8 @@ body { .lp-hero-slider { position: relative; min-height: 370px; + transition: transform 260ms ease; + will-change: transform; } .lp-float-card { diff --git a/src/components/PublicLanding.tsx b/src/components/PublicLanding.tsx index 392f5d0..f334aba 100644 --- a/src/components/PublicLanding.tsx +++ b/src/components/PublicLanding.tsx @@ -239,6 +239,8 @@ export default function PublicLanding() { const [scrolled, setScrolled] = createSignal(false); const [mobileOpen, setMobileOpen] = createSignal(false); const [scrollY, setScrollY] = createSignal(0); + const [reduceMotion, setReduceMotion] = createSignal(false); + const [heroTilt, setHeroTilt] = createSignal({ x: 0, y: 0 }); const [heroIdx, setHeroIdx] = createSignal(0); const [filter, setFilter] = createSignal<'all' | 'customer' | 'professional' | 'company' | 'job_seeker'>('all'); const [pathPage, setPathPage] = createSignal(0); @@ -249,6 +251,10 @@ export default function PublicLanding() { const [openFaq, setOpenFaq] = createSignal(0); onMount(() => { + const media = window.matchMedia('(prefers-reduced-motion: reduce)'); + const syncMotion = () => setReduceMotion(media.matches); + syncMotion(); + const onScroll = () => { setScrolled(window.scrollY > 10); setScrollY(window.scrollY || 0); @@ -271,6 +277,7 @@ export default function PublicLanding() { syncCardsPerPage(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', syncCardsPerPage); + media.addEventListener('change', syncMotion); const heroTimer = window.setInterval(() => setHeroIdx((x) => (x + 1) % heroSlides.length), 3500); const pathTimer = window.setInterval(() => setPathPage((x) => x + 1), 4200); @@ -288,6 +295,7 @@ export default function PublicLanding() { onCleanup(() => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', syncCardsPerPage); + media.removeEventListener('change', syncMotion); window.clearInterval(heroTimer); window.clearInterval(pathTimer); window.clearInterval(benefitTimer); @@ -377,7 +385,17 @@ export default function PublicLanding() { -
+
{ + 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 })} + >

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

@@ -389,7 +407,14 @@ export default function PublicLanding() { Apply for Jobs
-
+
{(slide, idx) => (