This commit is contained in:
2023-05-04 19:28:59 +05:00
parent 6ed5cde59c
commit 0c8c0c93de
7 changed files with 330 additions and 376 deletions
-161
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.
+212 -91
View File
@@ -10,6 +10,8 @@ import api from "./utils/api";
import FeatureCard from "./components/FeatureCard";
import RelevantExpCard from "./components/RelevantExpCard";
import Title from "./components/Title";
import FeatureCardMobile from "./components/FeatureCardMobile";
import { EffectComposer, Bloom } from "@react-three/postprocessing";
function App() {
const parallaxRef = useRef<HTMLDivElement>(null);
@@ -19,8 +21,8 @@ function App() {
const [company, setCompany] = useState<string>("");
const [phone, setPhone] = useState<string>("");
const [mapPosition, setMapPosition] = useState<string>("29% 100%");
const [mapCity, setMapCity] = useState<string>("Тюмень");
// const [mapPosition, setMapPosition] = useState<string>("29% 100%");
// const [mapCity, setMapCity] = useState<string>("Тюмень");
const [isShowRelevantExpCards, setIsShowRelevantExpCards] =
useState<boolean>(false);
@@ -31,10 +33,14 @@ function App() {
const featureImagesContainer = useRef<HTMLDivElement>(null);
const featureImages = [
"https://images.unsplash.com/photo-1682595950157-8d1cc0ef388f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1682402178953-f2cb484d4024?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&q=60",
"https://plus.unsplash.com/premium_photo-1676648534973-dd205cb63d99?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMnx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1682353213492-8433d437855a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxM3x8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
"/images/cards/1.jpg",
"/images/cards/2.jpg",
"/images/cards/3.jpg",
"/images/cards/4.jpg",
"/images/cards/5.jpg",
"/images/cards/6.jpg",
"/images/cards/7.jpg",
"/images/cards/8.jpg",
];
const [selectedFeatureImageIndex, setSelectedFeatureImageIndex] =
useState<number>(0);
@@ -88,21 +94,21 @@ function App() {
alert("Заявка отправлена!");
}
function handleClickComplexCard(city: string) {
if (city === "Тюмень") {
setMapPosition("29% 100%");
} else if (city === "Екатеринбург") {
setMapPosition("22% 93%");
} else if (city === "Брянск") {
setMapPosition("1.5% 48%");
} else if (city === "Санкт-Петербург") {
setMapPosition("6% 16%");
} else if (city === "Нижний Тагил") {
setMapPosition("19% 77%");
}
// function handleClickComplexCard(city: string) {
// if (city === "Тюмень") {
// setMapPosition("29% 100%");
// } else if (city === "Екатеринбург") {
// setMapPosition("22% 93%");
// } else if (city === "Брянск") {
// setMapPosition("1.5% 48%");
// } else if (city === "Санкт-Петербург") {
// setMapPosition("6% 16%");
// } else if (city === "Нижний Тагил") {
// setMapPosition("19% 77%");
// }
setMapCity(city);
}
// setMapCity(city);
// }
useEffect(() => {
window.addEventListener("scroll", handleScroll);
@@ -116,7 +122,7 @@ function App() {
<div className="bg-[#131317] text-white">
<div
ref={parallaxRef}
className="relative lg:container mx-auto p-4 xl:max-w-screen-2xl"
className="relative lg:container mx-auto p-4 xl:max-w-screen-2xl overflow-hidden"
>
<div className="space-y-44 mb-44">
<div className="flex justify-between">
@@ -154,12 +160,12 @@ function App() {
{/* <div className="h-24 w-0.5 bg-[#23242A]"></div> */}
</div>
</div>
<div className="absolute top-0 right-0 ">
<div className="absolute top-0 right-0 sm:translate-x-0 sm:translate-y-0 translate-x-[40%] translate-y-[40%]">
<img src="/images/shapes/1.svg" alt="" />
</div>
</div>
<div className="relative xl:space-y-48 lg:space-y-40 sm:space-y-28 space-y-20">
<div className="relative xl:space-y-48 lg:space-y-40 sm:space-y-28 space-y-20 overflow-hidden">
<div
className="max-w-screen h-screen bg-cover bg-no-repeat bg-center rounded-xl overflow-hidden"
style={{ backgroundImage: "url('/images/content.jpg')" }}
@@ -265,14 +271,12 @@ function App() {
преимущества объекта
</div>
</div>
<div className="absolute w-full h-full top-[-64px] left-0 flex justify-center items-center">
<div className="lg:flex hidden absolute w-full h-full top-[-64px] left-0 justify-center items-center">
<img src="/images/shapes/2.svg" alt="" />
</div>
{/* <div className="h-0.5 bg-[#23242A]"></div> */}
{/* <Slider /> */}
<div className="grid lg:grid-cols-2 relative z-50">
<div className="relative lg:grid hidden lg:grid-cols-2 ">
<FeatureCard
text="Интеграция с CRM - системой"
text="Интеграция с CRM системой"
handleMouseEnter={() => setSelectedFeatureImageIndex(0)}
/>
<div className="row-span-2 h-full border border-[#454554] backdrop-blur-lg bg-[rgba(46, 46, 56, 0.1)] ">
@@ -301,54 +305,70 @@ function App() {
/>
<FeatureCard
text="Виртуальный тур по жилому комплексу"
handleMouseEnter={() => setSelectedFeatureImageIndex(2)}
handleMouseEnter={() => setSelectedFeatureImageIndex(4)}
/>
<FeatureCard
text="Формирование вишлиста"
handleMouseEnter={() => setSelectedFeatureImageIndex(1)}
handleMouseEnter={() => setSelectedFeatureImageIndex(5)}
/>
<FeatureCard
text="Конфигуратор интерьера"
handleMouseEnter={() => setSelectedFeatureImageIndex(0)}
handleMouseEnter={() => setSelectedFeatureImageIndex(6)}
/>
<FeatureCard
text="Отправка коммерческого предложения"
handleMouseEnter={() => setSelectedFeatureImageIndex(3)}
handleMouseEnter={() => setSelectedFeatureImageIndex(7)}
/>
</div>
<div className="relative lg:hidden block">
<FeatureCardMobile
title="Интеграция с CRM системой"
text="Фильтр позволит отметить конкретные преимущества, определить количество комнат, желаемый этаж, цену, и получить выборку подходящих вариантов"
image="/images/cards/1.jpg"
/>
<FeatureCardMobile
title="Параметрический поиск квартир"
text="Приложение передает информацию о клиенте в CRM систему застройщика и получает актуальную информацию по ценам и статусам квартир."
image="/images/cards/2.jpg"
/>
<FeatureCardMobile
title="Вся инфрастуктура на одном экране"
text="Возможность оценить инфраструктуру района покажет важные для клиента точки интереса и время, за которое он сможет до них дойти."
image="/images/cards/3.jpg"
/>
<FeatureCardMobile
title="Виртуальный тур по жилому комплексу"
text="Клиент лично оценит угол инсоляции, малые архитектурные формы и ландшафт, перемещаясь по комплексу с помощью тапа."
image="/images/cards/4.jpg"
/>
<FeatureCardMobile
title="Конфигуратор интерьера"
text="Клиент может свободно выбирать мебель и дизайн с помощью конфигуратора интерьера. Возможно выбрать стиль всей квартиры или изменить отдельные детали."
image="/images/cards/5.jpg"
/>
<FeatureCardMobile
title="Формирование вишлиста"
text="Клиент может добавить варианты квартир в избранное, сравнить их между собой по основным параметрам и выбрать свою будущую квартиру."
image="/images/cards/6.jpg"
/>
<FeatureCardMobile
title="Любой рендер за несколько секунд"
text="Когда для рекламы вам понадобится любой объект с любого ракурса, просто сделайте фотографию внутри презентации."
image="/images/cards/7.jpg"
/>
<FeatureCardMobile
title="Отправка коммерческого предложения"
text="Коммерческое предложение с выбранными квартирами может быть отправлено клиенту на почту или распечатано и отдано лично в руки."
image="/images/cards/8.jpg"
/>
</div>
</div>
</div>
<div className="lg:container mx-auto p-4 xl:max-w-screen-2xl overflow-hidden">
<div className="lg:container mx-auto p-4 xl:max-w-screen-2xl">
<div className="xl:grid grid-cols-2 gap-6 relative">
<div ref={helmetRef} className="xl:block hidden">
{helmetInView && (
<motion.div
initial={{ opacity: 0, x: "25%" }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.25, duration: 3 }}
viewport={{ once: true }}
className=" absolute w-full h-full"
>
<Canvas className="min-h-[1024px] w-[600px] -translate-y-80 -translate-x-[30%]">
<Suspense fallback={null}>
<ambientLight intensity={0.5} />
<directionalLight color="white" position={[-3, 1, 5]} />
<Model />
{/* <OrbitControls
enablePan={true}
enableZoom={true}
enableRotate={true}
/> */}
</Suspense>
</Canvas>
</motion.div>
)}
</div>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 2.5, duration: 1 }}
className="lg:space-y-16 space-y-8"
>
<Title>Экскурсия в виртуальной реальности</Title>
@@ -362,6 +382,45 @@ function App() {
Записаться в шоу-рум
</button>
</motion.div>
<div ref={helmetRef} className="xl:block hidden">
{helmetInView && (
<motion.div
initial={{ opacity: 0, x: "25%" }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.25, duration: 3.25 }}
className=" absolute w-full h-full"
>
<Canvas className="min-h-[1024px] w-[600px] -translate-y-[25%] -translate-x-[25%]">
<Suspense fallback={null}>
<ambientLight intensity={1} />
<directionalLight color="white" position={[-3, 1, 5]} />
<Model />
{/* <OrbitControls
enablePan={true}
enableZoom={true}
enableRotate={true}
/> */}
<EffectComposer>
{/* <DepthOfField
focusDistance={0}
focalLength={0.02}
bokehScale={2}
height={480}
/> */}
{/* <Bloom
luminanceThreshold={0}
luminanceSmoothing={0.9}
height={300}
/> */}
{/* <Noise opacity={0.02} />
<Vignette eskil={false} offset={0.1} darkness={1.1} /> */}
</EffectComposer>
</Suspense>
</Canvas>
</motion.div>
)}
</div>
</div>
</div>
@@ -371,7 +430,11 @@ function App() {
</div>
<div className="relative grid xl:grid-cols-2 gap-8">
<div className="space-y-8">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="space-y-8"
>
<Title>Анализируем поведение пользователей</Title>
<div className="2xl:text-2xl sm:text-xl text-lg space-y-4">
<p>
@@ -384,11 +447,15 @@ function App() {
комплекса еще эффективнее.
</p>
</div>
</div>
</motion.div>
<div className="grid sm:grid-cols-3 gap-4">
<div className="sm:col-span-2 space-y-4">
<div className="2xl:p-8 sm:p-6 p-4 space-y-6 bg-[#272730] rounded-lg">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="2xl:p-8 sm:p-6 p-4 space-y-6 bg-[#272730] rounded-lg"
>
<p className="2xl:text-xl sm:text-base text-sm uppercase tracking-wider">
Конверсия менеджеров в брони
</p>
@@ -398,7 +465,11 @@ function App() {
К. Н. Федоров
</span>
<div className="w-[45%]">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] h-10 rounded"></div>
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "100%" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] h-10 rounded"
></motion.div>
</div>
<span className="w-[15%] text-right">45%</span>
</div>
@@ -408,7 +479,11 @@ function App() {
И. Ф. Яковлева
</span>
<div className="w-[45%]">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] h-10 rounded"></div>
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "80%" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] h-10 rounded"
></motion.div>
</div>
<span className="w-[15%] text-right">30%</span>
</div>
@@ -418,14 +493,22 @@ function App() {
А. М. Ташева
</span>
<div className="w-[45%]">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[83px] h-10 rounded"></div>
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "83px" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[83px] h-10 rounded"
></motion.div>
</div>
<span className="w-[15%] text-right">20%</span>
</div>
</div>
</div>
</motion.div>
<div className="2xl:p-8 sm:p-6 p-4 space-y-6 bg-[#272730] rounded-lg">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="2xl:p-8 sm:p-6 p-4 space-y-6 bg-[#272730] rounded-lg"
>
<p className="2xl:text-xl sm:text-base text-sm uppercase tracking-wider">
Популярные типы квартир, %
</p>
@@ -469,27 +552,41 @@ function App() {
</div>
</div>
</div>
</div>
</motion.div>
<div className="2xl:p-8 sm:p-6 p-4 space-y-6 bg-[#272730] rounded-lg">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="2xl:p-8 sm:p-6 p-4 space-y-6 bg-[#272730] rounded-lg"
>
<p className="2xl:text-xl sm:text-base text-sm uppercase tracking-wider">
Воронка продаж
</p>
<div className="space-y-4">
<div className="grid grid-cols-5 gap-4 items-center">
<div className="col-span-4 2xl:text-xl sm:text-base text-sm bg-gradient-to-bl from-[#D375FF1A] to-[#798FFF1A] rounded flex justify-center space-x-4">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-full h-10 rounded flex justify-center items-center">
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "100%" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-full h-10 rounded flex justify-center items-center"
>
Сеансы
</div>
</motion.div>
</div>
<span className="col-span-1 text-right w-full 2xl:text-xl">100%</span>
<span className="col-span-1 text-right w-full 2xl:text-xl">
100%
</span>
</div>
<div className="grid grid-cols-5 gap-4 items-center">
<div className="col-span-4 2xl:text-xl sm:text-base text-sm bg-gradient-to-bl from-[#D375FF1A] to-[#798FFF1A] rounded flex justify-center space-x-4">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[90%] h-10 rounded flex justify-center items-center">
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "90%" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[90%] h-10 rounded flex justify-center items-center whitespace-nowrap"
>
В избранное
</div>
</motion.div>
</div>
<span className="col-span-1 text-right w-full 2xl:text-xl">
93,47%
@@ -498,9 +595,13 @@ function App() {
<div className="grid grid-cols-5 gap-4 items-center">
<div className="col-span-4 2xl:text-xl sm:text-base text-sm bg-gradient-to-bl from-[#D375FF1A] to-[#798FFF1A] rounded flex justify-center space-x-4">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[50%] h-10 rounded flex justify-center items-center">
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "50%" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[50%] h-10 rounded flex justify-center items-center"
>
Брони
</div>
</motion.div>
</div>
<span className="col-span-1 text-right w-full 2xl:text-xl">
45,68%
@@ -509,20 +610,28 @@ function App() {
<div className="grid grid-cols-5 gap-4 items-center">
<div className="col-span-4 2xl:text-xl sm:text-base text-sm bg-gradient-to-bl from-[#D375FF1A] to-[#798FFF1A] rounded flex justify-center space-x-4">
<div className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[35%] h-10 rounded flex justify-center items-center">
<motion.div
initial={{ width: 0 }}
whileInView={{ width: "35%" }}
className="bg-gradient-to-bl from-[#BC75FF] to-[#798FFF] w-[35%] h-10 rounded flex justify-center items-center"
>
Продажи
</div>
</motion.div>
</div>
<span className="col-span-1 text-right w-full 2xl:text-xl">
29,13%
</span>
</div>
</div>
</div>
</motion.div>
</div>
<div className="grid sm:grid-cols-1 grid-cols-2 gap-4 sm:space-y-4">
<div className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4">
<div className="grid sm:grid-cols-1 grid-cols-2 gap-4">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4"
>
<div className="font-gilroy text-gradient">
<p className="sm:text-6xl text-5xl">12</p>
<p className="text-xl font-medium">минут</p>
@@ -530,9 +639,13 @@ function App() {
<p className="2xl:text-xl sm:text-base text-sm">
Среднее время сеанса
</p>
</div>
</motion.div>
<div className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4"
>
<div className="font-gilroy text-gradient">
<p className="sm:text-6xl text-5xl">856</p>
{/* <p className="text-xl font-medium">минут</p> */}
@@ -540,9 +653,13 @@ function App() {
<p className="2xl:text-xl sm:text-base text-sm">
Коммерческих предложений сформировано
</p>
</div>
</motion.div>
<div className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4"
>
<div className="font-gilroy text-gradient">
<p className="sm:text-6xl text-5xl">12,41%</p>
{/* <p className="text-xl font-medium">минут</p> */}
@@ -550,9 +667,13 @@ function App() {
<p className="2xl:text-xl sm:text-base text-sm">
Конверсия из сеанса в бронь
</p>
</div>
</motion.div>
<div className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="bg-[#272730] rounded-lg flex flex-col justify-between items-start 2xl:p-8 sm:p-6 p-4 space-y-4"
>
<div className="font-gilroy text-gradient">
<p className="sm:text-6xl text-5xl">132,1</p>
<p className="text-xl font-medium">млн. р.</p>
@@ -560,7 +681,7 @@ function App() {
<p className="2xl:text-xl sm:text-base text-sm">
Получено через Graff.estate
</p>
</div>
</motion.div>
</div>
</div>
</div>
@@ -829,12 +950,12 @@ function App() {
<div className="space-y-8">
<div className="space-x-4">
<label className="text-xl">
<input
{/* <input
type="checkbox"
name=""
className="bg-[#454554] hover:bg-[#454554] cursor-pointer
w-10 h-10 rounded-lg checked:bg-[#454554] checked:hover:bg-[#454554] border-0 focus:ring-offset-0 focus:ring-transparent mr-4"
/>
/> */}
<span className="text-[#ABABBA] text-opacity-50">
Я согласен с
</span>{" "}
@@ -845,7 +966,7 @@ function App() {
</div>
<button
type="submit"
className="2xl:text-3xl text-2xl w-full px-8 py-4 bg-gradient-to-tr from-[#BC75FF] to-[#798FFF] rounded-full opacity-95 hover:opacity-100 transition-opacity"
className="2xl:text-3xl sm:text-2xl text-lg w-full px-8 py-4 bg-gradient-to-tr from-[#BC75FF] to-[#798FFF] rounded-full opacity-95 hover:opacity-100 transition-opacity"
>
Отправить заявку
</button>
+23 -12
View File
@@ -2,6 +2,7 @@ import React, { ChangeEvent, useEffect, useState } from "react";
import SearchableSelect from "./SearchableSelect";
import api from "../utils/api";
import { motion } from "framer-motion";
import RangeSlider from "./RangeSlider";
function Calc() {
const [regions, setRegions] = useState<any[]>([]);
@@ -225,13 +226,23 @@ function Calc() {
<p className="2xl:text-base text-sm text-[#C5C7CE]">
Очных консультаций в месяц
</p>
<input
type="text"
pattern="^\d+$"
className="px-5 py-3.5 w-full outline-none placeholder:text-white rounded border border-transparent transition-colors bg-[#454554] focus:border-[#BC75FF]"
value={consultsPerMonth}
onChange={handleChangeConsultsPerMonth}
/>
<div className="relative">
<div className="absolute -bottom-[6px] left-0 w-full">
<RangeSlider
min={10}
max={1000}
defaultValue={consultsPerMonth}
handleChange={(value) => setConsultsPerMonth(value)}
/>
</div>
<input
type="text"
pattern="^\d+$"
className="px-5 py-3.5 w-full outline-none placeholder:text-white rounded border border-transparent transition-colors bg-[#454554] focus:border-[#BC75FF]"
value={consultsPerMonth}
onChange={handleChangeConsultsPerMonth}
/>
</div>
</div>
<div className="bg-[#272730] 2xl:p-6 p-4 2xl:space-y-[29px] space-y-[25px] rounded">
@@ -294,8 +305,8 @@ function Calc() {
Результаты расчета
</p>
<div className="grid xl:grid-cols-1 grid-cols-2 xl:gap-0 gap-6 xl:space-y-6">
<div className="xl:border-b-2 xl:border-t-0 border-t-2 border-[#2E3038] xl:pt-0 pt-6 xl:pb-6 space-y-6">
<div className="grid xl:grid-cols-1 lg:grid-cols-2 grid-cols-1 xl:gap-0 gap-6 xl:space-y-6">
<div className="xl:border-b-2 xl:border-t-0 lg:border-t-2 border-t-0 border-[#2E3038] xl:pt-0 pt-6 xl:pb-6 space-y-6">
<p className="text-[#C5C7CE]">Срок реализации</p>
<div className="grid grid-cols-2">
<div className="space-y-1">
@@ -310,7 +321,7 @@ function Calc() {
<p className="2xl:text-xl">{implementationTimeCase}</p>
</div>
{isEnabled && (
<p className="text-xl fade-in">
<p className="2xl:text-xl sm:text-base text-sm fade-in">
На{" "}
<span className="text-[#D375FF]">
{diffImplementationTime} {diffImplementationTimeCase}
@@ -336,7 +347,7 @@ function Calc() {
<p className="2xl:text-xl">млн. р.</p>
</div>
{isEnabled && (
<p className="text-xl fade-in">
<p className="2xl:text-xl sm:text-base text-sm fade-in">
На{" "}
<span className="text-[#D375FF]">
{diffProfitPerMonth} млн. р.
@@ -351,7 +362,7 @@ function Calc() {
<div className="pt-3.5">
<button
className={[
"w-full px-6 py-3 rounded-full",
"xl:w-full lg:w-[calc(100%/2-12px)] sm:w-fit w-full px-6 py-3 rounded-full sm:text-xl text-lg",
isEnabled ? "bg-[#2E2E38]" : "bg-gradient",
].join(" ")}
onClick={() => setIsEnabled(!isEnabled)}
@@ -0,0 +1,80 @@
import { motion } from "framer-motion";
import React from "react";
interface IFeatureCard {
title: string;
text: string;
image: string;
}
function FeatureCardMobile({ title, text, image }: IFeatureCard) {
return (
<div>
<motion.div
initial={{ height: "144px" }}
whileInView={{ height: "448px" }}
viewport={{ once: true }}
className="relative flex flex-col justify-between border border-[#454554] 2xl:h-44 h-36 p-4 transition-colors bg-[#2E2E38] bg-opacity-10"
>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
className="absolute top-0 left-0 w-full h-full bg-center bg-no-repeat bg-cover"
style={{ backgroundImage: `url('${image}')` }}
></motion.div>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
className="absolute top-0 left-0 w-full h-full bg-gradient-to-b from-transparent to-[#17171CE5]"
></motion.div>
<motion.svg
initial={{ opacity: 1 }}
whileInView={{ opacity: 0 }}
viewport={{ once: true }}
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="relative 2xl:h-full 2xl:w-full h-6 w-6"
>
<g clipPath="url(#clip0_1414_844)">
<path
d="M2.14528 38.9894L39 1M39 1L38.7903 39M39 1H1"
stroke="#D9D9D9"
strokeWidth="3"
/>
</g>
<defs>
<clipPath id="clip0_1414_844">
<rect
width="40"
height="40"
fill="white"
transform="matrix(1 0 0 -1 0 40)"
/>
</clipPath>
</defs>
</motion.svg>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
className="relative overflow-hidden"
>
<p className="font-gilroy uppercase 2xl:text-2xl sm:text-xl tracking-wider">
{title}
</p>
<p className="relative 2xl:text-2xl sm:text-xl">{text}</p>
</motion.div>
</motion.div>
</div>
);
}
export default FeatureCardMobile;
+12 -109
View File
@@ -4,124 +4,27 @@ interface IRangeSlider {
min: number;
max: number;
defaultValue: number;
onChange: (value: number) => void;
handleChange: (value: number) => void;
}
function RangeSlider({ min, max, defaultValue, onChange }: IRangeSlider) {
function RangeSlider({ min, max, defaultValue, handleChange }: IRangeSlider) {
const [value, setValue] = useState<number>(defaultValue);
const [isEdited, setIsEdited] = useState<boolean>(false);
const [editableValue, setEditableValue] = useState<number>(value);
function saveValue() {
if (editableValue < min || editableValue > max) {
setEditableValue(Math.round((max + min) / 2));
setValue(Math.round((max + min) / 2));
} else {
setValue(editableValue);
}
setIsEdited(false);
}
useEffect(() => {
setValue(defaultValue);
}, [defaultValue]);
useEffect(() => {
onChange(value);
}, [value]);
function handleChangeEditableValue(e: ChangeEvent<HTMLInputElement>) {
const pattern = new RegExp(e.target.pattern);
if (pattern.test(e.target.value)) {
if (+e.target.value >= 1000000000) {
setEditableValue(1000000000);
} else if (+e.target.value < 1) {
setEditableValue(1);
} else {
setEditableValue(+e.target.value);
}
}
}
return (
<div className="space-y-1">
<p className="text-xl flex space-x-2">
{!isEdited ? (
<>
<span>{value.toLocaleString()}</span>
<button
className="opacity-90 hover:opacity-100 transition-opacity"
onClick={() => setIsEdited(true)}
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 5H4C3.44772 5 3 5.44772 3 6V20C3 20.5523 3.44772 21 4 21H18C18.5523 21 19 20.5523 19 20V12M8 16V14L15 7L17 9L10 16H8ZM17 5L19 3L21 5L19 7L17 5Z"
stroke="#F2F2F2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
</>
) : (
<>
<input
type="text"
pattern="^[0-9]+$"
size={editableValue.toString().length}
className="bg-[#23242A] outline-none"
value={editableValue}
onChange={handleChangeEditableValue}
autoFocus
/>
<button
className="opacity-90 hover:opacity-100 transition-opacity"
onClick={saveValue}
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 11L10 16L19 8"
stroke="#F2F2F2"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
</>
)}
</p>
<input
type="range"
min={min}
max={max}
value={value}
className="transition-all w-full h-0.5 bg-[#798FFF] custom-slider"
onChange={(e) => (
setValue(+e.target.value),
setEditableValue(Math.round(+e.target.value))
)}
/>
<div className="flex justify-between text-[#798FFF]">
<span>{min.toLocaleString()}</span>
<span>{max.toLocaleString()}</span>
</div>
</div>
<input
type="range"
min={min}
max={max}
value={value}
className="transition-all w-full h-0.5 bg-[#798FFF] custom-slider"
onChange={(e) => (
handleChange(+e.target.value), setValue(+e.target.value)
)}
/>
);
}
+3 -3
View File
@@ -8,7 +8,7 @@ import { useGLTF, useAnimations } from "@react-three/drei";
export function Model(props: any) {
const group = useRef(null);
const { nodes, materials, animations }: any = useGLTF("/VRAnim_46.glb");
const { nodes, materials, animations }: any = useGLTF("/VRAnim_47.glb");
const { actions }: any = useAnimations(animations, group);
useEffect(() => {
@@ -22,7 +22,7 @@ export function Model(props: any) {
<group ref={group} {...props} dispose={null}>
<group
name="Scene"
position={[0, 0, -100]}
position={[0, 0, -80]}
rotation={[0, Math.PI / -2, 0]}
>
<mesh
@@ -35,4 +35,4 @@ export function Model(props: any) {
);
}
useGLTF.preload("/VRAnim_46.glb");
useGLTF.preload("/VRAnim_47.glb");