diff --git a/src/pages/menu/components/CategoriesList/CategoriesList.module.css b/src/pages/menu/components/CategoriesList/CategoriesList.module.css index 6eba30b..d94da31 100644 --- a/src/pages/menu/components/CategoriesList/CategoriesList.module.css +++ b/src/pages/menu/components/CategoriesList/CategoriesList.module.css @@ -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 */ diff --git a/src/pages/menu/components/CategoriesList/CategoriesList.tsx b/src/pages/menu/components/CategoriesList/CategoriesList.tsx index 7ddf640..8368ba7 100644 --- a/src/pages/menu/components/CategoriesList/CategoriesList.tsx +++ b/src/pages/menu/components/CategoriesList/CategoriesList.tsx @@ -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"; @@ -25,6 +25,11 @@ export function CategoriesList({ categories }: CategoriesListProps) { setActiveCategory, } = 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) { @@ -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 ( <>