This commit is contained in:
2023-11-22 18:59:30 +05:00
parent 94ccd27eb5
commit b8cec033bb
38 changed files with 551 additions and 176 deletions
+2
View File
@@ -14,9 +14,11 @@
"framer-motion": "^10.16.5",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-circular-progressbar": "^2.1.0",
"react-dom": "^18.2.0",
"react-rangeslider": "^2.2.0",
"react-router-dom": "^6.18.0",
"react-swipeable": "^7.0.1",
"usehooks-ts": "^2.9.1"
},
"devDependencies": {
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

+168 -96
View File
@@ -3,7 +3,7 @@ import "./App.css";
import LogoIcon from "./components/icons/LogoIcon";
import BlendingHeader from "./components/blendings/BlendingHeader";
import FeatureItem from "./components/FeatureItem";
import BlendVR from "./components/blendings/BlendVR";
// import BlendVR from "./components/blendings/BlendVR";
import BlendStream from "./components/blendings/BlendStream";
import StreamButton from "./components/StreamButton";
import "react-rangeslider/lib/index.css";
@@ -18,15 +18,17 @@ import Calc from "./components/Calc";
import BlendingCalc from "./components/blendings/BlendingCalc";
import BlendingClients from "./components/blendings/BlendingClients";
import Heading2 from "./components/Headings/Heading2";
import PlayIcon from "./components/icons/PlayIcon";
// import PlayIcon from "./components/icons/PlayIcon";
import VideoSliderMobile from "./components/VideoSliderMobile";
function App() {
const [selectedVideo, setSelectedVideo] = useState<string>(
"https://graff.estate/videos/features/virtual_tour.mp4"
);
const [isShowProjects, setIsShowProjects] = useState<boolean>(false);
return (
<div className="min-h-screen text-white 2xl:px-10 xl:px-8 sm:px-6 px-4">
<div className="min-h-screen text-white 2xl:px-10 xl:px-8 sm:px-6 px-4 overflow-x-clip">
<div className="relative conatiner mx-auto 2xl:max-w-screen-2xl">
<div className="flex justify-between py-6 2xl:mb-28 xl:mb-[88px] sm:mb-12 mb-14">
<div>
@@ -190,22 +192,22 @@ function App() {
</div>
</div>
<div className="grid grid-cols-2 gap-4 2xl:mb-40 sm:mb-[120px] mb-20">
<div className="xl:grid flex flex-col grid-cols-2 xl:gap-4 sm:gap-10 gap-8 2xl:mb-40 sm:mb-[120px] mb-20">
<div className="flex flex-col gap-20">
<div className="flex flex-col gap-8">
<div className="xl:flex flex-col grid sm:grid-cols-2 xl:gap-8 gap-3">
<Heading2>
Функциональные
<br />
<span style={{ WebkitTextFillColor: "#fff" }}>возможности</span>
</Heading2>
<p className="w-2/3">
<p className="xl:w-2/3 xl:text-base text-sm">
Интерактивная презентация увлекает покупателей и предоставляет
актуальную информацию о жилом комплексе, отвечая на все вопросы
и показывая важные особенности и преимущества объекта
</p>
</div>
<div className="pr-6">
<div className="pr-6 xl:block hidden">
<FeatureItem
title="Виртуальный тур по жилому комплексу"
desc="Клиент лично оценит угол инсоляции, малые архитектурные формы и ландшафт, перемещаясь по комплексу с помощью тапа."
@@ -238,7 +240,7 @@ function App() {
/>
<FeatureItem
title="Формирование вишлиста"
desc="Фильтр позволит отметить конкретные преимущества, определить количество комнат, желаемый этаж, цену, и получить выборку подходящих вариантов."
desc="Клиент может добавить варианты квартир в избранное, сравнить их между собой по основным параметрам и выбрать свою будущую квартиру."
video="https://graff.estate/videos/features/wish.mp4"
handleHoverStart={(video) => setSelectedVideo(video)}
/>
@@ -266,67 +268,43 @@ function App() {
/>
</div>
</div>
<div className="aspect-video sticky top-[25%]">
<div className="aspect-video sticky top-[25%] xl:block hidden">
<FeatureVideoViewBox video={selectedVideo} />
</div>
<VideoSliderMobile />
</div>
<div className="relative grid grid-cols-4 gap-4 2xl:mb-40 sm:mb-[120px] mb-20">
<div className="col-span-2 flex flex-col gap-16">
<h2 className="font-gilroy text-[64px] leading-none max-w-[780px] font-medium text-gradient">
Экскурсия{" "}
<div className="relative grid grid-cols-2 gap-4 2xl:mb-40 sm:mb-[120px] mb-20">
<div className="flex flex-col gap-8">
<Heading2>
Экскурсия
<br />
<span style={{ WebkitTextFillColor: "#fff" }}>
в виртуальной реальности
</span>
</h2>
</Heading2>
<Button>Записаться в шоу-рум</Button>
</div>
<p className="">
Клиенту достаточно надеть шлем виртуальной реальности, чтобы
прогуляться, оценить и ощутить пространство{" "}
</p>
<div className="flex flex-col gap-4">
<p>
Он полностью погружается в воссозданную реальность, чувствует
удобство и уровень комфорта
<p className="2xl:text-base text-sm">
Клиенту достаточно надеть шлем виртуальной реальности, чтобы
прогуляться, оценить и ощутить пространство{" "}
</p>
<div className="relative flex justify-center items-center">
<video
src="https://graff.estate/videos/vr.mp4"
muted
// autoPlay
loop
playsInline
preload="metadata"
className=""
/>
<button className="group absolute border border-[#3D425C] bg-[#14161F] bg-opacity-20 p-4 rounded-full">
<span className="block group-hover:scale-125 transition-transform">
<PlayIcon />
</span>
</button>
</div>
</div>
<div className="col-span-4 flex justify-center mb-16">
<img src="/images/VRHeadset.png" alt="" className="w-4/5" />
</div>
<div className="absolute top-[50%] left-[50%] -translate-x-[50%] -translate-y-[50%] blur-[22px] -z-10">
<BlendVR />
<Button className="sm:block hidden">Записаться в шоу-рум</Button>
</div>
<div className=""></div>
</div>
<div className="grid grid-cols-2 gap-4 2xl:mb-40 sm:mb-[120px] mb-20">
<div>
<div className="flex flex-col gap-8 mb-[204px]">
<h2 className="font-gilroy text-[64px] text-gradient leading-none font-medium">
<Heading2>
Анализируем
<br />
<span style={{ WebkitTextFillColor: "#fff" }}>
поведение пользователей
</span>
</h2>
</Heading2>
<p className="w-2/3">
Система внутренней аналитики программы собирает информацию о
поведении пользователя и эффективности работы менеджеров для
@@ -345,7 +323,7 @@ function App() {
<div className="relative grid grid-cols-4 gap-4 mb-16">
<div className="col-span-2 flex flex-col justify-between">
<h2 className="font-gilroy text-[64px] text-gradient leading-none font-medium">
<Heading2>
Graff.estate stream
<br />
<span style={{ WebkitTextFillColor: "#fff" }}>
@@ -353,7 +331,7 @@ function App() {
<br />
жилого комплекса
</span>
</h2>
</Heading2>
<Button>Узнать больше</Button>
</div>
<div className="flex flex-col gap-12">
@@ -400,13 +378,13 @@ function App() {
<div className="relative flex flex-col gap-16 2xl:mb-40 sm:mb-[120px] mb-20">
<div className="flex flex-col gap-8">
<h2 className="font-gilroy text-[64px] text-gradient leading-none font-medium">
<Heading2>
Оцените эффективность интерактивного
<br />
<span style={{ WebkitTextFillColor: "#fff" }}>
инструмента продаж
</span>
</h2>
</Heading2>
<div className="grid grid-cols-2 gap-4">
<p className="w-2/3">
Мы изучили отраслевую аналитику на рынке продаж новых квартир и
@@ -428,71 +406,165 @@ function App() {
</div>
<div className="flex flex-col gap-16 2xl:mb-40 sm:mb-[120px] mb-20">
<h2 className="font-gilroy text-[64px] text-gradient leading-none font-medium w-fit">
Проекты
</h2>
<div className="grid grid-cols-3 gap-8">
<Heading2>Проекты</Heading2>
<div className="grid xl:grid-cols-3 sm:grid-cols-2 2xl:gap-8 xl:gap-6 gap-3">
<ProjectCard
title="ЖК «Голос в сердце города»"
company="Голос Девелопмент, Челябинск"
image="/images/projects/photo01.jpg"
stream
stage={1}
/>
<ProjectCard
title="ЖК «Кама»"
company="ГК Альфа, Пермь"
image="/images/projects/photo02.jpg"
stage={2}
/>
<ProjectCard
title="ЖК «Август»"
company="Родина Девелопмент, Тюмень"
image="/images/ViewBox.jpg"
releaseDate="23.11.2023"
image="/images/projects/photo03.jpg"
stage={4}
/>
<ProjectCard
title="ЖК «DNS Сити»"
company="НКС Девелопмент, Владивосток"
image="/images/projects/photo04.jpg"
/>
<ProjectCard
title="ЖК «Upside Towers»"
company="Upside Development, Москва"
image="/images/ViewBox.jpg"
releaseDate="22.11.2023"
image="/images/projects/photo05.jpg"
/>
<ProjectCard
title="ЖК «Scala City»"
company="Рисан, Пенза"
image="/images/projects/photo06.jpg"
/>
<ProjectCard
title="ЖК «Мираполис»"
company="ГК Основа, Москва"
image="/images/ViewBox.jpg"
releaseDate="21.11.2023"
/>
<ProjectCard
title="ЖК «Life Резиденция»"
company="Paritet Pro Development, Тюмень"
image="/images/ViewBox.jpg"
releaseDate="20.11.2023"
/>
<ProjectCard
title="МФК «Re:volution towers»"
company="НКС Девелопмент, Екатеринбург"
image="/images/ViewBox.jpg"
releaseDate="15.11.2023"
stream
/>
<ProjectCard
title="ЖК «Новатор»"
company="ГК СБК, Тюмень"
image="/images/ViewBox.jpg"
releaseDate="15.11.2023"
/>
<ProjectCard
title="ЖК «Айвазовский City»"
company="ГК ЭНКО, Тюмень"
image="/images/ViewBox.jpg"
releaseDate="15.11.2023"
stream
image="/images/projects/photo07.jpg"
/>
<ProjectCard
title="ЖК «Ориент»"
company="СК+, Хабаровск"
image="/images/ViewBox.jpg"
releaseDate="15.11.2023"
stream
image="/images/projects/photo08.jpg"
/>
<MoreProjectButton />
{!isShowProjects ? (
<MoreProjectButton handleClick={() => setIsShowProjects(true)} />
) : (
<>
<ProjectCard
title="ЖК «Новатор»"
company="СБК, Тюмень"
image="/images/projects/photo09.jpg"
stream
stage={1}
/>
<ProjectCard
title="ЖК «Фотограф»"
company="Мавис, Санкт-Петербург"
image="/images/projects/photo10.jpg"
stage={2}
/>
<ProjectCard
title="ЖК «Life Резиденция»"
company="Паритет Девелопмент, Тюмень"
image="/images/projects/photo11.jpg"
stage={3}
/>
<ProjectCard
title="МФК «Re:volution towers»"
company="НКС Девелопмент, Екатеринбург"
image="/images/projects/photo12.jpg"
/>
<ProjectCard
title="ЖК «Айвазовский»"
company="ЭНКО, Тюмень"
image="/images/projects/photo13.jpg"
/>
<ProjectCard
title="ЖК «Авторский квартал Машаров»"
company="Сибинтел Девелопмент, Тюмень"
image="/images/projects/photo14.jpg"
/>
<ProjectCard
title="ЖК «Уральский»"
company="Эфес, Екатеринбург"
image="/images/projects/photo15.jpg"
/>
<ProjectCard
title="Iskan Abu Dhabi"
company="ОАЭ, Абу-Даби"
image="/images/projects/photo16.jpg"
/>
<ProjectCard
title="ЖК «Графика»"
company="Мавис, Санкт-Петербург"
image="/images/projects/photo17.jpg"
/>
<ProjectCard
title="ЖК «4you»"
company="Атлас Девелопмент, Екатеринбург"
image="/images/projects/photo18.jpg"
/>
<ProjectCard
title="ЖК «Новая Атмосфера»"
company="Застройщик Атмосфера, Брянск"
image="/images/projects/photo19.jpg"
/>
<ProjectCard
title="ЖК «Тринити»"
company="НКС-девелопмент, Екатеринбург"
image="/images/projects/photo20.jpg"
/>
<ProjectCard
title="ЖК «Дом на Опалихинской»"
company="Корпорация «Маяк», Екатеринбург"
image="/images/projects/photo21.jpg"
/>
</>
)}
</div>
</div>
<div className="relative flex flex-col gap-16 2xl:mb-40 sm:mb-[120px] mb-20">
<h2 className="font-gilroy text-[64px] text-gradient leading-none font-medium">
<Heading2>
Наши клиенты{" "}
<span style={{ WebkitTextFillColor: "#fff" }}>в девелопменте</span>
</h2>
<img src="/images/ClientsLogos.png" alt="" />
</Heading2>
<img
src="/images/clients-logos.png"
alt=""
className="sm:block hidden"
/>
<img
src="/images/clients-logos-mobile.png"
alt=""
className="sm:hidden block"
/>
<div className="absolute top-0 right-0 blur-[34px]">
<BlendingClients />
</div>
+94 -32
View File
@@ -158,8 +158,8 @@ function Calc() {
return (
<div className="relative flex flex-col gap-16">
<div className="grid grid-cols-4">
<div>
<div className="grid xl:grid-cols-4 sm:grid-cols-3">
<div className="xl:col-auto sm:col-span-full xl:block sm:grid grid-cols-2">
<CalcSelect
label="Регион"
placeholder="Выберите регион"
@@ -175,7 +175,7 @@ function Calc() {
}
}}
/>
<div className="border border-t-0 border-[#3D425C] p-6">
<div className="border xl:border-t-0 xl:border-l sm:border-l-0 border-[#3D425C] 2xl:p-6 p-4">
<p className="text-[#52587A] text-xs leading-[120%]">
Установлены усредненные показатели по региону.
<br />
@@ -190,33 +190,33 @@ function Calc() {
</p>
</div>
</div>
<div className="px-8 py-6 flex flex-col justify-between border border-l-0 border-[#3D425C]">
<div className="2xl:px-8 2xl:py-6 px-6 py-4 flex flex-col justify-between gap-6 border xl:border-l-0 xl:border-t border-t-0 border-[#3D425C]">
<p className="text-sm">
Средняя площадь
<br />
жилья в комплексе, м2
</p>
<p className="text-5xl font-gilroy font-medium leading-none">
<p className="2xl:text-5xl text-[32px] font-gilroy font-medium leading-none">
{(selectedRegion?.areaInComplex || 1500).toLocaleString()}
</p>
</div>
<div className="px-8 py-6 flex flex-col justify-between border border-l-0 border-[#3D425C]">
<div className="2xl:px-8 2xl:py-6 px-6 py-4 flex flex-col justify-between border border-l-0 xl:border-t border-t-0 border-[#3D425C]">
<p className="text-sm">
Средняя площадь
<br />
квартиры, м2
</p>
<p className="text-5xl font-gilroy font-medium leading-none">
<p className="2xl:text-5xl text-[32px] font-gilroy font-medium leading-none">
{(selectedRegion?.areaApartment || 100).toLocaleString()}
</p>
</div>
<div className="px-8 py-6 flex flex-col justify-between border border-l-0 border-[#3D425C]">
<div className="2xl:px-8 2xl:py-6 px-6 py-4 flex flex-col justify-between border border-l-0 xl:border-t border-t-0 border-[#3D425C]">
<p className="text-sm">
Средняя стоимость
<br />
одного м2, тыс. руб.
</p>
<p className="text-5xl font-gilroy font-medium leading-none">
<p className="2xl:text-5xl text-[32px] font-gilroy font-medium leading-none">
{(selectedRegion?.costPerSquare || 100).toLocaleString()}
</p>
</div>
@@ -225,10 +225,10 @@ function Calc() {
<div className="grid grid-cols-4">
<div className="flex flex-col gap-6 mr-8 border-b border-[#3D425C]">
<div className="flex justify-between">
<p className="font-gilroy font-medium">
<p className="font-gilroy font-medium 2xl:text-base text-sm">
Очных консультаций в месяц
</p>
<p className="font-gilroy font-medium text-[#798FFF]">
<p className="font-gilroy font-medium text-[#798FFF] 2xl:text-base text-sm">
{consultations}
</p>
</div>
@@ -255,20 +255,20 @@ function Calc() {
<div className="col-span-3 grid grid-cols-2">
<div>
<div className="px-8 py-6 border border-[#3D425C] flex flex-col gap-4">
<div className="2xl:px-8 2xl:py-6 px-6 py-4 border border-[#3D425C] flex flex-col gap-4">
<p className="text-sm">Срок реализации</p>
<div className="grid grid-cols-2">
<p
className={`text-5xl font-gilroy font-medium flex items-end gap-1.5 w-fit ${
className={`2xl:text-5xl text-[32px] font-gilroy font-medium flex items-end gap-1.5 w-fit ${
isToolEnabled && "text-gradient"
}`}
>
<span>
<span className="leading-none">
{isToolEnabled
? implementationPeriod
: oldImplementationPeriod}
</span>
<span className="text-2xl">
<span className="2xl:text-2xl text-xl leading-none">
{isToolEnabled
? implementationPeriodEnding
: oldImplementationPeriodEnding}
@@ -291,19 +291,21 @@ function Calc() {
</div>
</div>
<div className="px-8 py-6 border border-t-0 border-[#3D425C] flex flex-col gap-4">
<div className="2xl:px-8 2xl:py-6 px-6 py-4 border border-t-0 border-[#3D425C] flex flex-col gap-4">
<p className="text-sm">Месячный доход</p>
<div className="grid grid-cols-2">
<p
className={`text-5xl font-gilroy font-medium flex items-end gap-1.5 w-fit ${
className={`2xl:text-5xl text-[32px] font-gilroy font-medium flex items-end gap-1.5 w-fit ${
isToolEnabled && "text-gradient"
}`}
>
<span>
<span className="leading-none">
{isToolEnabled ? monthlyIncome : oldMonthlyIncome}
</span>
<span
className={`${isToolEnabled && "text-gradient"} text-2xl`}
className={`${
isToolEnabled && "text-gradient"
} 2xl:text-2xl text-xl leading-none`}
>
млн руб.
</span>
@@ -322,24 +324,28 @@ function Calc() {
</div>
</div>
</div>
<div className="px-8 py-6 border border-l-0 border-[#3D425C] flex flex-col gap-4">
<div className="2xl:px-8 2xl:py-6 px-6 py-4 border border-l-0 border-[#3D425C] flex flex-col gap-4">
<p className="text-sm">Статистика продаж</p>
<div className="flex flex-col gap-3">
<div className="flex items-center gap-4">
<p className="w-[36px] text-sm">100%</p>
<div className="w-[284px] bg-[#212431] rounded-full flex justify-center">
<div className="p-3.5 bg-gradient rounded-full w-full">
<div className="flex flex-col 2xl:gap-3 gap-1.5">
{/* <div className="grid grid-cols-3 items-center gap-4">
<p className="w-fit 2xl:text-sm text-xs">100%</p>
<div className=" bg-[#212431] rounded-full flex justify-center">
<div className="2xl:p-3.5 p-2 bg-gradient rounded-full w-full">
<p className="text-center">{consultations}</p>
</div>
</div>
<p className="text-sm text-[#8088A7]">Консультаций в офисе</p>
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Консультаций в офисе
</p>
</div>
<div className="flex items-center gap-4">
<p className="w-[36px] text-sm">{isToolEnabled ? 48 : 30}%</p>
<p className="w-[36px] 2xl:text-sm text-xs">
{isToolEnabled ? 48 : 30}%
</p>
<div className="w-[284px] bg-[#212431] rounded-full flex justify-center">
<div
className={`p-3.5 bg-gradient rounded-full transition-all w-[50%] ${
className={`2xl:p-3.5 p-2 bg-gradient rounded-full transition-all w-[50%] ${
isToolEnabled ? "w-[60%]" : "w-[50%]"
}`}
>
@@ -348,14 +354,18 @@ function Calc() {
</p>
</div>
</div>
<p className="text-sm text-[#8088A7]">Бронь квартиры</p>
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Бронь квартиры
</p>
</div>
<div className="flex items-center gap-4">
<p className="w-[36px] text-sm">{isToolEnabled ? 42 : 30}%</p>
<p className="w-[36px] 2xl:text-sm text-xs">
{isToolEnabled ? 42 : 30}%
</p>
<div className="w-[284px] bg-[#212431] rounded-full flex justify-center">
<div
className={`p-3.5 bg-gradient rounded-full transition-all ${
className={`2xl:p-3.5 p-2 bg-gradient rounded-full transition-all ${
isToolEnabled ? "w-[32%]" : "w-[22%]"
}`}
>
@@ -364,7 +374,59 @@ function Calc() {
</p>
</div>
</div>
<p className="text-sm text-[#8088A7]">Продажа</p>
<p className="2xl:text-sm text-xs text-[#8088A7]">Продажа</p>
</div> */}
<div className="flex gap-4">
<div className="flex flex-col 2xl:gap-3 gap-1.5 justify-around">
<p className="2xl:text-sm text-xs">100%</p>
<p className="2xl:text-sm text-xs">
{isToolEnabled ? 48 : 30}%
</p>
<p className="2xl:text-sm text-xs">
{isToolEnabled ? 42 : 30}%
</p>
</div>
<div className="w-full flex flex-col 2xl:gap-3 gap-1.5 justify-around">
<div className="bg-[#212431] rounded-full flex justify-center">
<div className="bg-gradient 2xl:py-3.5 py-2 rounded-full w-full">
<p className="text-center">{consultations}</p>
</div>
</div>
<div className="bg-[#212431] rounded-full flex justify-center">
<div
className={`bg-gradient 2xl:py-3.5 py-2 rounded-full ${
isToolEnabled ? "w-[60%]" : "w-[50%]"
}`}
>
<p className="text-center">
{isToolEnabled ? reservation : oldReservation}
</p>
</div>
</div>
<div className="bg-[#212431] rounded-full flex justify-center">
<div
className={`bg-gradient 2xl:py-3.5 py-2 rounded-full ${
isToolEnabled ? "w-[32%]" : "w-[22%]"
}`}
>
<p className="text-center">
{isToolEnabled ? sales : oldSales}
</p>
</div>
</div>
</div>
<div className="flex flex-col 2xl:gap-3 gap-1.5 justify-around">
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Консультаций в офисе
</p>
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Бронь квартиры
</p>
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Продажа
</p>
</div>
</div>
</div>
</div>
+4 -4
View File
@@ -34,19 +34,19 @@ function CalcSelect({
<div
className={`border ${
isShow ? "border-[#798FFF]" : "border-[#3D425C]"
} p-6 pr-8 flex flex-col justify-center h-24 cursor-pointer transition-colors`}
} 2xl:p-6 2xl:pr-8 p-4 pr-6 flex flex-col justify-center h-24 cursor-pointer transition-colors`}
onClick={() => setIsShow((prev) => !prev)}
>
<div className="relative h-full cursor-pointer">
<div className="flex flex-col justify-between h-full ">
<label className="opacity-50 font-gilroy font-medium leading-none cursor-pointer">
<label className="2xl:text-base text-sm opacity-50 font-gilroy font-medium leading-none cursor-pointer">
{label}
</label>
<input
readOnly
type="text"
placeholder={placeholder}
className="w-full bg-transparent outline-none cursor-pointer"
className="2xl:text-base text-sm w-full bg-transparent outline-none cursor-pointer"
value={selectedOption}
/>
</div>
@@ -60,7 +60,7 @@ function CalcSelect({
{options.map((option, index) => (
<button
key={index}
className="px-6 py-3 pr-8 hover:bg-white hover:bg-opacity-10 transition-colors w-full text-left flex justify-between"
className="2xl:pl-6 2xl:pr-8 2xl:py-3 pl-4 pr-6 py-2 2xl:text-base text-sm hover:bg-white hover:bg-opacity-10 transition-colors w-full text-left flex justify-between"
onClick={() => handleClick(option)}
>
<span>{option}</span>
+2 -2
View File
@@ -12,7 +12,7 @@ function ExampleCard({ title, company, image }: ExampleCardProps) {
<motion.div
initial={{ opacity: 0, translateY: 64 }}
whileInView={{ opacity: 1, translateY: 0 }}
viewport={{ once: true, margin: "-200px" }}
viewport={{ once: true, margin: "-10%" }}
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98] }}
className="aspect-video bg-cover bg-center bg-no-repeat"
style={{ backgroundImage: `url('${image}')` }}
@@ -20,7 +20,7 @@ function ExampleCard({ title, company, image }: ExampleCardProps) {
<motion.div
initial={{ opacity: 0, translateY: 64 }}
whileInView={{ opacity: 1, translateY: 0 }}
viewport={{ once: true, margin: "-100px" }}
viewport={{ once: true, margin: "-10%" }}
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }}
className="flex flex-col gap-1"
>
+2 -17
View File
@@ -18,8 +18,8 @@ function FeatureVideoViewBox({ video }: FeatureVideoViewBoxProps) {
videoEl.loop = true;
videoEl.playsInline = true;
videoEl.preload = "metadata";
videoEl.onloadeddata = () => console.log("onloadeddata");
videoEl.classList.add("absolute", "h-fit");
// videoEl.onloadeddata = () => console.log("onloadeddata");
videoContainerRef.current.appendChild(videoEl);
@@ -30,22 +30,7 @@ function FeatureVideoViewBox({ video }: FeatureVideoViewBoxProps) {
}
}, [video]);
return (
<div ref={videoContainerRef} className="relative h-fit">
{/* {videos.map((videoSrc, index) => (
<video
key={index}
src={videoSrc}
muted
autoPlay
playsInline
loop
onLoadedData={handleLoadedData}
className="absolute"
/>
))} */}
</div>
);
return <div ref={videoContainerRef} className="relative h-fit"></div>;
}
export default FeatureVideoViewBox;
+1 -1
View File
@@ -8,7 +8,7 @@ interface Heading2Props {
function Heading2({ children, className }: Heading2Props) {
return (
<h2
className={`2xl:text-[64px] xl:text-5xl text-[40px] text-gradient font-gilroy font-medium leading-none ${className}`}
className={`2xl:text-[64px] xl:text-5xl text-[40px] text-gradient font-gilroy font-medium leading-none w-fit ${className}`}
>
{children}
</h2>
+7 -2
View File
@@ -1,14 +1,19 @@
import { motion } from "framer-motion";
import PlusIcon from "./icons/PlusIcon";
function MoreProjectButton() {
interface MoreProjectButtonProps {
handleClick?: () => void;
}
function MoreProjectButton({ handleClick }: MoreProjectButtonProps) {
return (
<motion.button
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }}
className="aspect-[4/3] border border-[#3D425C] rounded-[48px] flex flex-col justify-center items-center gap-2"
className="sm:aspect-[4/3] border border-[#3D425C] rounded-[48px] px-6 py-4 flex sm:flex-col sm:justify-center justify-between items-center gap-2"
onClick={handleClick}
>
<PlusIcon />
<p className="font-gilroy font-medium leading-none">Показать еще</p>
+22
View File
@@ -0,0 +1,22 @@
import { CircularProgressbar, buildStyles } from "react-circular-progressbar";
interface ProgressPieProps {
value: number;
}
function ProgressPie({ value }: ProgressPieProps) {
return (
<CircularProgressbar
value={value}
strokeWidth={50}
styles={buildStyles({
trailColor: "#3D425C",
pathColor: "#798FFF",
strokeLinecap: "butt",
})}
className="w-5 h-5"
/>
);
}
export default ProgressPie;
+25 -16
View File
@@ -1,53 +1,62 @@
import { isAfter, parse } from "date-fns";
import { motion } from "framer-motion";
import ProgressPie from "./ProgressPie";
interface ProjectCardProps {
title: string;
company: string;
image: string;
releaseDate: string;
stream?: boolean;
stage?: number;
}
function ProjectCard({
title,
company,
image,
releaseDate,
stage = 6,
stream,
}: ProjectCardProps) {
const stagePercentage = Math.round((100 / 6) * stage);
return (
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }}
className="aspect-[4/3] p-6 bg-cover bg-center bg-no-repeat flex items-end"
style={{
background: `linear-gradient(180deg, rgba(20, 22, 31, 0.00) 0%, rgba(20, 22, 31, 0.60) 100%), url('${image}'), lightgray 50% / cover no-repeat`,
}}
className="group relative aspect-[4/3] p-4 flex items-end overflow-hidden"
>
<div className="flex flex-col gap-4">
<div
className="group-hover:scale-110 transition-transform duration-500 absolute top-0 left-0 w-full h-full bg-cover bg-center bg-no-repeat"
style={{
backgroundImage: `url(${image})`,
}}
></div>
<div className="absolute top-0 left-0 w-full h-full bg-gradient-card"></div>
<div className="relative flex flex-col gap-4">
<div>
<p className="text-2xl font-gilroy font-medium">{title}</p>
<p className="text-sm">{company}</p>
<p className="2xl:text-2xl text-xl font-gilroy font-medium">
{title}
</p>
<p className="2xl:text-sm text-xs">{company}</p>
</div>
<div className="flex gap-2">
{isAfter(parse(releaseDate, "dd.MM.yyyy", new Date()), new Date()) ? (
<div className="bg-[#14161F] px-4 py-2.5 rounded-full w-fit">
<div className="flex gap-1">
{stage < 6 ? (
<div className="bg-[#14161F] px-3 py-2 rounded-full w-fit flex items-center gap-1">
<p className="font-gilroy font-medium leading-none">
Релиз {releaseDate}
{stagePercentage}%
</p>
<ProgressPie value={stagePercentage} />
</div>
) : (
<div className="bg-gradient px-4 py-2.5 rounded-full w-fit">
<div className="bg-gradient px-3 py-2 rounded-full w-fit">
<p className="font-gilroy font-medium leading-none">Сдан</p>
</div>
)}
{stream && (
<div className="bg-[#14161F] px-4 py-2.5 rounded-full w-fit flex items-center gap-2">
<div className="bg-[#14161F] px-3 py-2 rounded-full w-fit flex items-center gap-2">
<div className="w-2 h-2 bg-gradient rounded-full"></div>
<p className="font-gilroy font-semibold leading-none text-gradient">
Stream
+164
View File
@@ -0,0 +1,164 @@
/* eslint-disable react-hooks/rules-of-hooks */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { motion } from "framer-motion";
import { useEffect, useRef, useState } from "react";
import ArrowLeftIcon from "./icons/ArrowLeftIcon";
import ArrowRightIcon from "./icons/ArrowRightIcon";
import { useSwipeable } from "react-swipeable";
function VideoSliderMobile() {
const [items] = useState<any[]>([
{
title: "Виртуальный тур по жилому комплексу",
desc: "Клиент лично оценит угол инсоляции, малые архитектурные формы и ландшафт, перемещаясь по комплексу с помощью тапа.",
video: "https://graff.estate/videos/features/virtual_tour.mp4",
},
{
title: "Вся инфрастуктура на одном экране",
desc: "Возможность оценить инфраструктуру района покажет важные для клиента точки интереса и время, за которое он сможет до них дойти.",
video: "https://graff.estate/videos/features/nks_infra.mp4",
},
{
title: "Конфигуратор интерьера",
desc: "Клиент может свободно выбирать мебель и дизайн с помощью конфигуратора интерьера. Возможно выбрать стиль всей квартиры или изменить отдельные детали.",
video: "https://graff.estate/videos/features/uralsky.mp4",
},
{
title: "Параметрический поиск квартир",
desc: "Фильтр позволит отметить конкретные преимущества, определить количество комнат, желаемый этаж, цену, и получить выборку подходящих вариантов.",
video: "https://graff.estate/videos/features/parametric.mp4",
},
{
title: "Любой рендер за несколько секунд",
desc: "Когда для рекламы вам понадобится любой объект с любого ракурса, просто сделайте фотографию внутри презентации.",
video: "https://graff.estate/videos/features/render.mp4",
},
{
title: "Формирование вишлиста",
desc: "Клиент может добавить варианты квартир в избранное, сравнить их между собой по основным параметрам и выбрать свою будущую квартиру.",
video: "https://graff.estate/videos/features/wish.mp4",
},
{
title: "Интеграция с CRM-системой",
desc: "Приложение передает информацию о клиенте в CRM-систему застройщика и получает актуальную информацию по ценам и статусам квартир.",
video: "https://graff.estate/videos/features/integra_crm.mp4",
},
{
title: "Отправка коммерческого предложения",
desc: "Коммерческое предложение с выбранными квартирами может быть отправлено клиенту на почту или распечатано и отдано лично в руки.",
video: "https://graff.estate/videos/features/send.mp4",
},
{
title: "Интерактивная инсоляция",
desc: "Функция позволяет в режиме реального времени увидеть уровень освещенности выбранной квартиры, а если вы изучаете экстерьер жилого комплекса – функция покажет архитектурную подсветку.",
video: "",
},
{
title: "Подбор квартир на генплане",
desc: "Сделать генплан удобным инструментом выбора квартиры поможет подсветка выбранных квартир прямо на фасаде Жилого комплекса.",
video: "",
},
]);
const [activeIndex, setActiveIndex] = useState<number>(0);
const videoRefs = items.map(() => useRef<HTMLVideoElement>(null));
const handlers = useSwipeable({
onSwiped: (e) => {
if (e.dir === "Left") {
handleClickNext();
}
if (e.dir === "Right") {
handleClickPrev();
}
},
});
function handleClickPrev() {
if (activeIndex === 0) {
setActiveIndex(items.length - 1);
return;
}
setActiveIndex((prev) => prev - 1);
}
function handleClickNext() {
if (activeIndex === items.length - 1) {
setActiveIndex(0);
return;
}
setActiveIndex((prev) => prev + 1);
}
useEffect(() => {
items.forEach((_, index) => {
if (activeIndex === index) {
videoRefs[index].current?.play();
} else {
videoRefs[index].current?.pause();
}
});
}, [activeIndex]);
return (
<div {...handlers} className="xl:hidden flex flex-col sm:gap-6 gap-4 border-b border-[#3D425C] pb-5">
<div
// ref={videosContainerRef}
className={`relative flex sm:gap-[88px] items-start transition-all duration-500`}
style={{ left: `-${activeIndex * 100}%` }}
>
{items.map((item, index) => (
<motion.video
ref={videoRefs[index]}
key={index}
src={item.video}
muted
loop
playsInline
preload="metadata"
className={`relative aspect-video transition-all duration-500 sm:w-[calc(100%-88px)] ${
index === activeIndex
? ""
: "sm:scale-[70%] scale-[80%] sm:-translate-y-[15%] -translate-y-[10%] sm:-translate-x-[calc(15%+88px-12px)] -translate-x-[calc(10%-8px)]"
}`}
/>
))}
</div>
<div className="flex justify-between sm:gap-[30px] gap-3 sm:h-auto h-[168px]">
<div className="flex flex-col gap-3">
<p className="text-xl font-gilroy font-medium">
{items[activeIndex].title}
</p>
<p className="text-sm">{items[activeIndex].desc}</p>
</div>
<div className="relative flex flex-col items-center gap-4">
<div className="sm:absolute -top-[64px]">
<p className="sm:text-2xl text-xl font-gilroy font-medium">
{activeIndex + 1}/{items.length}
</p>
</div>
<div className="flex flex-col gap-2 self-end">
<button
onClick={handleClickNext}
className="sm:p-4 p-2 border border-[#3D425C] rounded-full outline-none"
>
<ArrowRightIcon />
</button>
<button
onClick={handleClickPrev}
className="sm:p-4 p-2 border border-[#3D425C] rounded-full outline-none"
>
<ArrowLeftIcon />
</button>
</div>
</div>
</div>
</div>
);
}
export default VideoSliderMobile;
@@ -0,0 +1,25 @@
interface IconProps {
className?: string;
}
function ArrowLeftIcon({ className }: IconProps) {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19 12C19 11.4477 18.5523 11 18 11L8.5183 11L13.0496 6.72759C13.4515 6.34871 13.4701 5.71582 13.0912 5.31398C12.7124 4.91215 12.0795 4.89353 11.6776 5.27241L5.31399 11.2724C5.11359 11.4613 5 11.7246 5 12C5 12.2754 5.11359 12.5386 5.31399 12.7276L11.6776 18.7276C12.0795 19.1065 12.7124 19.0878 13.0912 18.686C13.4701 18.2842 13.4515 17.6513 13.0496 17.2724L8.5183 13L18 13C18.5523 13 19 12.5523 19 12Z"
fill="currentColor"
/>
</svg>
);
}
export default ArrowLeftIcon;
+11 -6
View File
@@ -1,17 +1,22 @@
function ArrowRightIcon() {
interface IconProps {
className?: string;
}
function ArrowRightIcon({ className }: IconProps) {
return (
<svg
width="32"
height="32"
viewBox="0 0 32 32"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.66667 16.0003C6.66667 16.7367 7.26363 17.3337 8 17.3337L20.6423 17.3337L14.6005 23.0302C14.0647 23.5354 14.0399 24.3792 14.545 24.915C15.0502 25.4508 15.8941 25.4756 16.4298 24.9704L24.9147 16.9705C25.1819 16.7185 25.3333 16.3676 25.3333 16.0003C25.3333 15.6331 25.1819 15.2821 24.9147 15.0302L16.4298 7.03021C15.8941 6.52504 15.0502 6.54986 14.545 7.08565C14.0399 7.62143 14.0647 8.46528 14.6005 8.97045L20.6423 14.667L8 14.667C7.26363 14.667 6.66667 15.264 6.66667 16.0003Z"
fill="white"
d="M5 12C5 12.5523 5.44771 13 6 13L15.4817 13L10.9504 17.2724C10.5485 17.6513 10.5299 18.2842 10.9088 18.686C11.2876 19.0879 11.9205 19.1065 12.3224 18.7276L18.686 12.7276C18.8864 12.5387 19 12.2754 19 12C19 11.7246 18.8864 11.4614 18.686 11.2724L12.3224 5.27241C11.9205 4.89354 11.2876 4.91215 10.9088 5.31399C10.5299 5.71583 10.5485 6.34872 10.9504 6.72759L15.4817 11L6 11C5.44772 11 5 11.4477 5 12Z"
fill="currentColor"
/>
</svg>
);
+14
View File
@@ -70,3 +70,17 @@ body {
height: 6px;
background-color: #fff;
}
.bg-gradient-card {
content: "";
/* position: absolute; */
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
180deg,
rgba(20, 22, 31, 0) 0%,
rgba(20, 22, 31, 0.6) 100%
);
}
+10
View File
@@ -1404,6 +1404,11 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
react-circular-progressbar@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-circular-progressbar/-/react-circular-progressbar-2.1.0.tgz#99e5ae499c21de82223b498289e96f66adb8fa3a"
integrity sha512-xp4THTrod4aLpGy68FX/k1Q3nzrfHUjUe5v6FsdwXBl3YVMwgeXYQKDrku7n/D6qsJA9CuunarAboC2xCiKs1g==
react-dom@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
@@ -1440,6 +1445,11 @@ react-router@6.18.0:
dependencies:
"@remix-run/router" "1.11.0"
react-swipeable@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-7.0.1.tgz#cd299f5986c5e4a7ee979839658c228f660e1e0c"
integrity sha512-RKB17JdQzvECfnVj9yDZsiYn3vH0eyva/ZbrCZXZR0qp66PBRhtg4F9yJcJTWYT5Adadi+x4NoG53BxKHwIYLQ==
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"