CategoriesList: apply draggable effects
This commit is contained in:
@@ -120,6 +120,25 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.5rem 1rem 1rem 1rem;
|
padding: 0.5rem 1rem 1rem 1rem;
|
||||||
margin-bottom: 0.5rem;
|
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 */
|
/* Enhanced responsive categories container */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Card, Grid, Space } from "antd";
|
|||||||
import ImageWithFallback from "components/ImageWithFallback";
|
import ImageWithFallback from "components/ImageWithFallback";
|
||||||
import ProText from "components/ProText";
|
import ProText from "components/ProText";
|
||||||
import { useScrollHandler } from "contexts/ScrollHandlerContext";
|
import { useScrollHandler } from "contexts/ScrollHandlerContext";
|
||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
import { useAppSelector } from "redux/hooks";
|
import { useAppSelector } from "redux/hooks";
|
||||||
import { colors } from "ThemeConstants";
|
import { colors } from "ThemeConstants";
|
||||||
import { default_image } from "utils/constants";
|
import { default_image } from "utils/constants";
|
||||||
@@ -25,6 +25,11 @@ export function CategoriesList({ categories }: CategoriesListProps) {
|
|||||||
setActiveCategory,
|
setActiveCategory,
|
||||||
} = useScrollHandler();
|
} = useScrollHandler();
|
||||||
const { isRTL } = useAppSelector((state) => state.locale);
|
const { isRTL } = useAppSelector((state) => state.locale);
|
||||||
|
|
||||||
|
// Drag scroll functionality
|
||||||
|
const isDragging = useRef(false);
|
||||||
|
const startX = useRef(0);
|
||||||
|
const scrollLeft = useRef(0);
|
||||||
|
|
||||||
const getCategoryCardStyle = useCallback(() => {
|
const getCategoryCardStyle = useCallback(() => {
|
||||||
if (xs) {
|
if (xs) {
|
||||||
@@ -55,11 +60,11 @@ export function CategoriesList({ categories }: CategoriesListProps) {
|
|||||||
// Function to scroll category card into view when active category changes automatically
|
// Function to scroll category card into view when active category changes automatically
|
||||||
const scrollCategoryCardIntoView = useCallback((categoryId: number) => {
|
const scrollCategoryCardIntoView = useCallback((categoryId: number) => {
|
||||||
const categoryCard = document.querySelector(
|
const categoryCard = document.querySelector(
|
||||||
`[data-category-id="${categoryId}"]`
|
`[data-category-id="${categoryId}"]`,
|
||||||
);
|
);
|
||||||
if (categoryCard) {
|
if (categoryCard) {
|
||||||
const categoriesContainer = categoryCard.closest(
|
const categoriesContainer = categoryCard.closest(
|
||||||
`.${styles.categoriesContainer}`
|
`.${styles.categoriesContainer}`,
|
||||||
);
|
);
|
||||||
if (categoriesContainer) {
|
if (categoriesContainer) {
|
||||||
const cardElement = categoryCard as HTMLElement;
|
const cardElement = categoryCard as HTMLElement;
|
||||||
@@ -93,6 +98,60 @@ export function CategoriesList({ categories }: CategoriesListProps) {
|
|||||||
}
|
}
|
||||||
}, [activeCategory, scrollCategoryCardIntoView]);
|
}, [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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@@ -101,12 +160,24 @@ export function CategoriesList({ categories }: CategoriesListProps) {
|
|||||||
isCategoriesSticky ? styles.categoriesSticky : ""
|
isCategoriesSticky ? styles.categoriesSticky : ""
|
||||||
}`}
|
}`}
|
||||||
style={!isCategoriesSticky ? { paddingTop: "1rem" } : {}}
|
style={!isCategoriesSticky ? { paddingTop: "1rem" } : {}}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
onMouseMove={handleMouseMove}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
onMouseLeave={handleMouseLeave}
|
||||||
|
onTouchStart={handleTouchStart}
|
||||||
|
onTouchMove={handleTouchMove}
|
||||||
|
onTouchEnd={handleTouchEnd}
|
||||||
>
|
>
|
||||||
{categories?.map((category) => (
|
{categories?.map((category) => (
|
||||||
<div key={category.id}>
|
<div key={category.id}>
|
||||||
<Card
|
<Card
|
||||||
key={category.id}
|
key={category.id}
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
|
// Prevent click if we were dragging
|
||||||
|
if (isDragging.current) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
scrollToCategory(category.id);
|
scrollToCategory(category.id);
|
||||||
}}
|
}}
|
||||||
data-category-id={category.id}
|
data-category-id={category.id}
|
||||||
@@ -146,8 +217,8 @@ export function CategoriesList({ categories }: CategoriesListProps) {
|
|||||||
xs
|
xs
|
||||||
? styles.categoryMenuItemImageMobile
|
? styles.categoryMenuItemImageMobile
|
||||||
: md
|
: md
|
||||||
? styles.categoryMenuItemImageTablet
|
? styles.categoryMenuItemImageTablet
|
||||||
: styles.categoryMenuItemImageDesktop
|
: styles.categoryMenuItemImageDesktop
|
||||||
}`}
|
}`}
|
||||||
// {...getCategoryImageStyle()}
|
// {...getCategoryImageStyle()}
|
||||||
width={105}
|
width={105}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ function MenuPage() {
|
|||||||
orderType={orderType || ""}
|
orderType={orderType || ""}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!isLoading ? (
|
{isLoading ? (
|
||||||
<MenuSkeleton categoryCount={10} itemCount={30} variant="default" />
|
<MenuSkeleton categoryCount={10} itemCount={30} variant="default" />
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.menuContainer}>
|
<div className={styles.menuContainer}>
|
||||||
|
|||||||
Reference in New Issue
Block a user