From cbc64b6e3868e3bd50ff648f3b9e3f35ad727040 Mon Sep 17 00:00:00 2001 From: Mohammed Al-yaseen Date: Sat, 11 Oct 2025 20:34:22 +0300 Subject: [PATCH] menu: UI enhancements in desktop sizes - add product dialog - enhance product page layout for desktop size --- src/components/Icons/item/DescIcon1.tsx | 11 +- src/components/Icons/item/DescIcon2.tsx | 11 +- src/components/Icons/item/DescIcon3.tsx | 11 +- .../ItemDescriptionIcons.tsx | 9 +- .../menu/components/MenuList/MenuList.tsx | 45 ++- .../ProductPreviewDialog.module.css | 3 + .../ProductPreviewDialog.tsx | 34 ++ .../components/ProductPreviewDialog/index.ts | 1 + src/pages/product/components/ExtraGroups.tsx | 6 +- .../product/components/ProductFooter.tsx | 69 ++-- src/pages/product/components/Variants.tsx | 4 +- src/pages/product/page.tsx | 298 ++++++++++-------- src/pages/product/product.module.css | 143 ++++++++- 13 files changed, 456 insertions(+), 189 deletions(-) create mode 100644 src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.module.css create mode 100644 src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.tsx create mode 100644 src/pages/menu/components/ProductPreviewDialog/index.ts diff --git a/src/components/Icons/item/DescIcon1.tsx b/src/components/Icons/item/DescIcon1.tsx index 00713db..46777b9 100644 --- a/src/components/Icons/item/DescIcon1.tsx +++ b/src/components/Icons/item/DescIcon1.tsx @@ -1,9 +1,10 @@ interface DescIcon1Type { className?: string; onClick?: () => void; + pathColor?: string; } -const DescIcon1 = ({ className, onClick }: DescIcon1Type) => { +const DescIcon1 = ({ className, onClick,pathColor }: DescIcon1Type) => { return ( { fillRule="evenodd" clipRule="evenodd" d="M0.622 8C0.622 12.0667 3.93333 15.378 8 15.378C12.068 15.378 15.378 12.0673 15.378 8C15.378 3.93267 12.068 0.622 8 0.622C3.93333 0.622 0.622 3.93333 0.622 8ZM0 8C0 12.4113 3.58867 16 8 16C12.4113 16 16 12.4113 16 8C16 3.58867 12.4113 0 8 0C3.58867 0 0 3.58867 0 8Z" - fill="#000044" + fill={pathColor} /> diff --git a/src/components/Icons/item/DescIcon2.tsx b/src/components/Icons/item/DescIcon2.tsx index d6b3fe8..2f738c4 100644 --- a/src/components/Icons/item/DescIcon2.tsx +++ b/src/components/Icons/item/DescIcon2.tsx @@ -1,9 +1,10 @@ interface DescIcon2Type { className?: string; onClick?: () => void; + pathColor?: string; } -const DescIcon2 = ({ className, onClick }: DescIcon2Type) => { +const DescIcon2 = ({ className, onClick, pathColor }: DescIcon2Type) => { return ( { fillRule="evenodd" clipRule="evenodd" d="M0.622 8C0.622 12.0667 3.93333 15.378 8 15.378C12.068 15.378 15.378 12.0673 15.378 8C15.378 3.93267 12.068 0.622 8 0.622C3.93333 0.622 0.622 3.93333 0.622 8ZM0 8C0 12.4113 3.58867 16 8 16C12.4113 16 16 12.4113 16 8C16 3.58867 12.4113 0 8 0C3.58867 0 0 3.58867 0 8Z" - fill="#000044" + fill={pathColor} /> diff --git a/src/components/Icons/item/DescIcon3.tsx b/src/components/Icons/item/DescIcon3.tsx index 72407f7..16f4a84 100644 --- a/src/components/Icons/item/DescIcon3.tsx +++ b/src/components/Icons/item/DescIcon3.tsx @@ -1,9 +1,10 @@ interface DescIcon3Type { className?: string; onClick?: () => void; + pathColor?: string; } -const DescIcon3 = ({ className, onClick }: DescIcon3Type) => { +const DescIcon3 = ({ className, onClick, pathColor }: DescIcon3Type) => { return ( { fillRule="evenodd" clipRule="evenodd" d="M0.622 8C0.622 12.0667 3.93333 15.378 8 15.378C12.0667 15.378 15.378 12.0667 15.378 8C15.378 3.93333 12.068 0.622 8 0.622C3.93333 0.622 0.622 3.93333 0.622 8ZM0 8C0 12.4113 3.58867 16 8 16C12.4113 16 16 12.4113 16 8C16 3.58867 12.4113 0 8 0C3.58867 0 0 3.58867 0 8Z" - fill="#000044" + fill={pathColor} /> { fillRule="evenodd" clipRule="evenodd" d="M5.79528 4.01336C5.71861 4.09803 5.64195 4.1947 5.55395 4.2787C5.46061 4.3667 5.43061 4.45203 5.47728 4.5807C5.55995 4.80603 5.57061 5.04403 5.56928 5.28536C5.56261 6.0487 5.55995 6.81203 5.57061 7.57536C5.57395 7.7807 5.48928 7.9127 5.32728 7.99936C5.01661 8.16603 4.68395 8.20936 4.34528 8.1127C4.02528 8.0227 3.83195 7.7147 3.85861 7.3207C3.87261 7.10603 3.93528 6.8947 3.97528 6.68203C3.98728 6.62003 3.99795 6.55803 4.00861 6.4967C3.96795 6.50736 3.94595 6.52336 3.93528 6.54336C3.70995 6.9967 3.53195 7.4647 3.55795 7.9847C3.57928 8.41403 3.83795 8.7627 4.23795 8.8507C4.43528 8.89403 4.65128 8.90003 4.85128 8.8707C5.51328 8.77336 6.07795 8.07136 6.04461 7.46736C6.01128 6.83403 6.04195 6.1967 6.03461 5.5607C6.03195 5.30203 6.04195 5.05203 6.17261 4.82003C6.18135 4.80203 6.18616 4.78238 6.18674 4.76239C6.18731 4.74239 6.18363 4.7225 6.17595 4.70403C6.05528 4.4767 5.92795 4.2527 5.79528 4.01336ZM11.8259 7.75803C11.5939 7.80603 11.3859 7.85603 11.1766 7.89136C10.8799 7.94003 10.5819 7.9827 10.2859 7.8847C9.62595 7.6687 9.22728 7.1887 9.04461 6.54003C8.91128 6.0667 8.84328 5.57403 8.75795 5.08803C8.71528 4.84803 8.69795 4.6047 8.66595 4.3327C8.59661 4.43936 8.54861 4.5247 8.48928 4.6007C8.42661 4.6807 8.42061 4.76403 8.42595 4.86203C8.44661 5.24536 8.46928 5.6287 8.46728 6.01203C8.46395 6.47203 8.39061 6.92203 8.16861 7.33203C8.09728 7.46403 8.00528 7.58403 7.92261 7.70936C7.90483 7.67803 7.89913 7.64127 7.90661 7.60603C7.96128 7.23803 7.99795 6.8687 7.93261 6.4987C7.81728 5.85136 7.45461 5.35336 6.97928 4.92736C6.93528 4.8887 6.88128 4.8607 6.82995 4.83203C6.74328 4.78203 6.66328 4.80336 6.63328 4.89536C6.57195 5.07936 6.49728 5.2667 6.48195 5.4567C6.45928 5.74603 6.74261 6.07003 7.02461 6.11536C7.18461 6.1407 7.33928 6.18203 7.42661 6.32603C7.52661 6.49136 7.64395 6.6627 7.68195 6.8467C7.73661 7.11403 7.72528 7.39536 7.74661 7.6707C7.75861 7.82536 7.68528 7.9227 7.56528 8.00803C7.18061 8.28136 6.75661 8.4647 6.30728 8.5967C6.26395 8.60936 6.22128 8.62536 6.14528 8.6507C7.80728 9.06936 8.70728 7.9567 8.74061 6.54603C8.75928 6.6207 8.76928 6.66536 8.78195 6.70936C8.86595 7.0027 8.92395 7.30803 9.03928 7.58936C9.34995 8.34536 10.1699 8.80936 10.9366 8.6627C11.4993 8.5547 12.0526 8.39603 12.6353 8.41136L12.8806 7.76203C12.6966 7.6187 12.5219 7.49736 12.3659 7.35603C12.1833 7.19136 12.0173 7.00803 11.8426 6.8347C11.6393 6.63336 11.4226 6.45003 11.1479 6.35536C10.6719 6.19136 10.0993 6.51803 10.0006 7.0107C10.1213 6.96936 10.2399 6.92536 10.3606 6.88803C10.5479 6.82936 10.7366 6.8287 10.9166 6.9147C11.2953 7.0947 11.5633 7.3967 11.8259 7.75803Z" - fill="#000044" + fill={pathColor} /> diff --git a/src/components/ItemDescriptionIcons/ItemDescriptionIcons.tsx b/src/components/ItemDescriptionIcons/ItemDescriptionIcons.tsx index d8d5e19..c9fd943 100644 --- a/src/components/ItemDescriptionIcons/ItemDescriptionIcons.tsx +++ b/src/components/ItemDescriptionIcons/ItemDescriptionIcons.tsx @@ -1,14 +1,17 @@ import DescIcon1 from "components/Icons/item/DescIcon1"; import DescIcon2 from "components/Icons/item/DescIcon2"; import DescIcon3 from "components/Icons/item/DescIcon3"; +import { useAppSelector } from "redux/hooks"; import styles from "./ItemDescriptionIcons.module.css"; export function ItemDescriptionIcons({ className }: { className?: string }) { + const { themeName } = useAppSelector((state) => state.theme); + const pathColor = themeName === "dark" ? "white" : "#000044"; return (
- - - + + +
); } diff --git a/src/pages/menu/components/MenuList/MenuList.tsx b/src/pages/menu/components/MenuList/MenuList.tsx index 96922ca..974f4ae 100644 --- a/src/pages/menu/components/MenuList/MenuList.tsx +++ b/src/pages/menu/components/MenuList/MenuList.tsx @@ -1,10 +1,13 @@ -import { Badge, Card, Grid } from "antd"; +import { Badge, Card } from "antd"; import ArabicPrice from "components/ArabicPrice"; import ImageWithFallback from "components/ImageWithFallback"; import { ItemDescriptionIcons } from "components/ItemDescriptionIcons/ItemDescriptionIcons"; import ProText from "components/ProText"; import ProTitle from "components/ProTitle"; +import useBreakPoint from "hooks/useBreakPoint"; import { AddToCartButton } from "pages/menu/components/AddToCartButton/AddToCartButton.tsx"; +import { ProductPreviewDialog } from "pages/menu/components/ProductPreviewDialog"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { useAppSelector } from "redux/hooks"; @@ -23,18 +26,34 @@ interface MenuListProps { categoryRefs: React.RefObject<{ [key: number]: HTMLDivElement | null }>; } -const { useBreakpoint } = Grid; - export function MenuList({ data, categoryRefs }: MenuListProps) { const { isRTL } = useAppSelector((state) => state.locale); const products = data?.products; - const { xs, md } = useBreakpoint(); + const { isMobile, isTablet, isDesktop } = useBreakPoint(); const { items } = useAppSelector((state) => state.order); const restaurantName = localStorage.getItem("restaurantName"); const navigate = useNavigate(); const { t } = useTranslation(); const { themeName } = useAppSelector((state) => state.theme); + // Dialog state + const [isDialogOpen, setIsDialogOpen] = useState(false); + + // Handle product click - open dialog on desktop, navigate on mobile/tablet + const handleProductClick = (item: Product) => { + localStorage.setItem("product", JSON.stringify(item)); + if (isDesktop) { + setIsDialogOpen(true); + } else { + navigate(`/${restaurantName}/product/${item.id}`); + } + }; + + // Handle dialog close + const handleDialogClose = () => { + setIsDialogOpen(false); + }; + // Show error state if data exists but has no products if (data && (!data.products || data.products.length === 0)) { return ( @@ -104,10 +123,7 @@ export function MenuList({ data, categoryRefs }: MenuListProps) {
{ - localStorage.setItem("product", JSON.stringify(item)); - navigate(`/${restaurantName}/product/${item.id}`); - }} + onClick={() => handleProductClick(item)} >
+ + {/* Product Preview Dialog for Desktop */} + ); } diff --git a/src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.module.css b/src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.module.css new file mode 100644 index 0000000..188e202 --- /dev/null +++ b/src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.module.css @@ -0,0 +1,3 @@ +.productModal{ + width: 80vw; +} \ No newline at end of file diff --git a/src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.tsx b/src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.tsx new file mode 100644 index 0000000..47c9686 --- /dev/null +++ b/src/pages/menu/components/ProductPreviewDialog/ProductPreviewDialog.tsx @@ -0,0 +1,34 @@ +import { Modal } from "antd"; +import ProductDetailPage from "pages/product/page"; +import styles from "./ProductPreviewDialog.module.css"; + +interface ProductPreviewDialogProps { + isOpen: boolean; + onClose: () => void; +} + +export function ProductPreviewDialog({ + isOpen, + onClose, +}: ProductPreviewDialogProps) { + // const { isRTL } = useAppSelector((state) => state.locale); + // const { themeName } = useAppSelector((state) => state.theme); + + return ( + + + + ); +} diff --git a/src/pages/menu/components/ProductPreviewDialog/index.ts b/src/pages/menu/components/ProductPreviewDialog/index.ts new file mode 100644 index 0000000..18a8f91 --- /dev/null +++ b/src/pages/menu/components/ProductPreviewDialog/index.ts @@ -0,0 +1 @@ +export { ProductPreviewDialog } from "./ProductPreviewDialog"; diff --git a/src/pages/product/components/ExtraGroups.tsx b/src/pages/product/components/ExtraGroups.tsx index 6456f67..3fae008 100644 --- a/src/pages/product/components/ExtraGroups.tsx +++ b/src/pages/product/components/ExtraGroups.tsx @@ -4,7 +4,7 @@ import ProText from "components/ProText"; import { Dispatch, SetStateAction } from "react"; import { useTranslation } from "react-i18next"; import { useAppSelector } from "redux/hooks"; -import { Extra4, TheExtrasGroup } from "utils/types/appTypes"; +import { TheExtrasGroup } from "utils/types/appTypes"; import styles from "../product.module.css"; export default function ExtraGroups({ @@ -89,7 +89,7 @@ export default function ExtraGroups({
({ + options={group.extras.map((extra: any) => ({ value: extra.id.toString(), label: isRTL ? extra.name : extra.nameAR, price: `+${extra.price}`, @@ -99,7 +99,7 @@ export default function ExtraGroups({ // Check if the new selection would exceed the limit if (values.length > group.limit) { message.error( - `You can only select up to ${group.limit} option${group.limit > 1 ? "s" : ""} from this group.` + `You can only select up to ${group.limit} option${group.limit > 1 ? "s" : ""} from this group.`, ); return; } diff --git a/src/pages/product/components/ProductFooter.tsx b/src/pages/product/components/ProductFooter.tsx index b19cd30..eb2faa3 100644 --- a/src/pages/product/components/ProductFooter.tsx +++ b/src/pages/product/components/ProductFooter.tsx @@ -1,20 +1,18 @@ import { ShoppingCartOutlined } from "@ant-design/icons"; -import { Button, Grid, message, Row } from "antd"; -import { BottomSheet } from "pages/cart/components/specialRequest/BottomSheet.tsx"; +import { Button, message, Row } from "antd"; import { addItem, selectCart, updateSpecialRequest, } from "features/order/orderSlice"; -import { useState } from "react"; +import useBreakPoint from "hooks/useBreakPoint"; +import { BottomSheet } from "pages/cart/components/specialRequest/BottomSheet.tsx"; +import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useNavigate, useParams } from "react-router-dom"; import { useAppDispatch, useAppSelector } from "redux/hooks"; import { colors, ProBlack2 } from "ThemeConstants"; import { Product } from "utils/types/appTypes"; -const { useBreakpoint } = Grid; - export default function ProductFooter({ product, isValid = true, @@ -30,14 +28,25 @@ export default function ProductFooter({ selectedGroups: string[]; quantity: number; }) { - const { id } = useParams(); const { t } = useTranslation(); const dispatch = useAppDispatch(); const { themeName } = useAppSelector((state) => state.theme); const { specialRequest } = useAppSelector(selectCart); const [isSpecialRequestOpen, setIsSpecialRequestOpen] = useState(false); - const { xs } = useBreakpoint(); - const navigate = useNavigate(); + const { isMobile, isDesktop } = useBreakPoint(); + + // Check if product has any customization options + const hasCustomizationOptions = useMemo(() => { + const hasVariants = product?.variants?.length > 0; + const hasExtras = product.extras.length > 0; + const hasExtraGroups = product?.theExtrasGroups?.length > 0; + + return hasVariants || hasExtras || hasExtraGroups; + }, [ + product?.variants?.length, + product.extras.length, + product?.theExtrasGroups?.length, + ]); const handleAddToCart = () => { if (!isValid) { @@ -75,17 +84,27 @@ export default function ProductFooter({ setIsSpecialRequestOpen(false); }; + // return ( <>
@@ -103,8 +122,8 @@ export default function ProductFooter({ disabled={!isValid} style={{ flex: 1, - height: xs ? "48px" : "48px", - fontSize: xs ? "1rem" : "16px", + height: isMobile ? "48px" : "48px", + fontSize: isMobile ? "1rem" : "16px", transition: "all 0.3s ease", width: "100%", borderRadius: 888, @@ -116,12 +135,12 @@ export default function ProductFooter({ cursor: isValid ? "pointer" : "not-allowed", }} onMouseEnter={(e) => { - if (!xs && isValid) { + if (!isMobile && isValid) { e.currentTarget.style.transform = "translateY(-2px)"; } }} onMouseLeave={(e) => { - if (!xs) { + if (!isMobile) { e.currentTarget.style.transform = "translateY(0)"; } }} @@ -132,12 +151,14 @@ export default function ProductFooter({
- + {!isDesktop && ( + + )} ); } diff --git a/src/pages/product/components/Variants.tsx b/src/pages/product/components/Variants.tsx index 4ecf478..8a80c04 100644 --- a/src/pages/product/components/Variants.tsx +++ b/src/pages/product/components/Variants.tsx @@ -1,6 +1,7 @@ import { Divider } from "antd"; import ProRatioGroups from "components/ProRatioGroups/ProRatioGroups"; import ProText from "components/ProText"; +import useBreakPoint from "hooks/useBreakPoint"; import { Dispatch, SetStateAction, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { useAppSelector } from "redux/hooks"; @@ -18,6 +19,7 @@ export default function Variants({ }) { const { isRTL } = useAppSelector((state) => state.locale); const { t } = useTranslation(); + const { isDesktop } = useBreakPoint(); // Determine variant levels based on options array length const variantLevels = useMemo(() => { @@ -108,7 +110,7 @@ export default function Variants({ <> {variantsList?.length > 0 && variantLevels.length > 0 && ( <> - + {!isDesktop && }
state.locale); - const { t } = useTranslation(); + const { isDesktop } = useBreakPoint(); const [quantity, setQuantity] = useState(1); const product = JSON.parse( - localStorage.getItem("product") || "null" + localStorage.getItem("product") || "null", ) as Product; // State for variant selections @@ -45,7 +45,7 @@ export default function ProductDetailPage() { if (!product?.variants || product.variants.length === 0) return []; const maxOptionsLength = Math.max( - ...product.variants.map((v) => v.options.length) + ...product.variants.map((v) => v.options.length), ); const levels: Array<{ level: number; @@ -64,7 +64,7 @@ export default function ProductDetailPage() { product.variants .filter((v) => v.options[i]?.option === optionKey) .map((v) => v.options[i]?.value) - .filter(Boolean) + .filter(Boolean), ), ]; @@ -84,7 +84,7 @@ export default function ProductDetailPage() { }, [product?.variants]); // Get the final selected variant ID (the variant that matches all current selections) - const getFinalSelectedVariantId = () => { + const getFinalSelectedVariantId = useCallback(() => { if (!product?.variants || Object.keys(selectedVariants).length === 0) return ""; @@ -98,26 +98,26 @@ export default function ProductDetailPage() { // Convert to string only if defined, otherwise return empty string return matchingVariant?.id?.toString() || ""; - }; + }, [product?.variants, selectedVariants]); - const getExtras = () => { + const getExtras = useCallback(() => { const finalSelectedVariantId = getFinalSelectedVariantId(); if (finalSelectedVariantId) { const variant = product?.variants?.find( - (variant) => variant.id === Number(finalSelectedVariantId) + (variant) => variant.id === Number(finalSelectedVariantId), ); if (variant?.extras?.length && variant.extras.length > 0) { return variant.extras; } } return product?.extras; - }; + }, [product?.variants, product?.extras, getFinalSelectedVariantId]); // Validation function to check if all required selections are made const validateRequiredSelections = () => { // Check if all variant levels are selected const allVariantsSelected = variantLevels.every( - (level) => selectedVariants[level.level] !== undefined + (level) => selectedVariants[level.level] !== undefined, ); // Check if all required extra groups are satisfied @@ -128,7 +128,7 @@ export default function ProductDetailPage() { return selectedCount === group.limit; } return true; // Optional groups are always satisfied - } + }, ); return allVariantsSelected && allRequiredExtraGroupsSatisfied; @@ -136,6 +136,21 @@ export default function ProductDetailPage() { const isValid = validateRequiredSelections(); + // Check if product has any customization options + const hasCustomizationOptions = useMemo(() => { + const hasVariants = + product?.variants?.length > 0 && variantLevels.length > 0; + const hasExtras = getExtras().length > 0; + const hasExtraGroups = product?.theExtrasGroups?.length > 0; + + return hasVariants || hasExtras || hasExtraGroups; + }, [ + product?.variants, + product?.theExtrasGroups, + variantLevels.length, + getExtras, + ]); + if (!product) { return (
@@ -152,141 +167,166 @@ export default function ProductDetailPage() { scrollbarWidth: "none", }} > -
- -
- -
- -
+ {!isDesktop && ( +
+ +
+ )}
- -
-
+
+ - - {isRTL ? product?.nameOther : product?.name}{" "} - - {product?.description && ( + loadingContainerStyle={{ + width: "100%", + }} + /> +
+ +
+
+
- {isRTL ? product?.descriptionAR : product?.description} + {isRTL ? product?.nameOther : product?.name} - )} - -
- +
+ {product?.description && ( + + {isRTL ? product?.descriptionAR : product?.description} + + )} + +
+ +
-
-
- setQuantity(quantity)} - max={100} - min={1} - /> + + {isDesktop && ( +
+ setQuantity(quantity)} + max={100} + min={1} + /> +
+ )}
- {product?.variants?.length > 0 && variantLevels.length > 0 && ( - - )} - - {getExtras().length > 0 && ( - )} +
- {product.theExtrasGroups.length > 0 && ( - - )} - + {/* Right Column - Variants, Extras, and Extra Groups */} + {hasCustomizationOptions && ( +
+ + {product?.variants?.length > 0 && variantLevels.length > 0 && ( + + )} + + {getExtras().length > 0 && ( + + )} + + {product.theExtrasGroups.length > 0 && ( + + )} + +
+ )}
- + {!isDesktop && ( + + )}
); diff --git a/src/pages/product/product.module.css b/src/pages/product/product.module.css index 861a549..75bf510 100644 --- a/src/pages/product/product.module.css +++ b/src/pages/product/product.module.css @@ -1,7 +1,7 @@ .productDetailContainer { overflow: auto; scrollbar-width: none; - padding: 0 16px !important; + height: 100%; } .productContainer :global(.ant-radio-wrapper:last-child) { @@ -152,8 +152,135 @@ color: var(--primary2); } +/* Desktop Layout Styles */ +.desktopLayout { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 32px; + max-width: 1200px; + margin: 0 auto; + padding: 24px 0; +} + +.desktopLayoutFullWidth { + display: grid; + grid-template-columns: 1fr; + gap: 32px; + padding: 24px 0 0 0; +} + +.mobileLayout { + display: block; + width: 100%; +} + +.leftColumn { + display: flex; + flex-direction: column; + gap: 24px; +} + +.rightColumn { + display: flex; + flex-direction: column; + gap: 24px; + padding: 16px; + background: rgba(0, 0, 0, 0.01); + border-radius: 12px; + border: 1px solid rgba(0, 0, 0, 0.06); + overflow: auto; + scrollbar-width: none; +} + +.fullWidth { + width: 100%; +} + +.productImageSection { + position: relative; + border-radius: 0px; + overflow: hidden; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); + transition: + transform 0.3s ease, + box-shadow 0.3s ease; +} + +.productImageSection:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); +} + +.productInfoSection { + padding: 0 1rem; +} + +.productHeader { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 16px; + margin-bottom: 24px; +} + +.productDetails { + flex: 1; +} + +.quantitySection { + display: flex; + align-items: center; + justify-content: flex-end; + position: relative; + top: 5px +} + +/* Dark mode desktop styles */ +:global(.darkApp) .productImageSection { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); +} + +:global(.darkApp) .productImageSection:hover { + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4); +} + +:global(.darkApp) .rightColumn { + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.08); +} + /* Mobile responsiveness */ @media (max-width: 768px) { + .desktopLayout { + grid-template-columns: 1fr; + gap: 16px; + padding: 16px 0; + } + + .desktopLayoutFullWidth { + grid-template-columns: 1fr; + gap: 16px; + padding: 16px 0; + max-width: 100%; + } + + .rightColumn { + padding: 0; + background: transparent; + border: none; + gap: 16px; + } + + .productHeader { + flex-direction: column; + align-items: stretch; + gap: 16px; + } + + .quantitySection { + justify-content: center; + } + .descriptionSection { padding: 16px 16px 0 16px; } @@ -167,3 +294,17 @@ line-height: 1.6; } } + +.backButtonContainer { + position: absolute; + z-index: 999; + left: 20px; + top: 70px; + background-color: #fff; + border-radius: 50%; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +:global(.darkApp) .itemDescriptionIcons path { + fill: #ffffff !important; +}