mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
allow swiping on the the grid carousel title area (#1521)
This commit is contained in:
@@ -205,11 +205,69 @@ function BaseGridCarousel(props: GridCarouselProps) {
|
||||
],
|
||||
);
|
||||
|
||||
const swipeCooldownRef = useRef(0);
|
||||
const dragStartTargetRef = useRef<HTMLElement | null>(null);
|
||||
const swipeCooldownMs = 300;
|
||||
const swipeThreshold = 50;
|
||||
const swipeVelocityThreshold = 500;
|
||||
|
||||
const handleDragStart = useCallback((event: MouseEvent | PointerEvent | TouchEvent) => {
|
||||
dragStartTargetRef.current = (event.target as HTMLElement) || null;
|
||||
}, []);
|
||||
|
||||
const handleDragEnd = useCallback(
|
||||
(
|
||||
_event: MouseEvent | PointerEvent | TouchEvent,
|
||||
info: { offset: { x: number }; velocity: { x: number } },
|
||||
) => {
|
||||
const startTarget = dragStartTargetRef.current;
|
||||
if (startTarget) {
|
||||
if (startTarget.closest('button, a, input, select, textarea, [role="button"]')) {
|
||||
dragStartTargetRef.current = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const elapsed = now - swipeCooldownRef.current;
|
||||
|
||||
if (elapsed < swipeCooldownMs) {
|
||||
dragStartTargetRef.current = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const { offset, velocity } = info;
|
||||
const absOffset = Math.abs(offset.x);
|
||||
const absVelocity = Math.abs(velocity.x);
|
||||
|
||||
if (absOffset > swipeThreshold || absVelocity > swipeVelocityThreshold) {
|
||||
swipeCooldownRef.current = now;
|
||||
|
||||
if (offset.x > 0 && !isPrevDisabled) {
|
||||
handlePrevPage();
|
||||
} else if (offset.x < 0 && !isNextDisabled) {
|
||||
handleNextPage();
|
||||
}
|
||||
}
|
||||
|
||||
dragStartTargetRef.current = null;
|
||||
},
|
||||
[handleNextPage, handlePrevPage, isNextDisabled, isPrevDisabled],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.gridCarousel} ref={ref}>
|
||||
{cq.isCalculated && (
|
||||
<>
|
||||
<div className={styles.navigation}>
|
||||
<motion.div
|
||||
className={styles.navigation}
|
||||
drag="x"
|
||||
dragConstraints={{ left: 0, right: 0 }}
|
||||
dragElastic={0}
|
||||
dragMomentum={false}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragStart={handleDragStart}
|
||||
>
|
||||
{typeof title === 'string' ? (
|
||||
<Group gap="xs" justify="space-between" w="100%">
|
||||
<Group gap="xs">
|
||||
@@ -269,7 +327,7 @@ function BaseGridCarousel(props: GridCarouselProps) {
|
||||
</Group>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
<AnimatePresence custom={currentPage} initial={false} mode="wait">
|
||||
<motion.div
|
||||
animate="animate"
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
touch-action: pan-x;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.navigation:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.custom-title-container {
|
||||
@@ -32,6 +39,13 @@
|
||||
grid-template-columns: repeat(var(--cards-to-show, 2), minmax(0, 1fr));
|
||||
gap: var(--theme-spacing-md);
|
||||
overflow: hidden;
|
||||
touch-action: pan-x;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.grid:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.page-indicator {
|
||||
|
||||
Reference in New Issue
Block a user