419 lines
12 KiB
TypeScript
419 lines
12 KiB
TypeScript
import { Card, Skeleton } from "antd";
|
|
import useBreakPoint from "hooks/useBreakPoint";
|
|
import styles from "./MenuSkeleton.module.css";
|
|
|
|
interface MenuSkeletonProps {
|
|
categoryCount?: number;
|
|
itemCount?: number;
|
|
variant?:
|
|
| "default"
|
|
| "minimal"
|
|
| "detailed"
|
|
| "categories-only"
|
|
| "menu-only";
|
|
}
|
|
|
|
const MenuSkeleton = ({
|
|
categoryCount = 8,
|
|
itemCount = 8,
|
|
variant = "default",
|
|
}: MenuSkeletonProps) => {
|
|
const { isMobile, isTablet } = useBreakPoint();
|
|
|
|
const getCategoryCardStyle = () => {
|
|
if (isMobile) {
|
|
return {
|
|
width: 90,
|
|
height: 110,
|
|
};
|
|
} else if (isTablet) {
|
|
return {
|
|
width: 120,
|
|
height: 110,
|
|
};
|
|
} else {
|
|
return {
|
|
width: 140,
|
|
height: 160,
|
|
};
|
|
}
|
|
};
|
|
|
|
const getMenuItemCardStyle = () => {
|
|
if (isMobile) {
|
|
return {
|
|
height: 140,
|
|
padding: "12px 12px 12px 16px",
|
|
};
|
|
} else if (isTablet) {
|
|
return {
|
|
height: 160,
|
|
padding: "16px",
|
|
};
|
|
} else {
|
|
return {
|
|
height: 180,
|
|
padding: "20px",
|
|
};
|
|
}
|
|
};
|
|
|
|
const getCategoryImageStyle = () => {
|
|
if (isMobile) {
|
|
return {
|
|
width: 90,
|
|
height: 78,
|
|
borderTopLeftRadius: 8,
|
|
borderTopRightRadius: 8,
|
|
};
|
|
} else if (isTablet) {
|
|
return {
|
|
width: 120,
|
|
height: 78,
|
|
borderTopLeftRadius: 8,
|
|
borderTopRightRadius: 8,
|
|
};
|
|
} else {
|
|
return {
|
|
width: 140,
|
|
height: 78,
|
|
borderTopLeftRadius: 8,
|
|
borderTopRightRadius: 8,
|
|
};
|
|
}
|
|
};
|
|
|
|
const getMenuItemImageStyle = () => {
|
|
if (isMobile) {
|
|
return {
|
|
width: 90,
|
|
height: 95,
|
|
};
|
|
} else if (isTablet) {
|
|
return {
|
|
width: 120,
|
|
height: 120,
|
|
};
|
|
} else {
|
|
return {
|
|
width: 140,
|
|
height: 140,
|
|
};
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* 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" : isTablet ? "40px" : "36px",
|
|
top: isMobile ? "133px" : isTablet ? "150px" : "130px",
|
|
borderRadius: "50%",
|
|
width: isMobile ? "72px" : isTablet ? "80px" : "150px",
|
|
height: isMobile ? "72px" : isTablet ? "80px" : "150px",
|
|
border: "3px solid var(--background)",
|
|
zIndex: 10,
|
|
overflow: "hidden",
|
|
}}
|
|
/>
|
|
|
|
{/* 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
|
|
className={
|
|
styles.restaurantDescriptionSkeleton +
|
|
" " +
|
|
"restaurant-description-skeleton"
|
|
}
|
|
>
|
|
<Skeleton
|
|
active
|
|
paragraph={{
|
|
rows: 1,
|
|
width: ["100%"],
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Loyalty Card Skeleton */}
|
|
<div className={styles.loyaltySkeleton}>
|
|
<Card className={styles.loyaltyCardSkeleton}>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
marginBottom: "0.5rem",
|
|
}}
|
|
>
|
|
<div
|
|
style={{ display: "flex", alignItems: "center", gap: "8px" }}
|
|
>
|
|
<Skeleton.Image
|
|
active
|
|
style={{
|
|
width: "24px",
|
|
height: "24px",
|
|
borderRadius: "4px",
|
|
}}
|
|
/>
|
|
<Skeleton.Input
|
|
active
|
|
style={{
|
|
width: "120px",
|
|
height: "16px",
|
|
}}
|
|
/>
|
|
</div>
|
|
<Skeleton.Image
|
|
active
|
|
style={{
|
|
width: "24px",
|
|
height: "24px",
|
|
borderRadius: "4px",
|
|
}}
|
|
/>
|
|
</div>
|
|
<br />
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<div style={{ display: "flex", gap: "4px" }}>
|
|
{Array.from({ length: 5 }).map((_, index) => (
|
|
<Skeleton.Image
|
|
key={index}
|
|
active
|
|
style={{
|
|
width: "32px",
|
|
height: "32px",
|
|
borderRadius: "50%",
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
<Skeleton.Button
|
|
active
|
|
style={{
|
|
width: "80px",
|
|
height: "32px",
|
|
borderRadius: "16px",
|
|
}}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Categories Skeleton */}
|
|
{(variant === "default" ||
|
|
variant === "minimal" ||
|
|
variant === "detailed" ||
|
|
variant === "categories-only") && (
|
|
<div
|
|
style={{
|
|
padding: isMobile ? "0 1rem" : isTablet ? "0 24px" : "0 24px",
|
|
display: "flex",
|
|
gap: 8,
|
|
overflow: "hidden",
|
|
marginBottom: isMobile ? "4rem" : isTablet ? "8px" : "16px",
|
|
}}
|
|
>
|
|
{Array.from({
|
|
length:
|
|
variant === "minimal"
|
|
? Math.min(categoryCount, 4)
|
|
: categoryCount,
|
|
}).map((_, index) => (
|
|
<div
|
|
key={index}
|
|
style={{
|
|
marginRight: isMobile ? "3px" : "8px",
|
|
}}
|
|
>
|
|
<Card
|
|
style={{ borderRadius: 8 }}
|
|
styles={{
|
|
body: {
|
|
...getCategoryCardStyle(),
|
|
padding: 0,
|
|
},
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
gap: "0px",
|
|
width: "100%",
|
|
height: "100%",
|
|
}}
|
|
>
|
|
<Skeleton.Image
|
|
active
|
|
style={{
|
|
...getCategoryImageStyle(),
|
|
borderBottomLeftRadius: 0,
|
|
borderBottomRightRadius: 0,
|
|
}}
|
|
/>
|
|
<div
|
|
style={{
|
|
flex: 1,
|
|
padding: isMobile ? "4px" : "8px",
|
|
textAlign: "center",
|
|
width: "100%",
|
|
}}
|
|
>
|
|
<Skeleton
|
|
active
|
|
paragraph={{ rows: 0 }}
|
|
style={{
|
|
margin: 0,
|
|
padding: isMobile ? 3 : 8,
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Menu Items Skeleton */}
|
|
{(variant === "default" ||
|
|
variant === "minimal" ||
|
|
variant === "detailed" ||
|
|
variant === "menu-only") && (
|
|
<div
|
|
className={styles.menuSections}
|
|
style={{
|
|
padding: isMobile ? "0 1rem" : isTablet ? "0 24px" : "0 24px",
|
|
}}
|
|
>
|
|
{Array.from({ length: variant === "minimal" ? 1 : 3 }).map(
|
|
(_, sectionIndex) => (
|
|
<div key={sectionIndex} className={styles.menuSection}>
|
|
{/* Section Header Skeleton */}
|
|
{/* <div
|
|
style={{
|
|
margin: isMobile ? "20px 0 15px 0" : isTablet ? "30px 0 20px 0" : "40px 0 25px 0",
|
|
padding: isTablet ? "0 12px" : isDesktop ? "0 16px" : "0"
|
|
}}
|
|
>
|
|
<Skeleton.Input
|
|
active
|
|
size="large"
|
|
style={{
|
|
width: isMobile ? 120 : isTablet ? 160 : 200,
|
|
height: isMobile ? 24 : isTablet ? 28 : 32,
|
|
}}
|
|
/>
|
|
</div> */}
|
|
|
|
<div
|
|
className={`${styles.menuItemsGrid} ${styles.menuItemsGrid}`}
|
|
>
|
|
{Array.from({
|
|
length:
|
|
variant === "minimal"
|
|
? Math.min(itemCount, 4)
|
|
: itemCount,
|
|
}).map((_, itemIndex) => (
|
|
<Card
|
|
key={itemIndex}
|
|
className="responsive-card"
|
|
style={{ borderRadius: 8 }}
|
|
styles={{
|
|
body: {
|
|
...getMenuItemCardStyle(),
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
justifyContent: "space-between",
|
|
},
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "space-around",
|
|
gap: isMobile ? 12 : 16,
|
|
position: "relative",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
lineHeight: 1,
|
|
height: "100%",
|
|
flex: 1,
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
{/* Item Description Skeleton */}
|
|
<Skeleton
|
|
active
|
|
paragraph={{
|
|
rows: isMobile ? 1 : 2,
|
|
width: ["100%", "90%", "70%"],
|
|
}}
|
|
style={{
|
|
marginBottom: isMobile ? 8 : isTablet ? 16 : 20,
|
|
}}
|
|
/>
|
|
{/* Action Icons Skeleton */}
|
|
</div>
|
|
|
|
<div style={{ position: "relative" }}>
|
|
{/* Item Image Skeleton */}
|
|
<Skeleton.Image
|
|
active
|
|
style={{
|
|
...getMenuItemImageStyle(),
|
|
}}
|
|
/>{" "}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
),
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default MenuSkeleton;
|