reviews starting

This commit is contained in:
2024-03-28 18:27:11 +05:00
parent 4bd08ed72c
commit 36de0777aa
2 changed files with 345 additions and 158 deletions
-1
View File
@@ -28,7 +28,6 @@ import YouTubeIcon from "@components/icons/YouTubeIcon";
import TelegramIcon from "@components/icons/TelegramIcon";
import { IProject } from "../types/IProject";
import { SortedProject } from "../types/SortedProject";
import { ProjectYear } from "../types/ProjectYear";
import Winners from "@components/Winners";
import { getTime, getDate, getYear } from "date-fns";
import ProjectsSection from "@components/ProjectsSection";
+345 -157
View File
@@ -1,10 +1,17 @@
import { createRef, useEffect, useLayoutEffect, useRef, useState } from "react";
// import { createRef, useEffect, useLayoutEffect, useRef, useState } from "react";
// import { useSwipeable } from "react-swipeable";
// import { motion } from "framer-motion";
// import { Transition } from "react-transition-group";
// import ArrowLeftIcon from "./icons/ArrowLeftIcon";
// import ArrowRightIcon from "./icons/ArrowRightIcon";
// import { Video } from "../types/Video";
import { createRef, useEffect, useState } from "react";
import { useInView } from "react-intersection-observer";
import { useSwipeable } from "react-swipeable";
import { motion } from "framer-motion";
import { Transition } from "react-transition-group";
import { Video } from "../types/Video";
import ArrowLeftIcon from "./icons/ArrowLeftIcon";
import ArrowRightIcon from "./icons/ArrowRightIcon";
import { Video } from "../types/Video";
import { Transition } from "react-transition-group";
const VIDEOS: Video[] = [
{
@@ -30,174 +37,355 @@ const VIDEOS: Video[] = [
},
];
const Reviews = () => {
const [isViewportEntered, setIsViewportEntered] = useState<boolean>(false);
// const Reviews = () => {
// const [isViewportEntered, setIsViewportEntered] = useState<boolean>(false);
function handleViewportEnter() {
if (isViewportEntered) return;
setIsViewportEntered(true);
}
const [cardWidth, setCardWidth] = useState(0);
// function handleViewportEnter() {
// if (isViewportEntered) return;
// setIsViewportEntered(true);
// }
// const [cardWidth, setCardWidth] = useState(0);
// const handlers = useSwipeable({
// onSwipedLeft: handleOnRightMove,
// onSwipedRight: handleOnLeftMove,
// trackMouse: true,
// });
// const [selectedVideo, setSelectedVideo] = useState<number>(0);
// const [_document, setDocument] = useState<Document>();
// function handleOnLeftMove(): void {
// if (selectedVideo > 0) {
// setSelectedVideo((prev) => prev - 1);
// }
// }
// function handleOnRightMove(): void {
// if (selectedVideo < 2) {
// setSelectedVideo((prev) => prev + 1);
// }
// }
// useEffect(() => {
// setDocument(document);
// }, []);
// useEffect(() => {
// if (!_document) return;
// const clientWidth = _document.children[0].clientWidth;
// if (clientWidth >= 1600) {
// setCardWidth(1000);
// } else if (clientWidth >= 1280) {
// setCardWidth(805);
// } else if (clientWidth >= 640) {
// setCardWidth(736);
// } else {
// setCardWidth(clientWidth - 16);
// }
// }, [_document]);
// return (
// <motion.div
// onViewportEnter={handleViewportEnter}
// className="container mx-auto 2xl:max-w-screen-2xl flex flex-col justify-center 2xl:mb-[200px] sm:mb-[120px] mb-20"
// >
// <div className="sm:border-b border-b-[#3D425C] 2xl:h-[594px] xl:h-[484px] sm:h-[404px] h-full">
// <div className="flex sm:h-full h-fit sm:flex-row flex-col sm:w-full sm:mx-0 mx-auto">
// <div className=" flex flex-col justify-between 2xl:min-w-[496px] xl:min-w-[395px] sm:min-w-[263px] sm:pb-6 xl:pb-10 sm:h-full">
// <div className="2xl:pr-10 xl:pr-8 sm:pr-[37px]">
// <h2 className="font-medium 2xl:text-[64px] xl:text-5xl text-[40px] leading-10 sm:mb-8 mb-6 font-gilroy">
// <p className="from-[#798FFF] to-[#D375FF] bg-gradient-to-r bg-clip-text text-transparent">
// Отзывы
// </p>
// <p>клиентов</p>
// </h2>
// <div className="flex gap-6 2xl:pb-8 xl:pb-6 ">
// <div className="w-[72px] h-[72px] bg-white rounded-full" />
// <div>
// <h2 className="text-2xl font-semibold">Егор Бобров</h2>
// <p className="w-[272px] opacity-80">
// Коммерческий директор авторского квартала «Машаров»{" "}
// </p>
// </div>
// </div>
// <div
// className={`absolute 2xl:w-[456px] xl:w-[363px] sm:w-[350px] w-[280px] transition-opacity duration-300 mb-7`}
// >
// <p className="font-normal 2xl:text-[16px] xl:text-[14px] sm:block hidden">
// Эффективность инструмента была подтверждена буквально в первый
// день после его внедрения. Например, один из клиентов, посетив
// офис и увидев свою будущую квартиру с помощью интерактивной
// панели, сразу решил купить недвижимость в этом проекте,
// отказавшись от других вариантов
// </p>
// </div>
// {/* {VIDEOS.map((item, index) => (
// <Transition
// key={index}
// in={Boolean(index === selectedVideo)}
// timeout={300}
// >
// {(state) => (
// <div
// className={`absolute 2xl:w-[456px] xl:w-[363px] sm:w-[350px] w-[280px] transition-opacity duration-300 ${state} mb-7`}
// >
// <p className="font-normal 2xl:text-[16px] xl:text-[14px] sm:block hidden">
// Эффективность инструмента была подтверждена буквально в
// первый день после его внедрения. Например, один из
// клиентов, посетив офис и увидев свою будущую квартиру с
// помощью интерактивной панели, сразу решил купить
// недвижимость в этом проекте, отказавшись от других
// вариантов
// </p>
// </div>
// )}
// </Transition>
// ))} */}
// </div>
// <div className="gap-2 sm:flex hidden">
// <button
// className="p-4 border border-[#3D425C] rounded-full"
// onClick={handleOnLeftMove}
// >
// <ArrowLeftIcon />
// </button>
// <button
// className="p-4 border border-[#3D425C] rounded-full"
// onClick={handleOnRightMove}
// >
// <ArrowRightIcon />
// </button>
// </div>
// </div>
// <div className="relative sm:border-l border-l-[#3D425C] sm:h-full h-[548px] w-full">
// <div className="absolute overflow-x-clip h-full ">
// <div {...handlers} className="absolute h-full w-full z-10" />
// <div
// className="flex gap-4 w-full h-full transition-all duration-300 ease-in-out 2xl:pl-10 xl:pl-8 sm:pl-3 xl:pb-10 sm:pb-[25px] "
// style={{
// transform: `translateX(${-selectedVideo * cardWidth}px)`,
// }}
// >
// {VIDEOS.map((video, index) => (
// <div
// key={video.id}
// className={`relative 2xl:w-[984px] xl:w-[789px] sm:w-[720px] w-[calc(100vw-32px)] 2xl:h-[554px] xl:h-[444px] sm:h-[404px] h-[206px] transition-opacity duration-300 ${
// selectedVideo === index ? "opacity-100" : "opacity-60"
// }`}
// >
// <img src="/images/posters/integra_crm.jpg" alt="img" />
// </div>
// ))}
// </div>
// </div>
// </div>
// <div className=" p-6 block sm:hidden mb-6">
// <h2 className="font-semibold text-sm leading-[18px] pb-2">
// {VIDEOS[selectedVideo].title}
// </h2>
// <p className="text-[12px] leading-[18px]">
// {VIDEOS[selectedVideo].desc}
// </p>
// </div>
// <div className="mx-auto flex gap-2 h-2 sm:hidden">
// {VIDEOS.map((video, index) => (
// <div
// key={video.id}
// className="h-full w-2 rounded-full transition-all duration-300"
// style={{
// background: `${
// selectedVideo === index ? "white" : "#a1a2a6"
// }`,
// }}
// />
// ))}
// </div>
// </div>
// </div>
// </motion.div>
// );
// };
function Reviews() {
const [selectedVideoIndex, setSelectedVideoIndex] = useState(0);
const videoRefs = VIDEOS.map(() => createRef<HTMLVideoElement>());
const [videoWidth, setVideoWidth] = useState<number>(0);
const [videoHeigth, setVideoHeigth] = useState<number>(0);
const { ref, inView } = useInView();
const [isEntered, setIsEntered] = useState(false);
const handlers = useSwipeable({
onSwipedLeft: handleOnRightMove,
onSwipedRight: handleOnLeftMove,
onSwipedLeft: next,
onSwipedRight: prev,
trackMouse: true,
});
const [selectedVideo, setSelectedVideo] = useState<number>(0);
const [_document, setDocument] = useState<Document>();
function handleOnLeftMove(): void {
if (selectedVideo > 0) {
setSelectedVideo((prev) => prev - 1);
}
}
function handleOnRightMove(): void {
if (selectedVideo < 2) {
setSelectedVideo((prev) => prev + 1);
}
}
useEffect(() => {
setDocument(document);
}, []);
useEffect(() => {
if (!_document) return;
const clientWidth = _document.children[0].clientWidth;
if (clientWidth >= 1600) {
setCardWidth(1000);
} else if (clientWidth >= 1280) {
setCardWidth(805);
} else if (clientWidth >= 640) {
setCardWidth(736);
function handleEnded() {
if (selectedVideoIndex === VIDEOS.length - 1) {
setSelectedVideoIndex(0);
} else {
setCardWidth(clientWidth - 16);
setSelectedVideoIndex((prev) => prev + 1);
}
}, [_document]);
}
function prev() {
if (selectedVideoIndex === 0) return;
setSelectedVideoIndex((prev) => prev - 1);
}
function next() {
if (selectedVideoIndex === VIDEOS.length - 1) return;
setSelectedVideoIndex((prev) => prev + 1);
}
useEffect(() => {
if (!inView || isEntered) return;
setIsEntered(true);
}, [inView]);
return (
<motion.div
onViewportEnter={handleViewportEnter}
className="container mx-auto 2xl:max-w-screen-2xl flex flex-col justify-center 2xl:mb-[200px] sm:mb-[120px] mb-20"
<div
ref={ref}
className="container mx-auto 2xl:max-w-screen-2xl mb-[120px]"
>
<div className="sm:border-b border-b-[#3D425C] 2xl:h-[594px] xl:h-[484px] sm:h-[404px] h-full">
<div className="flex sm:h-full h-fit sm:flex-row flex-col sm:w-full sm:mx-0 mx-auto">
<div className=" flex flex-col justify-between 2xl:min-w-[496px] xl:min-w-[395px] sm:min-w-[263px] sm:pb-6 xl:pb-10 sm:h-full">
<div className="2xl:pr-10 xl:pr-8 sm:pr-[37px]">
<h2 className="font-medium 2xl:text-[64px] xl:text-5xl text-[40px] leading-10 sm:mb-8 mb-6 font-gilroy">
<p className="from-[#798FFF] to-[#D375FF] bg-gradient-to-r bg-clip-text text-transparent">
Отзывы
</p>
<p>клиентов</p>
</h2>
<div className="flex gap-6 2xl:pb-8 xl:pb-6 ">
<div className="w-[72px] h-[72px] bg-white rounded-full" />
<div>
<h2 className="text-2xl font-semibold">Егор Бобров</h2>
<p className="w-[272px] opacity-80">
Коммерческий директор авторского квартала «Машаров»{" "}
</p>
</div>
</div>
<div
className={`absolute 2xl:w-[456px] xl:w-[363px] sm:w-[350px] w-[280px] transition-opacity duration-300 mb-7`}
>
<p className="font-normal 2xl:text-[16px] xl:text-[14px] sm:block hidden">
Эффективность инструмента была подтверждена буквально в первый
день после его внедрения. Например, один из клиентов, посетив
офис и увидев свою будущую квартиру с помощью интерактивной
панели, сразу решил купить недвижимость в этом проекте,
отказавшись от других вариантов
</p>
</div>
{/* {VIDEOS.map((item, index) => (
<Transition
key={index}
in={Boolean(index === selectedVideo)}
timeout={300}
>
{(state) => (
<div
className={`absolute 2xl:w-[456px] xl:w-[363px] sm:w-[350px] w-[280px] transition-opacity duration-300 ${state} mb-7`}
>
<p className="font-normal 2xl:text-[16px] xl:text-[14px] sm:block hidden">
Эффективность инструмента была подтверждена буквально в
первый день после его внедрения. Например, один из
клиентов, посетив офис и увидев свою будущую квартиру с
помощью интерактивной панели, сразу решил купить
недвижимость в этом проекте, отказавшись от других
вариантов
</p>
</div>
)}
</Transition>
))} */}
</div>
<div className="gap-2 sm:flex hidden">
<button
className="p-4 border border-[#3D425C] rounded-full"
onClick={handleOnLeftMove}
>
<ArrowLeftIcon />
</button>
<button
className="p-4 border border-[#3D425C] rounded-full"
onClick={handleOnRightMove}
>
<ArrowRightIcon />
</button>
</div>
</div>
<div className="relative sm:border-l border-l-[#3D425C] sm:h-full h-[548px] w-full">
<div className="absolute overflow-x-clip h-full ">
<div {...handlers} className="absolute h-full w-full z-10" />
<div
className="flex gap-4 w-full h-full transition-all duration-300 ease-in-out 2xl:pl-10 xl:pl-8 sm:pl-3 xl:pb-10 sm:pb-[25px] "
style={{
transform: `translateX(${-selectedVideo * cardWidth}px)`,
}}
>
{VIDEOS.map((video, index) => (
<div
key={video.id}
className={`relative 2xl:w-[984px] xl:w-[789px] sm:w-[720px] w-[calc(100vw-32px)] 2xl:h-[554px] xl:h-[444px] sm:h-[404px] h-[206px] transition-opacity duration-300 ${
selectedVideo === index ? "opacity-100" : "opacity-60"
}`}
>
<img src="/images/posters/integra_crm.jpg" alt="img" />
</div>
))}
</div>
</div>
</div>
<div className=" p-6 block sm:hidden mb-6">
<h2 className="font-semibold text-sm leading-[18px] pb-2">
{VIDEOS[selectedVideo].title}
</h2>
<p className="text-[12px] leading-[18px]">
{VIDEOS[selectedVideo].desc}
<div className="flex 2xl:h-[760px] xl:h-[687px] sm:h-[500px] h-[875px] sm:border-b border-b-[#3D425C] sm:flex-row flex-col">
<div className="left 2xl:min-w-[496px] xl:min-w-[395px] sm:min-w-[354px] flex flex-col sm:pb-10 pb-6">
<h2 className="font-medium 2xl:text-[64px] xl:text-5xl text-[40px] sm:mb-10 mb-6 font-gilroy leading-10">
<p className="from-[#798FFF] to-[#D375FF] bg-gradient-to-r bg-clip-text text-transparent">
Отзывы
</p>
</div>
<div className="mx-auto flex gap-2 h-2 sm:hidden">
{VIDEOS.map((video, index) => (
<div
key={video.id}
className="h-full w-2 rounded-full transition-all duration-300"
style={{
background: `${
selectedVideo === index ? "white" : "#a1a2a6"
}`,
}}
/>
<p>клиентов</p>
</h2>
<div className="relative bg-white sm:block hidden">
{VIDEOS.map((item, index) => (
<Transition
key={index}
in={Boolean(index === selectedVideoIndex)}
timeout={300}
>
{(state) => (
<div
className={`absolute transition-opacity duration-300 pr-10 ${state}`}
>
{item.title ? (
<p className="font-semibold mb-4 2xl:text-xl xl:text-[16px]">
{item.title}
</p>
) : (
<></>
)}
<p className="font-normal 2xl:text-[16px] xl:text-[14px]">
{item.desc}
</p>
</div>
)}
</Transition>
))}
</div>
<div className="gap-2 hidden sm:flex mt-auto">
<button
className="p-4 border border-[#3D425C] rounded-full"
onClick={prev}
>
<ArrowLeftIcon />
</button>
<button
className="p-4 border border-[#3D425C] rounded-full"
onClick={next}
>
<ArrowRightIcon />
</button>
</div>
</div>
<div
{...handlers}
className="right relative sm:border-l border-l-[#3D425C] flex gap-4 sm:pb-10 sm:pl-10 select-none"
style={{
clipPath: `rect(auto auto auto 0)`,
}}
>
{VIDEOS.map((video, index) => (
<div
key={video.id}
className="relative sm:aspect-[16/9] aspect-auto bg-black transition-transform duration-300 sm:h-auto sm:min-w-0 h-[546px]"
style={{
transform: `translateX(-${
videoWidth * selectedVideoIndex + 16 * selectedVideoIndex
}px)`,
}}
>
<img
src={isEntered ? video.value : undefined}
alt={video.title}
ref={videoRefs[index]}
className="aspect-[16/9] object-cover w-full h-full min-w-screen"
onLoadedData={() =>
setTimeout(() => {
setVideoWidth(videoRefs[0].current!.clientWidth);
setVideoHeigth(videoRefs[0].current!.clientHeight);
}, 200)
}
/>
{/* <video
ref={videoRefs[index]}
src={isEntered ? video.value : undefined}
poster={video.poster}
muted
playsInline
className="aspect-[16/9] object-cover w-full h-full min-w-screen"
onEnded={handleEnded}
onLoadedData={() =>
setTimeout(() => {
setVideoWidth(videoRefs[0].current!.clientWidth);
setVideoHeigth(videoRefs[0].current!.clientHeight);
}, 200)
}
/> */}
</div>
))}
</div>
<div className="relative block sm:hidden h-[100%] bg-[#212431] p-6">
{VIDEOS.map((item, index) => (
<Transition
key={index}
in={Boolean(index === selectedVideoIndex)}
timeout={300}
>
{(state) => (
<div
className={`absolute transition-opacity duration-300 pr-10 ${state}`}
>
{item.title ? (
<p className="font-semibold mb-4 2xl:text-xl xl:text-[16px]">
{item.title}
</p>
) : (
<></>
)}
<p className="font-normal 2xl:text-[16px] xl:text-[14px]">
{item.desc}
</p>
</div>
)}
</Transition>
))}
</div>
<div className="mx-auto flex gap-2 min-h-2 sm:hidden relative mt-6">
{VIDEOS.map((video, index) => (
<div
key={video.id}
className="h-full w-2 rounded-full transition-all duration-300"
style={{
background: `${
selectedVideoIndex === index ? "white" : "#a1a2a6"
}`,
}}
/>
))}
</div>
</div>
</motion.div>
</div>
);
};
}
export default Reviews;