expertise : fix active text centering - related to #52
All checks were successful
Deploy / Deploy to Production (push) Successful in 28s

This commit is contained in:
isUnknown 2026-04-03 10:54:40 +02:00
parent 6e0b0bd551
commit 4b946d4cf0
2 changed files with 34 additions and 5 deletions

View file

@ -111,6 +111,11 @@
z-index: 2;
transition: transform .3s var(--ease-standard);
pointer-events: none;
}
footer p, footer, a {
pointer-events: all;
}
:global(footer:not([data-template="white-paper"] footer)) {

View file

@ -6,14 +6,17 @@
let { data } = $props()
// --- DOM refs ---
let videoFwd = $state(null)
let videoRev = $state(null)
let sectionEl = $state(null)
let videoFwd = $state(null)
let videoRev = $state(null)
let sectionEl = $state(null)
let textContainer = $state(null)
let itemEls = $state([])
// --- State ---
let isReverse = $state(false)
let duration = $state(0)
let currentItem = $state(0)
let offsetY = $state(0)
// --- Non-reactive ---
let playhead = 0 // forward-equivalent position, updated from timeupdate
@ -39,6 +42,14 @@
}
})
function computeOffset() {
if (!textContainer || !itemEls[currentItem]) return
const wh = window.innerHeight
const wrapperRect = textContainer.parentElement.getBoundingClientRect()
const el = itemEls[currentItem]
offsetY = wh / 2 - wrapperRect.top - el.offsetTop - el.offsetHeight / 2
}
function initVideo() {
if (!videoFwd) return
const start = () => {
@ -47,6 +58,7 @@
playhead = 0
isReverse = false
if (videoRev) videoRev.currentTime = duration
requestAnimationFrame(() => computeOffset())
// Force first-frame decode (required on mobile Safari)
videoFwd.play().then(() => videoFwd.pause()).catch(() => {})
}
@ -61,6 +73,7 @@
playhead = 0
isReverse = false
currentItem = 0
offsetY = 0
if (videoFwd) { videoFwd.pause(); videoFwd.currentTime = 0 }
if (videoRev) { videoRev.pause() }
}
@ -126,6 +139,7 @@
clearTimeout(lockTimer)
lockTimer = setTimeout(() => { canScroll = true }, 650)
requestAnimationFrame(() => { if (isActive) computeOffset() })
dir === 'down' ? playForward() : playReverse()
}
@ -174,12 +188,17 @@
if (e.key === 'ArrowDown') { e.preventDefault(); navigate('down') }
if (e.key === 'ArrowUp') { e.preventDefault(); navigate('up') }
}
const onResize = () => { if (isActive) computeOffset() }
window.addEventListener('resize', onResize)
window.addEventListener('orientationchange', onResize)
window.addEventListener('keydown', onKeyDown)
return () => {
sectionEl?.removeEventListener('wheel', onWheel)
sectionEl?.removeEventListener('touchstart', onTouchStart)
sectionEl?.removeEventListener('touchend', onTouchEnd)
window.removeEventListener('resize', onResize)
window.removeEventListener('orientationchange', onResize)
window.removeEventListener('keydown', onKeyDown)
videoFwd?.removeEventListener('timeupdate', onFwdTime)
videoRev?.removeEventListener('timeupdate', onRevTime)
@ -224,9 +243,13 @@
<!-- Text items -->
<div class="expertise-text-wrapper" aria-live="polite" aria-atomic="true">
<div class="expertise-text">
<div
class="expertise-text"
bind:this={textContainer}
style="transform: translateY({offsetY}px)"
>
{#each items as item, i}
<div class="expertise-item" class:active={i === currentItem}>
<div class="expertise-item" class:active={i === currentItem} bind:this={itemEls[i]}>
{@html item.text}
</div>
{/each}
@ -287,6 +310,7 @@
.expertise-text {
position: relative;
width: 100%;
transition: transform 0.6s var(--ease-standard);
}
.expertise-item {