@@ -5,6 +5,7 @@ const i18n = useI18n();
55
66const SPEED = 20 ;
77const GAP = 8 ;
8+ const COPIES = 2 ;
89const STOP_EASE = 0.28 ;
910const RESUME_EASE = 0.22 ;
1011const GLIDE_EASE = 0.12 ;
@@ -14,15 +15,14 @@ const track = useTemplateRef<HTMLElement>("track");
1415const paused = ref (false );
1516let frame = 0 ;
1617let reducedMotion = false ;
17- // our own position, so the auto scroll, the arrows and the wheel all write to one value
1818let pos = 0 ;
1919let applied = 0 ;
2020let glide = 0 ;
21+ let parked = false ;
2122
2223function period() {
2324 const element = track .value ;
24- // the row is rendered twice, so one copy plus the gap that follows it is a full turn
25- return element ? (element .scrollWidth + GAP ) / 2 : 0 ;
25+ return element ? (element .scrollWidth + GAP ) / COPIES : 0 ;
2626}
2727
2828function move(amount : number ) {
@@ -52,7 +52,6 @@ function onWheel(event: WheelEvent) {
5252onMounted (() => {
5353 reducedMotion = window .matchMedia (" (prefers-reduced-motion: reduce)" ).matches ;
5454
55- // start at full speed
5655 let velocity = reducedMotion ? 0 : SPEED ;
5756 let last = performance .now ();
5857
@@ -81,8 +80,14 @@ onMounted(() => {
8180 }
8281
8382 const turn = period ();
84- if (turn > 0 ) {
85- pos = ((pos % turn ) + turn ) % turn ;
83+ // inset the wrap band from both ends, or a native swipe hits the browser's scroll clamp instead of looping
84+ const slack = (turn - GAP - element .clientWidth ) / 2 ;
85+ if (slack > 0 ) {
86+ if (! parked ) {
87+ pos = turn ;
88+ parked = true ;
89+ }
90+ pos = slack + ((((pos - slack ) % turn ) + turn ) % turn );
8691 element .scrollLeft = pos ;
8792 applied = element .scrollLeft ;
8893 }
@@ -99,8 +104,8 @@ const { data: projects } = await useAsyncData("discovery-daily", () => useIntern
99104 default : () => [] as ProjectCompact [],
100105});
101106
102- // the row is rendered twice so the scroll can wrap without a visible seam
103- const loop = computed (() => [ ... projects . value , ... projects .value ] );
107+ // the row is repeated so the scroll can wrap without a visible seam
108+ const loop = computed (() => Array . from ({ length: COPIES }, () => projects .value ). flat () );
104109 </script >
105110
106111<template >
0 commit comments