create product
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import React from "react";
|
||||
import { clx } from "@/helpers/utils";
|
||||
|
||||
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={clx("grid", mobileCols, desktopColsMd, desktopColsLg, mobileGap, desktopGap, className)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ export const Paths = {
|
||||
list: '/requests',
|
||||
},
|
||||
product: {
|
||||
list: '/product/list'
|
||||
list: '/product/list',
|
||||
create: '/product/create'
|
||||
},
|
||||
order: {
|
||||
list: '/order/list'
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ textarea::placeholder {
|
||||
|
||||
@theme {
|
||||
--color-primary: #ffa800;
|
||||
--color-border: #f5f7fc;
|
||||
--color-border: #d0d0d0;
|
||||
--color-secondary: #ebedf5;
|
||||
--color-description: #c3c7dd;
|
||||
--color-desc: #8c90a3;
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import Button from '@/components/Button'
|
||||
import GridWrapper from '@/components/GridWrapper';
|
||||
import Input from '@/components/Input';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import UploadBox from '@/components/UploadBox';
|
||||
import { clx } from '@/helpers/utils';
|
||||
import { AddSquare } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
|
||||
const CreateProduct: FC = () => {
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<div className='flex justify-between items-center'>
|
||||
|
||||
<h1 className='text-lg font-light'>محصول جدید</h1>
|
||||
<Button
|
||||
className='w-fit px-6'
|
||||
>
|
||||
<div className='flex gap-1.5'>
|
||||
<AddSquare size={18} color='black' />
|
||||
<div className='text-[13px] font-light'>محصول جدید</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 bg-white p-6 rounded-3xl '>
|
||||
<div className='font-light'>
|
||||
اطلاعات محصول
|
||||
</div>
|
||||
|
||||
<div className='mt-6 rowTwoInput'>
|
||||
<Input
|
||||
label='عنوان محصول'
|
||||
name='title'
|
||||
onChange={() => { }}
|
||||
/>
|
||||
<Input
|
||||
label='لینک در وبسایت'
|
||||
name='title'
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-6'>
|
||||
<UploadBox
|
||||
label='تصویر محصول'
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-6'>
|
||||
<div>بسته تعداد</div>
|
||||
<div className='mt-2.5 flex gap-4'>
|
||||
<div className='h-8 w-[72px] text-sm rounded-lg border border-[#C3C7DD] flex items-center justify-center'>100</div>
|
||||
<div className='h-8 w-[72px] text-sm rounded-lg border border-[#C3C7DD] flex items-center justify-center'>100</div>
|
||||
<div className='h-8 w-[72px] text-sm rounded-lg border border-[#C3C7DD] flex items-center justify-center'>100</div>
|
||||
<div className={clx(
|
||||
'h-8 w-[72px] text-sm rounded-lg border border-[#C3C7DD] flex items-center justify-center',
|
||||
'border-primary '
|
||||
)}>100</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 bg-white p-6 rounded-3xl '>
|
||||
<h1 className='font-light text-lg'>
|
||||
ویژگی های محصول
|
||||
</h1>
|
||||
|
||||
<div className='mt-6'>
|
||||
<GridWrapper
|
||||
desktop={5}
|
||||
mobile={2}
|
||||
|
||||
>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Checkbox
|
||||
/>
|
||||
<div className='text-sm font-light'>نوع روکش</div>
|
||||
</div>
|
||||
</GridWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateProduct;
|
||||
@@ -9,6 +9,7 @@ import RequestList from '@/pages/requests/RequestList'
|
||||
import ProductList from '@/pages/product/List'
|
||||
import OrdersList from '@/pages/order/List'
|
||||
import FeaturesList from '@/pages/Features/List'
|
||||
import CreateProduct from '@/pages/product/Create'
|
||||
|
||||
const MainRouter: FC = () => {
|
||||
return (
|
||||
@@ -26,6 +27,7 @@ const MainRouter: FC = () => {
|
||||
|
||||
<Route path={Paths.requests.list} element={<RequestList />} />
|
||||
<Route path={Paths.product.list} element={<ProductList />} />
|
||||
<Route path={Paths.product.create} element={<CreateProduct />} />
|
||||
<Route path={Paths.order.list} element={<OrdersList />} />
|
||||
<Route path={Paths.features.list} element={<FeaturesList />} />
|
||||
</Routes>
|
||||
|
||||
@@ -32,7 +32,7 @@ const SideBar: FC = () => {
|
||||
)}
|
||||
>
|
||||
<div className='px-6'>
|
||||
<div className='flex border-b-2 border-border pb-10'>
|
||||
<div className='flex border-b-2 border-[#F5F7FC] pb-10'>
|
||||
<img src={LogoImage} className='w-[120px]' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user