CategoriesList: apply draggable effects
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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}
|
||||
@@ -146,8 +217,8 @@ export function CategoriesList({ categories }: CategoriesListProps) {
|
||||
xs
|
||||
? styles.categoryMenuItemImageMobile
|
||||
: md
|
||||
? styles.categoryMenuItemImageTablet
|
||||
: styles.categoryMenuItemImageDesktop
|
||||
? styles.categoryMenuItemImageTablet
|
||||
: styles.categoryMenuItemImageDesktop
|
||||
}`}
|
||||
// {...getCategoryImageStyle()}
|
||||
width={105}
|
||||
|
||||
@@ -56,7 +56,7 @@ function MenuPage() {
|
||||
orderType={orderType || ""}
|
||||
/>
|
||||
|
||||
{!isLoading ? (
|
||||
{isLoading ? (
|
||||
<MenuSkeleton categoryCount={10} itemCount={30} variant="default" />
|
||||
) : (
|
||||
<div className={styles.menuContainer}>
|
||||
|
||||
Reference in New Issue
Block a user