add: menu filter modal

This commit is contained in:
Mahyar Khanbolooki
2025-07-09 00:34:17 +03:30
parent 82cdaffe6d
commit 7207e92e38
4 changed files with 88 additions and 7 deletions
+38 -1
View File
@@ -11,6 +11,10 @@ import VerticalScrollView from "@/components/listview/VerticalScrollView";
import MenuItemRenderer from "@/components/listview/MenuItemRenderer"; import MenuItemRenderer from "@/components/listview/MenuItemRenderer";
import React from "react"; import React from "react";
import MenuItem from "@/components/listview/MenuItem"; import MenuItem from "@/components/listview/MenuItem";
import BlurredOverlayContainer from "@/components/overlays/BlurredOverlayContainer";
import CloseIcon from "@/components/icons/CloseIcon";
import clsx from "clsx";
import Button from "@/components/button/PrimaryButton";
const categories = new Array(13).fill({ title: "خوراک", icon: "" }); const categories = new Array(13).fill({ title: "خوراک", icon: "" });
@@ -118,6 +122,7 @@ const foods = [
const MenuIndex = () => { const MenuIndex = () => {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [selectedCategory, setSelectedCategory] = useState(0); const [selectedCategory, setSelectedCategory] = useState(0);
const [filterModal, setFilterModal] = useState(false);
const updateSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => { const updateSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value); setSearch(e.target.value);
@@ -127,6 +132,11 @@ const MenuIndex = () => {
setSelectedCategory(id); setSelectedCategory(id);
}, []); }, []);
const toggleFilterModal = useCallback(() => {
setFilterModal((state) => !state);
}, []);
const filteredReceiptItems = useMemo(() => { const filteredReceiptItems = useMemo(() => {
const lowerSearch = search.toLowerCase(); const lowerSearch = search.toLowerCase();
return foods.filter( return foods.filter(
@@ -136,6 +146,7 @@ const MenuIndex = () => {
); );
}, [selectedCategory, search]); }, [selectedCategory, search]);
return ( return (
<div className="flex flex-col gap-4 pt-4 items-center"> <div className="flex flex-col gap-4 pt-4 items-center">
<SearchBox value={search} onChange={updateSearch} /> <SearchBox value={search} onChange={updateSearch} />
@@ -164,7 +175,7 @@ const MenuIndex = () => {
{categories[selectedCategory]?.title} {categories[selectedCategory]?.title}
</span> </span>
<div className="inline-flex gap-2 justify-around items-center"> <div className="inline-flex gap-2 justify-around items-center">
<button className="rounded-xl h-8 bg-white ps-4 pe-2 py-1.5 inline-flex items-center justify-between gap-[7px]"> <button onClick={toggleFilterModal} className="rounded-xl h-8 bg-white ps-4 pe-2 py-1.5 inline-flex items-center justify-between gap-[7px]">
<EqualizerIcon /> <EqualizerIcon />
<span className="text-xs leading-5">فیلتر بر اساس</span> <span className="text-xs leading-5">فیلتر بر اساس</span>
</button> </button>
@@ -182,6 +193,32 @@ const MenuIndex = () => {
))} ))}
</VerticalScrollView> </VerticalScrollView>
</section> </section>
<BlurredOverlayContainer visible={filterModal} changeDelay="150" onClick={toggleFilterModal}>
<div
data-visible={filterModal}
className={clsx(
'absolute -bottom-full left-0 w-full bg-white/64 rounded-t-4xl pt-10 pb-6',
'data-[visible=true]:bottom-0 transition-all duration-150'
)}>
<div className="px-8 flex justify-between">
<div>فیلتر ها</div>
<div onClick={toggleFilterModal} className="bg-white/38 w-8 h-8 rounded-full p-1.5">
<CloseIcon size={20} />
</div>
</div>
<hr className="text-white/40 mb-7 mt-12" />
<div className="px-9 flex justify-between gap-[22px]">
<div className="w-full">
<Button>اعمال فیلتر</Button>
</div>
<div className="w-full">
<Button className="bg-disabled! text-disabled-text!">حذف فیلتر</Button>
</div>
</div>
</div>
</BlurredOverlayContainer>
</div> </div>
); );
}; };
+43
View File
@@ -0,0 +1,43 @@
import React from 'react';
interface CloseIconProps {
className?: string;
stroke?: string;
strokeWidth?: number;
size?: number;
}
const CloseIcon: React.FC<CloseIconProps> = ({
className = '',
stroke = '#8C90A3',
strokeWidth = 1.5,
size = 20,
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
className={className}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 15L15 5"
stroke={stroke}
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15 15L5 5"
stroke={stroke}
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
};
export default CloseIcon;
+1 -2
View File
@@ -76,8 +76,7 @@ function Menu({ menuState, toggleMenuState, nightModeState, togglenightModeState
return ( return (
<div className='w-full h-dvh'> <div className='w-full h-dvh'>
<BlurredOverlayContainer bgOpacity='40' visible={menuStateMemo} changeDelay='300'> <BlurredOverlayContainer bgOpacity='40' visible={menuStateMemo} onClick={toggleMenuState} changeDelay='300'>
<div className='w-full h-dvh overflow-hidden' onClick={toggleMenuState}></div>
<div <div
data-isvisible={menuStateMemo} data-isvisible={menuStateMemo}
onClick={(e) => { e.stopPropagation(); }} onClick={(e) => { e.stopPropagation(); }}
@@ -7,7 +7,7 @@ type Props = {
bgOpacity?: string bgOpacity?: string
changeDelay?: string changeDelay?: string
effectdelay?: string effectdelay?: string
} & React.DetailedHTMLProps<React.HTMLAttributes<HTMLButtonElement>, HTMLButtonElement> } & React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
const BlurredOverlayContainer = ({ const BlurredOverlayContainer = ({
visible = true, visible = true,
@@ -15,6 +15,7 @@ const BlurredOverlayContainer = ({
changeDelay = '0', changeDelay = '0',
effectdelay = '0', effectdelay = '0',
children, children,
onClick,
...props ...props
}: Props) => { }: Props) => {
const [loaded, setLoaded] = useState(visible) const [loaded, setLoaded] = useState(visible)
@@ -35,11 +36,11 @@ const BlurredOverlayContainer = ({
visible || loaded ? 'z-50' : !visible && !loaded ? '-z-50' : 'z-0' visible || loaded ? 'z-50' : !visible && !loaded ? '-z-50' : 'z-0'
return ( return (
<button <div
data-visible={visible} data-visible={visible}
data-loaded={loaded} data-loaded={loaded}
className={props.className + ` className={props.className + `
absolute inset-0 flex items-center justify-center h-dvh w-full fixed inset-0 flex items-center justify-center h-dvh w-full
backdrop-blur-sm backdrop-blur-sm
opacity-0 transition-opacity duration-300 ease-in-out delay-${effectdelay} opacity-0 transition-opacity duration-300 ease-in-out delay-${effectdelay}
${zClass} ${zClass}
@@ -47,8 +48,9 @@ const BlurredOverlayContainer = ({
style={{ backgroundColor: `rgba(0, 0, 0, ${+bgOpacity / 100})` }} style={{ backgroundColor: `rgba(0, 0, 0, ${+bgOpacity / 100})` }}
{...props} {...props}
> >
<div className='w-full h-dvh overflow-hidden' onClick={onClick}></div>
{children} {children}
</button> </div>
) )
} }