feat: add side menu

This commit is contained in:
Mahyar Khanbolooki
2025-07-04 15:49:38 +03:30
parent 691dc7c100
commit 424373bc3f
25 changed files with 758 additions and 11 deletions
+2
View File
@@ -13,6 +13,8 @@
--color-foreground: #333333;
--color-disabled: #E7E7E7;
--color-disabled-text: #8C90A3;
--color-menu-header: #C3C7DD;
--color-icon-deactive: #A8ABBF;
--radius-normal: 10px;
--text-sm2: 13px;
--text-xs2: 10px;
+1
View File
@@ -16,6 +16,7 @@ export default function RootLayout({
<html lang="en">
<body
dir="rtl"
className={`antialiased bg-background h-full`}
>
{children}
+1 -1
View File
@@ -1,4 +1,4 @@
import LoadingOverlay from '@/components/loading/LoadingOverlay'
import LoadingOverlay from '@/components/overlays/LoadingOverlay'
import React from 'react'
function Loading() {
+11 -3
View File
@@ -1,5 +1,6 @@
import BottomNavBar from "@/components/navigation/BottomNavBar";
import { ReactQueryProvider } from "@/components/providers/ReactQueryProvider";
import { Menu } from '@/components/menu/Menu';
export const metadata = {
title: 'Menu',
@@ -13,10 +14,17 @@ export default function MenuLayout({
return (
<ReactQueryProvider>
<main className="h-full pb-0">
{children}
</main>
<main className="h-full pb-0">
{children}
</main>
<aside>
<Menu />
</aside>
<footer>
<BottomNavBar />
</footer>
</ReactQueryProvider>
);
}
+19
View File
@@ -0,0 +1,19 @@
import React from 'react'
import { PiSun, PiMoon } from 'react-icons/pi'
export default function NightModeSwitch({ state, toggle }) {
return (
<button
onClick={toggle}
className={`visual-switch relative inline-flex justify-between px-1.5 h-6 w-11 items-center rounded-full transition-colors duration-300 ${state ? "bg-green-500" : "bg-gray-300"
}`}
>
<PiMoon color={state ? "#FFA800" : "#292D32"} className='z-10' size={12} />
<span
className={`absolute inline-block h-5 w-5 transform rounded-full bg-white transition-transform duration-300 ${state ? "translate-x-1" : "-translate-x-3.5"
}`}
/>
<PiSun color={!state ? "#FFA800" : "#292D32"} className='z-10' size={12} />
</button>
)
}
@@ -0,0 +1,84 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const CalendarSearchIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M8.00049 2V5"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.9995 2V5"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M18.2 21.4C19.9673 21.4 21.4 19.9673 21.4 18.2C21.4 16.4327 19.9673 15 18.2 15C16.4327 15 15 16.4327 15 18.2C15 19.9673 16.4327 21.4 18.2 21.4Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M22 22L21 21"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3.50049 9.08984H20.5005"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M13.37 22H8C4.5 22 3 20 3 17V8.5C3 5.5 4.5 3.5 8 3.5H16C19.5 3.5 21 5.5 21 8.5V13"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11.9945 13.7004H12.0035"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.29529 13.7004H8.30427"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.29529 16.7004H8.30427"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default CalendarSearchIcon;
+58
View File
@@ -0,0 +1,58 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const CupIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M12.1504 16.5V18.6"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.1499 22H17.1499V21C17.1499 19.9 16.2499 19 15.1499 19H9.1499C8.0499 19 7.1499 19.9 7.1499 21V22Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeMiterlimit="10"
/>
<path
d="M6.15039 22H18.1504"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12.0005 16C8.13049 16 5.00049 12.87 5.00049 9V6C5.00049 3.79 6.79049 2 9.00049 2H15.0005C17.2105 2 19.0005 3.79 19.0005 6V9C19.0005 12.87 15.8705 16 12.0005 16Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5.47004 11.6496C4.72004 11.4096 4.06004 10.9696 3.54004 10.4496C2.64004 9.44961 2.04004 8.24961 2.04004 6.84961C2.04004 5.44961 3.14004 4.34961 4.54004 4.34961H5.19004C4.99004 4.80961 4.89004 5.31961 4.89004 5.84961V8.84961C4.89004 9.84961 5.10004 10.7896 5.47004 11.6496Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M18.5298 11.6496C19.2798 11.4096 19.9398 10.9696 20.4598 10.4496C21.3598 9.44961 21.9598 8.24961 21.9598 6.84961C21.9598 5.44961 20.8598 4.34961 19.4598 4.34961H18.8098C19.0098 4.80961 19.1098 5.31961 19.1098 5.84961V8.84961C19.1098 9.84961 18.8998 10.7896 18.5298 11.6496Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default CupIcon;
@@ -0,0 +1,55 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const DirectboxReceiveIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M12 1.99976V7.99976L14 5.99976"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11.9995 8L9.99951 6"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7 12C3 12 3 13.79 3 16V17C3 19.76 3 22 8 22H16C20 22 21 19.76 21 17V16C21 13.79 21 12 17 12C16 12 15.72 12.21 15.2 12.6L14.18 13.68C13 14.94 11 14.94 9.81 13.68L8.8 12.6C8.28 12.21 8 12 7 12Z"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5.00049 12.0005V8.00053C5.00049 5.99053 5.00049 4.33053 8.00049 4.04053"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M18.9995 12.0005V8.00053C18.9995 5.99053 18.9995 4.33053 15.9995 4.04053"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default DirectboxReceiveIcon;
+38
View File
@@ -0,0 +1,38 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const ExitIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M8.8999 7.55999C9.2099 3.95999 11.0599 2.48999 15.1099 2.48999H15.2399C19.7099 2.48999 21.4999 4.27999 21.4999 8.74999V15.27C21.4999 19.74 19.7099 21.53 15.2399 21.53H15.1099C11.0899 21.53 9.2399 20.08 8.9099 16.54"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.0001 12H3.62012"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5.85 8.6499L2.5 11.9999L5.85 15.3499"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default ExitIcon;
@@ -0,0 +1,79 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const GameControllerIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M9.56953 12.4609L6.51953 15.5109"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6.55029 12.4905L9.60029 15.5405"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M13.5308 14H13.5391"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17.4707 14H17.479"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.5005 15.9769V15.9602"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.5005 12.0362V12.0195"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.00049 22H15.0005C20.0005 22 22.0005 20 22.0005 15V13C22.0005 8 20.0005 6 15.0005 6H9.00049C4.00049 6 2.00049 8 2.00049 13V15C2.00049 20 4.00049 22 9.00049 22Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M13.01 2L13 3.01C12.99 3.56 12.55 4 12 4H11.97C11.42 4 10.98 4.45 10.98 5C10.98 5.55 11.43 6 11.98 6H12.98"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default GameControllerIcon;
+45
View File
@@ -0,0 +1,45 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const NoteBoardIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M19.9995 8.25V18C19.9995 21 18.2095 22 15.9995 22H7.99951C5.78951 22 3.99951 21 3.99951 18V8.25C3.99951 5 5.78951 4.25 7.99951 4.25C7.99951 4.87 8.24948 5.43 8.65948 5.84C9.06948 6.25 9.62951 6.5 10.2495 6.5H13.7495C14.9895 6.5 15.9995 5.49 15.9995 4.25C18.2095 4.25 19.9995 5 19.9995 8.25Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12.0044 10V14.83"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12 17.8699H12.009"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.0005 4.25C16.0005 5.49 14.9905 6.5 13.7505 6.5H10.2505C9.63049 6.5 9.07046 6.25 8.66046 5.84C8.25046 5.43 8.00049 4.87 8.00049 4.25C8.00049 3.01 9.01049 2 10.2505 2H13.7505C14.3705 2 14.9305 2.25 15.3405 2.66C15.7505 3.07 16.0005 3.63 16.0005 4.25Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default NoteBoardIcon;
@@ -0,0 +1,38 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const NotificationBellIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M12.0196 2.9104C8.7096 2.9104 6.0196 5.6004 6.0196 8.9104V11.8004C6.0196 12.4104 5.7596 13.3404 5.4496 13.8604L4.2996 15.7704C3.5896 16.9504 4.0796 18.2604 5.3796 18.7004C9.6896 20.1404 14.3396 20.1404 18.6496 18.7004C19.8596 18.3004 20.3896 16.8704 19.7296 15.7704L18.5796 13.8604C18.2796 13.3404 18.0196 12.4104 18.0196 11.8004V8.9104C18.0196 5.6104 15.3196 2.9104 12.0196 2.9104Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
/>
<path
d="M13.8704 3.19994C13.5604 3.10994 13.2404 3.03994 12.9104 2.99994C11.9504 2.87994 11.0304 2.94994 10.1704 3.19994C10.4604 2.45994 11.1804 1.93994 12.0204 1.93994C12.8604 1.93994 13.5804 2.45994 13.8704 3.19994Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.0205 19.0601C15.0205 20.7101 13.6705 22.0601 12.0205 22.0601C11.2005 22.0601 10.4405 21.7201 9.90051 21.1801C9.36051 20.6401 9.02051 19.8801 9.02051 19.0601"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeMiterlimit="10"
/>
</svg>
);
export default NotificationBellIcon;
+52
View File
@@ -0,0 +1,52 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const ReceiptIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M6.73049 19.7C7.55049 18.82 8.80049 18.89 9.52049 19.85L10.5305 21.2C11.3405 22.27 12.6505 22.27 13.4605 21.2L14.4705 19.85C15.1905 18.89 16.4405 18.82 17.2605 19.7C19.0405 21.6 20.4905 20.97 20.4905 18.31V7.04C20.5005 3.01 19.5605 2 15.7805 2H8.22049C4.44049 2 3.50049 3.01 3.50049 7.04V18.3C3.50049 20.97 4.96049 21.59 6.73049 19.7Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.09656 11H8.10554"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10.8984 11H16.3984"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.09656 7H8.10554"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10.8984 7H16.3984"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default ReceiptIcon;
+33
View File
@@ -0,0 +1,33 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const SettingIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M2 12.8799V11.1199C2 10.0799 2.85 9.21994 3.9 9.21994C5.71 9.21994 6.45 7.93994 5.54 6.36994C5.02 5.46994 5.33 4.29994 6.24 3.77994L7.97 2.78994C8.76 2.31994 9.78 2.59994 10.25 3.38994L10.36 3.57994C11.26 5.14994 12.74 5.14994 13.65 3.57994L13.76 3.38994C14.23 2.59994 15.25 2.31994 16.04 2.78994L17.77 3.77994C18.68 4.29994 18.99 5.46994 18.47 6.36994C17.56 7.93994 18.3 9.21994 20.11 9.21994C21.15 9.21994 22.01 10.0699 22.01 11.1199V12.8799C22.01 13.9199 21.16 14.7799 20.11 14.7799C18.3 14.7799 17.56 16.0599 18.47 17.6299C18.99 18.5399 18.68 19.6999 17.77 20.2199L16.04 21.2099C15.25 21.6799 14.23 21.3999 13.76 20.6099L13.65 20.4199C12.75 18.8499 11.27 18.8499 10.36 20.4199L10.25 20.6099C9.78 21.3999 8.76 21.6799 7.97 21.2099L6.24 20.2199C5.33 19.6999 5.02 18.5299 5.54 17.6299C6.45 16.0599 5.71 14.7799 3.9 14.7799C2.85 14.7799 2 13.9199 2 12.8799Z"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default SettingIcon;
+30
View File
@@ -0,0 +1,30 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const ThumbsUpIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M7.47949 18.3505L10.5795 20.7505C10.9795 21.1505 11.8795 21.3505 12.4795 21.3505H16.2795C17.4795 21.3505 18.7795 20.4505 19.0795 19.2505L21.4795 11.9505C21.9795 10.5505 21.0795 9.35046 19.5795 9.35046H15.5795C14.9795 9.35046 14.4795 8.85046 14.5795 8.15046L15.0795 4.95046C15.2795 4.05046 14.6795 3.05046 13.7795 2.75046C12.9795 2.45046 11.9795 2.85046 11.5795 3.45046L7.47949 9.55046"
stroke="currentColor"
strokeWidth="1.5"
strokeMiterlimit="10"
/>
<path
d="M2.37988 18.3504V8.55039C2.37988 7.15039 2.97988 6.65039 4.37988 6.65039H5.37988C6.77988 6.65039 7.37988 7.15039 7.37988 8.55039V18.3504C7.37988 19.7504 6.77988 20.2504 5.37988 20.2504H4.37988C2.97988 20.2504 2.37988 19.7504 2.37988 18.3504Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default ThumbsUpIcon;
@@ -0,0 +1,45 @@
import React from 'react';
type Props = React.SVGProps<SVGSVGElement>;
const TicketDiscountIcon = (props: Props) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M19.5005 12.5C19.5005 11.12 20.6205 10 22.0005 10V9C22.0005 5 21.0005 4 17.0005 4H7.00049C3.00049 4 2.00049 5 2.00049 9V9.5C3.38049 9.5 4.50049 10.62 4.50049 12C4.50049 13.38 3.38049 14.5 2.00049 14.5V15C2.00049 19 3.00049 20 7.00049 20H17.0005C21.0005 20 22.0005 19 22.0005 15C20.6205 15 19.5005 13.88 19.5005 12.5Z"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9 14.75L15 8.75"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M14.994 14.75H15.003"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.99402 9.25H9.003"
stroke="#A8ABBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
export default TicketDiscountIcon;
+11
View File
@@ -0,0 +1,11 @@
import React from 'react'
import { CiSearch } from "react-icons/ci";
export default function SearchBox() {
return (
<div className='bg-[#EEF0F7] inline-flex rounded-xl px-4 h-12 w-full md:w-[370px] items-center content-center' >
<CiSearch className='text-[#8C90A3]' size={24} />
<input placeholder='جستجو' className='text-[#8C90A3] block outline-none border-none focus:ring-0 focus:outline-none text-sm px-[7px] h-full items-center w-full' type='text' />
</div>
)
}
+92
View File
@@ -0,0 +1,92 @@
'use client';
import React, { useState } from 'react'
import MenuItemType from './MenuItem'
import MenuItem from './MenuItem';
import NotificationBellIcon from '../icons/NotificationBellIcon';
import CupIcon from '../icons/CupIcon';
import TicketDiscountIcon from '../icons/TickerDiscountIcon';
import CalendarSearchIcon from '../icons/CalendarSearchIcon';
import ReceiptIcon from '../icons/ReceiptIcon';
import GameControllerIcon from '../icons/GameControllerIcon';
import ThumbsUpIcon from '../icons/ThumbsUpIcon';
import NoteBoardIcon from '../icons/NoteBoardIcon';
import DirectboxReceiveIcon from '../icons/DirectboxReceiveIcon';
import BlurredOverlayContainer from '../overlays/BlurredOverlayContainer';
import SettingIcon from '../icons/SettingsIcon';
import ExitIcon from '../icons/ExitIcon';
type MenuItemType = {
href: string | undefined;
title: string;
icon: React.ReactElement
}
const menuItems: Array<Array<MenuItemType>> = [
[
{
href: '/', title: 'صفحه اصلی', icon: <NotificationBellIcon className='text-icon-deactive' />
},
{
href: 'my-services', title: 'سرویس های من', icon: <CupIcon className='text-icon-deactive' />
},
{
href: 'services', title: 'سایر سرویس ها', icon: <TicketDiscountIcon className='text-icon-deactive' />
},
{
href: 'invoices', title: 'لیست', icon: <CalendarSearchIcon className='text-icon-deactive' />
},
{
href: 'transactions', title: 'تراکنش ها', icon: <ReceiptIcon className='text-icon-deactive' />
},
{
href: '/', title: 'صفحه اصلی', icon: <GameControllerIcon className='text-icon-deactive' />
},
{
href: 'my-services', title: 'سرویس های من', icon: <ThumbsUpIcon className='text-icon-deactive' />
},
{
href: 'services', title: 'سایر سرویس ها', icon: <NoteBoardIcon className='text-icon-deactive' />
},
{
href: 'invoices', title: 'نصب اپلیکیشن', icon: <DirectboxReceiveIcon className='text-icon-deactive' />
},
],
[],
[
{
href: undefined, title: 'تنظیمات', icon: <SettingIcon className='text-icon-deactive' />
},
{
href: undefined, title: 'خروج', icon: <ExitIcon className='text-icon-deactive' />
},
]
]
export function Menu() {
const [menuState, setMenuState] = useState(true);
return (
<BlurredOverlayContainer bgOpacity={40} onClick={() => setMenuState((state) => !state)} visible={menuState}>
<div data-visible={menuState} onClick={() => setMenuState((state) => !state)} className='absolute top-0 -right-full data-[visible]:right-0 transition-all duration-200 ease-in-out not-xl:!rounded-s-none overflow-clip bg-white w-[200px] h-full flex flex-col z-40'>
<ul className="overflow-y-auto hide-scrollbar pt-20 pb-10 flex flex-col justify-between h-full ">
<li>
<div className='flex flex-col gap-[60px]'>
<div className='flex flex-col gap-[23px]'>
<div className='pt-2 pr-10 text-menu-header'>منو</div>
{menuItems[0].map((v, i) => {
return <MenuItem key={i} href={v.href || ''} title={v.title} icon={v.icon} />
})}
</div>
</div>
</li>
<li className='flex flex-col gap-6 pt-16'>
{menuItems[2].map((v, i) => {
return <MenuItem key={i} href={v.href || ''} title={v.title} icon={v.icon} />
})}
</li>
</ul>
</div>
</BlurredOverlayContainer>
)
}
+20
View File
@@ -0,0 +1,20 @@
import Link, { LinkProps } from 'next/link'
import React from 'react'
type Props = {
icon: React.ReactElement
title: string
} & LinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>
export default function MenuItem({ href, title, icon, className, ...restProps }: Props) {
return (
<Link
{...restProps}
href={href}
className={`inline-flex gap-2 px-9 border-s-6 border-transparent text-disabled-text text-xs items-center font-light text-nowrap overflow-hidden h-6
data-[active]:border-s-6 data-[active]:border-black data-[active]:text-black ${className}`}>
{icon}
<div>{title}</div>
</Link>
)
}
+5 -5
View File
@@ -12,7 +12,7 @@ type Props = object
function BottomNavBar({ }: Props) {
return (
<div className="absolute bottom-0 left-0 w-full bg-transparent">
<div className="max-w-md mx-auto w-full aspect-[436/104] relative z-40">
<div className="max-w-md mx-auto w-full aspect-[436/104] relative z-30">
<svg
viewBox="0 0 436 104"
fill="none"
@@ -32,11 +32,11 @@ function BottomNavBar({ }: Props) {
<div
className="absolute z-20 w-full h-full px-2 grid grid-cols-5 gap-x-2 text-[10px] items-end"
>
<BottomNavLink href={'/auth'} icon={<HeartIcon />} value="پسند ها" />
<BottomNavLink href={''} icon={<NotifiBoardIcon />} value="اعلان ها" />
<BottomNavHighlightLink href={''} icon={<HomeHashtagIcon />} value="منو" />
<BottomNavLink href={''} icon={<PagerIcon />} value="پیجر" />
<BottomNavLink href={''} icon={<BagIcon />} value="سبد خرید" />
<BottomNavLink href={''} icon={<PagerIcon />} value="پیجر" />
<BottomNavHighlightLink href={''} icon={<HomeHashtagIcon />} value="منو" />
<BottomNavLink href={''} icon={<NotifiBoardIcon />} value="اعلان ها" />
<BottomNavLink href={'/auth'} icon={<HeartIcon />} value="پسند ها" />
</div>
</foreignObject>
@@ -0,0 +1,37 @@
'use client'
import React, { useEffect, useState } from 'react'
import PingAnimation from './animations/PingAnimation';
type Props = {
visible?: boolean;
bgOpacity?: number;
delay?: number;
} & React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
const BlurredOverlayContainer = ({ visible = true, bgOpacity = 30, delay = 0, children = <PingAnimation /> }: Props) => {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
// Trigger fade-in after mount
const timeout = setTimeout(() => setLoaded(visible), 300);
return () => clearTimeout(timeout);
}, [visible]);
return (
<div
data-visible={visible}
data-loaded={loaded}
className={`absolute inset-0 flex items-center justify-center
backdrop-blur-sm bg-black/${bgOpacity}
opacity-0 transition-opacity duration-300 ease-in-out delay-${delay}
data-[loaded=false]:-z-50
data-[visible=true]:z-50
data-[visible=true]:opacity-100`}
>
{children}
</div>
)
}
export default BlurredOverlayContainer
+1 -1
View File
@@ -23,7 +23,7 @@ const arrowClasses = {
const Tooltip = ({
children,
content,
title: content,
hidden = false,
position = 'top',
...rest
@@ -1,4 +1,4 @@
import LoadingOverlay from '@/components/loading/LoadingOverlay';
import LoadingOverlay from '@/components/overlays/LoadingOverlay';
import React from 'react'
type Props = {