Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
:root {
|
||||
--background: #f7f7f7;
|
||||
--foreground: #181818;
|
||||
--primary-light: #fff;
|
||||
--primary-dark: #0a0a0a;
|
||||
--primary: #ffb700;
|
||||
--primary2: #ffc600;
|
||||
--secondary: #09237d;
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
import {
|
||||
LogoutOutlined,
|
||||
QuestionOutlined,
|
||||
SettingOutlined,
|
||||
UserOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {
|
||||
Dropdown,
|
||||
Flex,
|
||||
FloatButton,
|
||||
Layout,
|
||||
MenuProps,
|
||||
message,
|
||||
theme,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import { logout } from "features/auth/authSlice.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAppDispatch } from "redux/hooks.ts";
|
||||
import { PATH_AUTH } from "utils/constants.ts";
|
||||
import LangSelect from "./components/langSelect/LangSelect.tsx";
|
||||
import HeaderNav from "./HeaderNav.tsx";
|
||||
import SideNav from "./SideNav.tsx";
|
||||
import "./styles.css";
|
||||
|
||||
const { Content } = Layout;
|
||||
const { Title } = Typography;
|
||||
type AppLayoutProps = {
|
||||
withSidebar?: boolean;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const AppLayout = ({ children, withSidebar = true }: AppLayoutProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
token: { borderRadius },
|
||||
} = theme.useToken();
|
||||
const [navFill, setNavFill] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const nodeRef = useRef(null);
|
||||
const floatBtnRef = useRef(null);
|
||||
const location = useLocation();
|
||||
const isMenu = location.pathname === "/menu";
|
||||
|
||||
const items: MenuProps["items"] = [
|
||||
{
|
||||
key: "user-profile-link",
|
||||
label: t("profile"),
|
||||
icon: <UserOutlined />,
|
||||
},
|
||||
{
|
||||
key: "user-settings-link",
|
||||
label: t("settings"),
|
||||
icon: <SettingOutlined />,
|
||||
},
|
||||
{
|
||||
key: "user-help-link",
|
||||
label: t("help center"),
|
||||
icon: <QuestionOutlined />,
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
key: "user-logout-link",
|
||||
label: t("logout"),
|
||||
icon: <LogoutOutlined />,
|
||||
danger: true,
|
||||
onClick: () => {
|
||||
message.open({
|
||||
type: "loading",
|
||||
content: t("msg-success-logout"),
|
||||
});
|
||||
|
||||
dispatch(logout());
|
||||
|
||||
setTimeout(() => {
|
||||
navigate(PATH_AUTH.signin);
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("scroll", () => {
|
||||
if (window.scrollY > 5) {
|
||||
setNavFill(true);
|
||||
} else {
|
||||
setNavFill(false);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout
|
||||
style={{
|
||||
minHeight: "100vh",
|
||||
// backgroundColor: 'white',
|
||||
}}
|
||||
>
|
||||
{withSidebar && (
|
||||
<SideNav
|
||||
trigger={null}
|
||||
style={{
|
||||
overflow: "auto",
|
||||
background: "none",
|
||||
border: "none",
|
||||
transition: "all .2s",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<HeaderNav
|
||||
style={{
|
||||
padding: "0px 20px 0px 20px",
|
||||
background: navFill ? "rgba(255, 255, 255, .5)" : "none",
|
||||
backdropFilter: navFill ? "blur(8px)" : "none",
|
||||
boxShadow: navFill ? "0 0 8px 2px rgba(0, 0, 0, 0.05)" : "none",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
height: "7vh",
|
||||
zIndex: 10,
|
||||
transition: "all .25s",
|
||||
}}
|
||||
>
|
||||
<Flex gap="middle" align="start" style={{ gap: 25 }}>
|
||||
<Tooltip title={dayjs().format("DD/MM/YYYY")}>
|
||||
<Title level={3} style={{ position: "relative", top: -2 }}>
|
||||
{dayjs().format("DD/MM/YYYY")}{" "}
|
||||
</Title>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={t("language")}>
|
||||
<LangSelect />
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
{/* <Flex align="center">
|
||||
<Input.Search
|
||||
placeholder="search"
|
||||
style={{
|
||||
width: isMobile ? "100%" : "400px",
|
||||
marginLeft: isMobile ? 0 : ".5rem",
|
||||
}}
|
||||
size="middle"
|
||||
/>
|
||||
</Flex> */}
|
||||
|
||||
<Flex align="end" gap="small">
|
||||
{/* <Tooltip title="Apps">
|
||||
<Button icon={<AppstoreOutlined />} type="text" size="large" />
|
||||
</Tooltip>
|
||||
<Tooltip title="Messages">
|
||||
<Button icon={<MessageOutlined />} type="text" size="large" />
|
||||
</Tooltip> */}
|
||||
{/* <Tooltip title="Theme">
|
||||
<Switch
|
||||
className=" hidden sm:inline py-1"
|
||||
checkedChildren={<MoonOutlined />}
|
||||
unCheckedChildren={<SunOutlined />}
|
||||
checked={mytheme === "light" ? true : false}
|
||||
onClick={() => dispatch(toggleTheme())}
|
||||
/>
|
||||
</Tooltip> */}
|
||||
|
||||
{/* <Badge
|
||||
count={2}
|
||||
size="small"
|
||||
style={{
|
||||
top: 15,
|
||||
right: 5,
|
||||
left: 5,
|
||||
}}
|
||||
>
|
||||
<BellOutlined
|
||||
style={{
|
||||
fontSize: 20,
|
||||
marginTop: 15,
|
||||
marginLeft: 15,
|
||||
marginRight: 15,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => setNotificationsDrawerOpen(true)}
|
||||
/>
|
||||
</Badge> */}
|
||||
<Dropdown menu={isMenu ? {} : { items }} trigger={["click"]}>
|
||||
<Flex>
|
||||
{!isMenu && (
|
||||
<img
|
||||
src={"/avatar.png"}
|
||||
alt="user profile photo"
|
||||
height={36}
|
||||
width={36}
|
||||
style={{
|
||||
borderRadius,
|
||||
objectFit: "cover",
|
||||
position: "relative",
|
||||
top: 5,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Dropdown>
|
||||
</Flex>
|
||||
</HeaderNav>
|
||||
<Content>
|
||||
<div ref={nodeRef} style={{ background: "none" }}>
|
||||
{children}
|
||||
</div>
|
||||
<div ref={floatBtnRef}>
|
||||
<FloatButton.BackTop />
|
||||
</div>
|
||||
</Content>
|
||||
{/* <FooterNav
|
||||
style={{
|
||||
textAlign: "center",
|
||||
marginLeft: collapsed ? 0 : "200px",
|
||||
background: "none",
|
||||
}}
|
||||
/> */}
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
80
src/layouts/app/AppLayout.tsx
Normal file
80
src/layouts/app/AppLayout.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { MoonOutlined, SunOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { Button, Flex, Image, Layout, Switch, Tooltip } from "antd";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import { toggleTheme } from "features/theme/themeSlice.ts";
|
||||
import useBreakPoint from "hooks/useBreakPoint.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
|
||||
import { colors, ProBlack2 } from "ThemeConstants.ts";
|
||||
import LangSelect from "./components/langSelect/LangSelect.tsx";
|
||||
import HeaderNav from "./HeaderNav.tsx";
|
||||
import "./styles.css";
|
||||
|
||||
const { Content } = Layout;
|
||||
type AppLayoutProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const AppLayout = ({ children }: AppLayoutProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const { themeName } = useAppSelector((state) => state.theme);
|
||||
const { isDesktop } = useBreakPoint();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout
|
||||
style={{
|
||||
minHeight: "100vh",
|
||||
}}
|
||||
>
|
||||
{isDesktop && (
|
||||
<HeaderNav className="header-nav">
|
||||
<Flex align="center" gap="middle">
|
||||
<Tooltip>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<UserOutlined />}
|
||||
className="user-icon"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
|
||||
<Flex align="center" gap="middle">
|
||||
<Tooltip title={t("language")}>
|
||||
<div style={{ position: "relative", top: -26 }}>
|
||||
<LangSelect />
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Theme">
|
||||
<Switch
|
||||
checkedChildren={<MoonOutlined />}
|
||||
unCheckedChildren={<SunOutlined />}
|
||||
checked={themeName === "light" ? true : false}
|
||||
onClick={() => dispatch(toggleTheme())}
|
||||
style={{
|
||||
background:
|
||||
themeName === "dark" ? colors.primary : ProBlack2,
|
||||
borderRadius: "12px",
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Image
|
||||
src="/me.png"
|
||||
alt="user profile photo"
|
||||
height={40}
|
||||
width={40}
|
||||
className="user-profile-image"
|
||||
preview={false}
|
||||
/>
|
||||
</Flex>
|
||||
</HeaderNav>
|
||||
)}
|
||||
<Content>{children}</Content>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1 +1,2 @@
|
||||
export { AppLayout } from './App.tsx';
|
||||
export { AppLayout } from './AppLayout.tsx';
|
||||
|
||||
|
||||
@@ -1,3 +1,44 @@
|
||||
.header-nav {
|
||||
padding: 0 1rem;
|
||||
background: #fff;
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
gap: 4px;
|
||||
transition: all 0.25s;
|
||||
height: 8vh;
|
||||
}
|
||||
|
||||
.user-icon {
|
||||
font-size: 16px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--primary-light);
|
||||
}
|
||||
|
||||
.user-profile-image {
|
||||
border-radius: 12px;
|
||||
object-fit: cover;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
:where(.darkApp) .user-profile-image {
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.trigger {
|
||||
padding: 0 8px;
|
||||
font-size: 18px;
|
||||
@@ -64,3 +105,11 @@
|
||||
right: 30px !important;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
:where(.darkApp) .header-nav {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
:where(.darkApp) .user-icon {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
.menuSections{
|
||||
.menuSections {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -630,28 +630,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Skeleton Loading Styles */
|
||||
.skeletonContainer {
|
||||
animation: skeletonPulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-image {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-input {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-button {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
@keyframes skeletonPulse {
|
||||
0% {
|
||||
opacity: 1;
|
||||
@@ -673,72 +651,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-active .ant-skeleton-input,
|
||||
.skeletonContainer .ant-skeleton-active .ant-skeleton-image,
|
||||
.skeletonContainer .ant-skeleton-active .ant-skeleton-button {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200px 100%;
|
||||
animation: skeletonShimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
/* Mobile-specific skeleton styles */
|
||||
@media (max-width: 768px) {
|
||||
.skeletonContainer .ant-skeleton {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-image {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-input {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-button {
|
||||
border-radius: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark theme skeleton styles */
|
||||
:global(.darkApp) .skeletonContainer .ant-skeleton-active .ant-skeleton-input,
|
||||
:global(.darkApp) .skeletonContainer .ant-skeleton-active .ant-skeleton-image,
|
||||
:global(.darkApp) .skeletonContainer .ant-skeleton-active .ant-skeleton-button {
|
||||
background: linear-gradient(90deg, #181818 25%, #363636 50%, #181818 75%);
|
||||
background-size: 200px 100%;
|
||||
animation: skeletonShimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
:global(.darkApp) .skeletonContainer .ant-skeleton-input,
|
||||
:global(.darkApp) .skeletonContainer .ant-skeleton-image,
|
||||
:global(.darkApp) .skeletonContainer .ant-skeleton-button {
|
||||
background-color: #181818;
|
||||
border-color: #363636;
|
||||
}
|
||||
|
||||
/* Tablet-specific skeleton styles */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.skeletonContainer {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-image {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-input {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.skeletonContainer .ant-skeleton-button {
|
||||
border-radius: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.menuItemsGridSticky {
|
||||
height: 60;
|
||||
}
|
||||
|
||||
@@ -48,13 +48,16 @@ export function MenuList({ data, categoryRefs }: MenuListProps) {
|
||||
}
|
||||
|
||||
// Group products by category
|
||||
const productsByCategory = products?.reduce((acc, product) => {
|
||||
const productsByCategory = products?.reduce(
|
||||
(acc, product) => {
|
||||
if (product.categoryId && !acc[product?.categoryId]) {
|
||||
acc[product?.categoryId] = [];
|
||||
}
|
||||
acc[product?.categoryId || 0].push(product);
|
||||
return acc;
|
||||
}, {} as Record<number, Product[]>);
|
||||
},
|
||||
{} as Record<number, Product[]>,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -170,14 +173,14 @@ export function MenuList({ data, categoryRefs }: MenuListProps) {
|
||||
style={{
|
||||
display: "-webkit-box",
|
||||
WebkitBoxOrient: "vertical",
|
||||
WebkitLineClamp: xs ? 2 : 4,
|
||||
WebkitLineClamp: 2,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
wordWrap: "break-word",
|
||||
overflowWrap: "break-word",
|
||||
lineHeight: "1.5rem",
|
||||
maxHeight: xs ? "3em" : "6.6em",
|
||||
fontSize: xs ? "1rem" : 18,
|
||||
maxHeight: "3em",
|
||||
fontSize: "1rem",
|
||||
letterSpacing: "0.01em",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -18,6 +18,24 @@
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.cover {
|
||||
width: 100%;
|
||||
height: "auto";
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: absolute;
|
||||
left: 33px;
|
||||
top: -64px;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid var(--background);
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.leftShape {
|
||||
position: absolute;
|
||||
top: 133px;
|
||||
@@ -49,6 +67,12 @@
|
||||
|
||||
/* Enhanced responsive categories container */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.logo {
|
||||
left: 40px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.categoriesContainer {
|
||||
height: 160px;
|
||||
padding: 0 24px;
|
||||
@@ -65,17 +89,23 @@
|
||||
}
|
||||
|
||||
.leftShape {
|
||||
top: 170px;
|
||||
top: 150px;
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
.rightShape {
|
||||
top: 170px;
|
||||
top: 150px;
|
||||
left: 116px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
.logo {
|
||||
left: 33px;
|
||||
top: 141px;
|
||||
width: 150px !important;
|
||||
height: 150px !important;
|
||||
}
|
||||
.categoriesContainer {
|
||||
height: 180px;
|
||||
padding: 0 24px;
|
||||
@@ -94,6 +124,16 @@
|
||||
max-width: 100vw !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.leftShape {
|
||||
top: 170px;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
.rightShape {
|
||||
top: 170px;
|
||||
left: 185px;
|
||||
}
|
||||
}
|
||||
|
||||
.menuSection:first-child h3 {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Card, Grid, Skeleton } from "antd";
|
||||
import { Card, Skeleton } from "antd";
|
||||
import useBreakPoint from "hooks/useBreakPoint";
|
||||
import styles from "./MenuSkeleton.module.css";
|
||||
|
||||
interface MenuSkeletonProps {
|
||||
@@ -12,17 +13,12 @@ interface MenuSkeletonProps {
|
||||
| "menu-only";
|
||||
}
|
||||
|
||||
const { useBreakpoint } = Grid;
|
||||
|
||||
const MenuSkeleton = ({
|
||||
categoryCount = 6,
|
||||
categoryCount = 8,
|
||||
itemCount = 8,
|
||||
variant = "default",
|
||||
}: MenuSkeletonProps) => {
|
||||
const { xs, md } = useBreakpoint();
|
||||
const isMobile = xs;
|
||||
const isTablet = !xs && !md;
|
||||
// const isDesktop = md;
|
||||
const { isMobile, isTablet } = useBreakPoint();
|
||||
|
||||
const getCategoryCardStyle = () => {
|
||||
if (isMobile) {
|
||||
@@ -106,51 +102,41 @@ const MenuSkeleton = ({
|
||||
}
|
||||
};
|
||||
|
||||
const getGridClass = () => {
|
||||
if (isMobile) {
|
||||
return styles.menuItemsGridMobile;
|
||||
} else if (isTablet) {
|
||||
return styles.menuItemsGridTablet;
|
||||
} else {
|
||||
return styles.menuItemsGridDesktop;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles.pageContainer} ${styles.skeletonContainer}`}>
|
||||
<>
|
||||
{/* Restaurant Header Skeleton */}
|
||||
<div className={styles.restaurantHeader}>
|
||||
{/* Cover Image Skeleton */}
|
||||
<Skeleton.Image
|
||||
active
|
||||
className={styles.cover}
|
||||
style={{
|
||||
width: "100vw",
|
||||
height: isMobile ? 182 : isTablet ? 200 : 220,
|
||||
borderRadius: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Logo Skeleton */}
|
||||
<Skeleton.Image
|
||||
active
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: isMobile ? "33px" : "40px",
|
||||
top: isMobile ? "133px" : isTablet ? "170px" : "170px",
|
||||
left: isMobile ? "33px" : isTablet ? "40px" : "36px",
|
||||
top: isMobile ? "133px" : isTablet ? "150px" : "130px",
|
||||
borderRadius: "50%",
|
||||
width: isMobile ? "72px" : isTablet ? "80px" : "80px",
|
||||
height: isMobile ? "72px" : isTablet ? "80px" : "80px",
|
||||
width: isMobile ? "72px" : isTablet ? "80px" : "150px",
|
||||
height: isMobile ? "72px" : isTablet ? "80px" : "150px",
|
||||
border: "3px solid var(--background)",
|
||||
zIndex: 10,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Decorative Shapes Skeleton */}
|
||||
{/* Decorative Shap es Skeleton */}
|
||||
<div className={styles.leftShape}></div>
|
||||
<div className={styles.rightShape}></div>
|
||||
</div>
|
||||
|
||||
<div className={`${styles.pageContainer} ${styles.skeletonContainer}`}>
|
||||
{/* Restaurant Info Skeleton */}
|
||||
<div className={styles.restaurantInfoSkeleton}>
|
||||
<div
|
||||
@@ -181,7 +167,9 @@ const MenuSkeleton = ({
|
||||
marginBottom: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<div
|
||||
style={{ display: "flex", alignItems: "center", gap: "8px" }}
|
||||
>
|
||||
<Skeleton.Image
|
||||
active
|
||||
style={{
|
||||
@@ -349,7 +337,9 @@ const MenuSkeleton = ({
|
||||
/>
|
||||
</div> */}
|
||||
|
||||
<div className={`${styles.menuItemsGrid} ${getGridClass()}`}>
|
||||
<div
|
||||
className={`${styles.menuItemsGrid} ${styles.menuItemsGrid}`}
|
||||
>
|
||||
{Array.from({
|
||||
length:
|
||||
variant === "minimal"
|
||||
@@ -416,11 +406,12 @@ const MenuSkeleton = ({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -570,6 +570,10 @@
|
||||
height: 40px !important;
|
||||
border-radius: 12px !important;
|
||||
}
|
||||
|
||||
.contentWrapper{
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop devices (min-width: 1025px) */
|
||||
|
||||
@@ -41,7 +41,7 @@ function MenuPage() {
|
||||
restaurantDetails?.restaurant.id,
|
||||
{
|
||||
skip: !restaurantDetails?.restaurant.id,
|
||||
}
|
||||
},
|
||||
);
|
||||
const { categoryRefs } = useScrollHandler();
|
||||
const { xs, md } = useBreakpoint();
|
||||
@@ -58,7 +58,7 @@ function MenuPage() {
|
||||
/>
|
||||
|
||||
{isLoading ? (
|
||||
<MenuSkeleton categoryCount={6} itemCount={8} variant="default" />
|
||||
<MenuSkeleton categoryCount={10} itemCount={8} variant="default" />
|
||||
) : (
|
||||
<div className={styles.menuContainer}>
|
||||
<div className={styles.restaurantHeader}>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Grid } from "antd";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { PrivateRoute } from "components/privateRoute/PrivateRoute";
|
||||
import { AppLayout } from "layouts";
|
||||
import HeaderMenuDrawer from "layouts/app/HeaderMenuDrawer";
|
||||
import AddressPage from "pages/address/page";
|
||||
import CartPage from "pages/cart/page";
|
||||
@@ -73,7 +74,15 @@ export const router = createHashRouter([
|
||||
|
||||
{
|
||||
path: "/:id/cart",
|
||||
element: <PageWrapper children={<CartPage />} />,
|
||||
element: (
|
||||
<PageWrapper
|
||||
children={
|
||||
<AppLayout>
|
||||
<CartPage />
|
||||
</AppLayout>
|
||||
}
|
||||
/>
|
||||
),
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user