feat : add section (productList , bestQuality) in shop page
This commit is contained in:
5
src/common/modal/index.tsx
Normal file
5
src/common/modal/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
const Modal = () => {
|
||||
return <div>index</div>;
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
@@ -1,9 +1,13 @@
|
||||
import { ButtonProps } from "../../types/props";
|
||||
|
||||
function Button({ children, onClick, extra }: ButtonProps) {
|
||||
function Button({ children, onClick, extra, active }: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
className={`px-4 py-1 md:px-5 md:py-2 rounded-md transition duration-300 ease-in-out transform bg-white text-[#333] hover:bg-gray-600 hover:text-white ${extra}`}
|
||||
className={`px-4 py-1 md:px-5 md:py-2 rounded-md transition duration-300 ease-in-out transform bg-white text-[#333] hover:bg-gray-600 hover:text-white ${
|
||||
active
|
||||
? "bg-yellow-600 shadow-yellow-600 hover:shadow-gray-600 shadow-lg text-white"
|
||||
: ""
|
||||
} ${extra}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
|
||||
50
src/components/productBox/index.tsx
Normal file
50
src/components/productBox/index.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { AM, EC, GA, US, GD, GB } from "country-flag-icons/react/1x1";
|
||||
import { ProductBoxProps } from "../../types/props";
|
||||
import Button from "../button";
|
||||
|
||||
const ProductBox = ({
|
||||
title,
|
||||
space,
|
||||
users,
|
||||
price,
|
||||
btnText,
|
||||
variant,
|
||||
}: ProductBoxProps) => {
|
||||
return (
|
||||
<div
|
||||
className={`p-4 w-full h-full flex flex-col gap-3 justify-center items-center rounded-lg shadow-inner ${
|
||||
variant === 1
|
||||
? "shadow-purple-800 bg-purple-600"
|
||||
: variant === 2
|
||||
? "shadow-orange-800 bg-orange-600"
|
||||
: variant === 3 && "shadow-indigo-800 bg-indigo-600"
|
||||
} bg-cover bg-center bg-banner`}
|
||||
>
|
||||
<h1 className="max-md:text-xl md:text-2xl font-bold">{title}</h1>
|
||||
<div className="w-full h-full p-2 flex gap-2 justify-between items-center">
|
||||
<div className="w-full h-full flex flex-col gap-2">
|
||||
<h2 className="max-md:text-lg md:text-xl text-center">{space} گیگ</h2>
|
||||
<p className="max-md:text-sm md:text-lg text-center">
|
||||
{users} کاربره
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full h-full gap-4 grid grid-cols-3">
|
||||
<GA className="w-5 lg:w-7 rounded-md" />
|
||||
<US className="w-5 lg:w-7 rounded-md" />
|
||||
<EC className="w-5 lg:w-7 rounded-md" />
|
||||
<AM className="w-5 lg:w-7 rounded-md" />
|
||||
<GB className="w-5 lg:w-7 rounded-md" />
|
||||
<GD className="w-5 lg:w-7 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-full bg-purple-950 text-center rounded-lg md:text-xl font-bold shadow-inner shadow-purple-600 px-4 py-2">
|
||||
{price} تومان
|
||||
</div>
|
||||
<div className="w-full h-full grid grid-cols-1">
|
||||
<Button extra="shadow-inner shadow-gray-400">{btnText}</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductBox;
|
||||
@@ -2,11 +2,11 @@ import { FC } from "react";
|
||||
|
||||
const PulsatingCircle: FC = () => {
|
||||
return (
|
||||
<div className="relative flex justify-center items-center w-52 h-52">
|
||||
<div className="absolute flex justify-center items-center w-24 h-24 border-4 border-yellow-400 rounded-full z-10">
|
||||
<span className="text-4xl text-yellow-400">1</span>
|
||||
<div className="relative flex justify-center items-center w-full h-full">
|
||||
<div className="relative flex justify-center items-center max-md:w-32 max-md:h-32 w-52 h-52 max-md:border-[10px] border-[15px] border-yellow-600 rounded-full z-10">
|
||||
<span className="text-6xl md:text-8xl text-white">1</span>
|
||||
</div>
|
||||
<div className="absolute w-24 h-24 border-4 border-yellow-400 rounded-full animate-pulse delay-75"></div>
|
||||
<div className="absolute max-md:w-32 max-md:h-32 w-52 h-52 border-4 border-yellow-600 rounded-full animate-pulse"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import BestQuality from "./section/bestQuality/BestQuality";
|
||||
import FastSell from "./section/fastSell/FastSell";
|
||||
import Intro from "./section/intro/Intro";
|
||||
import NowSell from "./section/nowSell/NowSell";
|
||||
import ProductList from "./section/productList/ProductList";
|
||||
|
||||
const Shop = () => {
|
||||
return (
|
||||
@@ -9,6 +11,8 @@ const Shop = () => {
|
||||
<Intro />
|
||||
<FastSell />
|
||||
<NowSell />
|
||||
<ProductList />
|
||||
<BestQuality />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
25
src/pages/shop/section/bestQuality/BestQuality.tsx
Normal file
25
src/pages/shop/section/bestQuality/BestQuality.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import PulsatingCircle from "../../../../components/pulsatingCircle";
|
||||
|
||||
const BestQuality = () => {
|
||||
return (
|
||||
<div className="w-full h-full mt-4 md:mt-10 mb-10 flex gap-10 flex-col justify-center items-center">
|
||||
<div className="w-full h-full flex justify-center items-center">
|
||||
<PulsatingCircle />
|
||||
</div>
|
||||
<div className="w-full h-full flex flex-col gap-2 md:gap-4 justify-center items-center">
|
||||
<h1 className="max-md:text-xl md:text-4xl font-bold">
|
||||
به عنوان{" "}
|
||||
<span className="max-md:text-xl md:text-5xl text-yellow-600 font-bold">
|
||||
اولین و بهترین
|
||||
</span>{" "}
|
||||
ارائه دهنده{" "}
|
||||
</h1>
|
||||
<h1 className="relative max-md:right-10 max-lg:right-20 lg:right-40 max-md:text-xl md:text-4xl font-bold">
|
||||
مفتخریم که در خدمت شما باشیم
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BestQuality;
|
||||
@@ -1,5 +1,7 @@
|
||||
import Button from "../../../../components/button";
|
||||
|
||||
import Rocket3D from "../../../../assets/ui/Rocket.png";
|
||||
|
||||
const Intro = () => {
|
||||
return (
|
||||
<div className="relative w-full h-full md:pt-40 mb-16 md:mb-32 gap-6 grid grid-cols-1 py-8 md:grid-cols-2">
|
||||
@@ -18,9 +20,9 @@ const Intro = () => {
|
||||
</div>
|
||||
<div className="w-full h-full flex justify-center py-4 mx-auto items-center">
|
||||
<img
|
||||
src="https://persain-game.com/front_end/img/Iphone%2015.png"
|
||||
src={Rocket3D}
|
||||
alt="intro"
|
||||
className="w-60 md:w-72 lg:w-80"
|
||||
className="w-60 md:w-72 lg:w-[25rem] animate-bounce"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
import { useState } from "react";
|
||||
import ButtonList from "./components/ButtonList";
|
||||
import ListAllProduct from "./components/ListAllProduct";
|
||||
|
||||
const ProductList = () => {
|
||||
return <div className="relative w-full h-full"></div>;
|
||||
const [activeId, setActiveId] = useState(1);
|
||||
const ProductsList = [
|
||||
{ id: 1, title: "سرویس اشتراکی" },
|
||||
{ id: 2, title: "سرویس گیمینگ" },
|
||||
{ id: 3, title: "سرویس مولتی" },
|
||||
];
|
||||
return (
|
||||
<div className="relative w-full h-full max-md:mt-4 md:mt-8 ">
|
||||
<div className="w-full h-full gap-4 md:gap-6 flex flex-col p-5 justify-center items-center">
|
||||
<h1 className="max-md:text-lg text-center text-2xl font-bold">
|
||||
برای انتخاب پلن مورد نظر کلیک کنید تا پلن و سرویس ها براتون نمایش داده
|
||||
شود
|
||||
</h1>
|
||||
<ButtonList
|
||||
ProductsList={ProductsList}
|
||||
activeId={activeId}
|
||||
setActiveId={setActiveId}
|
||||
/>
|
||||
<ListAllProduct activeId={activeId} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductList;
|
||||
|
||||
27
src/pages/shop/section/productList/components/ButtonList.tsx
Normal file
27
src/pages/shop/section/productList/components/ButtonList.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import Button from "../../../../../components/button";
|
||||
import { ButtonListProps } from "../../../../../types/props";
|
||||
|
||||
const ButtonList = ({
|
||||
ProductsList,
|
||||
activeId,
|
||||
setActiveId,
|
||||
}: ButtonListProps) => {
|
||||
return (
|
||||
<div className="w-full h-full gap-4 grid max-sm:grid-cols-1 max-md:grid-cols-2 md:grid-cols-4 ">
|
||||
{ProductsList?.map((i) => {
|
||||
return (
|
||||
<Button
|
||||
key={i.id}
|
||||
active={i.id === activeId}
|
||||
extra="py-4 text-lg"
|
||||
onClick={() => setActiveId(i.id)}
|
||||
>
|
||||
{i.title}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ButtonList;
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import ProductBox from "../../../../../components/productBox";
|
||||
|
||||
const ListAllProduct = ({ activeId }: { activeId: number }) => {
|
||||
const Product = [
|
||||
{
|
||||
id: 1,
|
||||
data: [
|
||||
{ id: 1, title: "مولتی سرور ۱", users: 2, price: "100/000", space: 40 },
|
||||
{ id: 2, title: "مولتی سرور ۲", users: 2, price: "200/000", space: 60 },
|
||||
{
|
||||
id: 3,
|
||||
title: "مولتی سرور ۳",
|
||||
users: 1,
|
||||
price: "300/000",
|
||||
space: 100,
|
||||
},
|
||||
{ id: 4, title: "مولتی سرور ۴", users: 3, price: "400/000", space: 50 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
title: " کاهش پینگ ۱",
|
||||
users: 2,
|
||||
price: "1/000/000",
|
||||
space: 40,
|
||||
},
|
||||
{ id: 2, title: "کاهش پینگ ۲", users: 2, price: "500/000", space: 60 },
|
||||
{
|
||||
id: 3,
|
||||
title: "کاهش پینگ ۳",
|
||||
users: 1,
|
||||
price: "800/000",
|
||||
space: 100,
|
||||
},
|
||||
{ id: 4, title: "کاهش پینگ ۴", users: 3, price: "200/000", space: 50 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
data: [
|
||||
{ id: 1, title: " سرور بازی ۱", users: 2, price: "50/000", space: 40 },
|
||||
{ id: 2, title: "سرور بازی ۲", users: 2, price: "100/000", space: 60 },
|
||||
{
|
||||
id: 3,
|
||||
title: "سرور بازی ۳",
|
||||
users: 1,
|
||||
price: "700/000",
|
||||
space: 100,
|
||||
},
|
||||
{ id: 4, title: "سرور بازی ۴", users: 3, price: "350/000", space: 50 },
|
||||
],
|
||||
},
|
||||
];
|
||||
const [dataProduct, setDataProduct] = useState(
|
||||
Product?.filter((i) => i.id === activeId)
|
||||
);
|
||||
useEffect(() => {
|
||||
setDataProduct(Product?.filter((i) => i.id === activeId));
|
||||
}, [activeId]);
|
||||
|
||||
return (
|
||||
<div className="w-full h-full border-4 gap-5 border-spacing-1 border-solid border-yellow-600 rounded-lg p-3 grid max-sm:grid-cols-1 max-md:grid-cols-2 max-lg:grid-cols-3 lg:grid-cols-4">
|
||||
{dataProduct?.map((item) => {
|
||||
return (
|
||||
<Fragment key={item.id}>
|
||||
{item.data?.map((i) => {
|
||||
return (
|
||||
<ProductBox
|
||||
key={i.id}
|
||||
variant={item.id}
|
||||
btnText="خرید"
|
||||
price={i.price}
|
||||
space={i.space}
|
||||
title={i.title}
|
||||
users={i.users}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListAllProduct;
|
||||
18
src/types/props.d.ts
vendored
18
src/types/props.d.ts
vendored
@@ -12,6 +12,7 @@ export interface ButtonProps {
|
||||
children: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
extra?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
// begin Route
|
||||
@@ -49,7 +50,7 @@ export interface NavData {
|
||||
}
|
||||
|
||||
// begin ListTutorial.tsx
|
||||
import { SetStateAction } from "react";
|
||||
import { Component, SetStateAction } from "react";
|
||||
|
||||
export type TutorialList = { id: number; name: string }[];
|
||||
|
||||
@@ -69,3 +70,18 @@ interface TypewriterProps {
|
||||
text: string;
|
||||
speed?: number; // سرعت تایپ در میلیثانیه
|
||||
}
|
||||
|
||||
interface ButtonListProps {
|
||||
ProductsList: { id: number; title: string }[];
|
||||
activeId: number;
|
||||
setActiveId: SetStateAction;
|
||||
}
|
||||
|
||||
interface ProductBoxProps {
|
||||
title: string;
|
||||
space: number;
|
||||
users: number;
|
||||
price: string;
|
||||
btnText: string;
|
||||
variant: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user