Desktop responsive: search page, cart list, masonry grid
- MondrianProductList: add desktop 4-column masonry (mobile 2-col unchanged); improves home "for you", search results and seller feed at lg+ - search: hide mobile SearchTopBar at lg, add results heading + centered 1320px container - cart list: responsive 2-column grid of cart cards + desktop heading - MyLayout: desktop chrome gate now covers / , /search/* and /cart Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e1c5899002
commit
9650073b04
@ -96,8 +96,17 @@ const MondrianProductList = ({
|
||||
|
||||
const oddHeight = useMemo(() => [220, 260, 320, 200, 280], []);
|
||||
const evenHeight = useMemo(() => [280, 200, 260, 220, 320], []);
|
||||
|
||||
// Desktop masonry: distribute products across 4 columns (round-robin).
|
||||
const desktopColumns = useMemo(() => {
|
||||
const cols: MondrianList[][] = [[], [], [], []];
|
||||
products.forEach((p, i) => cols[i % 4].push(p));
|
||||
return cols;
|
||||
}, [products]);
|
||||
const desktopHeights = useMemo(() => [300, 360, 260, 340, 280, 320], []);
|
||||
|
||||
return (
|
||||
<div className="px-4 flex flex-col w-full">
|
||||
<div className="px-4 lg:px-0 flex flex-col w-full">
|
||||
{!isCommonList ? (
|
||||
<>
|
||||
{isLoading ? (
|
||||
@ -113,7 +122,8 @@ const MondrianProductList = ({
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex gap-1 w-full">
|
||||
{/* Mobile / tablet: original two-column masonry (unchanged) */}
|
||||
<div className="flex gap-1 w-full lg:hidden">
|
||||
{/* Column 1 (Odd products - index 0, 2, ...) */}
|
||||
<div className="flex flex-col gap-1 w-[calc(50%)]">
|
||||
{oddProducts.map((product, index: number) => {
|
||||
@ -146,6 +156,26 @@ const MondrianProductList = ({
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop: 4-column masonry */}
|
||||
<div className="hidden lg:flex gap-4 w-full">
|
||||
{desktopColumns.map((col, ci) => (
|
||||
<div key={ci} className="flex flex-col gap-4 flex-1 min-w-0">
|
||||
{col.map((product, index) => (
|
||||
<ProductCard
|
||||
key={product.id}
|
||||
product={product}
|
||||
height={
|
||||
desktopHeights[(ci + index) % desktopHeights.length]
|
||||
}
|
||||
storeId={storeId}
|
||||
storePage={storePage}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{hasNextPage && <MondrianSkeleton isMini={true} />}
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -27,10 +27,12 @@ import productsOutline from "~/assets/icons/navbar/products-outline.svg";
|
||||
*/
|
||||
const MyLayout = React.memo(({ children }: { children: React.ReactNode }) => {
|
||||
const location = useLocation();
|
||||
// Desktop chrome is rolled out per-page. Only routes listed here get the
|
||||
// Desktop chrome is rolled out per-page. Only routes matched here get the
|
||||
// full-width desktop layout; everything else keeps the current (mobile)
|
||||
// experience at all widths so nothing regresses while we build the rest.
|
||||
const isDesktopReady = location.pathname === "/";
|
||||
const p = location.pathname;
|
||||
const isDesktopReady =
|
||||
p === "/" || p.startsWith("/search/") || p === "/cart";
|
||||
const isThread = !!location.pathname.split("threads")[1];
|
||||
|
||||
return (
|
||||
|
||||
@ -59,11 +59,16 @@ export default function CartIndex() {
|
||||
};
|
||||
return (
|
||||
<div className="bg-background">
|
||||
{/* Header */}
|
||||
<ProfilePagesHeader hideBackButton={true} title="لیست سبد خرید" />
|
||||
{/* Header (mobile) */}
|
||||
<div className="lg:hidden">
|
||||
<ProfilePagesHeader hideBackButton={true} title="لیست سبد خرید" />
|
||||
</div>
|
||||
|
||||
{/* Cart Content */}
|
||||
<div className="flex flex-col gap-4 p-4">
|
||||
<div className="flex flex-col gap-4 p-4 lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:py-8">
|
||||
<h1 className="hidden lg:block text-[28px] font-extrabold mb-2">
|
||||
سبد خرید
|
||||
</h1>
|
||||
<UiProvider
|
||||
isLoading={isLoading}
|
||||
isError={isError}
|
||||
@ -73,7 +78,7 @@ export default function CartIndex() {
|
||||
}}
|
||||
type="cart"
|
||||
>
|
||||
<div className="space-y-4 w-full">
|
||||
<div className="space-y-4 w-full lg:space-y-0 lg:grid lg:grid-cols-2 lg:gap-5">
|
||||
{carts.map((cart) => {
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { MetaFunction } from "@remix-run/node";
|
||||
import { useNavigate, useParams } from "@remix-run/react";
|
||||
import { Link, useNavigate, useParams } from "@remix-run/react";
|
||||
import { onSearch } from "../utils/helpers";
|
||||
import { PackageSearch } from "lucide-react";
|
||||
import { useSearchInfinite } from "../requestHandler/use-search-hooks";
|
||||
@ -31,15 +31,32 @@ export default function Search() {
|
||||
} = useSearchInfinite(query);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 bg-WHITE">
|
||||
<SearchTopBar
|
||||
searchValue={searchValue}
|
||||
setSearchValue={setSearchValue}
|
||||
placeholder="جستجو..."
|
||||
minimumPrice={320000}
|
||||
maximumPrice={1000000}
|
||||
onSearch={() => onSearch(searchValue, navigate)}
|
||||
/>
|
||||
<div className="flex flex-col gap-6 bg-WHITE lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:py-6">
|
||||
<div className="lg:hidden">
|
||||
<SearchTopBar
|
||||
searchValue={searchValue}
|
||||
setSearchValue={setSearchValue}
|
||||
placeholder="جستجو..."
|
||||
minimumPrice={320000}
|
||||
maximumPrice={1000000}
|
||||
onSearch={() => onSearch(searchValue, navigate)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Desktop results heading */}
|
||||
<div className="hidden lg:block">
|
||||
<nav className="flex items-center gap-2 text-[13px] text-GRAY">
|
||||
<Link to="/" className="hover:text-BLACK">
|
||||
خانه
|
||||
</Link>
|
||||
<span>/</span>
|
||||
<span>جستجو</span>
|
||||
</nav>
|
||||
<h1 className="text-[26px] font-extrabold mt-2">
|
||||
نتایج برای «<span className="text-VITROWN_BLUE">{query}</span>»
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<MondrianProductList
|
||||
products={
|
||||
data?.pages
|
||||
|
||||
Loading…
Reference in New Issue
Block a user