CategoriesList: apply draggable effects

This commit is contained in:
2025-10-11 20:51:21 +03:00
parent 563d44d0ca
commit 1cc254063d
3 changed files with 97 additions and 7 deletions

View File

@@ -120,6 +120,25 @@
gap: 0.5rem;
padding: 0.5rem 1rem 1rem 1rem;
margin-bottom: 0.5rem;
cursor: grab;
user-select: none;
}
.categoriesContainer:active {
cursor: grabbing;
}
.categoriesContainer::-webkit-scrollbar {
display: none;
}
/* Smooth scrolling for drag interactions */
.categoriesContainer.dragging {
scroll-behavior: auto;
}
.categoriesContainer.dragging * {
pointer-events: none;
}
/* Enhanced responsive categories container */

View File

@@ -2,7 +2,7 @@ import { Card, Grid, Space } from "antd";
import ImageWithFallback from "components/ImageWithFallback";
import ProText from "components/ProText";
import { useScrollHandler } from "contexts/ScrollHandlerContext";
import { useCallback, useEffect } from "react";
import { useCallback, useEffect, useRef } from "react";
import { useAppSelector } from "redux/hooks";
import { colors } from "ThemeConstants";
import { default_image } from "utils/constants";
@@ -26,6 +26,11 @@ export function CategoriesList({ categories }: CategoriesListProps) {
} = useScrollHandler();
const { isRTL } = useAppSelector((state) => state.locale);
// Drag scroll functionality
const isDragging = useRef(false);
const startX = useRef(0);
const scrollLeft = useRef(0);
const getCategoryCardStyle = useCallback(() => {
if (xs) {
return {
@@ -55,11 +60,11 @@ export function CategoriesList({ categories }: CategoriesListProps) {
// Function to scroll category card into view when active category changes automatically
const scrollCategoryCardIntoView = useCallback((categoryId: number) => {
const categoryCard = document.querySelector(
`[data-category-id="${categoryId}"]`
`[data-category-id="${categoryId}"]`,
);
if (categoryCard) {
const categoriesContainer = categoryCard.closest(
`.${styles.categoriesContainer}`
`.${styles.categoriesContainer}`,
);
if (categoriesContainer) {
const cardElement = categoryCard as HTMLElement;
@@ -93,6 +98,60 @@ export function CategoriesList({ categories }: CategoriesListProps) {
}
}, [activeCategory, scrollCategoryCardIntoView]);
// Drag scroll event handlers
const handleMouseDown = useCallback((e: React.MouseEvent) => {
const container = categoriesContainerRef?.current;
if (!container) return;
isDragging.current = true;
startX.current = e.pageX - container.offsetLeft;
scrollLeft.current = container.scrollLeft;
// Prevent text selection during drag
e.preventDefault();
}, [categoriesContainerRef]);
const handleMouseMove = useCallback((e: React.MouseEvent) => {
const container = categoriesContainerRef?.current;
if (!container || !isDragging.current) return;
e.preventDefault();
const x = e.pageX - container.offsetLeft;
const walk = (x - startX.current) * 2; // Multiply for faster scrolling
container.scrollLeft = scrollLeft.current - walk;
}, [categoriesContainerRef]);
const handleMouseUp = useCallback(() => {
isDragging.current = false;
}, []);
const handleMouseLeave = useCallback(() => {
isDragging.current = false;
}, []);
// Touch event handlers for mobile
const handleTouchStart = useCallback((e: React.TouchEvent) => {
const container = categoriesContainerRef?.current;
if (!container) return;
isDragging.current = true;
startX.current = e.touches[0].pageX - container.offsetLeft;
scrollLeft.current = container.scrollLeft;
}, [categoriesContainerRef]);
const handleTouchMove = useCallback((e: React.TouchEvent) => {
const container = categoriesContainerRef?.current;
if (!container || !isDragging.current) return;
const x = e.touches[0].pageX - container.offsetLeft;
const walk = (x - startX.current) * 2;
container.scrollLeft = scrollLeft.current - walk;
}, [categoriesContainerRef]);
const handleTouchEnd = useCallback(() => {
isDragging.current = false;
}, []);
return (
<>
<div
@@ -101,12 +160,24 @@ export function CategoriesList({ categories }: CategoriesListProps) {
isCategoriesSticky ? styles.categoriesSticky : ""
}`}
style={!isCategoriesSticky ? { paddingTop: "1rem" } : {}}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseLeave}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
>
{categories?.map((category) => (
<div key={category.id}>
<Card
key={category.id}
onClick={() => {
onClick={(e) => {
// Prevent click if we were dragging
if (isDragging.current) {
e.preventDefault();
return;
}
scrollToCategory(category.id);
}}
data-category-id={category.id}

View File

@@ -56,7 +56,7 @@ function MenuPage() {
orderType={orderType || ""}
/>
{!isLoading ? (
{isLoading ? (
<MenuSkeleton categoryCount={10} itemCount={30} variant="default" />
) : (
<div className={styles.menuContainer}>