This commit is contained in:
2025-01-29 19:05:22 +05:00
parent a2595a4676
commit 0bf1c1071a
10 changed files with 661 additions and 238 deletions
+4
View File
@@ -145,6 +145,10 @@ body {
@apply sm:text-[clamp(12px,12px+(100vw-360px)/1560*2,14px)] text-xs leading-none;
}
@utility text-gradient {
@apply bg-gradient-to-r from-[#798FFF] to-[#D375FF] bg-clip-text;
}
@keyframes infinite-scroll {
0% {
transform: translateX(0);
+1 -1
View File
@@ -17,7 +17,7 @@ export function Clients() {
return (
<div className="lg:space-y-16 space-y-10 lg:mt-40 mt-[100px]">
<Title>
<Title className="mx-auto text-center max-w-2/3">
<span className="text-gradient">
{companies !== undefined && getCompaniesCount(companies.length)}
</span>{' '}
@@ -1,11 +1,11 @@
import { PresentationLG } from './PresentationLG';
import { PresentationMD } from './PresentationMD';
import { PresentationMd2 } from './PresentationMd2';
export function Presentation() {
return (
<>
<PresentationLG />
<PresentationMD />
<PresentationMd2 />
</>
);
}
@@ -38,7 +38,7 @@ export function PresentationLG() {
и увеличивают темпы продаж квартир в жилом комплексе
</Title>
<div className="h-[480vh]" ref={ref}>
<div className="gap-x-3 items-stretch h-[480vh] max-h-[80vh] overflow-hidden w-full transition-transform sticky grid grid-cols-6 grid-rows-1 duration-1000 top-24">
<div className="gap-x-3 items-stretch h-[480vh] max-h-[80vh] overflow-hidden w-full sticky grid grid-cols-6 grid-rows-1 duration-1000 top-24">
<Searching slide={slide} />
<AnimatePresence>{slide === 5 && <IntegrationCRM />}</AnimatePresence>
<VideoLayer slide={slide} videoRefs={videoRefs} />
@@ -1,10 +1,14 @@
'use client';
import { EmotionalIcon } from '@/components/icons/EmotionalIcon';
import { Flat1 } from '@/components/icons/Flat1';
import { Flat2 } from '@/components/icons/Flat2';
import { KidsIcon } from '@/components/icons/KidsIcon';
import { LocationIcon } from '@/components/icons/LocationIcon';
import { MailIcon } from '@/components/icons/MailIcon';
import { MetroIcon } from '@/components/icons/MetroIcon';
import { NatureIcon } from '@/components/icons/NatureIcon';
import { PhoneIcon } from '@/components/icons/PhoneIcon';
import { SafetyIcon } from '@/components/icons/SafetyIcon';
import { ShopIcon } from '@/components/icons/ShopIcon';
import { SportIcon } from '@/components/icons/SportIcon';
@@ -12,19 +16,31 @@ import { StudyIcon } from '@/components/icons/StudyIcon';
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
import { SeasonCard } from '@/ui/SeasonCard';
import { SlideBadge } from '@/ui/SlideBadge';
import { Title } from '@/ui/Title';
import Image from 'next/image';
export function PresentationMD() {
return (
<div className="md:max-lg:block hidden space-y-[500px] h-[calc(auto+500px)]">
<div className="top-16 h-[80vh] sticky flex flex-col bg-[#0F1011]">
<div className="space-y-12 mt-25 md:max-lg:block hidden">
<Title>
Интерактивная презентация
<span className="text-gradient">
{' '}
улучшает опыт выбора недвижимости{' '}
</span>
и увеличивают темпы продаж квартир в жилом комплексе
</Title>
<div className="space-y-[100vh] h-[1200vh]">
<div className="top-0 pt-16 h-screen sticky flex flex-col bg-[#0F1011]">
<video
src="/videos/pages/home/presentation/1_search.mp4"
loop
muted
playsInline
autoPlay
className="flex-1"
/>
<div className="gap-x-3 flex flex-1">
<div className="gap-x-3 flex min-h-[30vh]">
<div className="p-6 rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] to-transparent flex flex-col justify-between flex-1">
<p className="heading2 font-medium">Выбор квартиры на генплане</p>
<div className="space-y-4">
@@ -67,15 +83,16 @@ export function PresentationMD() {
</div>
</div>
</div>
<div className="top-16 sticky flex flex-col bg-[#0F1011] pb-5">
<div className="top-0 pt-16 sticky flex flex-col bg-[#0F1011] h-screen">
<video
src="/videos/pages/home/presentation/2_3dtour.mp4"
loop
muted
playsInline
className="object-center"
autoPlay
className="flex-1"
/>
<div className="space-y-6 bg-[#0F1011] aflex-1">
<div className="space-y-6 bg-[#0F1011]">
<p className="heading2 font-medium text-center">3D-тур</p>
<div className="grid items-stretch grid-cols-3 grid-rows-2 gap-2">
{[
@@ -105,12 +122,14 @@ export function PresentationMD() {
</div>
</div>
</div>
<div className="top-16 sticky flex flex-col pb-5 bg-[#0F1011]">
<div className="top-0 pt-16 sticky flex flex-col bg-[#0F1011] h-screen">
<video
src="/videos/pages/home/presentation/3_infrastructure.mp4"
loop
muted
playsInline
autoPlay
className="flex-1"
/>
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid gap-y-7 grid-rows-[5fr_2fr] grid-cols-2">
<p className="heading2 font-medium">
@@ -119,8 +138,8 @@ export function PresentationMD() {
<p className="text1">
Режим «Инфраструктура» знакомит пользователя с перспективной
застройкой целого района. В зависимости от срока сдачи либо
функциональной нагрузки того или иного блока можно ввести выделение
цветом.
функциональной нагрузки того или иного блока можно ввести
выделение цветом.
</p>
<div className="flex col-span-2 gap-[5px]">
<div className="w-18 h-18 aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
@@ -161,14 +180,16 @@ export function PresentationMD() {
</div>
</div>
</div>
<div className="top-16 sticky flex flex-col bg-[#0F1011] pb-5">
<div className="top-0 pt-16 sticky flex flex-col bg-[#0F1011] h-screen">
<video
src="/videos/pages/home/presentation/4_insolation.mp4"
loop
muted
playsInline
autoPlay
className="flex-1"
/>
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid gap-y-[30px] grid-cols-2 grid-rows-[1fr_3fr] flex-1">
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid gap-y-[30px] grid-cols-2 grid-rows-[1fr_3fr]">
<p className="heading2 font-medium">Интерактивная инсоляция</p>
<p className="text1">
Клиент может наблюдать, как световое пятно перемещается в
@@ -199,12 +220,14 @@ export function PresentationMD() {
</div>
</div>
</div>
<div className="top-16 sticky flex flex-col gap-16 pb-5 bg-[#0F1011]">
<div className="top-0 pt-16 sticky flex flex-col bg-[#0F1011] h-screen">
<video
src="/videos/pages/home/presentation/5_engine.mp4"
loop
muted
autoPlay
playsInline
className="flex-1"
/>
<div className="space-y-6">
<p className="heading2 font-medium text-center">
@@ -226,7 +249,7 @@ export function PresentationMD() {
},
].map(({ src, title }) => (
<div
className="flex flex-col gap-16 items-stretch pt-5 pb-2 pl-4 pr-2 bg-[#37393B99] rounded-2xl flex-1"
className="flex flex-col gap-10 items-stretch pt-5 pb-2 pl-4 pr-2 bg-[#37393B99] rounded-2xl flex-1"
key={title}
>
<p className="text1">{title}</p>
@@ -244,6 +267,70 @@ export function PresentationMD() {
</div>
</div>
</div>
<div className="flex flex-col bg-[#0F1011] sticky top-0 pt-16 h-screen">
<video
src="/videos/pages/home/presentation/6_reservation.mp4"
loop
muted
playsInline
autoPlay
className="flex-1"
/>
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid grid-cols-2">
<p className="heading2 font-medium">
Интеграция с CRM-системой застройщика
</p>
<div className="space-y-10">
<div className="space-y-4">
<div className="flex">
<div className="w-12 h-12 rounded-lg bg-[#B5F54E] flex items-center text-black font-medium justify-center -rotate-[4deg] text1 shadow-[0_2px_10px_0_#00000033] z-[2]">
2K
</div>
<div className="bg-[#37393B] rounded-lg right-2 relative shadow-[0_2px_10px_0_#00000033] z-[1]">
<ClassNameWrapper className="w-12 h-12">
<Flat1 />
</ClassNameWrapper>
</div>
<div className="bg-[#37393B] rounded-lg -rotate-[4deg] right-4 relative shadow-[0_2px_10px_0_#00000033]">
<ClassNameWrapper className="w-12 h-12">
<Flat2 />
</ClassNameWrapper>
</div>
</div>
<p className="text1">
Клиент всегда видит актуальные данные об интересующем его
лоте, включая статус и стоимость.
</p>
</div>
<div className="space-y-4">
<div className="flex">
<Image
src={'/img/pages/home/presentation/vova.png'}
width={48}
height={48}
alt="vovka"
className="rounded-lg -rotate-[4deg] shadow-[0_2px_10px_0_#00000033] z-[2]"
/>
<div className="rounded-lg bg-[#37393B] flex justify-center items-center relative right-2 w-12 h-12 shadow-[0_2px_10px_0_#00000033] z-[1]">
<ClassNameWrapper className="w-[21px] h-[21px]">
<MailIcon />
</ClassNameWrapper>
</div>
<div className="rounded-lg bg-[#37393B] flex justify-center items-center relative right-4 -rotate-[4deg] w-12 h-12 shadow-[0_2px_10px_0_#00000033]">
<ClassNameWrapper className="w-[21px] h-[21px]">
<PhoneIcon />
</ClassNameWrapper>
</div>
</div>
<p className="text1">
Инструмент продаж сам создаст карточку клиента в вашей
CRM-системе и назначит ответственного менеджера.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,333 @@
'use client';
import { EmotionalIcon } from '@/components/icons/EmotionalIcon';
import { Flat1 } from '@/components/icons/Flat1';
import { Flat2 } from '@/components/icons/Flat2';
import { KidsIcon } from '@/components/icons/KidsIcon';
import { LocationIcon } from '@/components/icons/LocationIcon';
import { MailIcon } from '@/components/icons/MailIcon';
import { MetroIcon } from '@/components/icons/MetroIcon';
import { NatureIcon } from '@/components/icons/NatureIcon';
import { PhoneIcon } from '@/components/icons/PhoneIcon';
import { SafetyIcon } from '@/components/icons/SafetyIcon';
import { ShopIcon } from '@/components/icons/ShopIcon';
import { SportIcon } from '@/components/icons/SportIcon';
import { StudyIcon } from '@/components/icons/StudyIcon';
import { videos } from '@/consts/presentation/videos';
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
import { useScroll } from '@/hooks/useScroll';
import { SeasonCard } from '@/ui/SeasonCard';
import { SlideBadge } from '@/ui/SlideBadge';
import { Title } from '@/ui/Title';
import Image from 'next/image';
import { createRef, RefObject, useEffect, useRef, useState } from 'react';
export function PresentationMd2() {
const [slide, setSlide] = useState(0);
const [videoRefs, setVideoRefs] = useState<RefObject<HTMLVideoElement>[]>([]);
const ref = useRef<HTMLDivElement>(null);
const scroll = useScroll(ref);
useEffect(() => setVideoRefs(videos.map(createRef<HTMLVideoElement>)), []);
useEffect(
() =>
setSlide(
Math.max(
0,
Math.min(
5,
Math.trunc(
(window.innerHeight - 388 - scroll) / (window.innerHeight + 199)
)
)
)
),
[scroll]
);
useEffect(() => {
console.log(-scroll, window.innerHeight + 388);
}, [scroll]);
useEffect(() => {
videoRefs[slide]?.current?.play();
}, [slide, videoRefs]);
return (
<div className="mt-25 max-md:hidden lg:hidden">
<div className="space-y-12 sticky top-25">
<Title>
Интерактивная презентация{' '}
<span className="text-gradient">
улучшает опыт выбора недвижимости
</span>{' '}
и увеличивают темпы продаж квартир в жилом комплексе
</Title>
<div className="relative h-95">
{videos.map((video, index) => (
<video
key={video}
src={`/videos/pages/home/presentation/${video}.mp4`}
loop
muted
playsInline
ref={videoRefs[index]}
style={{
zIndex: videos.length - index,
}}
className={`absolute w-full h-full transition-opacity${
slide > index && index !== videos.length - 1 ? ' opacity-0' : ''
}`}
/>
))}
</div>
</div>
<div className="flex flex-col gap-y-[100vh]" ref={ref}>
<div className="flex h-[348px] gap-3 sticky top-[calc(100vh-388px)]">
<div className="p-6 rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] to-transparent flex flex-col justify-between flex-1">
<p className="heading2 font-medium">
1. Выбор квартиры на генплане
</p>
<div className="space-y-4">
<div className="flex gap-6">
<ClassNameWrapper className="w-8 h-8">
<EmotionalIcon />
</ClassNameWrapper>
<p className="text1 max-w-[60%]">
Эмоциональное вовлечение пользователя в выбор квартиры
</p>
</div>
<div className="flex gap-6">
<ClassNameWrapper className="w-8 h-8">
<LocationIcon />
</ClassNameWrapper>
<p className="text1 max-w-[60%]">
Удобство выбора расположения и видовых характеристик
</p>
</div>
</div>
</div>
<div className="p-6 rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] to-transparent flex flex-col justify-between flex-1">
<p className="heading2 font-medium">Поиск по параметрам</p>
<div className="flex flex-wrap gap-2">
{[
'Расположение',
'Комнатность',
'Стоимость',
'Инсоляция',
'Особенности планировки',
].map((tag) => (
<p
key={tag}
className="px-5 py-[11px] rounded-2xl border border-[#37393B] font-medium btnm"
>
{tag}
</p>
))}
</div>
</div>
</div>
<div className="space-y-6 bg-[#0F1011] backdrop-blur-xs h-[348px] sticky top-[calc(100vh-388px)]">
<p className="heading2 font-medium text-center">2. 3D-тур</p>
<div className="grid items-stretch grid-cols-3 grid-rows-2 gap-2">
{[
{
title: 'Двор',
src: '/img/pages/home/presentation/court.png',
},
{
title: 'Места общего пользования',
src: '/img/pages/home/presentation/mop.png',
},
{
title: 'Квартиры',
src: '/img/pages/home/presentation/flats.png',
},
{
title: 'Паркинг',
src: '/img/pages/home/presentation/parking.png',
},
{
title: 'Коммерческие помещения',
src: '/img/pages/home/presentation/office.png',
},
].map((item) => (
<SlideBadge {...item} key={item.title} />
))}
</div>
</div>
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid gap-7 grid-rows-[5fr_2fr] grid-cols-2 h-[348px] sticky top-[calc(100vh-388px)]">
<p className="heading2 font-medium">
3. Демонстрация инфраструктуры вокруг будущего комплекса
</p>
<p className="text1">
Режим «Инфраструктура» знакомит пользователя с перспективной
застройкой целого района. В зависимости от срока сдачи либо
функциональной нагрузки того или иного блока можно ввести выделение
цветом.
</p>
<div className="flex col-span-2 gap-[5px]">
<div className="w-18 h-18 aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<ClassNameWrapper className={'w-11 text-[#232425]'}>
<NatureIcon />
</ClassNameWrapper>
</div>
<div className="w-18 h-18 aspect-square rounded-full bg-[#37393B99] flex justify-center items-center">
<ClassNameWrapper className={'w-11 text-[#7A7A7A]'}>
<KidsIcon />
</ClassNameWrapper>
</div>
<div className="w-18 h-18 aspect-square rounded-full bg-[#37393B99] flex justify-center items-center">
<ClassNameWrapper className={'w-11 text-[#7A7A7A]'}>
<MetroIcon />
</ClassNameWrapper>
</div>
<div className="w-18 h-18 aspect-square rounded-full bg-[#37393B99] flex justify-center items-center">
<ClassNameWrapper className={'w-11 text-[#7A7A7A]'}>
<ShopIcon />
</ClassNameWrapper>
</div>
<div className="w-18 h-18 aspect-square rounded-full bg-[#37393B99] flex justify-center items-center">
<ClassNameWrapper className={'w-11 text-[#7A7A7A]'}>
<SportIcon />
</ClassNameWrapper>
</div>
<div className="w-18 h-18 aspect-square rounded-full bg-[#37393B99] flex justify-center items-center">
<ClassNameWrapper className={'w-11 text-[#7A7A7A]'}>
<StudyIcon />
</ClassNameWrapper>
</div>
<div className="w-18 h-18 aspect-square rounded-full bg-[#37393B99] flex justify-center items-center">
<ClassNameWrapper className="w-11 text-[#7A7A7A]">
<SafetyIcon />
</ClassNameWrapper>
</div>
</div>
</div>
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid gap-y-[30px] grid-cols-2 grid-rows-[1fr_3fr] h-[348px] sticky top-[calc(100vh-388px)]">
<p className="heading2 font-medium">4. Интерактивная инсоляция</p>
<p className="text1">
Клиент может наблюдать, как световое пятно перемещается в
зависимости от времени суток и сезона, поскольку солнечный свет
имеет физическое воздействие.
</p>
<div className="col-span-2 flex justify-between gap-x-[5px]">
{[
{
title: 'Лето',
src: '/img/pages/home/presentation/summer.png',
},
{
title: 'Зима',
src: '/img/pages/home/presentation/winter.png',
},
{
title: 'Осень',
src: '/img/pages/home/presentation/autumn.png',
},
].map((item) => (
<SeasonCard
{...item}
key={item.title}
className="flex flex-col items-center justify-between flex-1"
/>
))}
</div>
</div>
<div className="space-y-6 h-[348px] sticky top-[calc(100vh-388px)] bg-[#0F1011]">
<p className="heading2 font-medium text-center">
5. Модуль инженерных систем
</p>
<div className="flex flex-1 gap-2">
{[
{
src: '/img/pages/home/presentation/ventilation.png',
title: 'Вентиляция',
},
{
src: '/img/pages/home/presentation/heating.png',
title: 'Отопление',
},
{
src: '/img/pages/home/presentation/facade.png',
title: 'Фасад',
},
].map(({ src, title }) => (
<div
className="flex flex-col gap-10 items-stretch pt-5 pb-2 pl-4 pr-2 bg-[#37393B99] rounded-2xl flex-1"
key={title}
>
<p className="text1">{title}</p>
<div className="relative w-[calc(216/240*100%)] self-end">
<Image
src={src}
fill
alt={title}
className="rounded-xl self-end !relative w-full h-full"
sizes="100%"
/>
</div>
</div>
))}
</div>
</div>
<div className="rounded-2xl backdrop-blur-[500px] bg-[#0F101199] bg-radial-[at_50%_0%] from-[#7A7A7A99] p-6 grid grid-cols-2 h-[348px] sticky top-[calc(100vh-388px)]">
<p className="heading2 font-medium">
6. Интеграция с CRM-системой застройщика
</p>
<div className="flex flex-col justify-between">
<div className="space-y-4">
<div className="flex">
<div className="w-12 h-12 rounded-lg bg-[#B5F54E] flex items-center text-black font-medium justify-center -rotate-[4deg] text1 shadow-[0_2px_10px_0_#00000033] z-[2]">
2K
</div>
<div className="bg-[#37393B] rounded-lg right-2 relative shadow-[0_2px_10px_0_#00000033] z-[1]">
<ClassNameWrapper className="w-12 h-12">
<Flat1 />
</ClassNameWrapper>
</div>
<div className="bg-[#37393B] rounded-lg -rotate-[4deg] right-4 relative shadow-[0_2px_10px_0_#00000033]">
<ClassNameWrapper className="w-12 h-12">
<Flat2 />
</ClassNameWrapper>
</div>
</div>
<p className="text1">
Клиент всегда видит актуальные данные об интересующем его лоте,
включая статус и стоимость.
</p>
</div>
<div className="space-y-4">
<div className="flex">
<Image
src={'/img/pages/home/presentation/vova.png'}
width={48}
height={48}
alt="vovka"
className="rounded-lg -rotate-[4deg] shadow-[0_2px_10px_0_#00000033] z-[2]"
/>
<div className="rounded-lg bg-[#37393B] flex justify-center items-center relative right-2 w-12 h-12 shadow-[0_2px_10px_0_#00000033] z-[1]">
<ClassNameWrapper className="w-[21px] h-[21px]">
<MailIcon />
</ClassNameWrapper>
</div>
<div className="rounded-lg bg-[#37393B] flex justify-center items-center relative right-4 -rotate-[4deg] w-12 h-12 shadow-[0_2px_10px_0_#00000033]">
<ClassNameWrapper className="w-[21px] h-[21px]">
<PhoneIcon />
</ClassNameWrapper>
</div>
</div>
<p className="text1">
Инструмент продаж сам создаст карточку клиента в вашей
CRM-системе и назначит ответственного менеджера.
</p>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -1,3 +1,4 @@
import { videos } from '@/consts/presentation/videos';
import { SlideBadge } from '@/ui/SlideBadge';
import { Slide2Marquee } from '@/ui/SlideMarquee';
import { AnimatePresence, motion } from 'framer-motion';
@@ -20,14 +21,7 @@ export function VideoLayer({
: 'col-start-1'
}`}
>
{[
'1_search',
'2_3dtour',
'3_infrastructure',
'4_insolation',
'5_engine',
'6_reservation',
].map((video, index, videos) => (
{videos.map((video, index) => (
<video
key={video}
src={`/videos/pages/home/presentation/${video}.mp4`}
@@ -38,7 +32,7 @@ export function VideoLayer({
style={{
zIndex: videos.length - index,
}}
className={`absolute w-full h-full object-covera transition-descrete${
className={`absolute w-full h-full transition-opacity${
slide > index && index !== videos.length - 1 ? ' opacity-0' : ''
}`}
/>
+8
View File
@@ -0,0 +1,8 @@
export const videos = [
'1_search',
'2_3dtour',
'3_infrastructure',
'4_insolation',
'5_engine',
'6_reservation',
];
+6 -9
View File
@@ -5,19 +5,16 @@ export function useScroll(ref: RefObject<HTMLElement>) {
ref.current?.getBoundingClientRect().top ?? 0
);
// eslint-disable-next-line react-hooks/exhaustive-deps
function handleScroll() {
setScroll(ref.current!.getBoundingClientRect().top);
}
useEffect(() => {
const element = ref.current;
if (!element) return;
const handleScroll = () => {
setScroll(element.getBoundingClientRect().top);
};
document.addEventListener('scroll', handleScroll);
return () => document.removeEventListener('scroll', handleScroll);
}, [ref]);
}, [handleScroll, ref]);
return scroll;
}
+1 -1
View File
@@ -18,7 +18,7 @@ export function SeasonCard({
<div className="relative md:max-lg:max-w-[calc(138/224*100%)]">
<Image
src={src}
className="!relative object-cover lg:min-w-full md:min-w-[calc(138/224*100%)]"
className="!relative lg:min-w-full md:min-w-[calc(138/224*100%)]"
alt={title}
fill
sizes="(min-width: 768px) calc(138/224*100%), (min-width: 1024px) 100%"