feat : add section fastSell and add section nowSell and add particle bg

This commit is contained in:
Ali Josheghani
2024-05-27 01:03:29 +03:30
parent c14e025ad9
commit 17922b0206
19 changed files with 993 additions and 314 deletions

904
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,9 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@tsparticles/engine": "^3.4.0",
"@tsparticles/react": "^3.0.0",
"@tsparticles/slim": "^3.4.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",

30
src/assets/bg/banner.svg Normal file
View File

@@ -0,0 +1,30 @@
<svg width="1226" height="437" viewBox="0 0 1226 437" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.03">
<path d="M1338.43 304.479C1285.14 344.06 1175.84 453.131 1165.01 572.768C1151.46 722.313 944.691 810.879 734.87 782.593C525.049 754.306 260.787 354.025 42.457 575.648" stroke="#181417" stroke-width="2"/>
<path d="M1361.56 340.17C1308.26 379.751 1198.97 488.822 1188.13 608.459C1174.59 758.004 967.819 846.57 757.998 818.284C548.177 789.998 283.915 389.716 65.5853 611.339" stroke="#181417" stroke-width="2"/>
<path d="M1275.37 127.479C1222.08 167.06 1112.79 276.132 1101.95 395.768C1088.4 545.314 881.637 633.879 671.816 605.593C461.995 577.307 197.733 177.026 -20.5965 398.649" stroke="#181417" stroke-width="2"/>
<path d="M1207.21 -40.7501C1153.92 -1.16903 1044.62 107.902 1033.79 227.539C1020.24 377.084 813.471 465.65 603.65 437.364C393.829 409.078 129.567 8.79618 -88.7629 230.419" stroke="#181417" stroke-width="2"/>
<path d="M1146.35 -190.955C1093.05 -151.374 983.762 -42.3028 972.923 77.3337C959.374 226.879 752.608 315.445 542.787 287.159C332.966 258.873 68.704 -141.409 -149.626 80.2139" stroke="#181417" stroke-width="2"/>
<path d="M1078.18 -359.185C1024.89 -319.604 915.595 -210.533 904.756 -90.8961C891.208 58.6495 684.441 147.215 474.621 118.929C264.8 90.6429 0.537651 -309.639 -217.792 -88.0158" stroke="#181417" stroke-width="2"/>
<path d="M1010.01 -527.414C956.721 -487.833 847.429 -378.762 836.59 -259.126C823.042 -109.58 616.275 -21.0143 406.454 -49.3005C196.633 -77.5866 -67.6288 -477.868 -285.959 -256.245" stroke="#181417" stroke-width="2"/>
<path d="M1370.94 382.33C1317.65 421.912 1208.35 530.983 1197.51 650.619C1183.97 800.165 977.199 888.731 767.378 860.444C557.557 832.158 293.295 431.877 74.9654 653.5" stroke="#181417" stroke-width="2"/>
<path d="M1284.75 169.64C1231.46 209.221 1122.17 318.292 1111.33 437.929C1097.78 587.474 891.017 676.04 681.196 647.754C471.375 619.468 207.113 219.186 -11.2164 440.809" stroke="#181417" stroke-width="2"/>
<path d="M1216.59 1.41051C1163.3 40.9916 1054 150.063 1043.17 269.699C1029.62 419.245 822.851 507.811 613.03 479.524C403.209 451.238 138.947 50.9568 -79.3828 272.58" stroke="#181417" stroke-width="2"/>
<path d="M1155.73 -148.795C1102.43 -109.213 993.142 -0.142145 982.303 119.494C968.755 269.04 761.988 357.606 552.167 329.319C342.346 301.033 78.0842 -99.2482 -140.246 122.375" stroke="#181417" stroke-width="2"/>
<path d="M1087.56 -317.024C1034.27 -277.443 924.975 -168.372 914.137 -48.7354C900.588 100.81 693.822 189.376 484.001 161.09C274.18 132.804 9.91778 -267.478 -208.412 -45.8552" stroke="#181417" stroke-width="2"/>
<path d="M1019.39 -485.254C966.101 -445.673 856.809 -336.602 845.97 -216.965C832.422 -67.4196 625.655 21.1461 415.834 -7.14008C206.013 -35.4262 -58.2486 -435.708 -276.578 -214.085" stroke="#181417" stroke-width="2"/>
<path d="M1379.98 428.422C1326.69 468.003 1217.4 577.074 1206.56 696.711C1193.01 846.256 986.246 934.822 776.425 906.536C566.604 878.25 302.342 477.968 84.0126 699.591" stroke="#181417" stroke-width="2"/>
<path d="M1293.8 215.732C1240.51 255.313 1131.22 364.384 1120.38 484.021C1106.83 633.566 900.064 722.132 690.243 693.846C480.423 665.56 216.161 265.278 -2.1693 486.901" stroke="#181417" stroke-width="2"/>
<path d="M1225.64 47.5021C1172.34 87.0832 1063.05 196.154 1052.21 315.791C1038.66 465.337 831.898 553.902 622.077 525.616C412.256 497.33 147.994 97.0484 -70.3356 318.671" stroke="#181417" stroke-width="2"/>
<path d="M1164.77 -102.703C1111.48 -63.1219 1002.19 45.9494 991.35 165.586C977.802 315.131 771.035 403.697 561.214 375.411C351.393 347.125 87.1314 -53.1567 -131.198 168.466" stroke="#181417" stroke-width="2"/>
<path d="M1096.61 -270.933C1043.31 -231.352 934.023 -122.28 923.184 -2.64387C909.635 146.902 702.869 235.467 493.048 207.181C283.227 178.895 18.965 -221.386 -199.365 0.236399" stroke="#181417" stroke-width="2"/>
<path d="M1028.44 -439.162C975.148 -399.581 865.856 -290.51 855.017 -170.873C841.469 -21.3278 634.702 67.2379 424.881 38.9517C215.06 10.6656 -49.2015 -389.616 -267.531 -167.993" stroke="#181417" stroke-width="2"/>
<path d="M957.839 -613.4C904.547 -573.819 795.255 -464.748 784.416 -345.111C770.868 -195.566 564.101 -107 354.281 -135.286C144.46 -163.572 -119.802 -563.854 -338.132 -342.231" stroke="#181417" stroke-width="2"/>
<path d="M1299.26 262.476C1245.97 302.057 1136.68 411.128 1125.84 530.765C1112.29 680.31 905.524 768.876 695.703 740.59C485.882 712.304 221.621 312.022 3.29066 533.645" stroke="#181417" stroke-width="2"/>
<path d="M1231.1 94.246C1177.8 133.827 1068.51 242.898 1057.67 362.535C1044.12 512.08 837.358 600.646 627.537 572.36C417.716 544.074 153.454 143.792 -64.8757 365.415" stroke="#181417" stroke-width="2"/>
<path d="M1170.23 -55.9589C1116.94 -16.3778 1007.65 92.6935 996.81 212.33C983.262 361.876 776.495 450.441 566.674 422.155C356.853 393.869 92.5913 -6.41256 -125.739 215.21" stroke="#181417" stroke-width="2"/>
<path d="M1102.07 -224.189C1048.77 -184.608 939.482 -75.5362 928.644 44.1003C915.095 193.646 708.329 282.211 498.508 253.925C288.687 225.639 24.4248 -174.642 -193.905 46.9805" stroke="#181417" stroke-width="2"/>
<path d="M1033.9 -392.418C980.608 -352.837 871.316 -243.766 860.477 -124.129C846.929 25.4163 640.162 113.982 430.341 85.6959C220.52 57.4097 -43.7415 -342.872 -262.071 -121.249" stroke="#181417" stroke-width="2"/>
<path d="M963.299 -566.656C910.007 -527.075 800.715 -418.003 789.876 -298.367C776.328 -148.821 569.561 -60.2558 359.74 -88.5419C149.919 -116.828 -114.342 -517.11 -332.672 -295.487" stroke="#181417" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,23 @@
import React from "react";
const LoaderSpin = ({ children }: { children: React.ReactNode }) => {
return (
<div className="relative w-full h-full flex justify-center items-center">
<svg className="max-md:w-32 max-md:h-32 w-52 h-52" viewBox="0 0 50 50">
<circle
className="path stroke-yellow-600"
cx="25"
cy="25"
r="20"
fill="none"
strokeWidth="4"
strokeDasharray={126}
strokeDashoffset={126}
></circle>
</svg>
<div className="absolute left-1/2 -translate-x-1/2">{children}</div>
</div>
);
};
export default LoaderSpin;

View File

@@ -0,0 +1,118 @@
import { useEffect, useMemo, useState } from "react";
import Particles, { initParticlesEngine } from "@tsparticles/react";
import {
type Container,
type ISourceOptions,
MoveDirection,
OutMode,
} from "@tsparticles/engine";
// import { loadAll } from "@tsparticles/all"; // if you are going to use `loadAll`, install the "@tsparticles/all" package too.
// import { loadFull } from "tsparticles"; // if you are going to use `loadFull`, install the "tsparticles" package too.
import { loadSlim } from "@tsparticles/slim"; // if you are going to use `loadSlim`, install the "@tsparticles/slim" package too.
// import { loadBasic } from "@tsparticles/basic"; // if you are going to use `loadBasic`, install the "@tsparticles/basic" package too.
export default function Particle() {
const [init, setInit] = useState(false);
// this should be run only once per application lifetime
useEffect(() => {
initParticlesEngine(async (engine) => {
// you can initiate the tsParticles instance (engine) here, adding custom shapes or presets
// this loads the tsparticles package bundle, it's the easiest method for getting everything ready
// starting from v2 you can add only the features you need reducing the bundle size
//await loadAll(engine);
//await loadFull(engine);
await loadSlim(engine);
//await loadBasic(engine);
}).then(() => {
setInit(true);
});
}, []);
const particlesLoaded = async (container?: Container): Promise<void> => {
console.log(container);
};
const options: ISourceOptions = useMemo(
() => ({
background: {
color: {
value: "",
},
},
fpsLimit: 120,
interactivity: {
events: {
onClick: {
enable: true,
mode: "push",
},
onHover: {
enable: true,
mode: "repulse",
},
},
modes: {
push: {
quantity: 4,
},
repulse: {
distance: 200,
duration: 0.4,
},
},
},
particles: {
color: {
value: "#ffffff",
},
links: {
color: "#ffffff",
distance: 150,
enable: true,
opacity: 0.5,
width: 1,
},
move: {
direction: MoveDirection.none,
enable: true,
outModes: {
default: OutMode.out,
},
random: false,
speed: 3,
straight: false,
},
number: {
density: {
enable: true,
},
value: 80,
},
opacity: {
value: 0.5,
},
shape: {
type: "circle",
},
size: {
value: { min: 1, max: 5 },
},
},
detectRetina: true,
}),
[]
);
if (init) {
return (
<Particles
id="tsparticles"
particlesLoaded={particlesLoaded}
options={options}
/>
);
}
return <></>;
}

View File

@@ -0,0 +1,14 @@
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>
<div className="absolute w-24 h-24 border-4 border-yellow-400 rounded-full animate-pulse delay-75"></div>
</div>
);
};
export default PulsatingCircle;

View File

@@ -0,0 +1,27 @@
import { useState, useEffect } from "react";
import { TypewriterProps } from "../../types/props";
const Typewriter = ({ text, speed = 100 }: TypewriterProps) => {
const [displayedText, setDisplayedText] = useState<string>("");
const [index, setIndex] = useState<number>(0);
useEffect(() => {
if (index < text.length) {
const timeoutId = setTimeout(() => {
setDisplayedText((prev) => prev + text.charAt(index));
setIndex((prev) => prev + 1);
}, speed);
return () => clearTimeout(timeoutId);
}
}, [index, text, speed]);
return (
<div>
<h1 className="text-2xl md:text-3xl lg:text-4xl relative text-center">
{displayedText}
</h1>
</div>
);
};
export default Typewriter;

View File

@@ -29,8 +29,8 @@
color: #fff; color: #fff;
} }
.glass { .glass {
@apply backdrop-blur-[19px] backdrop-saturate-[200%] bg-[rgba(17,25,40,0.25)] rounded-xl; @apply backdrop-blur-[5px] backdrop-saturate-[10%] bg-[rgba(17,25,40,0.25)] rounded-xl;
-webkit-backdrop-filter: blur(19px) saturate(200%); -webkit-backdrop-filter: blur(5px) saturate(10%);
} }
/* برای مرورگرهای WebKit (مثل Chrome و Safari) */ /* برای مرورگرهای WebKit (مثل Chrome و Safari) */
::-webkit-scrollbar { ::-webkit-scrollbar {
@@ -69,4 +69,17 @@
border: 3px solid transparent; border: 3px solid transparent;
background-clip: content-box; background-clip: content-box;
} }
.path {
animation: dash 2s linear forwards;
}
@keyframes dash {
from {
stroke-dashoffset: 126;
}
to {
stroke-dashoffset: -20;
}
}
} }

View File

@@ -1,12 +1,14 @@
import { Outlet } from "react-router-dom"; import { Outlet } from "react-router-dom";
import Header from "../components/header"; import Header from "../components/header";
import Footer from "../components/footer"; import Footer from "../components/footer";
import Particle from "../components/particle";
const Layout = () => { const Layout = () => {
return ( return (
<div <div
className={`relative bg-noisy w-full flex flex-col justify-between min-h-screen`} className={`relative bg-noisy w-full flex flex-col justify-between min-h-screen`}
> >
<Particle />
<div className="relative w-full h-full"> <div className="relative w-full h-full">
<Header /> <Header />
<main className="w-full h-full px-5 py-0"> <main className="w-full h-full px-5 py-0">

View File

@@ -1,11 +1,15 @@
import Alert from "../../components/alert/Alert"; import FastSell from "./section/fastSell/FastSell";
import Intro from "./section/intro/Intro";
import NowSell from "./section/nowSell/NowSell";
const Shop = () => { const Shop = () => {
return ( return (
<div className="relative w-full h-full px-4 py-2"> <div className="relative w-full h-full py-2">
<Alert type="warning" message=""> <div className="relative w-full h-full glass px-4 py-2">
به زودی صفحه فروشگاه اضافه می شود <Intro />
</Alert> <FastSell />
<NowSell />
</div>
</div> </div>
); );
}; };

View File

@@ -0,0 +1,19 @@
import { FaPowerOff } from "react-icons/fa6";
import LoaderSpin from "../../../../components/loaderSpin";
import Typewriter from "../../../../components/typeWriter";
const FastSell = () => {
return (
<div className="relative w-full h-full md:mt-14 mb-8 flex justify-center items-center">
<div className="w-full h-full flex flex-col gap-5 justify-center items-center">
<LoaderSpin>
<FaPowerOff className="max-md:text-6xl text-8xl text-white" />
</LoaderSpin>
<Typewriter text="میبینی ؟ همینقدر" />
<Typewriter text="ساده و سریــــــــــــــع" />
</div>
</div>
);
};
export default FastSell;

View File

@@ -0,0 +1,30 @@
import Button from "../../../../components/button";
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">
<div className="w-full h-full flex flex-col gap-8 justify-center mx-auto items-center">
<h1 className="text-start flex flex-col gap-3 md:gap-4 text-3xl md:text-4xl lg:text-5xl">
<span className="inline-block">بزرگترین فروشگاه</span>
<span className="text-yellow-600 font-bold max-md:text-center">
کاهش پینگ
</span>{" "}
<span className="inline-block max-md:text-center">در ایران</span>
</h1>
<p className="text-center text-xl text-gray-600">
سال ها تجربه پشت یک کانفیگ شماست
</p>
<Button>همین الان میخرم</Button>
</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"
alt="intro"
className="w-60 md:w-72 lg:w-80"
/>
</div>
</div>
);
};
export default Intro;

View File

@@ -0,0 +1,13 @@
import Content from "./components/Content";
const NowSell = () => {
return (
<div className="relative w-full h-full mt-16 p-5">
<div className="relative w-full max-md:h-[15rem] md:h-[20rem] lg:h-[25rem] p-2 rounded-2xl bg-white shadow-lg bg-banner bg-center bg-cover shadow-current flex justify-center items-center">
<Content />
</div>
</div>
);
};
export default NowSell;

View File

@@ -0,0 +1,23 @@
import Button from "../../../../../components/button";
const Content = () => {
return (
<div className="w-full h-full flex flex-col text-center max-md:gap-3 gap-5 justify-center text-black items-center max-md:py-5 px-5 py-10">
<h1 className="text-4xl max-md:text-2xl lg:text-5xl font-bold">
با چندین سال
</h1>
<h1 className="text-4xl max-md:text-2xl lg:text-5xl font-bold">
تجربـــــــــــــــــــه
</h1>
<p className="text-2xl max-md:text-sm text-gray-500">
بهترین نتیجه رو بهتون تقدیم میکنیم
</p>
<Button extra="!bg-black text-white text-2xl max-md:text-lg max-md:!py-2 mt-4 !py-4 !px-10 !rounded-xl">
{" "}
همین الان میخرم
</Button>
</div>
);
};
export default Content;

View File

@@ -0,0 +1,5 @@
const ProductList = () => {
return <div className="relative w-full h-full"></div>;
};
export default ProductList;

View File

@@ -15,22 +15,10 @@ const Tutorials = () => {
}, },
{ {
id: 3, id: 3,
name: "آموزش cisco در اندروید",
},
{
id: 4,
name: "آموزش cisco در آیفون",
},
{
id: 5,
name: "آموزش سرویس مولتی", name: "آموزش سرویس مولتی",
}, },
{ {
id: 6, id: 4,
name: "آموزش cisco در ویندوز",
},
{
id: 7,
name: "آموزش open vpn در اندروید", name: "آموزش open vpn در اندروید",
}, },
]; ];

View File

@@ -20,35 +20,21 @@ const Learn = ({ activeTutorial, tutorialList }: LearnProps) => {
{ {
id: 3, id: 3,
images: [ images: [
{ urlimg: "https://persain-game.com/front_end/img/cisco-android1.jpg" }, { urlimg: "https://persain-game.com/front_end/img/1-eshterki.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/cisco-android2.jpg" }, { urlimg: "https://persain-game.com/front_end/img/2-eshteraki.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/cisco-android3.jpg" }, { urlimg: "https://persain-game.com/front_end/img/3-eshteraki.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/4-eshteraki.jpg" },
], ],
}, },
{ {
id: 4, id: 4,
images: [ images: [
{ urlimg: "https://persain-game.com/front_end/img/cisco-iphone1.jpg" }, { urlimg: "https://persain-game.com/front_end/img/1-eshterki.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/cisco-iphone2.jpg" }, { urlimg: "https://persain-game.com/front_end/img/2-eshteraki.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/cisco-iphone3.jpg" }, { urlimg: "https://persain-game.com/front_end/img/3-eshteraki.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/4-eshteraki.jpg" },
], ],
}, },
{
id: 5,
images: [],
},
{
id: 6,
images: [
{ urlimg: "https://persain-game.com/front_end/img/cisco-pc.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/cisco-pc2.jpg" },
{ urlimg: "https://persain-game.com/front_end/img/cisco-pc3.jpg" },
],
},
{
id: 7,
images: [],
},
]; ];
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [list, setList] = useState( const [list, setList] = useState(
@@ -85,12 +71,13 @@ const Learn = ({ activeTutorial, tutorialList }: LearnProps) => {
{tutorialImagesState?.map((i) => { {tutorialImagesState?.map((i) => {
return ( return (
<div key={i.id}> <div key={i.id}>
{i.images?.map((item) => { {i.images?.map((item, index) => {
return ( return (
<img <img
className="w-full md:w-1/2 mb-3 rounded-lg mx-auto h-full" className="w-full md:w-1/2 mb-3 rounded-lg mx-auto h-full"
src={item.urlimg} src={item.urlimg}
alt="images" alt="images"
key={index}
onLoad={(e) => handleLoadingImage(e)} onLoad={(e) => handleLoadingImage(e)}
/> />
); );

View File

@@ -11,7 +11,7 @@ export interface AlertProps {
export interface ButtonProps { export interface ButtonProps {
children: React.ReactNode; children: React.ReactNode;
onClick?: () => void; onClick?: () => void;
extra?: React.CSSProperties; extra?: string;
} }
// begin Route // begin Route
@@ -63,3 +63,9 @@ export type LearnProps = {
activeTutorial: number; activeTutorial: number;
tutorialList: TutorialList; tutorialList: TutorialList;
}; };
// begin TypeWriter.tsx
interface TypewriterProps {
text: string;
speed?: number; // سرعت تایپ در میلی‌ثانیه
}

View File

@@ -5,6 +5,16 @@ export default {
extend: { extend: {
backgroundImage: { backgroundImage: {
noisy: "url('/src/assets/bg/noisy.png')", noisy: "url('/src/assets/bg/noisy.png')",
banner: "url('/src/assets/bg/banner.svg')",
},
animation: {
pulse: "pulse 1.5s ease-in-out infinite",
},
keyframes: {
pulse: {
"0%": { transform: "scale(1)", opacity: "1" },
"100%": { transform: "scale(1.5)", opacity: "0" },
},
}, },
}, },
}, },