Improve day swipe and sleep handling

This commit is contained in:
2026-05-21 13:00:10 +02:00
parent 2047cae61c
commit a087eb508b
5 changed files with 206 additions and 53 deletions
+69 -12
View File
@@ -1223,7 +1223,7 @@
valueInput.placeholder = config.placeholder;
valueInput.required = !!config.showValue;
valueInput.value = config.showValue ? valueInput.value : "";
valueInput.step = type === "sleep" ? "0.25" : "1";
valueInput.step = type === "sleep" ? "0.01" : "1";
}
if (unitInput) {
unitInput.value = config.unit;
@@ -1454,11 +1454,61 @@
let dragging = false;
let didSwipe = false;
let activePointerId = null;
let currentOffset = 0;
let targetOffset = 0;
let animationFrame = null;
const prefetchedDays = new Set();
const setSlideProgress = offset => {
const progress = Math.min(1, Math.abs(offset) / 120);
daySlider.style.setProperty("--day-slider-offset", `${offset.toFixed(1)}px`);
daySlider.style.setProperty("--day-slider-scale", (1 - (progress * 0.025)).toFixed(3));
swipeContainer.style.setProperty("--day-prev-hint", offset > 0 ? progress.toFixed(3) : "0");
swipeContainer.style.setProperty("--day-next-hint", offset < 0 ? progress.toFixed(3) : "0");
};
const animateSlide = () => {
currentOffset += (targetOffset - currentOffset) * 0.34;
if (Math.abs(targetOffset - currentOffset) < 0.4) {
currentOffset = targetOffset;
}
setSlideProgress(currentOffset);
if (currentOffset !== targetOffset) {
animationFrame = window.requestAnimationFrame(animateSlide);
} else {
animationFrame = null;
}
};
const setTargetOffset = offset => {
targetOffset = offset;
if (animationFrame === null) {
animationFrame = window.requestAnimationFrame(animateSlide);
}
};
const preloadDay = date => {
if (!date || prefetchedDays.has(date)) {
return;
}
prefetchedDays.add(date);
window.fetch(dashboardDayPath(date), {
credentials: "same-origin",
cache: "force-cache",
priority: "low"
}).catch(() => {});
};
preloadDay(swipeContainer.dataset.prevDate);
preloadDay(swipeContainer.dataset.nextDate);
const resetStrip = () => {
dayStrip.classList.remove("is-dragging");
daySlider.classList.remove("is-dragging");
daySlider.style.setProperty("--day-slider-offset", "0px");
setTargetOffset(0);
};
const handleSwipe = (deltaX, deltaY) => {
@@ -1469,18 +1519,18 @@
if (deltaX < 0 && swipeContainer.dataset.nextDate) {
didSwipe = true;
daySlider.style.setProperty("--day-slider-offset", "-120%");
setSlideProgress(-window.innerWidth);
window.location.href = dashboardDayPath(swipeContainer.dataset.nextDate);
} else if (deltaX > 0 && swipeContainer.dataset.prevDate) {
didSwipe = true;
daySlider.style.setProperty("--day-slider-offset", "120%");
setSlideProgress(window.innerWidth);
window.location.href = dashboardDayPath(swipeContainer.dataset.prevDate);
} else {
resetStrip();
}
};
dayStrip.addEventListener("pointerdown", event => {
daySlider.addEventListener("pointerdown", event => {
if (event.target.closest("input, textarea, select, label, [data-stepper], .dashboard-overlay")) {
dragging = false;
return;
@@ -1493,10 +1543,10 @@
pointerStartY = event.clientY;
dayStrip.classList.add("is-dragging");
daySlider.classList.add("is-dragging");
dayStrip.setPointerCapture?.(event.pointerId);
daySlider.setPointerCapture?.(event.pointerId);
});
dayStrip.addEventListener("pointermove", event => {
daySlider.addEventListener("pointermove", event => {
if (!dragging || (activePointerId !== null && event.pointerId !== activePointerId)) {
return;
}
@@ -1510,10 +1560,17 @@
return;
}
daySlider.style.setProperty("--day-slider-offset", `${Math.max(-120, Math.min(120, deltaX))}px`);
const dampedOffset = Math.sign(deltaX) * Math.min(148, Math.pow(Math.abs(deltaX), 0.88) * 1.6);
setTargetOffset(dampedOffset);
if (deltaX < -32) {
preloadDay(swipeContainer.dataset.nextDate);
} else if (deltaX > 32) {
preloadDay(swipeContainer.dataset.prevDate);
}
});
dayStrip.addEventListener("pointerup", event => {
daySlider.addEventListener("pointerup", event => {
if (!dragging) {
return;
}
@@ -1523,13 +1580,13 @@
handleSwipe(event.clientX - pointerStartX, event.clientY - pointerStartY);
});
dayStrip.addEventListener("pointercancel", () => {
daySlider.addEventListener("pointercancel", () => {
dragging = false;
activePointerId = null;
resetStrip();
});
dayStrip.addEventListener("lostpointercapture", () => {
daySlider.addEventListener("lostpointercapture", () => {
if (!dragging) {
return;
}
@@ -1539,7 +1596,7 @@
resetStrip();
});
dayStrip.addEventListener("click", event => {
daySlider.addEventListener("click", event => {
if (!didSwipe) {
return;
}