diff --git a/bun.lockb b/bun.lockb new file mode 100644 index 00000000..78443fa9 Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json index 86040e87..f97534e8 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "generate": "graphql-codegen --config .graphqlrc.json" }, "dependencies": { + "@measured/puck": "^0.18.0", + "@tailwindcss/postcss": "^4.0.0", + "@tailwindcss/vite": "^4.0.0", "@tanstack/react-query": "^5.62.7", "@tanstack/react-query-devtools": "^5.64.2", "@tinymce/tinymce-react": "^5.1.1", @@ -23,6 +26,7 @@ "ky": "^1.4.0", "libphonenumber-js": "^1.11.7", "next": "14.2.5", + "postcss": "^8.5.1", "react": "^18", "react-circular-progressbar": "^2.1.0", "react-dom": "^18", @@ -34,6 +38,7 @@ "react-swipeable": "^7.0.1", "react-transition-group": "^4.4.5", "sharp": "^0.33.5", + "tailwindcss": "^4.0.0", "tinymce": "^7.4.1", "usehooks-ts": "^3.1.0", "zustand": "^4.5.4" @@ -46,11 +51,8 @@ "@types/react-phone-number-input": "^3.1.37", "@types/react-rangeslider": "^2.2.7", "@types/react-transition-group": "^4.4.11", - "autoprefixer": "^10.4.19", "eslint": "^8", "eslint-config-next": "14.2.5", - "postcss": "^8", - "tailwindcss": "^3.4.1", "typescript": "^5" } } diff --git a/postcss.config.mjs b/postcss.config.mjs index 1a69fd2a..5d6d8457 100644 --- a/postcss.config.mjs +++ b/postcss.config.mjs @@ -1,7 +1,7 @@ /** @type {import('postcss-load-config').Config} */ const config = { plugins: { - tailwindcss: {}, + '@tailwindcss/postcss': {}, }, }; diff --git a/public/img/pages/home/interactivePresentation/screen.png b/public/img/pages/home/interactivePresentation/screen.png new file mode 100644 index 00000000..420a11fe Binary files /dev/null and b/public/img/pages/home/interactivePresentation/screen.png differ diff --git a/public/videos/pages/home/interactive/1_search.mp4 b/public/videos/pages/home/interactive/1_search.mp4 new file mode 100644 index 00000000..5a7b560f Binary files /dev/null and b/public/videos/pages/home/interactive/1_search.mp4 differ diff --git a/public/videos/pages/home/interactive/2_3dtour.mp4 b/public/videos/pages/home/interactive/2_3dtour.mp4 new file mode 100644 index 00000000..87ed62b8 Binary files /dev/null and b/public/videos/pages/home/interactive/2_3dtour.mp4 differ diff --git a/public/videos/pages/home/interactive/3_infrastructure.mp4 b/public/videos/pages/home/interactive/3_infrastructure.mp4 new file mode 100644 index 00000000..b0acb18c Binary files /dev/null and b/public/videos/pages/home/interactive/3_infrastructure.mp4 differ diff --git a/public/videos/pages/home/interactive/4_insolation.mp4 b/public/videos/pages/home/interactive/4_insolation.mp4 new file mode 100644 index 00000000..f830588b Binary files /dev/null and b/public/videos/pages/home/interactive/4_insolation.mp4 differ diff --git a/public/videos/pages/home/interactive/5_reservation.mp4 b/public/videos/pages/home/interactive/5_reservation.mp4 new file mode 100644 index 00000000..0efc36b6 Binary files /dev/null and b/public/videos/pages/home/interactive/5_reservation.mp4 differ diff --git a/public/videos/pages/home/interactive/6_engine.mp4 b/public/videos/pages/home/interactive/6_engine.mp4 new file mode 100644 index 00000000..16389c04 Binary files /dev/null and b/public/videos/pages/home/interactive/6_engine.mp4 differ diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index f3a65ee4..50617020 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -2,6 +2,7 @@ import { api } from '@/api'; import { Awards } from '@/components/pages/MainPage/Awards'; import { Calculator } from '@/components/pages/MainPage/Calculator/Calculator'; import { Clients } from '@/components/pages/MainPage/Clients'; +import { InteractivePresentation } from '@/components/pages/MainPage/InteractivePresentaion/IntreractivePresentation'; import { ProjectsMap } from '@/components/pages/MainPage/Map/ProjectsMap'; import { Projects } from '@/components/pages/MainPage/Projects'; import { Statistics } from '@/components/pages/MainPage/Statistics'; @@ -57,7 +58,7 @@ export default async function HomePage() { return ( - {/* */} + diff --git a/src/app/globals.css b/src/app/globals.css index f3b16d3c..c12d0b26 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,6 +1,9 @@ @import url('/fonts/TTHovesProAll/stylesheet.css'); +@import 'tailwindcss'; -@tailwind base; +@theme { + --gradient: linear-gradient(87deg, #798fff 15%, #d375ff 100%); +} @layer base { .no-tailwindcss-base { @@ -57,9 +60,6 @@ } } -@tailwind components; -@tailwind utilities; - html { scroll-behavior: smooth; } @@ -70,9 +70,9 @@ body { background-color: #0f1011; } -.bg-gradient { +/* .bg-gradient { background: linear-gradient(87deg, #798fff 15%, #d375ff 100%); -} +} */ .bg-gradient-card { content: ''; @@ -109,6 +109,7 @@ body { .h1 { @apply -tracking-[.02em] 2xl:text-[clamp(96px,96px+(100vw-1560px)/360*16,112px)] text-[clamp(40px,40px+(100vw-360px)/1240*56,96px)] leading-[clamp(36px,36px+(100vw-360px)/1240*50.4,86.4px)] font-medium; } + .h2 { @apply -tracking-[.02em] 2xl:text-[clamp(64px,64px+(100vw-1560px)/360*12,76px)] text-[clamp(28px,28px+(100vw-360px)/1240*36,64px)] leading-none font-medium; } @@ -217,7 +218,7 @@ body { } .accent { - @apply min-[1440px]:text-[clamp(32px,32px+(100vw-1440px)/480*8,40px)] text-2xl min-[1440px]:leading-[1.1] leading-none; + @apply min-[1440px]:text-[clamp(32px,32px+(100vw-1440px)/480*8,40px)] text-[clamp(24px,32px+(100vw-360px)/1080*8,32px)] min-[1440px]:leading-[1.1] leading-none; } .text1 { diff --git a/src/components/ArticleActions.tsx b/src/components/ArticleActions.tsx index af318cba..e7f83b05 100644 --- a/src/components/ArticleActions.tsx +++ b/src/components/ArticleActions.tsx @@ -7,7 +7,7 @@ import { usePathname, useRouter } from 'next/navigation'; import { UseFormSetValue } from 'react-hook-form'; import { DeleteIcon } from './icons/DeleteIcon'; import { EditIcon } from './icons/EditIcon'; -import { ArticleFormModal, IArticleFormInput } from './modals/ArticleFormModal'; +import { ArticleFormModal, IArticleInput } from './modals/ArticleFormModal'; import { DeleteArticleModal } from './modals/DeleteArticleModal'; export function ArticleActions({ @@ -20,7 +20,7 @@ export function ArticleActions({ setValue, inCard = false, }: IArticle & { - setValue?: UseFormSetValue; + setValue?: UseFormSetValue; inCard?: boolean; }) { const { push } = useRouter(); @@ -61,13 +61,13 @@ export function ArticleActions({ <> diff --git a/src/components/Layout/Feedback.tsx b/src/components/Layout/Feedback.tsx index f911586f..0a406f2d 100644 --- a/src/components/Layout/Feedback.tsx +++ b/src/components/Layout/Feedback.tsx @@ -17,14 +17,14 @@ export function Feedback() { return (
-

+

Хотите увеличить конверсию?
Давайте обсудим детали.

-
+

Нам нужна

diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index 94d624a9..0c23a2ca 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -3,6 +3,7 @@ import { api } from '@/api'; import { ClassNameWrapper } from '@/hocs/ClassNameWrapper'; import { useMediaQueries } from '@/hooks/useMediaQueries'; +import { useScroll } from '@/hooks/useScroll'; import { useCheckAuthQuery } from '@/queries/checkAuth'; import { useModalStore } from '@/stores/useModalStore'; import { Button } from '@/ui/Button'; @@ -49,6 +50,7 @@ export function Header() { const burgerBtnRef = useRef(null); const productsRef = useRef(null); const productsBtnRef = useRef(null); + const logoRef = useRef(null); useOnClickOutside([productsRef, productsBtnRef], () => { setProductsOpened(false); @@ -58,9 +60,11 @@ export function Header() { setBurgerOpened(false); }); + const scroll = useScroll(logoRef); + return (
- + @@ -80,14 +84,16 @@ export function Header() { }} className="fixed lg:top-5 top-4 p-1 rounded-[20px] bg-[#37393B99] backdrop-blur-2xl flex gap-1 z-[12]" > - - - - - + {((isLg && scroll < -logoRef.current?.clientHeight!) || !isLg) && ( + + + + + + )}
-
+
-
+
diff --git a/src/components/pages/BlogPage/ArticleCard.tsx b/src/components/pages/BlogPage/ArticleCard.tsx index c89d52a4..553b8f51 100644 --- a/src/components/pages/BlogPage/ArticleCard.tsx +++ b/src/components/pages/BlogPage/ArticleCard.tsx @@ -39,7 +39,7 @@ export function ArticleCard({ className="!relative object-cover rounded-xl z-[1]" /> {auth && ( -
+
)}

{title}

diff --git a/src/components/pages/MainPage/Calculator/Calculator.tsx b/src/components/pages/MainPage/Calculator/Calculator.tsx index 94f3ed25..b79167af 100644 --- a/src/components/pages/MainPage/Calculator/Calculator.tsx +++ b/src/components/pages/MainPage/Calculator/Calculator.tsx @@ -133,8 +133,10 @@ export function Calculator() { return (
- Оцените эффективность инструмента{' '} - <span className="text-gradient">GRAFF.estate</span> + Оцените эффективность + <br /> + инструмента + <span className="text-gradient"> GRAFF.estate</span>
{selectedRegion && ( @@ -167,18 +169,21 @@ export function Calculator() { diff --git a/src/components/pages/MainPage/Calculator/StatColumn.tsx b/src/components/pages/MainPage/Calculator/StatColumn.tsx index 588bb0d0..78f0816b 100644 --- a/src/components/pages/MainPage/Calculator/StatColumn.tsx +++ b/src/components/pages/MainPage/Calculator/StatColumn.tsx @@ -2,19 +2,21 @@ export function StatsColumn({ color, title, percents, + label, value, }: { percents: number; value: number; title: string; color: string; + label: string; }) { return (

{value}

- {percents}% + {label}%

diff --git a/src/components/pages/MainPage/Clients.tsx b/src/components/pages/MainPage/Clients.tsx index 787df32c..f4bee36c 100644 --- a/src/components/pages/MainPage/Clients.tsx +++ b/src/components/pages/MainPage/Clients.tsx @@ -28,7 +28,7 @@ export function Clients() { {companies?.map( (company) => company.logo && ( -
+
- - Интерактивная презентация - <span className="text-gradient"> - {' '} - улучшает опыт выбора недвижимости{' '} - </span> - и увеличивают темпы продаж квартир в жилом комплексе - -
- - -
- - - - -
-
- -
- - - -
-
- -
-
-
-
- 2K -
- - - - - - -
-

- Клиент всегда видит актуальные данные об интересующем его лоте, - включая статус и стоимость. -

-
-
-
- Вова -
- - - -
-
- -
-
-

- Клиент всегда видит актуальные данные об интересующем его лоте, - включая статус и стоимость. -

-
-
-
-
+
+ + +
); } export function DoubleCard() { return ( -
+
-
+

Эмоциональне вовлечение пользователя в выбор квартиры

-
+

Удобство выбора расположения и видовых характеристик

-
+
{[ @@ -178,11 +82,11 @@ export function CardContainer({ text ? '' : ' justify-between' }`} > -

{title}

+

{title}

{children}
- {text &&

{text}

} + {text &&

{text}

}
); } @@ -198,7 +102,9 @@ export function SeasonCard({ }) { return (
); } + +export function Slide1() { + return ( +
+ +
+
+
+ ); +} + +export function Slide2() { + return ( +
+
+ ); +} + +export function Slide3() { + return ( +
+
+
+
+

+ Демонстрация инфраструктуры вокруг будущего комплекса +

+
+
+ + + + + + + + + + + + +
+
+
+
+ ); +} diff --git a/src/components/pages/MainPage/Motivation.tsx b/src/components/pages/MainPage/Motivation.tsx index e0b10901..070aee45 100644 --- a/src/components/pages/MainPage/Motivation.tsx +++ b/src/components/pages/MainPage/Motivation.tsx @@ -8,6 +8,7 @@ import { useEffect, useRef, useState } from 'react'; export function Motivation() { const ref = useRef(null); + const videoRef = useRef(null); const [initTopOffset, setInitTopOffset] = useState(0); @@ -19,12 +20,15 @@ export function Motivation() { const { isLg } = useMediaQueries(); - const videoRef = useRef(null); - return (
- - Помогаем девелоперам продавать недвижимость проще и  + <Title + headerLevel={1} + className="sm:max-lg:text-5xl text-center 2xl:atext-[160px]" + > + Помогаем девелоперам + <br /> + продавать недвижимость проще и  <span className="relative"> <span className="text-[#37393B]">быстрее</span> <span className="absolute top-[55%] -left-[2.5%] 2xl:h-1.5 h-1 w-[105%] bg-white" /> @@ -37,7 +41,7 @@ export function Motivation() { width: isLg ? `calc((100vw - 40px) * ${ 1 + - (isLg && initTopOffset - scroll > 400 && scroll !== 0 + (isLg && initTopOffset - scroll > 650 && scroll !== 0 ? scroll >= 150 ? Math.min( (0.33 * (initTopOffset - scroll - 200)) / @@ -104,17 +108,8 @@ export function Motivation() { <p className="font-medium heading2 sm:max-w-[50%]"> Интеграция в офисы продаж </p> - <div - className="sm:absolute relative lg:w-[calc(168/412*100%)] sm:w-[calc(168/362*100%)] w-[calc(134/166*100%)] sm:bottom-6 sm:right-6 self-center rounded-full aspect-square bg-white" - role="progressbar" - aria-valuenow={ - ((videoRef.current?.currentTime ?? 0) / - (videoRef.current?.duration ?? 1)) * - 100 - } - aria-valuemin={0} - aria-valuemax={100} - > + <div className="sm:absolute relative lg:w-[calc(168/412*100%)] sm:w-[calc(168/362*100%)] w-[calc(134/166*100%)] sm:bottom-6 sm:right-6 self-center"> + {/* <CircularProgressbar value={ref.current?.currentTime/ref.current?.duration} /> */} <video ref={videoRef} src="/videos/pages/home/story.mp4" diff --git a/src/components/pages/MainPage/Statistics.tsx b/src/components/pages/MainPage/Statistics.tsx index c7367e9b..84ce59cd 100644 --- a/src/components/pages/MainPage/Statistics.tsx +++ b/src/components/pages/MainPage/Statistics.tsx @@ -43,7 +43,7 @@ export function Statistics() { <p className="heading2 font-medium"> <span className="line1">4</span> раз </p> - <div className="absolute w-[calc(103/338*100%)] sm:max-xl:w-[calc(103/380*100%)] sm:bottom-12 sm:right-16 bottom-12 right-14"> + <div className="absolute w-[calc(103/338*100%)] sm:max-xl:w-[calc(103/380*100%)] sm:bottom-12 sm:right-16 bottom-12 right-14 xl:hidden"> <Image src="/img/pages/home/stats/Forum_Zoolog_09-03(2).png" fill @@ -52,7 +52,7 @@ export function Statistics() { sizes="" /> </div> - <div className="absolute w-[calc(103/338*100%)] sm:max-xl:w-[calc(103/380*100%)] sm:bottom-6 sm:right-6 bottom-6 right-4"> + <div className="absolute w-[calc(103/338*100%)] sm:max-xl:w-[calc(103/380*100%)] sm:bottom-6 sm:right-6 bottom-6 right-4 xl:hidden"> <Image src="/img/pages/home/stats/Forum_Zoolog_09-03.png" fill diff --git a/src/components/pages/MainPage/Streaming/Streaming.tsx b/src/components/pages/MainPage/Streaming/Streaming.tsx index 6ba496d1..71b7c98d 100644 --- a/src/components/pages/MainPage/Streaming/Streaming.tsx +++ b/src/components/pages/MainPage/Streaming/Streaming.tsx @@ -48,7 +48,6 @@ export function Streaming() { const handleMouseMove = useCallback((e: MouseEvent) => { if (!ref.current) return; const { bottom, left, top, right } = ref.current.getBoundingClientRect(); - ref.current?.getBoundingClientRect().right; if ( ref.current && e.clientX < right && @@ -72,14 +71,15 @@ export function Streaming() { }, []); useEffect(() => { - ref.current?.addEventListener('mousemove', handleMouseMove); + const el = ref.current; + el?.addEventListener('mousemove', handleMouseMove); animate(); return () => { cancelAnimationFrame(requestRef.current!); - ref.current?.removeEventListener('mousemove', handleMouseMove); + el?.removeEventListener('mousemove', handleMouseMove); }; - }, []); + }, [animate, handleMouseMove]); return ( <div className="lg:mt-[140px] mt-[100px] lg:space-y-16 sm:space-y-12 space-y-10"> @@ -96,13 +96,13 @@ export function Streaming() { {data?.map((project) => ( <StreamingProject key={project.id} href="/" {...project} /> ))} - <div className="border border-[#3D425C] rounded-2xl flex justify-center items-center p-6 sm:max-lg:min-w-[300px]"> + <div className="border border-[#3D425C] rounded-2xl flex justify-center items-center p-6 sm:max-lg:min-w-[300px] group"> <div className="flex flex-col items-center space-y-6"> <p className="heading2 font-medium text-center"> Расскажем и покажем как это работает на созвоне </p> <Button - className="btnl px-6 py-4 rounded-lg" + className="btnl group-hover:scale-105 px-6 py-4 transition-transform rounded-lg" onClick={() => setModal(<ModalWithFeedbackForm />, 'form')} > Оставить заявку @@ -120,10 +120,10 @@ export function Streaming() { className="lg:aspect-[1400/640] sm:aspect-[736/480] aspect-[340/600] rounded-2xl w-full h-full object-cover" /> <div className="absolute left-0 top-0 h-5/6 w-full z-[1]"> - <div ref={ref} className="group relative w-full h-full"> + <div ref={ref} className="relative w-full h-full"> <button ref={btnRef} - className="bg-[#37393B99] p-[50px] backdrop-blur-[30.72px] rounded-full group-hover:opacity-100 transition-opacity group-hover:cursor-none opacity-0 fixed z-[1]a" + className="bg-[#37393B99] p-[50px] backdrop-blur-[30.72px] rounded-full in-hover:opacity-100 transition-opacity in-hover:cursor-none opacity-0 sticky z-[1]a" style={{ left: point[0] - 64, top: point[1] - 64 }} onClick={handleVideoClick} > diff --git a/src/components/pages/MainPage/Streaming/StreamingProject.tsx b/src/components/pages/MainPage/Streaming/StreamingProject.tsx index 60189705..a1a0c7a5 100644 --- a/src/components/pages/MainPage/Streaming/StreamingProject.tsx +++ b/src/components/pages/MainPage/Streaming/StreamingProject.tsx @@ -16,9 +16,9 @@ export function StreamingProject({ const { isLg } = useMediaQueries(); return ( - <div className="lg:aspect-[344/396] sm:aspect-[300/344] sm:max-lg:min-w-[300px] rounded-2xl p-4 flex group relative overflow-hidden"> + <div className="lg:aspect-[344/396] sm:aspect-[300/344] sm:max-lg:min-w-[300px] rounded-2xl p-4 flex relative overflow-hidden group"> <div - className="absolute w-full h-full top-0 left-0 rounded-2xl group-hover:scale-110 transition-transform" + className="rounded-2xl group-hover:scale-110 absolute top-0 left-0 w-full h-full transition-transform" style={{ background: `linear-gradient(to ${ isLg ? 'bottom' : 'top' @@ -46,7 +46,7 @@ export function StreamingProject({ </div> <Link href={href} - className="hidden lg:group-hover:block absolute w-full h-full left-0 bottom-0 rounded-2xl font-medium bg-[radial-gradient(#000000CC,transparent)]a backdrop-blur-[3px] content-center text-center z-[2]" + className="hidden lg:group-hover:block absolute w-full h-full left-0 bottom-0 rounded-2xl font-medium backdrop-blur-[3px] content-center text-center z-[2]" > <p className="btnl flex justify-center gap-2"> Начать демонстрацию <ArrowMoreIcon /> diff --git a/src/ui/Button.tsx b/src/ui/Button.tsx index 60704914..d59c33f2 100644 --- a/src/ui/Button.tsx +++ b/src/ui/Button.tsx @@ -42,7 +42,7 @@ export function Button({ icon ? 'pr-4' : '' } flex gap-1 items-center overflow-hidden w-${width} ${className} justify-between`} > - <span className="group-hover:opacity-10 opacity-0 bg-black transition-opacity absolute top-0 left-0 w-full h-full"></span> + <span className="group-hover:opacity-10 absolute top-0 left-0 w-full h-full transition-opacity bg-black opacity-0"></span> <span className={'relative font-medium' + (icon ? '' : ' m-auto')}> {children} </span> diff --git a/src/ui/HeaderLink.tsx b/src/ui/HeaderLink.tsx index f9d3a303..5b6326d7 100644 --- a/src/ui/HeaderLink.tsx +++ b/src/ui/HeaderLink.tsx @@ -3,7 +3,7 @@ import Link from 'next/link'; export function HeaderLink({ href, text, - className, + className = '', }: { href: string; text: string; @@ -12,7 +12,9 @@ export function HeaderLink({ return ( <Link href={href} - className={`md:px-6 md:py-4 outline-none px-2 py-2 font-medium text-nowrap md:btnm accent hover:bg-[#37393B99] active:bg-white active:text-black rounded-2xl transition-colors flex items-center ${className}`} + className={`md:px-6 md:py-4 outline-none px-2 py-2 font-medium text-nowrap hover:bg-[#37393B99] active:bg-white active:text-black rounded-2xl transition-colors flex items-center${ + className ? ' ' + className : '' + }`} > {text} </Link>