This commit is contained in:
2025-02-24 18:04:03 +05:00
parent c792f1b41d
commit bda04247cb
40 changed files with 389 additions and 198 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+3 -2
View File
@@ -20,8 +20,9 @@ export default async function BlogLayout({
<section className="space-y-12">
<div className="flex flex-col gap-6 items-center">
<Title className="text-center" headerLevel={2}>
В блоге собраны все публикации о работе компании:
<span className="text-[#7A7A7A]"> новости, статьи и видео</span>
Все о работе компании:
<br />
<span className="text-[#7A7A7A]"> статьи, видео и публикации</span>
</Title>
<StoriesButton />
</div>
+1 -1
View File
@@ -1,3 +1,3 @@
export default function Page() {
return <></>;
return <div className="h-[6.432vw]" />;
}
+7 -1
View File
@@ -1,3 +1,9 @@
import { Prime } from '@/components/pages/PrimePage/PrimePage';
export default function PrimePage() {
return <div className="relative">{/* <Prime /> */}</div>;
return (
<div className="relative">
<Prime />
</div>
);
}
+9 -8
View File
@@ -21,9 +21,7 @@ export function Feedback() {
return (
<div
id="contacts"
className={`lg:mb-20 sm:mb-12 lg:flex lg:gap-3 max-lg:space-y-12 justify-between${
pathname !== '/form' ? ' lg:mt-[11.458vw] mt-25' : ''
} mb-10`}
className={`lg:mb-20 md:mb-12 lg:flex lg:gap-3 max-lg:space-y-12 justify-between lg:mt-[14.07vh] mt-25 mb-10`}
>
<h2 className="line2 font-medium max-lg:mb-6 lg:max-w-[45%]">
<span className="text-[#7A7A7A]">Хотите увеличить конверсию?</span>
@@ -73,10 +71,13 @@ export function FeedbackForm() {
{!formState.isSubmitted ? (
<FormProvider {...form}>
<form
className="sm:space-y-7 space-y-3"
className="lg:space-y-[1.944vw] md:max-lg:space-y-7 space-y-3"
onSubmit={handleSubmit(onSubmit)}
>
<CheckboxesGroup name="products" options={projectsTags} />
<div className="lg:space-y-[1.111vw] space-y-4">
<p className="heading2 font-medium">Нам надо</p>
<CheckboxesGroup name="products" options={projectsTags} />
</div>
<input
id="name"
type="text"
@@ -109,17 +110,17 @@ export function FeedbackForm() {
{...register('email')}
className="bg-transparent border-b border-[#37393B] focus:border-white py-4 rounded-none btnl outline-none transition-all w-full placeholder:btnl placeholder:font-medium placeholder:select-none"
/>
<div className="sm:flex items-stretch gap-3">
<div className="md:flex items-stretch lg:gap-[0.833vw] gap-3">
<Button
type="submit"
rounded="2xl"
className="btnl max-sm:mb-3 max-sm:w-full py-5 cursor-pointer"
className="btnl max-md:mb-3 max-md:w-full py-5 cursor-pointer"
>
Оставить заявку
</Button>
<Link
href={'/policy'}
className="text2 xl:max-w-[60%] sm:max-lg:max-w-[40%] sm:max-lg:py-1"
className="text2 xl:max-w-[60%] md:max-lg:max-w-[40%] md:max-lg:py-1"
>
<p>
<span className="text-[#7A7A7A]">
+9 -9
View File
@@ -8,29 +8,29 @@ import YoutubeIcon from '../../../public/icons/youtube.svg';
export function Footer() {
return (
<footer className="lg:px-5 lg:pb-5 sm:px-4 sm:pb-4 px-[10px] pb-[10px] space-y-6">
<div className="max-sm:flex-col lg:gap-3 sm:gap-2 flex gap-1">
<footer className="lg:px-5 lg:pb-5 md:max-lg:px-4 md:max-lg:pb-4 px-[10px] pb-[10px] space-y-6 mb-0">
<div className="max-md:flex-col lg:gap-[0.833vw] md:max-lg:gap-2 flex gap-1">
<Link
href={'tel:' + '8 800 770 00 67'.replaceAll(' ', '')}
className="p-6 flex flex-col justify-between max-sm:gap-y-10 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] rounded-2xl flex-1 hover:bg-[#37393B99] bg-transparent transition-colors"
className="p-6 flex flex-col justify-between max-md:gap-y-10 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] lg:rounded-[1.111vw] rounded-2xl lg:aspect-[696/248] w-[48.333vw] hover:bg-[#37393B99] bg-transparent transition-colors"
>
<p className="text-[#7A7A7A] text1 font-medium">Позвонить</p>
<div className="lg:line2 sm:max-lg:heading1 line2 flex items-center font-medium">
<div className="lg:line2 md:max-lg:heading1 line2 flex items-center font-medium">
8 800 770 00 67
<ArrowMoreIcon className="text-white lg:w-[5.556vw] lg:h-[5.556vw] md:max-lg:w-[4.167vw] md:max-lg:h-[4.167vw] w-[10vw] h-[10vw]" />
</div>
</Link>
<Link
href={'mailto:' + 'info@graff.tech'}
className="p-6 flex flex-col justify-between max-sm:gap-y-10 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] rounded-2xl flex-1 hover:bg-[#37393B99] bg-transparent transition-colors"
className="p-6 flex flex-col justify-between max-md:gap-y-10 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] lg:rounded-[1.111vw] rounded-2xl lg:aspect-[624/248] flex-1a w-[43.333vw] hover:bg-[#37393B99] bg-transparent transition-colors"
>
<p className="text-[#7A7A7A] text1 font-medium">Написать</p>
<div className="lg:line2 sm:max-lg:heading1 line2 flex items-center font-medium">
<div className="lg:line2 md:max-lg:heading1 line2 flex items-center font-medium">
info@graff.tech
<ArrowMoreIcon className="text-white lg:w-[5.556vw] lg:h-[5.556vw] md:max-lg:w-[4.167vw] md:max-lg:h-[4.167vw] w-[10vw] h-[10vw]" />
</div>
</Link>
<div className="gap-y-2 justify-stretch sm:gap-x-2 gap-x-1 sm:flex-col flex">
<div className="gap-y-2 justify-stretch md:gap-x-2 gap-x-1 md:flex-col flex">
<ContactLink href="https://t.me/graffestate">
<TelegramIcon className="lg:w-[1.389vw] lg:h-[1.389vw] md:max-lg:w-[2.083vw] md:max-lg:h-[2.083vw] w-[5.556vw] h-[5.556vw] text-white group-hover:text-black" />
</ContactLink>
@@ -57,7 +57,7 @@ export function Footer() {
</p>
<Link
href={'https://graff.tech'}
className="text-[#37393B] text1 font-medium leading-[18.9px] lg:w-fit sm:col-start-2 sm:text-right w-full"
className="text-[#37393B] text1 font-medium leading-[18.9px] lg:w-fit md:col-start-2 md:text-right w-full"
>
graff.tech
</Link>
@@ -74,7 +74,7 @@ export function ContactLink({
return (
<Link
href={href}
className={`rounded-2xl bg-[#37393B99] p-[18px] hover:bg-white transition-colors hover:text-black flex justify-center w-full group ${className}`}
className={`lg:rounded-[1.111vw] rounded-2xl bg-[#37393B99] lg:p-[1.25vw] p-[18px] hover:bg-white transition-colors hover:text-black flex justify-center w-full group ${className}`}
>
{children}
</Link>
@@ -27,7 +27,7 @@ export function ArticleCard({
onClick={() => !drafted && push('/blog/' + slug)}
className={`${
className ? className + ' ' : ''
}hover:backdrop-blur-[500px] cursor-pointer h-full group max-lg:bg-[radial-gradient(ellipse_at_bottom,#7A7A7A50,transparent)] hover:bg-[radial-gradient(ellipse_at_bottom,#7A7A7A50,transparent)] flex flex-col justify-between gap-3 transition-[background-size] lg:bg-[length:100%_0%] bg-bottom hover:bg-[length:100%_100%] bg-no-repeat rounded-2xl p-3 relative`}
}hover:backdrop-blur-[500px] cursor-pointer h-full group max-lg:bg-[radial-gradient(ellipse_at_bottom,#7A7A7A50,transparent)] hover:bg-[radial-gradient(ellipse_at_bottom,#7A7A7A50,transparent)] flex flex-col justify-between gap-3 transition-[background-size] lg:bg-[length:100%_0%] bg-bottom hover:bg-[length:100%_100%] bg-no-repeat rounded-2xl lg:p-[0.833vw] p-3 relative`}
>
<Image
src={process.env.NEXT_PUBLIC_S3_BUCKET + cardImage}
@@ -39,7 +39,7 @@ export function ArticleCard({
<p className="heading2 font-medium text-ellipsis [-webkit-line-clamp:2] line-clamp-2">
{title}
</p>
<div className="flex flex-nowrap lg:gap-[0.278vw]a gap-1">
<div className="flex flex-wrap lg:gap-[0.278vw] gap-1">
{tags.map((tag) => (
<PostTag
text={tag}
+1 -1
View File
@@ -7,7 +7,7 @@ export function DraftsList({ tags }: { tags: string[] | string }) {
return (
<div className="space-y-2 ml-3 max-lg:hidden">
<p className="text-[#7A7A7A] text1">Черновики</p>
<div className="gap-x-3 gap-y-6 flex flex-wrap">
<div className="lg:gap-x-[0.833vw] md:gap-x-3 gap-y-6 flex flex-wrap">
{drafts && drafts.length > 0 ? (
drafts?.map((article) => (
<ArticleCard
+1 -1
View File
@@ -44,7 +44,7 @@ export function AwardItem({
}) {
return (
<div
className={`bg-[radial-gradient(ellipse_at_right_center,#7a7a7a50,transparent)] rounded-2xl p-6 flex flex-col justify-between lg:w-1/3 lg:aspect-[459/496] sm:aspect-[362/412] relative transition-all ${
className={`bg-[radial-gradient(ellipse_at_right_center,#7a7a7a50,transparent)] lg:rounded-[1.111vw] rounded-2xl lg:p-[1.667vw] p-6 flex flex-col justify-between lg:w-1/3 lg:aspect-[459/496] sm:aspect-[362/412] relative transition-all ${
index === 0
? 'lg:self-end'
: index === 1
@@ -15,7 +15,7 @@ export const ClientItem = forwardRef<HTMLDivElement, ICompany>(
<GridItem className="!relativea">
<div
ref={ref}
className="rounded-2xl select-none cursor-grab lg:w-[calc((100vw-120px)/11)] md:max-lg:w-[calc((100vw-64px)/5)] w-[calc((100vw-36px)/3)] aspect-square backdrop-blur-3xl relative bg-[#23242599] group hover:bg-[#232425] transition-colors overflow-hidden"
className="lg:rounded-[1.111vw] rounded-2xl select-none cursor-grab lg:w-[calc((100vw-120px)/11)] md:max-lg:w-[calc((100vw-64px)/5)] w-[calc((100vw-36px)/3)] aspect-square backdrop-blur-3xl relative bg-[#23242599] group hover:bg-[#232425] transition-colors overflow-hidden"
>
<div className="aspect-square relative flex items-center justify-center p-5">
<div className="max-w-4/5 absolute w-full">
+4 -2
View File
@@ -32,7 +32,10 @@ export function Motivation() {
return (
<div className="lg:space-y-[4.444vw] md:max-lg:space-y-[6.25vw] max-md:space-y-[11.111vw]">
<Title headerLevel={1} className="text-center">
<Title
headerLevel={1}
className="text-center min-[2560px]:max-w-3/4 min-[2560px]:mx-auto"
>
Помогаем девелоперам продавать
<span className="max-lg:hidden">&nbsp;</span>
<span className="lg:hidden"> </span>недвижимость проще&nbsp;и&nbsp;
@@ -40,7 +43,6 @@ export function Motivation() {
<span className="text-[#37393B]">быстрее </span>
<span className="absolute top-[55%] -left-[2.5%] 2xl:h-1.5 h-1 w-[105%] bg-white" />
</span>
{/* <span className="max-md:hidden">&nbsp;</span> */}
дороже
</Title>
<div className="grid lg:gap-[0.833vw] md:max-lg:gap-[1.563vw] gap-[2.222vw]">
@@ -1,14 +1,10 @@
'use client';
import { videos } from '@/consts/presentation/videos';
import { Title } from '@/ui/Title';
import {
motion,
useInView,
useMotionValueEvent,
useScroll,
} from 'framer-motion';
import { useRef, useState, useTransition } from 'react';
import RestartIcon from '../../../../../public/icons/restart.svg';
import { useInView, useMotionValueEvent, useScroll } from 'framer-motion';
import { useRef, useState } from 'react';
import { PrimeProgressItem } from '../../PrimePage/PrimePage';
import { Infrastructure } from './Infrastructure';
import { Insolation } from './Insolation';
import { IntegrationCRM } from './IntegrationCRM';
@@ -20,7 +16,7 @@ export function PresentationDesktop() {
const { scrollYProgress } = useScroll({ container: target });
const inView = useInView(target, { margin: '80% 0% -80% 0%' });
const inView = useInView(target, { margin: '85% 0% -85% 0%' });
const [slide, setSlide] = useState(0);
@@ -28,16 +24,21 @@ export function PresentationDesktop() {
setSlide(Math.trunc(value * 6))
);
const [isPending, startTransition] = useTransition();
return (
<div className="space-y-16 mt-[100px] max-lg:hidden">
<Title>
<div className="mt-25 mb-50 max-lg:hidden relative">
<Title className="mb-16">
Интерактивная презентация{' '}
<span className="text-gradient">улучшает опыт выбора недвижимости</span>{' '}
и&nbsp;увеличивают темпы продаж квартир в&nbsp;жилом комплексе
</Title>
<div className="relative">
<div className="flex gap-x-3 items-stretch h-[80vh] absolute overflow-hidden w-full top-0">
<SearchAndSelect scroll={scrollYProgress} />
<VideoLayer scroll={scrollYProgress} />
<Infrastructure scroll={scrollYProgress} />
<Insolation scroll={scrollYProgress} />
<IntegrationCRM scroll={scrollYProgress} />
</div>
<div
className={`snap-y snap-mandatory h-[80vh] z-10 relative [scrollbar-width:none] ${
inView ? 'overflow-y-scroll' : 'overflow-hidden'
@@ -51,59 +52,25 @@ export function PresentationDesktop() {
<div className="h-full snap-start snap-always" />
<div className="h-full snap-start snap-always" />
</div>
<div className="flex gap-x-3 items-stretch h-[80vh] absolute overflow-hidden w-full top-0">
<SearchAndSelect scroll={scrollYProgress} />
<VideoLayer scroll={scrollYProgress} />
<Infrastructure scroll={scrollYProgress} />
<Insolation scroll={scrollYProgress} />
<IntegrationCRM scroll={scrollYProgress} />
<div className="flex absolute p-2 rounded-[27px] bg-[#37393B99] backdrop-blur-[20px] left-1/2 -translate-x-1/2 mt-5">
{videos.map(({ src, anchorImg }, index) => (
<PrimeProgressItem
onClick={() => {
target.current?.scrollTo({
top: (index * target.current?.scrollHeight) / videos.length,
});
}}
active={
index === slide ||
(index === videos.length - 1 && slide === videos.length)
}
src={anchorImg}
title={src}
key={src}
/>
))}
</div>
</div>
<div className="flex w-[97.222vw] gap-3 items-center -mt-5">
{Array.from({ length: 6 }).map((_, i) => (
<SlideProgress
key={i}
active={slide >= i}
clickHandler={() => {
target.current?.scrollTo({
top: (i * target.current?.scrollHeight) / 6,
});
}}
/>
))}
<button
onClick={() =>
startTransition(() => target.current?.scrollTo({ top: 0 }))
}
className="cursor-pointer group"
>
<RestartIcon
className={`lg:w-[1.111vw] lg:h-[1.111vw] w-4 h-4 text-white transition-transform${
isPending ? ' -rotate-360' : ''
}`}
/>
</button>
</div>
</div>
);
}
function SlideProgress({
active,
clickHandler,
}: {
active: boolean;
clickHandler: () => void;
}) {
return (
<div
className="w-full bg-[#7a7a7a] h-2 rounded-2xl relative overflow-hidden cursor-pointer"
onClick={clickHandler}
>
<motion.div
animate={active ? { scaleX: 1 } : { scaleX: 0 }}
className="h-2 bg-white w-full origin-left left-0 top-0 rounded-2xl absolute"
/>
</div>
);
}
@@ -72,10 +72,10 @@ export function PresentationMini() {
ref={videoContainer}
className="md:aspect-[721/400] aspect-[340/193] w-[94.444vw] md:w-[93.88vw] mx-auto relative max-md:scale-115"
>
{videos.map((video, index) => (
{videos.map(({ src }, index) => (
<video
key={video}
src={`/videos/pages/home/presentation/${video}.mp4`}
key={src}
src={`/videos/pages/home/presentation/${src}.mp4`}
loop
muted
playsInline
@@ -83,12 +83,12 @@ export function PresentationMini() {
style={{
zIndex: videos.length - index,
}}
className={`absolute h-fullw-full object-covera transition-opacity${
className={`absolute h-full w-full transition-opacity${
slide > index && index !== videos.length - 1 ? ' opacity-0' : ''
}`}
/>
))}
<div className="left-1/2 -bottom-px z-10 absolute -translate-x-1/2 bg-gradient-to-b from-[#0F101100] to-[#0F1011] w-full h-[calc(80/400*100%)]" />
<div className="left-1/2 bottom-0 z-10 absolute -translate-x-1/2 bg-gradient-to-b from-[#0F101100] to-[#0F1011] w-full h-1/5" />
</div>
</div>
<div className="flex flex-col gap-y-[40vh]" ref={target}>
@@ -20,7 +20,7 @@ export function SearchAndSelect({
return (
<motion.div
style={isLg ? { opacity } : { top, opacity: opacityMini }}
className="xs:max-md:p-5 p-4 flex max-md:flex-col lg:flex-col h-full md:gap-3 xs:max-md:gap-y-7 gap-y-3 lg:z-10 lg:w-[31.875vw] max-md:rounded-2xl max-lg:sticky select-none max-md:bg-radial-[at_100%_100%] from-[#7A7A7A66] max-md:backdrop-blur-[500px]"
className="xs:max-md:p-5 flex max-md:flex-col lg:flex-col h-full md:gap-3 xs:max-md:gap-y-7 gap-y-3 lg:z-10 lg:w-[31.875vw] max-md:rounded-2xl max-lg:sticky select-none max-md:bg-radial-[at_100%_100%] from-[#7A7A7A66] max-md:backdrop-blur-[500px]"
>
<div className="lg:p-[1.667vw] md:max-lg:p-6 md:rounded-2xl md:bg-radial-[at_100%_100%] from-[#7A7A7A66] md:backdrop-blur-[500px] xs:max-md:space-y-4 space-y-20 md:flex flex-col justify-between md:flex-1">
<p className="heading2 font-medium">Выбор квартиры на генплане</p>
@@ -42,10 +42,10 @@ export function VideoLayer({ scroll }: { scroll: MotionValue<number> }) {
className="absolute overflow-hidden h-full transition-all"
>
{videoRefs.length &&
videos.map((video, index) => (
videos.map(({ src }, index) => (
<motion.video
key={video}
src={`/videos/pages/home/presentation/${video}.mp4`}
key={src}
src={`/videos/pages/home/presentation/${src}.mp4`}
ref={videoRefs[index]}
loop
muted
+8 -8
View File
@@ -83,23 +83,23 @@ export function Statistics() {
<span className="line1">4</span>раз
</p>
<div className="absolute md:w-[13.438vw] w-[28.667vw] md:max-lg:bottom-12 md:max-lg:right-16 bottom-12 right-14 lg:hidden">
<div className="relative">
<div className="relative rounded-2xl">
<Image
src="/img/pages/home/stats/Forum_Zoolog_09-03(2).png"
src="/img/pages/home/stats/Forum_Zoolog_09-03(2).jpg"
fill
alt="forum zoolog"
className="!relative"
className="!relative rounded-2xl"
sizes="100%"
/>
</div>
</div>
<div className="absolute md:w-[13.438vw] w-[28.667vw] md:max-lg:bottom-6 md:max-lg:right-6 bottom-6 right-4 lg:hidden">
<div className="relative">
<div className="relative rounded-2xl">
<Image
src="/img/pages/home/stats/Forum_Zoolog_09-03.png"
src="/img/pages/home/stats/Forum_Zoolog_09-03.jpg"
fill
alt="forum zoolog"
className="!relative"
className="!relative rounded-2xl"
sizes="100%"
/>
</div>
@@ -118,7 +118,7 @@ export function Statistics() {
src="/img/pages/home/stats/Forum_Zoolog_09-03(2).jpg"
fill
alt="forum zoolog"
className="!relative rounded-lg"
className="!relative rounded-2xl"
sizes="100%"
/>
</div>
@@ -127,7 +127,7 @@ export function Statistics() {
src="/img/pages/home/stats/Forum_Zoolog_09-03.jpg"
fill
alt="forum zoolog"
className="!relative rounded-lg"
className="!relative rounded-2xl"
sizes="100%"
/>
</div>
@@ -52,7 +52,7 @@ export function Streaming() {
/>
))}
<div
className={`border border-[#3D425C] rounded-2xl flex flex-1 justify-center duration-500 items-center p-6 md:max-lg:min-w-[300px] group max-md:absolute self-stretch max-md:h-full transition-transform select-none max-md:w-[calc(100%-40px)] max-md:bg-[#0F101199] max-md:backdrop-blur-2xl ${
className={`bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF00] p-0.5 rounded-2xl flex flex-1 justify-center duration-500 items-center md:max-lg:min-w-[300px] group max-md:absolute self-stretch max-md:h-full transition-transform select-none max-md:w-[calc(100%-40px)] max-md:bg-[#0F101199] max-md:backdrop-blur-2xl ${
data &&
(data.length - 1 === current
? 'max-md:translate-z-10'
@@ -67,16 +67,18 @@ export function Streaming() {
: '')
}`}
>
<div className="flex flex-col items-center space-y-6">
<p className="heading2 font-medium text-center">
Расскажем и покажем как это работает на&nbsp;созвоне
</p>
<Link
href={'/form'}
className="btnm font-medium group-hover:scale-105 px-6 py-[17px] transition-transform rounded-xl bg-gradient"
>
Оставить заявку
</Link>
<div className="md:bg-[#0F1011] h-full w-full rounded-2xl content-center p-6">
<div className="flex flex-col items-center space-y-6">
<p className="heading2 font-medium text-center">
Расскажем и покажем как это работает на&nbsp;созвоне
</p>
<Link
href={'/form'}
className="btnm font-medium group-hover:scale-105 px-6 py-[17px] transition-transform rounded-xl bg-gradient"
>
Оставить заявку
</Link>
</div>
</div>
</div>
</div>
@@ -64,7 +64,7 @@ export function StreamingProject({
</div>
<Link
href={streaming.find((s) => s.title === title)?.url ?? '/'}
className="hidden lg:group-hover:block absolute w-full h-full left-0 bottom-0 md:max-lg:rounded-2xl rounded-xl font-medium backdrop-blur-[3px] content-center text-center z-0"
className="lg:group-hover:opacity-100 opacity-0 transition-opacity duration-500 absolute w-full h-full left-0 bottom-0 md:max-lg:rounded-2xl rounded-xl font-medium backdrop-blur-[3px] content-center text-center z-0"
>
<p className="btnl flex justify-center gap-2">
Начать демонстрацию{' '}
@@ -2,13 +2,14 @@ import { motion, MotionValue, useTransform } from 'framer-motion';
import Image from 'next/image';
export function CommercialOffer({ scroll }: { scroll: MotionValue<number> }) {
const x = useTransform(scroll, [], []);
const opacity = useTransform(scroll, [], []);
const x = useTransform(scroll, [5 / 6, 6 / 6], ['100%', '0%']);
const opacity = useTransform(scroll, [5 / 6, 6 / 6], [0, 1]);
return (
<motion.div
// style={{ x, opacity }}
className="p-6 backdrop-blur-xs rounded-2xl bg-[radial-gradient(ellipse_at_right,#7A7A7A66,transparent)] absolute h-full w-[23.611vw] flex flex-col justify-between gap-6"
style={{ x, opacity }}
className="p-6 backdrop-blur-xs rounded-2xl right-0 bg-[radial-gradient(ellipse_at_right,#7A7A7A66,transparent)] absolute h-full w-[23.611vw] flex flex-col justify-between gap-6"
>
<p className="heading2 font-medium">Отправка коммерческого предложения</p>
<div className="w-[20.278vw] aspect-[292/264] relative flex justify-center items-center">
+7 -3
View File
@@ -1,12 +1,16 @@
import { motion, MotionValue, useTransform } from 'framer-motion';
export function Favorites({ scroll }: { scroll: MotionValue<number> }) {
const x = useTransform(scroll, [], []);
const opacity = useTransform(scroll, [0, 1 / 6, 2 / 6], [0, 1, 0]);
const x = useTransform(
scroll,
[2 / 6, 3 / 6, 4 / 6],
['-100%', '0%', '-100%']
);
const opacity = useTransform(scroll, [2 / 6, 3 / 6, 4 / 6], [0, 1, 0]);
return (
<motion.div
// style={{ x, opacity }}
style={{ x, opacity }}
className="p-6 backdrop-blur-xs rounded-2xl bg-[radial-gradient(ellipse_at_right,#7A7A7A66,transparent)] absolute h-full w-[23.611vw] flex flex-col justify-between gap-6"
>
<p className="heading2 font-medium">Формирование списка избранного</p>
@@ -5,42 +5,39 @@ import NatureIcon from '../../../../public/icons/nature.svg';
import ShopIcon from '../../../../public/icons/shop.svg';
export function Infrastructure({ scroll }: { scroll: MotionValue<number> }) {
const x = useTransform(scroll, [1 / 5, 2 / 5], ['100%', '0%']);
const x = useTransform(scroll, [1 / 6, 2 / 6, 3 / 6], ['100%', '0%', '100%']);
const opacity = useTransform(scroll, [1 / 5, 2 / 5, 3 / 5], [0, 1, 0]);
const opacity = useTransform(scroll, [1 / 6, 2 / 6, 3 / 6], [0, 1, 0]);
return (
<>
<motion.div
style={{ x, opacity }}
className="absolute right-0 rounded-2xl transition-[transform,opacity] p-[1.667vw] h-full bg-radial-[at_0%_100%] from-[#7A7A7A99] flex flex-col gap-2 z-10 backdrop-blur-[500px] select-none w-[23.611vw]"
>
<p className="heading2 font-medium">
Демонстрация инфраструктуры вокруг будущего комплекса
</p>
<div className="flex flex-1">
<div className="grid grid-cols-2 grid-rows-2 gap-[5px] m-auto">
<div className="w-[6.806vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<NatureIcon className="w-[4.444vw] text-[#232425]" />
</div>
<div className="w-[6.806vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<KidsIcon className="w-[4.444vw] text-[#232425]" />
</div>
<div className="w-[6.806vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<MetroIcon className="w-[4.444vw] text-[#232425]" />
</div>
<div className="w-[6.806vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<ShopIcon className="w-[4.444vw] text-[#232425]" />
</div>
<motion.div
style={{ x, opacity }}
className="absolute right-0 rounded-2xl transition-[transform,opacity] p-[1.667vw] top-1/2 -translate-y-1/2 h-[85.959%] bg-radial-[at_100%_100%] from-[#7A7A7A99] flex flex-col gap-2 z-10 backdrop-blur-[500px] select-none w-[23.611vw]"
>
<p className="heading2 font-medium">
Демонстрация инфраструктуры вокруг будущего комплекса
</p>
<div className="flex flex-1">
<div className="grid grid-cols-2 grid-rows-2 gap-[5px] m-auto">
<div className="w-[5.556vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<NatureIcon className="w-[3.644vw] text-[#232425]" />
</div>
<div className="w-[5.556vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<KidsIcon className="w-[3.644vw] text-[#232425]" />
</div>
<div className="w-[5.556vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<MetroIcon className="w-[3.644vw] text-[#232425]" />
</div>
<div className="w-[5.556vw] aspect-square rounded-full bg-[#B5F54E] flex justify-center items-center">
<ShopIcon className="w-[3.644vw] text-[#232425]" />
</div>
</div>
<p className="text1">
Режим «Инфраструктура» знакомит пользователя с перспективной
застройкой целого района. В зависимости от срока сдачи либо
функциональной нагрузки того или иного блока можно ввести выделение
цветом.
</p>
</motion.div>
</>
</div>
<p className="text2">
Режим «Инфраструктура» знакомит пользователя с перспективной застройкой
целого района. В зависимости от срока сдачи либо функциональной нагрузки
того или иного блока можно ввести выделение цветом.
</p>
</motion.div>
);
}
@@ -0,0 +1,43 @@
import { seasons } from '@/consts/presentation/seasons';
import { SeasonCard } from '@/ui/SeasonCard';
import { motion, MotionValue, useTransform } from 'framer-motion';
export function Insolation({ scroll }: { scroll: MotionValue<number> }) {
const x = useTransform(
scroll,
[4 / 6, 5 / 6, 6 / 6],
['-100%', '0%', '-100%']
);
const opacity = useTransform(scroll, [4 / 6, 5 / 6, 6 / 6], [0, 1, 0]);
return (
<motion.div
style={{ x, opacity }}
className="absolute h-full w-[23.611vw] rounded-2xl p-[1.667vw] bg-radial-[at_100%_100%] from-[#7A7A7A99] flex flex-col gap-2 z-10 backdrop-blur-[500px] select-none"
>
<p className="heading2 font-medium">Интерактивная инсоляция</p>
<div className="flex items-center justify-center w-full h-full">
{seasons.map(({ src, title }, index) => (
<SeasonCard
src={src}
title={title}
key={title}
className={
index === 1
? 'z-1'
: index === 0
? '-translate-y-42/194 translate-x-22/146'
: 'translate-y-67/194 -translate-x-42/146'
}
/>
))}
</div>
<p className="text1">
Клиент может наблюдать, как световое пятно перемещается в зависимости от
времени суток и сезона, поскольку солнечный свет имеет физическое
воздействие.
</p>
</motion.div>
);
}
@@ -0,0 +1,75 @@
import { motion, MotionValue, useTransform } from 'framer-motion';
import Image from 'next/image';
import MailIcon from '../../../../public/icons/mail.svg';
import PhoneIcon from '../../../../public/icons/phone.svg';
export function IntegrationCRM({ scroll }: { scroll: MotionValue<number> }) {
const opacity = useTransform(scroll, [3 / 6, 4 / 6, 5 / 6], [0, 1, 0]);
const x = useTransform(scroll, [3 / 6, 4 / 6, 5 / 6], ['100%', '0%', '100%']);
return (
<motion.div
style={{ x, opacity }}
className="absolute max-lg:hidden w-[23.611vw] h-full z-10 right-0 transition-[transform,opacity] p-[1.667vw] rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] to-transparent flex flex-col justify-between select-none"
>
<p className="heading2 font-medium">
Интеграция с CRM-системой
<br />
застройщика
</p>
<div className="space-y-15 max-w-9/10">
<div className="space-y-4">
<div className="flex">
<div className="w-16 h-16 rounded-[18px] 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="right-2 relative shadow-[0_2px_10px_0_#00000033] z-[1]">
<Image
src={'/img/pages/home/presentation/flat1.jpg'}
width={64}
height={64}
className="rounded-[18px]"
alt="rooms"
/>
</div>
<div className="-rotate-[4deg] right-4 relative shadow-[0_2px_10px_0_#00000033]">
<Image
src={'/img/pages/home/presentation/flat2.jpg'}
width={64}
height={64}
className="rounded-[18px]"
alt="rooms"
/>
</div>
</div>
<p className="text1">
Клиент всегда видит актуальные данные об интересующем его лоте,
включая статус и стоимость.
</p>
</div>
<div className="space-y-4">
<div className="flex">
<Image
src={'/img/pages/home/presentation/vova.jpg'}
width={64}
height={64}
alt="vovka"
className="rounded-[18px] -rotate-[4deg] shadow-[0_2px_10px_0_#00000033] z-[2]"
/>
<div className="rounded-[18px] bg-[#37393B] flex justify-center items-center relative right-2 w-16 h-16 shadow-[0_2px_10px_0_#00000033] z-[1]">
<MailIcon className="text-white w-8 h-8" />
</div>
<div className="rounded-[18px] bg-[#37393B] flex justify-center items-center relative right-4 -rotate-[4deg] w-16 h-16 shadow-[0_2px_10px_0_#00000033]">
<PhoneIcon className="w-8 h-8 text-white" />
</div>
</div>
<p className="text1">
Инструмент продаж сам создаст карточку клиента в вашей CRM-системе и
назначит ответственного менеджера.
</p>
</div>
</div>
</motion.div>
);
}
+71 -5
View File
@@ -1,11 +1,15 @@
'use client';
import { primeVideos } from '@/consts/presentation/videos';
import { Title } from '@/ui/Title';
import { useInView, useMotionValueEvent, useScroll } from 'framer-motion';
import Image from 'next/image';
import { useRef, useState } from 'react';
import { Insolation } from '../MainPage/Presentation/Insolation';
import { IntegrationCRM } from '../MainPage/Presentation/IntegrationCRM';
import { CommercialOffer } from './CommercialOffer';
import { Favorites } from './Favorites';
import { Infrastructure } from './Infrastructure';
import { Insolation } from './Insolation';
import { IntegrationCRM } from './IntegrationCRM';
import { SearchAndSelect } from './SearchAndSelect';
import { ThreeDTour } from './ThreeDTour';
import { VideoLayer } from './VideoLayer';
@@ -20,7 +24,7 @@ export function Prime() {
const [slide, setSlide] = useState(0);
useMotionValueEvent(scrollYProgress, 'change', (value) =>
setSlide(Math.trunc(value * 7))
setSlide(Math.trunc(value * primeVideos.length))
);
return (
@@ -50,12 +54,74 @@ export function Prime() {
<ThreeDTour scroll={scrollYProgress} />
<SearchAndSelect scroll={scrollYProgress} />
<Infrastructure scroll={scrollYProgress} />
{/* <Favorites scroll={scrollYProgress} /> */}
<Favorites scroll={scrollYProgress} />
<IntegrationCRM scroll={scrollYProgress} />
<Insolation scroll={scrollYProgress} />
{/* <CommercialOffer scroll={scrollYProgress} /> */}
<CommercialOffer scroll={scrollYProgress} />
</div>
<div className="flex absolute p-2 rounded-[27px] bg-[#37393B99] backdrop-blur-[20px] left-1/2 -translate-x-1/2">
{primeVideos.map(({ src, anchorImg }, index) => (
<PrimeProgressItem
onClick={() => {
target.current?.scrollTo({
top: (index * target.current?.scrollHeight) / 7,
});
}}
active={index === slide || (slide === 7 && index === 6)}
src={anchorImg}
title={src}
key={src}
/>
))}
</div>
</div>
</div>
);
}
export function PrimeProgressItem({
active,
src,
title,
onClick,
}: {
active: boolean;
src: string;
title: string;
onClick: () => void;
}) {
return (
<div onClick={onClick} className="group flex items-center cursor-pointer">
<div
className={
'h-px w-3 group-first:hidden transition-colors ' +
(!active
? 'bg-[#37393B]'
: 'bg-gradient-to-r from-[#37393B] to-white')
}
/>
<div
className={
'p-1 border relative rounded-2xl transition-colors' +
(!active ? ' border-[#37393B]' : '')
}
>
<Image
src={src}
fill
alt={title}
className="rounded-xl !relative"
sizes="(min-width: 1440px) 3.333vw"
/>
</div>
<div
className={
'h-px w-3 group-last:hidden transition-colors ' +
(!active
? 'bg-[#37393B]'
: 'bg-gradient-to-r from-white to-[#37393B]')
}
/>
</div>
);
}
@@ -4,12 +4,14 @@ import HeartIcon from '../../../../public/icons/hearth.svg';
import LocationIcon from '../../../../public/icons/location.svg';
export function SearchAndSelect({ scroll }: { scroll: MotionValue<number> }) {
const opacity = useTransform(scroll, [1 / 7, 2 / 7, 3 / 7], [0, 1, 0]);
const opacity = useTransform(scroll, [0, 1 / 6, 2 / 6], [0, 1, 0]);
const x = useTransform(scroll, [0, 1 / 6, 2 / 6], ['-100%', '0%', '-100%']);
return (
<motion.div
style={{ opacity }}
className="p-4 flex flex-col h-full gap-3 z-10 w-[23.611vw] select-none"
style={{ opacity, x }}
className="flex flex-col h-full gap-3 z-10 w-[23.611vw] select-none absolute"
>
<div className="p-[1.667vw] rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] space-y-20a flex flex-col justify-between flex-1">
<p className="heading2 font-medium">Выбор квартиры на генплане</p>
@@ -3,14 +3,14 @@ import { motion, MotionValue, useTransform } from 'framer-motion';
import Image from 'next/image';
export function ThreeDTour({ scroll }: { scroll: MotionValue<number> }) {
const opacity = useTransform(scroll, [0, 1 / 7], [1, 0]);
const opacity = useTransform(scroll, [0, 1 / 6], [1, 0]);
const x = useTransform(scroll, [0, 1 / 7], ['100%', '200%']);
const x = useTransform(scroll, [0, 1 / 6], ['0%', '100%']);
return (
<motion.div
style={{ opacity, x }}
className="p-[1.667vw] rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] h-[63.014%] flex flex-col justify-between gap-16 absolute"
className="p-[1.667vw] rounded-2xl bg-radial-[at_100%_100%] from-[#7A7A7A66] backdrop-blur-[500px] aspect-[340/368] flex flex-col justify-between gap-16 absolute right-0 w-[23.611vw] top-1/2 -translate-y-1/2"
>
<p className="heading2 font-medium">
Виртуальный тур по&nbsp;жилому комплексу
@@ -18,7 +18,7 @@ export function ThreeDTour({ scroll }: { scroll: MotionValue<number> }) {
<div className="grid grid-cols-3 gap-x-3 gap-y-6">
{threeDTour.map(({ src, title }) => (
<div className="space-y-1" key={title}>
<div className="relative aspect-square">
<div className="relative aspect-square max-w-[4.444vw] max-h-[4.444vw]">
<Image
src={src}
alt={title}
@@ -23,17 +23,17 @@ export function VideoLayer({ scroll }: { scroll: MotionValue<number> }) {
return (
<motion.div className="absolute overflow-hidden h-full transition-all w-[97.222vw]">
{videoRefs.length &&
primeVideos.map((video, index) =>
video ? (
primeVideos.map(({ src }, index) =>
src ? (
<motion.video
key={video}
src={`/videos/pages/home/presentation/${video}.mp4`}
key={src}
src={`/videos/pages/home/presentation/${src}.mp4`}
ref={videoRefs[index]}
loop
muted
playsInline
style={{ zIndex: primeVideos.length - index }}
className={`absolute w-[48.333vw] left-1/2 -translate-x-1/2 h-full object-cover transition-opacity${
className={`absolute w-[48.333vw] left-1/2 -translate-x-1/2 h-full transition-opacity${
slide > index && index !== primeVideos.length - 1
? ' opacity-0'
: ''
@@ -41,9 +41,9 @@ export function VideoLayer({ scroll }: { scroll: MotionValue<number> }) {
/>
) : (
<div
key={video}
key={src}
style={{ zIndex: primeVideos.length - index }}
className={`inset-0 bg-[green] transition-opacity${
className={`inset-0 transition-opacity${
slide > index && index !== primeVideos.length - 1
? ' opacity-0'
: ''
@@ -4,7 +4,7 @@ import Link from 'next/link';
export function AwardsCard({ className }: { className?: string }) {
return (
<div
className={`p-6 rounded-2xl bg-[#37393B99] xl:hidden max-sm:aspect-square relative flex flex-col justify-between overflow-hidden${
className={`lg:p-[1.667vw] p-6 lg:rounded-[1.111vw] rounded-2xl bg-[#37393B99] xl:hidden max-sm:aspect-square relative flex flex-col justify-between overflow-hidden${
className ? ' ' + className : ''
}`}
>
@@ -14,7 +14,7 @@ export function ProjectCard(project: IProject) {
whileInView={{ opacity: 1 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }}
className="group aspect-square rounded-2xl relative flex items-end p-4 overflow-hidden"
className="group aspect-square lg:rounded-[1.111vw] rounded-2xl relative flex items-end p-4 overflow-hidden"
>
<ItemActions item={project} />
<div
@@ -33,7 +33,7 @@ export function ProjectsSection({ projects }: { projects: IProject[] }) {
delay: 0.2,
}}
href={'/projects'}
className="rounded-xl bg-[#232425] hover:bg-[#23242599] transition-colors aspect-square self-center p-5 flex items-center justify-center btnl font-medium gap-2"
className="lg:rounded-[1.111vw] rounded-2xl bg-[#232425] hover:bg-[#23242599] transition-colors aspect-square self-center p-5 flex items-center justify-center btnl font-medium gap-2"
>
Смотреть все
<ArrowRightIcon className="lg:w-[1.389vw] lg:h-[1.389vw] md:max-lg:w-[2.604vw] md:max-lg:h-[2.604vw] w-5 h-5 text-white" />
+37 -13
View File
@@ -1,18 +1,42 @@
export const videos = [
'1_search',
'2_3dtour',
'3_infrastructure',
'4_insolation',
'5_engine',
'6_reservation',
{ src: '1_search', anchorImg: '/img/pages/prime/search-select.png' },
{ src: '2_3dtour', anchorImg: '/img/pages/prime/3dtour.png' },
{
src: '3_infrastructure',
anchorImg: '/img/pages/prime/infra.png',
},
{
src: '4_insolation',
anchorImg: '/img/pages/prime/insolation.png',
},
{ src: '5_engine', anchorImg: '/img/pages/prime/engine.png' },
{
src: '6_reservation',
anchorImg: '/img/pages/prime/crm.png',
},
];
export const primeVideos = [
'2_3dtour',
'1_search',
'3_infrastructure',
'',
'6_reservation',
'4_insolation',
'',
{ src: '2_3dtour', anchorImg: '/img/pages/prime/3dtour.png' },
{
src: '1_search',
anchorImg: '/img/pages/prime/search-select.png',
},
{
src: '3_infrastructure',
anchorImg: '/img/pages/prime/infra.png',
},
{
src: '',
anchorImg: '/img/pages/prime/favorites.png',
},
{
src: '6_reservation',
anchorImg: '/img/pages/prime/crm.png',
},
{
src: '4_insolation',
anchorImg: '/img/pages/prime/insolation.png',
},
{ src: '', anchorImg: '/img/pages/prime/cp.png' },
];
+2 -2
View File
@@ -22,12 +22,12 @@ export function CheckboxesGroup<IFieldValues extends FieldValues>({
const values: string[] = useWatch({ control, name }) || [];
return (
<div className="flex flex-wrap gap-2">
<div className="flex flex-wrap lg:gap-[0.556vw] gap-2">
{options.map((option) => (
<label
htmlFor={name + '_' + option}
key={option}
className={`cursor-pointer transition-colors rounded-xl font-medium text-nowrap select-none px-6 py-[17px] btnm ${
className={`cursor-pointer transition-colors rounded-[1.111vw] font-medium text-nowrap select-none lg:px-[1.667vw] px-6 lg:py-[1.181vw] py-[17px] btnm ${
value.includes(option)
? 'bg-white text-black'
: 'bg-[#37393B99] hover:bg-[#37393B]'
+1 -1
View File
@@ -8,7 +8,7 @@ export function PostTag({
return (
<div
className={
'lg:px-[0.833vw]a px-3 lg:py-[0.486vw]a py-[7px] rounded-[17px] btns font-medium ' +
'lg:px-[0.833vw] px-3 lg:py-[0.486vw] py-[7px] rounded-[17px] btns font-medium ' +
(active ? 'bg-gradient' : 'bg-[#37393B99]')
}
>