162 lines
4.4 KiB
TypeScript
162 lines
4.4 KiB
TypeScript
import React from "react";
|
|
import { cn } from "../lib/cn";
|
|
|
|
type GridWrapperProps = {
|
|
children: React.ReactNode;
|
|
desktop: number; // تعداد ستونها در دسکتاپ
|
|
mobile: number; // تعداد ستونها در موبایل
|
|
gapDesktop?: number; // فاصله بین آیتمها در دسکتاپ. اگر مقدار > 12 باشد به عنوان px تفسیر میشود (مثلاً 24 => 24px)
|
|
gapMobile?: number; // فاصله بین آیتمها در موبایل. اگر مقدار > 12 باشد به عنوان px تفسیر میشود
|
|
className?: string;
|
|
};
|
|
|
|
const GRID_COLS_CLASS: Record<number, string> = {
|
|
1: "grid-cols-1",
|
|
2: "grid-cols-2",
|
|
3: "grid-cols-3",
|
|
4: "grid-cols-4",
|
|
5: "grid-cols-5",
|
|
6: "grid-cols-6",
|
|
7: "grid-cols-7",
|
|
8: "grid-cols-8",
|
|
9: "grid-cols-9",
|
|
10: "grid-cols-10",
|
|
11: "grid-cols-11",
|
|
12: "grid-cols-12",
|
|
};
|
|
|
|
const MD_GRID_COLS_CLASS: Record<number, string> = {
|
|
1: "md:grid-cols-1",
|
|
2: "md:grid-cols-2",
|
|
3: "md:grid-cols-3",
|
|
4: "md:grid-cols-4",
|
|
5: "md:grid-cols-5",
|
|
6: "md:grid-cols-6",
|
|
7: "md:grid-cols-7",
|
|
8: "md:grid-cols-8",
|
|
9: "md:grid-cols-9",
|
|
10: "md:grid-cols-10",
|
|
11: "md:grid-cols-11",
|
|
12: "md:grid-cols-12",
|
|
};
|
|
|
|
// نسخهی دسکتاپ با پیشوند lg: به صورت literal تا با purge مشکلی نداشته باشد
|
|
const LG_GRID_COLS_CLASS: Record<number, string> = {
|
|
1: "lg:grid-cols-1",
|
|
2: "lg:grid-cols-2",
|
|
3: "lg:grid-cols-3",
|
|
4: "lg:grid-cols-4",
|
|
5: "lg:grid-cols-5",
|
|
6: "lg:grid-cols-6",
|
|
7: "lg:grid-cols-7",
|
|
8: "lg:grid-cols-8",
|
|
9: "lg:grid-cols-9",
|
|
10: "lg:grid-cols-10",
|
|
11: "lg:grid-cols-11",
|
|
12: "lg:grid-cols-12",
|
|
};
|
|
|
|
// نگاشت Gap بر اساس scale رایج Tailwind: gap-N که هر N معادل 4px است (N * 4px)
|
|
const GAP_CLASS: Record<number, string> = {
|
|
0: "gap-0",
|
|
1: "gap-1",
|
|
2: "gap-2",
|
|
3: "gap-3",
|
|
4: "gap-4",
|
|
5: "gap-5",
|
|
6: "gap-6",
|
|
7: "gap-7",
|
|
8: "gap-8",
|
|
9: "gap-9",
|
|
10: "gap-10",
|
|
11: "gap-11",
|
|
12: "gap-12",
|
|
13: "gap-13",
|
|
14: "gap-14",
|
|
15: "gap-15",
|
|
16: "gap-16",
|
|
17: "gap-17",
|
|
18: "gap-18",
|
|
19: "gap-19",
|
|
20: "gap-20",
|
|
21: "gap-21",
|
|
22: "gap-22",
|
|
23: "gap-23",
|
|
24: "gap-24",
|
|
};
|
|
|
|
const LG_GAP_CLASS: Record<number, string> = {
|
|
0: "lg:gap-0",
|
|
1: "lg:gap-1",
|
|
2: "lg:gap-2",
|
|
3: "lg:gap-3",
|
|
4: "lg:gap-4",
|
|
5: "lg:gap-5",
|
|
6: "lg:gap-6",
|
|
7: "lg:gap-7",
|
|
8: "lg:gap-8",
|
|
9: "lg:gap-9",
|
|
10: "lg:gap-10",
|
|
11: "lg:gap-11",
|
|
12: "lg:gap-12",
|
|
13: "lg:gap-13",
|
|
14: "lg:gap-14",
|
|
15: "lg:gap-15",
|
|
16: "lg:gap-16",
|
|
17: "lg:gap-17",
|
|
18: "lg:gap-18",
|
|
19: "lg:gap-19",
|
|
20: "lg:gap-20",
|
|
21: "lg:gap-21",
|
|
22: "lg:gap-22",
|
|
23: "lg:gap-23",
|
|
24: "lg:gap-24",
|
|
};
|
|
|
|
function clampToRange(value: number, min: number, max: number): number {
|
|
return Math.max(min, Math.min(max, value));
|
|
}
|
|
|
|
function getGridColsClass(count: number): string {
|
|
const safe = clampToRange(count, 1, 12);
|
|
return GRID_COLS_CLASS[safe];
|
|
}
|
|
|
|
function getLgGridColsClass(count: number): string {
|
|
const safe = clampToRange(count, 1, 12);
|
|
return LG_GRID_COLS_CLASS[safe];
|
|
}
|
|
|
|
function getMdGridColsClass(count: number): string {
|
|
const safe = clampToRange(count, 1, 12);
|
|
return MD_GRID_COLS_CLASS[safe];
|
|
}
|
|
|
|
function getGapClass(value?: number): string | undefined {
|
|
if (value === undefined) return undefined;
|
|
// اگر کاربر مقدار را به صورت px فرستاده باشد (بزرگتر از 12)، آن را به scale تبدیل میکنیم: N = round(px/4)
|
|
const interpretedAsScale = value > 12 ? Math.round(value / 4) : value;
|
|
const safe = clampToRange(interpretedAsScale, 0, 24);
|
|
return GAP_CLASS[safe];
|
|
}
|
|
|
|
function getLgGapClass(value?: number): string | undefined {
|
|
if (value === undefined) return undefined;
|
|
const interpretedAsScale = value > 12 ? Math.round(value / 4) : value;
|
|
const safe = clampToRange(interpretedAsScale, 0, 24);
|
|
return LG_GAP_CLASS[safe];
|
|
}
|
|
|
|
export default function GridWrapper(props: GridWrapperProps) {
|
|
const { children, desktop, mobile, className, gapDesktop = 4, gapMobile = 4 } = props;
|
|
|
|
const mobileCols = getGridColsClass(mobile);
|
|
const desktopColsMd = getMdGridColsClass(desktop);
|
|
const desktopColsLg = getLgGridColsClass(desktop);
|
|
|
|
const mobileGap = getGapClass(gapMobile);
|
|
const desktopGap = getLgGapClass(gapDesktop);
|
|
|
|
return <div className={cn("grid", mobileCols, desktopColsMd, desktopColsLg, mobileGap, desktopGap, className)}>{children}</div>;
|
|
}
|