Skip to content

Commit 0d34292

Browse files
committed
Fix native left scroll on mobile
1 parent cc4c8e7 commit 0d34292

1 file changed

Lines changed: 13 additions & 8 deletions

File tree

frontend/app/components/projects/DiscoveryStrip.vue

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const i18n = useI18n();
55
66
const SPEED = 20;
77
const GAP = 8;
8+
const COPIES = 2;
89
const STOP_EASE = 0.28;
910
const RESUME_EASE = 0.22;
1011
const GLIDE_EASE = 0.12;
@@ -14,15 +15,14 @@ const track = useTemplateRef<HTMLElement>("track");
1415
const paused = ref(false);
1516
let frame = 0;
1617
let reducedMotion = false;
17-
// our own position, so the auto scroll, the arrows and the wheel all write to one value
1818
let pos = 0;
1919
let applied = 0;
2020
let glide = 0;
21+
let parked = false;
2122
2223
function 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
2828
function move(amount: number) {
@@ -52,7 +52,6 @@ function onWheel(event: WheelEvent) {
5252
onMounted(() => {
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

Comments
 (0)