add: menu list
improve: ux
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
+156
-5
@@ -1,10 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useState } from "react";
|
import { Fragment, useCallback, useState } from "react";
|
||||||
import SearchBox from "@/components/input/SearchBox";
|
import SearchBox from "@/components/input/SearchBox";
|
||||||
import CategoryItemRenderer from "@/components/listview/CategoryItemRenderer";
|
import CategoryItemRenderer from "@/components/listview/CategoryItemRenderer";
|
||||||
import HorizontalScrollView from "@/components/listview/HorizontalScrollView";
|
import HorizontalScrollView from "@/components/listview/HorizontalScrollView";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import EqualizerIcon from "@/components/icons/EqualizerIcon";
|
||||||
|
import TextAlignIcon from "@/components/icons/TextAlignIcon";
|
||||||
|
import PlusIcon from "@/components/icons/PlusIcon";
|
||||||
|
import MinusIcon from "@/components/icons/MinusIcon";
|
||||||
|
import VerticalScrollView from "@/components/listview/VerticalScrollView";
|
||||||
|
import MenuItemRenderer from "@/components/listview/MenuItemRenderer";
|
||||||
|
|
||||||
const categories = [
|
const categories = [
|
||||||
{
|
{
|
||||||
@@ -48,6 +54,93 @@ const categories = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const foods = [
|
||||||
|
{
|
||||||
|
category: 0,
|
||||||
|
price: '69.000',
|
||||||
|
name: 'کباب چوبی ژیوان )سیخ چوبی(',
|
||||||
|
contains: 'فیله گوساله / سس سفید / قارچ و سیب زمینی/ پنیر پارمزان'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 1,
|
||||||
|
price: '49.000',
|
||||||
|
name: 'برگر گوشت گوساله',
|
||||||
|
contains: 'گوشت گوساله / پنیر چدار / کاهو / گوجه'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 2,
|
||||||
|
price: '29.000',
|
||||||
|
name: 'ساندویچ مرغ',
|
||||||
|
contains: 'مرغ / کاهو / گوجه / سس مایونز'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 0,
|
||||||
|
price: '89.000',
|
||||||
|
name: 'کباب ماهی',
|
||||||
|
contains: 'ماهی / سس لیمو / قارچ و سیب زمینی'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 1,
|
||||||
|
price: '39.000',
|
||||||
|
name: 'سالاد فصل',
|
||||||
|
contains: 'کاهو / گوجه / خیار / پنیر فتا'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 3,
|
||||||
|
price: '59.000',
|
||||||
|
name: 'پاستا گوشت',
|
||||||
|
contains: 'گوشت گوساله / پاستا / سس گوجه'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 2,
|
||||||
|
price: '49.000',
|
||||||
|
name: 'ساندویچ تن ماهی',
|
||||||
|
contains: 'تن ماهی / کاهو / گوجه / سس مایونز'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 0,
|
||||||
|
price: '79.000',
|
||||||
|
name: 'کباب گوشت گوسفندی',
|
||||||
|
contains: 'گوشت گوسفندی / سس سفید / قارچ و سیب زمینی'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 1,
|
||||||
|
price: '29.000',
|
||||||
|
name: 'برگر مرغ',
|
||||||
|
contains: 'مرغ / پنیر چدار / کاهو / گوجه'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 3,
|
||||||
|
price: '69.000',
|
||||||
|
name: 'سالاد میگو',
|
||||||
|
contains: 'میگو / کاهو / گوجه / خیار'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 2,
|
||||||
|
price: '39.000',
|
||||||
|
name: 'ساندویچ شاورما',
|
||||||
|
contains: 'مرغ / کاهو / گوجه / سس تارتار'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 0,
|
||||||
|
price: '99.000',
|
||||||
|
name: 'کباب گوشت بوقلمون',
|
||||||
|
contains: 'گوشت بوقلمون / سس سفید / قارچ و سیب زمینی'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 1,
|
||||||
|
price: '59.000',
|
||||||
|
name: 'برگر ماهی',
|
||||||
|
contains: 'ماهی / پنیر چدار / کاهو / گوجه'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: 3,
|
||||||
|
price: '49.000',
|
||||||
|
name: 'سالاد مرغ',
|
||||||
|
contains: 'مرغ / کاهو / گوجه / خیار'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function MenuIndex() {
|
export default function MenuIndex() {
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [selectedCategory, setSelectedCategory] = useState(0);
|
const [selectedCategory, setSelectedCategory] = useState(0);
|
||||||
@@ -64,24 +157,82 @@ export default function MenuIndex() {
|
|||||||
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} />
|
||||||
<HorizontalScrollView className="w-full not-sm:noscrollbar py-4!" itemRenderer={(child, index) => {
|
<HorizontalScrollView className="w-full noscrollbar py-4!" itemRenderer={(child, index) => {
|
||||||
return <CategoryItemRenderer className={`${index === selectedCategory && 'bg-white!'}`} onClick={() => updateCategory(index)} key={index}>{child}</CategoryItemRenderer>
|
return <CategoryItemRenderer className={`${index === selectedCategory && 'bg-white!'}`} onClick={() => updateCategory(index)} key={index}>{child}</CategoryItemRenderer>
|
||||||
}}>
|
}}>
|
||||||
{categories.map((item, index) => {
|
{categories.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
<Image
|
<Image
|
||||||
priority
|
priority
|
||||||
src={'/assets/images/food-image.png'}
|
src={'/assets/images/food-image.png'}
|
||||||
width={32}
|
width={32}
|
||||||
height={32}
|
height={32}
|
||||||
alt="category image"
|
alt="category image"
|
||||||
/>
|
/>
|
||||||
<span className="text-xs text-black">{item.title}</span>
|
<span className="text-xs text-black">{item.title}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<section className="w-full">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-base font-semibold">{categories[selectedCategory].title}</span>
|
||||||
|
<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]">
|
||||||
|
<EqualizerIcon />
|
||||||
|
<span className="text-xs leading-5">فیلتر بر اساس</span>
|
||||||
|
</button>
|
||||||
|
<button className="rounded-lg h-8 bg-white p-1.5">
|
||||||
|
<TextAlignIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<VerticalScrollView
|
||||||
|
className="mt-5! overflow-y-auto h-full"
|
||||||
|
itemRenderer={(child, index) => {
|
||||||
|
return (
|
||||||
|
<MenuItemRenderer key={index}>{child}</MenuItemRenderer>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{foods.map((food, index) => {
|
||||||
|
return (
|
||||||
|
<Fragment key={index}>
|
||||||
|
<Image
|
||||||
|
className="rounded-xl w-28 h-28"
|
||||||
|
src={'/assets/images/food-preview.png'}
|
||||||
|
height={100}
|
||||||
|
width={100}
|
||||||
|
alt="Food image"
|
||||||
|
/>
|
||||||
|
<div className="w-full h-full inline-flex flex-col justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm2 font-semibold">{food.name}</div>
|
||||||
|
<div className="text-[#7F7F7F] text-xs leading-5 font-normal mt-2">{food.contains}</div>
|
||||||
|
</div>
|
||||||
|
<div className="inline-flex justify-between w-full items-end">
|
||||||
|
<span className="w-full" dir="ltr">{food.price} T</span>
|
||||||
|
<div className="bg-background max-w-[115px] rounded-lg w-full h-8 inline-flex py-1 px-[5px] justify-between items-center gap-2">
|
||||||
|
{/* <PlusIcon />
|
||||||
|
<div className="text-sm2 pt-0.5 font-semibold" style={{verticalAlign: 'end'}}>افزودن</div> */}
|
||||||
|
|
||||||
|
<PlusIcon className="bg-white rounded-sm p-2" size={26} />
|
||||||
|
<div className="text-sm2 pt-0.5 font-semibold" style={{ verticalAlign: 'end' }}>2</div>
|
||||||
|
<MinusIcon className="bg-white rounded-sm p-2" size={26} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
</VerticalScrollView>
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface EqualizerIconProps {
|
||||||
|
className?: string;
|
||||||
|
stroke?: string;
|
||||||
|
strokeWidth?: number;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EqualizerIcon: React.FC<EqualizerIconProps> = ({
|
||||||
|
className = '',
|
||||||
|
stroke = '#333333',
|
||||||
|
strokeWidth = 1.5,
|
||||||
|
size = 16,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
className={className}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M14.6667 11.666H10"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3.3335 11.666H1.3335"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14.6665 4.33398H12.6665"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.00016 4.33398H1.3335"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.66683 9.66602H8.66683C9.40016 9.66602 10.0002 9.99935 10.0002 10.9993V12.3327C10.0002 13.3327 9.40016 13.666 8.66683 13.666H4.66683C3.9335 13.666 3.3335 13.3327 3.3335 12.3327V10.9993C3.3335 9.99935 3.9335 9.66602 4.66683 9.66602Z"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.33333 2.33398H11.3333C12.0667 2.33398 12.6667 2.66732 12.6667 3.66732V5.00065C12.6667 6.00065 12.0667 6.33398 11.3333 6.33398H7.33333C6.6 6.33398 6 6.00065 6 5.00065V3.66732C6 2.66732 6.6 2.33398 7.33333 2.33398Z"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EqualizerIcon;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface MinusIconProps {
|
||||||
|
className?: string;
|
||||||
|
stroke?: string;
|
||||||
|
strokeWidth?: number;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MinusIcon: React.FC<MinusIconProps> = ({
|
||||||
|
className = '',
|
||||||
|
stroke = '#333333',
|
||||||
|
strokeWidth = 1.5,
|
||||||
|
size = 10,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 10 2"
|
||||||
|
fill="none"
|
||||||
|
className={className}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M9.23145 1L1.23145 0.999999"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MinusIcon;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface PlusIconProps {
|
||||||
|
className?: string;
|
||||||
|
stroke?: string;
|
||||||
|
strokeWidth?: number;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlusIcon: React.FC<PlusIconProps> = ({
|
||||||
|
className = '',
|
||||||
|
stroke = '#333333',
|
||||||
|
strokeWidth = 1.5,
|
||||||
|
size = 10,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 10 10"
|
||||||
|
fill="none"
|
||||||
|
className={className}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5 1L5 9"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9 5L1 5"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlusIcon;
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface TextAlignIconProps {
|
||||||
|
className?: string;
|
||||||
|
stroke?: string;
|
||||||
|
strokeWidth?: number;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextAlignIcon: React.FC<TextAlignIconProps> = ({
|
||||||
|
className = '',
|
||||||
|
stroke = '#333333',
|
||||||
|
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="M10 14.1672L1.66667 14.1672"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10 10H1.66667"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10 5.83374H1.66667"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M18.3335 10.8335L15.8335 14.1668L13.3335 10.8335"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M15.8335 5.8335L15.8335 14.1668"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TextAlignIcon;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
} & React.HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
function MenuItemRenderer({ children, ...rest }: Props) {
|
||||||
|
return (
|
||||||
|
<div {...rest} className={`${rest.className} transition-all duration-200 ease-out w-full h-36 bg-white rounded-3xl px-4 pt-3.5 pb-3 flex justify-between gap-4`}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MenuItemRenderer;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React, { ReactElement, ReactNode } from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
itemRenderer?: (child: ReactNode, index: number) => ReactElement;
|
||||||
|
children: ReactNode;
|
||||||
|
} & React.OlHTMLAttributes<HTMLUListElement>;
|
||||||
|
|
||||||
|
function VerticalScrollView({ itemRenderer, children, ...restProps }: Props) {
|
||||||
|
const items = React.Children.toArray(children);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul
|
||||||
|
{...restProps}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflowY: 'auto',
|
||||||
|
gap: '16px',
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
listStyle: 'none',
|
||||||
|
...restProps.style,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{items.map((child, index) => (
|
||||||
|
<li key={index} style={{ flex: '0 0 auto' }}>
|
||||||
|
{itemRenderer ? itemRenderer(child, index) : child}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VerticalScrollView;
|
||||||
@@ -75,32 +75,34 @@ function Menu({ menuState, toggleMenuState, nightModeState, togglenightModeState
|
|||||||
const menuStateMemo = useMemo(() => menuState, [menuState]);
|
const menuStateMemo = useMemo(() => menuState, [menuState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BlurredOverlayContainer bgOpacity='40' visible={menuStateMemo} changeDelay='300'>
|
<div className='w-full h-dvh'>
|
||||||
<div className='w-full h-full' onClick={toggleMenuState}></div>
|
<BlurredOverlayContainer bgOpacity='40' visible={menuStateMemo} changeDelay='300'>
|
||||||
<div
|
<div className='w-full h-dvh overflow-hidden' onClick={toggleMenuState}></div>
|
||||||
data-isvisible={menuStateMemo}
|
<div
|
||||||
onClick={(e) => { e.stopPropagation(); }}
|
data-isvisible={menuStateMemo}
|
||||||
className={`absolute top-0 -right-full data-[isvisible=true]:right-0 transition-all duration-300 ease-in-out not-xl:!rounded-s-none overflow-clip bg-white w-[200px] h-full flex flex-col z-40`}>
|
onClick={(e) => { e.stopPropagation(); }}
|
||||||
<ul className="overflow-y-auto hide-scrollbar pt-20 pb-10 flex flex-col justify-between h-full ">
|
className={`fixed top-0 bottom-0 -right-full data-[isvisible=true]:right-0 transition-all duration-100 ease-in-out not-xl:!rounded-s-none overflow-clip bg-white w-[200px] h-dvh flex flex-col z-40`}>
|
||||||
<li>
|
<ul className="overflow-hidden noscrollbar pt-20 pb-10 flex flex-col justify-between h-full ">
|
||||||
<div className='flex flex-col gap-[60px]'>
|
<li>
|
||||||
<div className='flex flex-col gap-[23px]'>
|
<div className='flex flex-col gap-[60px]'>
|
||||||
<div className='pt-2 text-start px-12 text-menu-header'>منو</div>
|
<div className='flex flex-col gap-[23px]'>
|
||||||
{menuItems[0].map((v, i) => {
|
<div className='pt-2 text-start px-12 text-menu-header'>منو</div>
|
||||||
return <MenuItem key={i} href={v.href || ''} title={v.title} icon={v.icon} />
|
{menuItems[0].map((v, i) => {
|
||||||
})}
|
return <MenuItem key={i} href={v.href || ''} title={v.title} icon={v.icon} />
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
<li className='flex flex-col gap-6 pt-16'>
|
||||||
<li className='flex flex-col gap-6 pt-16'>
|
{menuItems[2].map((v, i) => {
|
||||||
{menuItems[2].map((v, i) => {
|
return <MenuItem key={i} href={v.href || ''} title={v.title} icon={v.icon} />
|
||||||
return <MenuItem key={i} href={v.href || ''} title={v.title} icon={v.icon} />
|
})}
|
||||||
})}
|
<MenuItem href={''} title={''} icon={<></>}><NightModeSwitch checked={nightModeState} onClick={togglenightModeState} /></MenuItem>
|
||||||
<MenuItem href={''} title={''} icon={<></>}><NightModeSwitch checked={nightModeState} onClick={togglenightModeState}/></MenuItem>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</BlurredOverlayContainer>
|
||||||
</BlurredOverlayContainer>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type Props = object
|
|||||||
|
|
||||||
function BottomNavBar({ }: Props) {
|
function BottomNavBar({ }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="absolute bottom-0 left-0 w-full bg-transparent">
|
<div className="fixed bottom-0 left-0 w-full bg-transparent">
|
||||||
<div className="max-w-md mx-auto w-full aspect-[436/104] relative z-30">
|
<div className="max-w-md mx-auto w-full aspect-[436/104] relative z-30">
|
||||||
<svg
|
<svg
|
||||||
viewBox="0 0 436 104"
|
viewBox="0 0 436 104"
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ const BlurredOverlayContainer = ({
|
|||||||
<button
|
<button
|
||||||
data-visible={visible}
|
data-visible={visible}
|
||||||
data-loaded={loaded}
|
data-loaded={loaded}
|
||||||
className={`absolute inset-0 flex items-center justify-center
|
className={props.className + `
|
||||||
|
absolute 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}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type Props = {
|
|||||||
|
|
||||||
function TopBar({ profileDropState, toggleProfileDropState, menuState, toggleMenuState, searchModalState, toggleSearchModalState, nightModeState, toggleNightModeState }: Props) {
|
function TopBar({ profileDropState, toggleProfileDropState, menuState, toggleMenuState, searchModalState, toggleSearchModalState, nightModeState, toggleNightModeState }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4 pb-0">
|
||||||
<div className='bg-white grid grid-cols-3 overflow-hidden rounded-2xl w-full h-12 lg:h-24 px-2 sm:p-6 xl:gap-8 items-center'>
|
<div className='bg-white grid grid-cols-3 overflow-hidden rounded-2xl w-full h-12 lg:h-24 px-2 sm:p-6 xl:gap-8 items-center'>
|
||||||
<div className='inline-flex justify-between items-center'>
|
<div className='inline-flex justify-between items-center'>
|
||||||
<button className='inline-block xl:hidden' onClick={toggleMenuState}>
|
<button className='inline-block xl:hidden' onClick={toggleMenuState}>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function ClientMenuRouteWrapper({ children }: Props) {
|
|||||||
// }, [location])
|
// }, [location])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className='h-screen overflow-hidden'>
|
||||||
<header>
|
<header>
|
||||||
<TopBar
|
<TopBar
|
||||||
profileDropState={profileDrop} toggleProfileDropState={toggleProfileDrop}
|
profileDropState={profileDrop} toggleProfileDropState={toggleProfileDrop}
|
||||||
@@ -44,7 +44,7 @@ function ClientMenuRouteWrapper({ children }: Props) {
|
|||||||
searchModalState={searchModal} toggleSearchModalState={toggleSearchModal}
|
searchModalState={searchModal} toggleSearchModalState={toggleSearchModal}
|
||||||
nightModeState={nightMode} toggleNightModeState={toggleNightMode} />
|
nightModeState={nightMode} toggleNightModeState={toggleNightMode} />
|
||||||
</header>
|
</header>
|
||||||
<main className="h-full px-4 pb-0">
|
<main className="h-full px-4 pb-44 overflow-y-auto noscrollbar">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
<aside>
|
<aside>
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ type Props = { } & React.AllHTMLAttributes<HTMLBodyElementEventMap>
|
|||||||
|
|
||||||
function ClientSideWrapper({ children }: Props) {
|
function ClientSideWrapper({ children }: Props) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user