Desktop: seller dashboard shell + gate carousel arrows to product gallery
- new store.$storeId.tsx layout: sticky admin sidebar (store/products/orders/ financial/shipping/threads/settings) beside content at lg; mobile unchanged - MyLayout: store/* gets a full-width desktop canvas (own sidebar), no shopper header/footer, mobile store-nav hidden at lg - store home: hide the redundant mobile store header at lg - ProductImageCarousel: prev/next arrows now opt-in (showArrows) so they only appear on the product gallery, not every masonry card
This commit is contained in:
parent
207d46eefd
commit
4af143bccf
@ -46,7 +46,10 @@ const MyLayout = React.memo(({ children }: { children: React.ReactNode }) => {
|
||||
// Auth pages get a full-width desktop canvas (so they can center their own
|
||||
// card) but no shopping header/footer.
|
||||
const isAuth = p === "/login" || p === "/logout";
|
||||
const expandOnDesktop = isDesktopReady || isAuth;
|
||||
// Seller dashboard: full-width canvas + its own sidebar (store.$storeId.tsx),
|
||||
// no shopper header/footer.
|
||||
const isStore = p.startsWith("/store/");
|
||||
const expandOnDesktop = isDesktopReady || isAuth || isStore;
|
||||
const isThread = !!location.pathname.split("threads")[1];
|
||||
|
||||
return (
|
||||
|
||||
@ -338,6 +338,7 @@ export const ProductDetailView = memo(function ProductDetailView({
|
||||
borderRadius={0}
|
||||
isActive={productActiveStatus}
|
||||
controlsIsOn={true}
|
||||
showArrows={true}
|
||||
onStatusChange={handleProductStatusChange}
|
||||
isChangeStatusDialogOpen={isChangeStatusDialogOpen}
|
||||
setIsChangeStatusDialogOpen={setIsChangeStatusDialogOpen}
|
||||
|
||||
@ -46,6 +46,7 @@ interface ProductImageCarouselProps {
|
||||
isOwner?: boolean;
|
||||
isActive?: boolean;
|
||||
controlsIsOn?: boolean;
|
||||
showArrows?: boolean;
|
||||
onStatusChange?: (newStatus: boolean) => void;
|
||||
isChangeStatusDialogOpen?: boolean;
|
||||
setIsChangeStatusDialogOpen?: (open: boolean) => void;
|
||||
@ -59,6 +60,7 @@ export const ProductImageCarousel = ({
|
||||
height,
|
||||
borderRadius,
|
||||
controlsIsOn = false,
|
||||
showArrows = false,
|
||||
isOwner = false,
|
||||
isActive = true,
|
||||
onStatusChange,
|
||||
@ -276,8 +278,8 @@ export const ProductImageCarousel = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Prev / next arrows (desktop) */}
|
||||
{images.length > 1 && (
|
||||
{/* Prev / next arrows (desktop, opt-in) */}
|
||||
{showArrows && images.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@ -105,7 +105,9 @@ export default function Store() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col pb-20 static md:relative ">
|
||||
<SellerDetailHeader sellerData={data} storeId={storeId} />
|
||||
<div className="lg:hidden">
|
||||
<SellerDetailHeader sellerData={data} storeId={storeId} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="px-4">
|
||||
<div className="flex px-4 border rounded-[10px] w-full py-2">
|
||||
|
||||
86
app/routes/store.$storeId.tsx
Normal file
86
app/routes/store.$storeId.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
import { Link, Outlet, useLocation, useParams } from "@remix-run/react";
|
||||
import {
|
||||
LayoutGrid,
|
||||
Package,
|
||||
ClipboardList,
|
||||
Wallet,
|
||||
Truck,
|
||||
MessageCircle,
|
||||
Settings,
|
||||
ArrowRight,
|
||||
} from "lucide-react";
|
||||
import { useSellerData } from "~/requestHandler/use-seller-hooks";
|
||||
import SellerLogo from "~/components/SellerLogo";
|
||||
|
||||
/**
|
||||
* Desktop layout for the seller dashboard. Renders a sticky admin sidebar
|
||||
* next to the page content at lg+; on mobile it's just the page content
|
||||
* (the existing mobile dashboard, with its store-mode bottom nav, is unchanged).
|
||||
*/
|
||||
export default function StoreLayout() {
|
||||
const { storeId } = useParams();
|
||||
const location = useLocation();
|
||||
const { data } = useSellerData(storeId);
|
||||
const base = `/store/${storeId}`;
|
||||
|
||||
const NAV = [
|
||||
{ label: "فروشگاه", to: base, icon: LayoutGrid, exact: true },
|
||||
{ label: "محصولات", to: `${base}/products`, icon: Package },
|
||||
{ label: "سفارشها", to: `${base}/orders`, icon: ClipboardList },
|
||||
{ label: "مالی", to: `${base}/financial-dashboard`, icon: Wallet },
|
||||
{ label: "روش ارسال", to: `${base}/shipping-method`, icon: Truck },
|
||||
{ label: "پیامها", to: `${base}/threads`, icon: MessageCircle },
|
||||
{ label: "تنظیمات", to: `${base}/setting`, icon: Settings },
|
||||
];
|
||||
|
||||
const isActive = (item: { to: string; exact?: boolean }) =>
|
||||
item.exact
|
||||
? location.pathname === item.to
|
||||
: location.pathname.startsWith(item.to);
|
||||
|
||||
return (
|
||||
<div className="lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:py-8 lg:grid lg:grid-cols-[260px_1fr] lg:gap-7 lg:items-start">
|
||||
{/* Desktop admin sidebar */}
|
||||
<aside className="hidden lg:block lg:sticky lg:top-6 border border-WHITE3 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 border-b border-WHITE3 flex items-center gap-3">
|
||||
<SellerLogo size="sm" src={data?.storeLogo} alt="store" />
|
||||
<div className="min-w-0">
|
||||
<p className="font-bold text-[15px] truncate">
|
||||
{data?.storeName || "فروشگاه من"}
|
||||
</p>
|
||||
<p className="text-GRAY text-[12px]">پنل مدیریت</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav className="p-2.5 flex flex-col gap-0.5">
|
||||
{NAV.map((n) => (
|
||||
<Link
|
||||
key={n.to}
|
||||
to={n.to}
|
||||
prefetch="intent"
|
||||
className={`flex items-center gap-3 px-3.5 py-3 rounded-xl text-[14.5px] font-semibold transition-colors ${
|
||||
isActive(n)
|
||||
? "bg-BLACK text-white"
|
||||
: "text-BLACK2 hover:bg-WHITE2"
|
||||
}`}
|
||||
>
|
||||
<n.icon size={20} />
|
||||
{n.label}
|
||||
</Link>
|
||||
))}
|
||||
<Link
|
||||
to="/"
|
||||
className="flex items-center gap-3 px-3.5 py-3 rounded-xl text-[14.5px] font-semibold text-BLACK2 hover:bg-WHITE2 transition-colors"
|
||||
>
|
||||
<ArrowRight size={20} />
|
||||
بازگشت به فروشگاه
|
||||
</Link>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{/* Page content */}
|
||||
<div className="min-w-0">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user