fixes, almost done slider, refactoring
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 249 KiB After Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 5.6 MiB After Width: | Height: | Size: 5.6 MiB |
|
Before Width: | Height: | Size: 343 KiB After Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 10 MiB After Width: | Height: | Size: 10 MiB |
|
Before Width: | Height: | Size: 688 KiB After Width: | Height: | Size: 688 KiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 471 KiB After Width: | Height: | Size: 471 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 399 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 203 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 677 B After Width: | Height: | Size: 677 B |
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 498 B |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 383 KiB |
|
Before Width: | Height: | Size: 74 KiB |
@@ -3,7 +3,9 @@ import dynamic from 'next/dynamic';
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
const DynamicRelevantSlider = dynamic(
|
||||
() =>
|
||||
import('@/components/Blog/RelevantSlider').then(m => m.RelevantSlider),
|
||||
import('@/components/pages/BlogPage/RelevantSlider').then(
|
||||
m => m.RelevantSlider,
|
||||
),
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@ export default function PostPage({
|
||||
const [date = '', month = '', year = ''] = post!.createdAt.split(' ');
|
||||
|
||||
const DynamicPostSlider = dynamic(
|
||||
() => import('@/components/Blog/PostSlider').then(mod => mod.PostSlider),
|
||||
() =>
|
||||
import('@/components/pages/BlogPage/PostSlider').then(
|
||||
mod => mod.PostSlider,
|
||||
),
|
||||
{
|
||||
ssr: false,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PostsFilters } from '@/components/Blog/PostsFilters';
|
||||
import { PostsList } from '@/components/Blog/PostsList';
|
||||
import { PostsFilters } from '@/components/pages/BlogPage/PostsFilters';
|
||||
import { PostsList } from '@/components/pages/BlogPage/PostsList';
|
||||
import { Title } from '@/ui/Title';
|
||||
|
||||
export default function BlogPage() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { AvailablesSlider } from '@/components/Main/Availables/AvailablesSlider';
|
||||
import { IntegrationsSlider } from '@/components/Main/Integrations/IntegrationsSlider';
|
||||
import { Motivation } from '@/components/Main/Motivation';
|
||||
import { Showreel } from '@/components/Main/Showreel';
|
||||
import { Statistics } from '@/components/Main/Statistics';
|
||||
import { AvailablesSlider } from '@/components/pages/MainPage/Availables/AvailablesSlider';
|
||||
import { IntegrationsSlider } from '@/components/pages/MainPage/Integrations/IntegrationsSlider';
|
||||
import { Motivation } from '@/components/pages/MainPage/Motivation';
|
||||
import { Showreel } from '@/components/pages/MainPage/Showreel';
|
||||
import { Statistics } from '@/components/pages/MainPage/Statistics';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@@ -13,19 +13,19 @@ export default function Home() {
|
||||
<IntegrationsSlider
|
||||
integrations={[
|
||||
{
|
||||
img: '/img/home-page/upsidetowers.png',
|
||||
img: '/img/pages/home/integrations/upsidetowers.png',
|
||||
title: 'ЖК «Upside Towers»',
|
||||
year: '2024',
|
||||
company: 'Upside Development, Москва',
|
||||
},
|
||||
{
|
||||
img: '/img/home-page/mirapolis.png',
|
||||
img: '/img/pages/home/integrations/mirapolis.png',
|
||||
title: 'ЖК «Мираполис»',
|
||||
year: '2024',
|
||||
company: 'ГК Основа, Москва',
|
||||
},
|
||||
{
|
||||
img: '/img/home-page/liferezidention.png',
|
||||
img: '/img/pages/home/integrations/liferezidention.png',
|
||||
title: 'ЖК «Life Резиденция»',
|
||||
year: '2020',
|
||||
company: 'ГК Паритет Девелопмент, Тюмень',
|
||||
@@ -35,13 +35,18 @@ export default function Home() {
|
||||
<AvailablesSlider
|
||||
availables={[
|
||||
{
|
||||
img: '/img/home-page/availables/1.jpg',
|
||||
img: '/img/pages/home/availables/1.jpg',
|
||||
title: 'Интеграция с CRM-системой',
|
||||
text: 'Приложение передает информацию о клиенте в CRM-систему застройщика и получает актуальную информацию по ценам и статусам квартир.',
|
||||
},
|
||||
{
|
||||
img: '/img/home-page/availables/2.jpg',
|
||||
title: 'Интеграция с CRM-системой',
|
||||
img: '/img/pages/home/availables/2.jpg',
|
||||
title: 'Интеграция с CRM-системой1',
|
||||
text: 'Приложение передает информацию о клиенте в CRM-систему застройщика и получает актуальную информацию по ценам и статусам квартир.',
|
||||
},
|
||||
{
|
||||
img: '/img/pages/home/availables/3.jpg',
|
||||
title: 'Интеграция с CRM-системой2',
|
||||
text: 'Приложение передает информацию о клиенте в CRM-систему застройщика и получает актуальную информацию по ценам и статусам квартир.',
|
||||
},
|
||||
]}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ProjectsFilters } from '@/components/Projects/ProjectsFilters';
|
||||
import { ProjectsList } from '@/components/Projects/ProjectsList';
|
||||
import { ProjectsFilters } from '@/components/pages/ProjectsPage/ProjectsFilters';
|
||||
import { ProjectsList } from '@/components/pages/ProjectsPage/ProjectsList';
|
||||
import { Title } from '@/ui/Title';
|
||||
|
||||
export default function ProjectsPage() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/api';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { ChangeEvent, FormEvent, useState } from 'react';
|
||||
import InputMask from 'react-input-mask';
|
||||
@@ -136,9 +137,15 @@ export function ContactsForm({ inModal = false }: { inModal?: boolean }) {
|
||||
disabled={isLoading}
|
||||
icon={
|
||||
isLoading ? (
|
||||
<LoaderIcon className="relative 2xl:w-8 2xl:h-8 w-6 h-6 animate-spin" />
|
||||
<ClassNameWrapper
|
||||
element={<LoaderIcon />}
|
||||
className="relative 2xl:w-8 2xl:h-8 w-6 h-6 animate-spin"
|
||||
/>
|
||||
) : (
|
||||
<SendIcon className="relative 2xl:w-8 2xl:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
element={<SendIcon />}
|
||||
className="relative 2xl:w-8 2xl:h-8 w-6 h-6"
|
||||
/>
|
||||
)
|
||||
}
|
||||
className="py-4"
|
||||
@@ -200,9 +207,15 @@ export function ContactsForm({ inModal = false }: { inModal?: boolean }) {
|
||||
disabled={isLoading}
|
||||
icon={
|
||||
isLoading ? (
|
||||
<LoaderIcon className="relative 2xl:w-8 2xl:h-8 w-6 h-6 animate-spin" />
|
||||
<ClassNameWrapper
|
||||
element={<LoaderIcon />}
|
||||
className="relative 2xl:w-8 2xl:h-8 w-6 h-6 animate-spin"
|
||||
/>
|
||||
) : (
|
||||
<SendIcon className="relative 2xl:w-8 2xl:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
element={<SendIcon />}
|
||||
className="relative 2xl:w-8 2xl:h-8 w-6 h-6"
|
||||
/>
|
||||
)
|
||||
}
|
||||
className="py-4"
|
||||
@@ -216,7 +229,10 @@ export function ContactsForm({ inModal = false }: { inModal?: boolean }) {
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-gradient sm:text-2xl text-xl w-fit font-semibold flex items-center gap-2">
|
||||
<span>Заявка отправлена</span>
|
||||
<CheckGradientIcon className="lg:w-8 lg:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
element={<CheckGradientIcon />}
|
||||
className="lg:w-8 lg:h-8 w-6 h-6"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { AppearanceHr } from '@/ui/AppearanceHr';
|
||||
import { MailIcon } from '../icons/MailIcon';
|
||||
import { PhoneIcon } from '../icons/PhoneIcon';
|
||||
@@ -36,14 +37,20 @@ export function Feedback() {
|
||||
className="2xl:h-16 h-14 px-6 py-4 2xl:text-base text-sm border rounded-full font-medium flex justify-between items-center w-full border-[#52587A] lg:opacity-80 lg:hover:opacity-100 transition-all"
|
||||
>
|
||||
<span>Написать</span>
|
||||
<MailIcon className="lg:w-8 lg:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
element={<MailIcon />}
|
||||
className="lg:w-8 lg:h-8 w-6 h-6"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="tel:88007700067"
|
||||
className="2xl:h-16 h-14 px-6 py-4 2xl:text-base text-sm border rounded-full font-medium flex justify-between items-center w-full border-[#52587A] lg:opacity-80 lg:hover:opacity-100 transition-all"
|
||||
>
|
||||
<span>Позвонить</span>
|
||||
<PhoneIcon className="lg:w-8 lg:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
className="lg:w-8 lg:h-8 w-6 h-6"
|
||||
element={<PhoneIcon />}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -60,21 +67,30 @@ export function Feedback() {
|
||||
target="_blank"
|
||||
className="group border border-[#3D425C] xl:p-4 p-3 rounded-full lg:hover:border-[#52587A] transition-all"
|
||||
>
|
||||
<YouTubeIcon className="2xl:w-8 2xl:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
element={<YouTubeIcon />}
|
||||
className="2xl:w-8 2xl:h-8 w-6 h-6"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://vk.com/graff.interactive"
|
||||
target="_blank"
|
||||
className="group border border-[#3D425C] xl:p-4 p-3 rounded-full lg:hover:border-[#52587A] transition-all"
|
||||
>
|
||||
<VKIcon className="2xl:w-8 2xl:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
className="2xl:w-8 2xl:h-8 w-6 h-6"
|
||||
element={<VKIcon />}
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://t.me/GRAFFinteractive"
|
||||
target="_blank"
|
||||
className="border rounded-full border-[#52587A] xl:p-4 p-3 opacity-80 lg:hover:opacity-100 transition-all"
|
||||
>
|
||||
<TelegramIcon className="2xl:w-8 2xl:h-8 w-6 h-6" />
|
||||
<ClassNameWrapper
|
||||
className="2xl:w-8 2xl:h-8 w-6 h-6"
|
||||
element={<TelegramIcon />}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { LogoIcon } from '@/components/icons/LogoIcon';
|
||||
import { LogoWithTextIcon } from '@/components/icons/LogoWithTextIcon';
|
||||
import { ModalWithForm } from '@/components/Layout/ModalWithForm';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { useWindowWidth } from '@/hooks/useWindowWidth';
|
||||
import { useModalStore } from '@/stores/useModalStore';
|
||||
import { BurgerLink } from '@/ui/BurgerLink';
|
||||
@@ -33,7 +34,7 @@ export function Header() {
|
||||
<div className="flex">
|
||||
<div className="w-[25vw] lg:pl-10 pl-6 flex items-center">
|
||||
<Link href={'/'}>
|
||||
<LogoIcon className="xl:hidden" />
|
||||
<ClassNameWrapper className="xl:hidden" element={<LogoIcon />} />
|
||||
{width >= 1280 && <LogoWithTextIcon />}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
export interface IAvailable {
|
||||
title: string;
|
||||
text: string;
|
||||
img: string;
|
||||
}
|
||||
|
||||
export function AvailableItem({
|
||||
current,
|
||||
img,
|
||||
text,
|
||||
title,
|
||||
}: IAvailable & { current: boolean }) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
// (current
|
||||
// ? 'min-w-[64vw] min-h-[35.5vw]'
|
||||
// : 'min-w-[31.7vw] min-h-[17.6vw]') +
|
||||
' bg-no-repeat bg-cover flex flex-col justify-end p-6 transition-transform duration-700 min-h-[17.6vw] min-w-[31.7vw] container' +
|
||||
(current ? ' scale-x-[calc(64/31.7)] scale-y-[calc(35.5/17.6)]' : '')
|
||||
}
|
||||
style={{ backgroundImage: `url(${img})` }}
|
||||
>
|
||||
{current && (
|
||||
<>
|
||||
<h3 className="h3 font-medium mb-4">{title}</h3>
|
||||
<p className="m-text max-w-[49%]">{text}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
export interface IIntegration {
|
||||
img: string;
|
||||
title: string;
|
||||
year: string;
|
||||
company: string;
|
||||
}
|
||||
|
||||
export function IntegrationItem({
|
||||
img,
|
||||
title,
|
||||
year,
|
||||
company,
|
||||
current,
|
||||
}: IIntegration & { current: boolean }) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'pointer-events-none transition-all flex flex-col min-w-[31.6vw] min-h-[31.8vw] [&:nth-child(2)]:animate-scaling'
|
||||
// (current ? ' animate-scaling' : '')
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={img}
|
||||
alt={''}
|
||||
fill
|
||||
objectFit="cover"
|
||||
className={
|
||||
'!relative transition-all flex-1 [&:nth-]' +
|
||||
(current ? '' : ' flex-1')
|
||||
}
|
||||
/>
|
||||
<div className="mt-4">
|
||||
<div className={`flex justify-between mb-${!current ? 1 : 2}`}>
|
||||
<h4 className="h4 font-medium">{title}</h4>
|
||||
<h4 className="h4 font-medium">{year}</h4>
|
||||
</div>
|
||||
<p className="m-caption font-medium text-[#737AA1]">{company}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export function ActiveCubeIcon({ className = '' }: { className?: string }) {
|
||||
export function ActiveCubeIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="13"
|
||||
@@ -6,7 +6,6 @@ export function ActiveCubeIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 13 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M12.5687 0.946289H4.58487L0.431641 5.37585V13.0537H8.11981L12.5687 8.91949V0.946289Z"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function ArrowDownIcon({ className = '' }: { className?: string }) {
|
||||
export function ArrowDownIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
@@ -6,7 +6,6 @@ export function ArrowDownIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path d="M6 10V0M6 10L11 5M6 10L1 5" stroke="#14161F" strokeWidth="1.5" />
|
||||
</svg>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function ArrowLeftIcon({ className = '' }: { className?: string }) {
|
||||
export function ArrowLeftIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -6,7 +6,6 @@ export function ArrowLeftIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<path
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function ArrowMoreIcon({ className = '' }: { className?: string }) {
|
||||
export function ArrowMoreIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -6,7 +6,6 @@ export function ArrowMoreIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<path
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
export function BurgerIcon({ className = '' }: { className?: string }) {
|
||||
export function BurgerIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function CheckGradientIcon({ className = '' }: { className?: string }) {
|
||||
export function CheckGradientIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -6,7 +6,6 @@ export function CheckGradientIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<g id="Icon/Check">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function CloseIcon({ className = '' }: { className?: string }) {
|
||||
export function CloseIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -7,7 +7,6 @@ export function CloseIcon({ className = '' }: { className?: string }) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
color="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M12.0002 11.9999L17.6572 6.34331M12.0002 11.9999L6.34337 6.34302M12.0002 11.9999L17.6571 17.6567M12.0002 11.9999L6.34326 17.6568"
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
export function CubeIcon({ className = '' }: { className?: string }) {
|
||||
export function CubeIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="13"
|
||||
height="14"
|
||||
viewBox="0 0 13 14"
|
||||
fill="none"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
export function EconomicEfficiencyIcon({
|
||||
className = '',
|
||||
}: {
|
||||
className?: string;
|
||||
}) {
|
||||
export function EconomicEfficiencyIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -10,7 +6,6 @@ export function EconomicEfficiencyIcon({
|
||||
height="16"
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function LoaderIcon({ className = '' }: { className?: string }) {
|
||||
export function LoaderIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -7,7 +7,6 @@ export function LoaderIcon({ className = '' }: { className?: string }) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
color="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/Circle">
|
||||
<path
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
export function LoadingIcon({ className = '' }: { className?: string }) {
|
||||
export function LoadingIcon() {
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
'use client';
|
||||
|
||||
export function LogoIcon({ className = '' }: { className?: string }) {
|
||||
export function LogoIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="41"
|
||||
@@ -8,7 +6,6 @@ export function LogoIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 41 40"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function MailIcon({ className = '' }: { className?: string }) {
|
||||
export function MailIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -7,7 +7,6 @@ export function MailIcon({ className = '' }: { className?: string }) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
color="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/Mail" opacity="0.8">
|
||||
<g id="Vector">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function MobileIcon({ className = '' }: { className?: string }) {
|
||||
export function MobileIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
@@ -6,7 +6,6 @@ export function MobileIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<path
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function PauseIcon({ className = '' }: { className?: string }) {
|
||||
export function PauseIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -6,7 +6,6 @@ export function PauseIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<rect x="5" y="3" width="5" height="18" rx="1" fill="white" />
|
||||
<rect x="14" y="3" width="5" height="18" rx="1" fill="white" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function PhoneIcon({ className = '' }: { className?: string }) {
|
||||
export function PhoneIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -7,7 +7,6 @@ export function PhoneIcon({ className = '' }: { className?: string }) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
color="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/Phone" opacity="0.8">
|
||||
<path
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function PlayIcon({ className = '' }: { className?: string }) {
|
||||
export function PlayIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@@ -6,7 +6,6 @@ export function PlayIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M19.5708 11.1425C20.2182 11.5309 20.2182 12.4691 19.5708 12.8575L7.5145 20.0913C6.84797 20.4912 6 20.0111 6 19.2338L6 4.76619C6 3.9889 6.84797 3.50878 7.5145 3.9087L19.5708 11.1425Z"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function SendIcon({ className = '' }: { className?: string }) {
|
||||
export function SendIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -6,7 +6,6 @@ export function SendIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<g id="Icon/Send">
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
export function SkolkovoIcon({
|
||||
className = '',
|
||||
type = 'standart',
|
||||
}: {
|
||||
className?: string;
|
||||
type?: 'mini' | 'standart';
|
||||
}) {
|
||||
return type === 'standart' ? (
|
||||
@@ -12,7 +10,6 @@ export function SkolkovoIcon({
|
||||
viewBox="0 0 80 59"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M9.02798 11.9813C8.39345 9.20125 11.154 6.73663 14.7256 6.73663C17.9441 6.73663 21.169 7.45959 22.3923 11.9682H26.52V18.8494C21.3784 14.6037 10.2316 17.2655 9.02798 11.9748M51.8225 10.0688H42.5336L33.696 19.7958V0.36805H26.5266V5.08041C26.2911 4.77808 26.049 4.47575 25.7677 4.18C23.1577 1.40648 19.4028 0 14.6014 0C9.04761 0 5.88806 2.49748 4.21343 4.59405C2.13978 7.19669 1.21089 10.7457 1.85196 13.6441C3.5135 21.1366 10.4279 22.3328 15.5106 22.9966C19.5206 23.5223 23.3605 24.2519 23.2558 27.8469C23.1511 31.5734 18.9645 32.4936 16.2236 32.4936C9.07377 32.4936 8.83174 27.1831 8.83174 27.1831H1.13892C1.25012 29.1745 1.85195 32.3818 4.29193 35.1291C6.96741 38.1392 10.9773 39.664 16.2171 39.664C20.2336 39.664 23.8969 38.3495 26.52 36.0098V39.2236H33.6895V30.0487L36.2276 27.2554L43.469 39.2236H51.816L41.2776 21.6952L51.8225 10.0819V10.0688Z"
|
||||
@@ -58,7 +55,6 @@ export function SkolkovoIcon({
|
||||
viewBox="0 0 92 27"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M26.9111 0H6.72664C3.0087 0 0 3.02317 0 6.74887V20.2511C0 23.9814 3.01322 27 6.72664 27H20.1844C23.9024 27 26.9111 23.9768 26.9111 20.2511V0ZM26.0301 0.883833V20.2511C26.0301 23.4873 23.4054 26.1162 20.1844 26.1162H6.72664C3.50111 26.1162 0.880929 23.4873 0.880929 20.2511V6.74887C0.880929 3.51721 3.50111 0.883833 6.72664 0.883833H26.0301Z"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function TelegramIcon({ className = '' }: { className?: string }) {
|
||||
export function TelegramIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -6,7 +6,6 @@ export function TelegramIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<g id="Icon/Telegram" opacity="0.8">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function TouchScreenIcon({ className = '' }: { className?: string }) {
|
||||
export function TouchScreenIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
@@ -6,7 +6,6 @@ export function TouchScreenIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<g clipPath="url(#clip0_1403_1738)">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function VKIcon({ className = '' }: { className?: string }) {
|
||||
export function VKIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -6,7 +6,6 @@ export function VKIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<g id="Icon/VK" opacity="0.8">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function VRIcon({ className = '' }: { className?: string }) {
|
||||
export function VRIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
@@ -6,7 +6,6 @@ export function VRIcon({ className = '' }: { className?: string }) {
|
||||
viewBox="0 0 21 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
color="currentColor"
|
||||
>
|
||||
<path
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function YouTubeIcon({ className = '' }: { className?: string }) {
|
||||
export function YouTubeIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
@@ -7,7 +7,6 @@ export function YouTubeIcon({ className = '' }: { className?: string }) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
color="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<g id="Icon/YouTube" opacity="0.8">
|
||||
<path
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowMoreIcon } from '@/components/icons/ArrowMoreIcon';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import type { IPost } from '@/types/IPost';
|
||||
import { PostDate } from '@/ui/PostDate';
|
||||
import { PostTag } from '@/ui/PostTag';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { ArrowMoreIcon } from '../icons/ArrowMoreIcon';
|
||||
|
||||
export function PostCard({ createdAt, title, desc, image, tags, id }: IPost) {
|
||||
const [date, month, year] = createdAt.split(' ');
|
||||
@@ -68,7 +69,7 @@ export function PostCard({ createdAt, title, desc, image, tags, id }: IPost) {
|
||||
month={month}
|
||||
year={year}
|
||||
/>
|
||||
<ArrowMoreIcon className="self-end" />
|
||||
<ClassNameWrapper className="self-end" element={<ArrowMoreIcon />} />
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { TagFilterItem } from '@/components/TagFilterItem';
|
||||
import { YearFilterDropdown } from '@/components/YearFilterDropdown';
|
||||
import { YearFilterItem } from '@/components/YearFilterItem';
|
||||
import { PostTags } from '@/consts/PostTags';
|
||||
import { PostYears } from '@/consts/PostYears';
|
||||
import { Vertical } from '@/ui/Vertical';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { TagFilterItem } from '../TagFilterItem';
|
||||
import { YearFilterDropdown } from '../YearFilterDropdown';
|
||||
import { YearFilterItem } from '../YearFilterItem';
|
||||
|
||||
export function PostsFilters() {
|
||||
const params = useSearchParams();
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowMoreIcon } from '@/components/icons/ArrowMoreIcon';
|
||||
import { IPost } from '@/types/IPost';
|
||||
import { AppearanceHr } from '@/ui/AppearanceHr';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { ArrowMoreIcon } from '../icons/ArrowMoreIcon';
|
||||
|
||||
export function RelevantPost({ image, title, id }: IPost) {
|
||||
const { push } = useRouter();
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowLeftIcon } from '@/components/icons/ArrowLeftIcon';
|
||||
import { Posts } from '@/consts/Posts';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { useWindowWidth } from '@/hooks/useWindowWidth';
|
||||
import { InfinitySlider } from '@/ui/InfinitySlider';
|
||||
import { useRef } from 'react';
|
||||
import { ArrowLeftIcon } from '../icons/ArrowLeftIcon';
|
||||
import { RelevantPost } from './RelevantPost';
|
||||
|
||||
export function RelevantSlider() {
|
||||
@@ -27,7 +28,10 @@ export function RelevantSlider() {
|
||||
className="rounded-full border border-[#3D425C] sm:p-4 p-2 lg:opacity-80 lg:hover:opacity-100"
|
||||
ref={right}
|
||||
>
|
||||
<ArrowLeftIcon className="rotate-180" />
|
||||
<ClassNameWrapper
|
||||
className="rotate-180"
|
||||
element={<ArrowLeftIcon />}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,49 @@
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export interface IAvailable {
|
||||
title: string;
|
||||
text: string;
|
||||
img: string;
|
||||
}
|
||||
|
||||
export function AvailableItem({
|
||||
current,
|
||||
img,
|
||||
text,
|
||||
title,
|
||||
}: IAvailable & { current: boolean }) {
|
||||
return (
|
||||
<div className="pointer-events-none min-h-[35.5vw] flex flex-col justify-end">
|
||||
<motion.div
|
||||
key={title}
|
||||
initial={{
|
||||
minWidth: '31.6vw',
|
||||
minHeight: '17.6vw',
|
||||
backgroundImage: `url(${img})`,
|
||||
}}
|
||||
animate={
|
||||
current
|
||||
? { minWidth: '64.3vw', minHeight: '35.5vw' }
|
||||
: {
|
||||
minWidth: '31.6vw',
|
||||
minHeight: '17.6vw',
|
||||
}
|
||||
}
|
||||
transition={{ duration: 1, delay: 0.75, type: 'just' }}
|
||||
exit={{
|
||||
minWidth: '31.6vw',
|
||||
minHeight: '17.6vw',
|
||||
transition: { duration: 1, type: 'just' },
|
||||
}}
|
||||
className="bg-no-repeat bg-cover flex flex-col justify-end p-6"
|
||||
>
|
||||
{current && (
|
||||
<>
|
||||
<h3 className="h3 font-medium mb-4">{title}</h3>
|
||||
<p className="m-text max-w-[49%]">{text}</p>
|
||||
</>
|
||||
)}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ export function AvailablesSlider({ availables }: { availables: IAvailable[] }) {
|
||||
slideElement={AvailableItem}
|
||||
slides={availables}
|
||||
title="Функциональные возможности"
|
||||
alignItems="end"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,48 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
|
||||
export interface IIntegration {
|
||||
img: string;
|
||||
title: string;
|
||||
year: string;
|
||||
company: string;
|
||||
}
|
||||
|
||||
export function IntegrationItem({
|
||||
img,
|
||||
title,
|
||||
year,
|
||||
company,
|
||||
current,
|
||||
}: IIntegration & { current: boolean }) {
|
||||
return (
|
||||
<div className="min-h-[48vw] h-full pointer-events-none">
|
||||
<motion.div
|
||||
key={title}
|
||||
initial={{ minWidth: '31.6vw', minHeight: '31.8vw' }}
|
||||
animate={current && { minWidth: '48vw', minHeight: '48vw' }}
|
||||
exit={{
|
||||
minWidth: '31.6vw',
|
||||
minHeight: '31.8vw',
|
||||
}}
|
||||
transition={{ duration: 1, delay: 0.75 }}
|
||||
className="flex flex-col"
|
||||
>
|
||||
<Image
|
||||
src={img}
|
||||
alt={''}
|
||||
fill
|
||||
objectFit="cover"
|
||||
className="!relative flex-1"
|
||||
/>
|
||||
<div className="mt-4">
|
||||
<div className={`flex justify-between mb-${!current ? 1 : 2}`}>
|
||||
<h4 className="h4 font-medium">{title}</h4>
|
||||
<h4 className="h4 font-medium">{year}</h4>
|
||||
</div>
|
||||
<p className="m-caption font-medium text-[#737AA1]">{company}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Title } from '../../ui/Title';
|
||||
import { ArrowDownIcon } from '../icons/ArrowDownIcon';
|
||||
import { SkolkovoIcon } from '../icons/SkolkovoIcon';
|
||||
import { ArrowDownIcon } from '@/components/icons/ArrowDownIcon';
|
||||
import { SkolkovoIcon } from '@/components/icons/SkolkovoIcon';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { Title } from '@/ui/Title';
|
||||
|
||||
export function Motivation() {
|
||||
return (
|
||||
@@ -12,7 +13,7 @@ export function Motivation() {
|
||||
продаж
|
||||
<span className="text-gradient"> для застройщиков</span>
|
||||
</Title>
|
||||
<SkolkovoIcon className="mt-4 mr-2" />
|
||||
<ClassNameWrapper className="mt-4 mr-2" element={<SkolkovoIcon />} />
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<h3 className="h3 font-medium min-w-[50vw]">
|
||||
@@ -6,7 +6,7 @@ export function Projects() {
|
||||
<div className="grid grid-cols-12 col-span-full gap-y-14 gap-x-4 pt-[120px]">
|
||||
<div className="col-span-6 col-start-4 object-cover flex flex-col">
|
||||
<Image
|
||||
src={'/img/home-page/projects/1.jpg'}
|
||||
src={'/img/pages/home/projects/1.jpg'}
|
||||
alt={''}
|
||||
className="w-full h-full"
|
||||
width={768}
|
||||
@@ -20,7 +20,7 @@ export function Projects() {
|
||||
<div className="col-span-3 col-start-10">
|
||||
<Image
|
||||
className="w-full "
|
||||
src={'/img/home-page/projects/2.jpg'}
|
||||
src={'/img/pages/home/projects/2.jpg'}
|
||||
alt={''}
|
||||
width={376}
|
||||
height={227}
|
||||
@@ -33,7 +33,7 @@ export function Projects() {
|
||||
<div className="col-span-4">
|
||||
<Image
|
||||
className="w-full"
|
||||
src={'/img/home-page/projects/3.jpg'}
|
||||
src={'/img/pages/home/projects/3.jpg'}
|
||||
alt={''}
|
||||
width={507}
|
||||
height={329}
|
||||
@@ -46,7 +46,7 @@ export function Projects() {
|
||||
<div className="col-span-4">
|
||||
<Image
|
||||
className="w-full"
|
||||
src={'/img/home-page/projects/4.jpg'}
|
||||
src={'/img/pages/home/projects/4.jpg'}
|
||||
alt={''}
|
||||
width={507}
|
||||
height={329}
|
||||
@@ -72,7 +72,7 @@ export function Projects() {
|
||||
<div className="col-span-6">
|
||||
<Image
|
||||
className="w-full"
|
||||
src={'/img/home-page/projects/5.jpg'}
|
||||
src={'/img/pages/home/projects/5.jpg'}
|
||||
alt={''}
|
||||
width={768}
|
||||
height={589}
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { LoadingIcon } from '@/components/icons/LoadingIcon';
|
||||
import { PauseIcon } from '@/components/icons/PauseIcon';
|
||||
import { PlayIcon } from '@/components/icons/PlayIcon';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { LoadingIcon } from '../icons/LoadingIcon';
|
||||
import { PauseIcon } from '../icons/PauseIcon';
|
||||
import { PlayIcon } from '../icons/PlayIcon';
|
||||
|
||||
export function Showreel() {
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
@@ -49,7 +50,7 @@ export function Showreel() {
|
||||
<div ref={ref} className="relative flex justify-center items-center">
|
||||
<video
|
||||
ref={videoRef}
|
||||
src="/videos/showreel_1080p_4000k_h264.mp4"
|
||||
src="/videos/pages/home/showreel_1080p_4000k_h264.mp4"
|
||||
muted
|
||||
loop
|
||||
className={
|
||||
@@ -73,9 +74,9 @@ export function Showreel() {
|
||||
className="absolute z-30 mx-auto p-8 rounded-full border"
|
||||
>
|
||||
{isPlaying ? (
|
||||
<PauseIcon className="w-10 h-10" />
|
||||
<ClassNameWrapper className="w-10 h-10" element={<PauseIcon />} />
|
||||
) : (
|
||||
<PlayIcon className="w-10 h-10" />
|
||||
<ClassNameWrapper className="w-10 h-10" element={<PlayIcon />} />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
@@ -88,7 +89,10 @@ export function Showreel() {
|
||||
>
|
||||
<div className="flex gap-4 items-center">
|
||||
<span>
|
||||
<LoadingIcon className="animate-spin h-5 w-5" />
|
||||
<ClassNameWrapper
|
||||
className="animate-spin w-5 h-5"
|
||||
element={<LoadingIcon />}
|
||||
/>
|
||||
</span>
|
||||
<span className="">Загружаем шоурил...</span>
|
||||
</div>
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CubeIcon } from '@/components/icons/CubeIcon';
|
||||
import { LineThrow } from '@/ui/LineThrow';
|
||||
import { Title } from '@/ui/Title';
|
||||
import { Manrope } from 'next/font/google';
|
||||
import Image from 'next/image';
|
||||
import { CubeIcon } from '../icons/CubeIcon';
|
||||
|
||||
const manrope = Manrope({ subsets: ['latin'] });
|
||||
|
||||
@@ -22,7 +22,7 @@ export function Statistics() {
|
||||
</div>
|
||||
<div className="col-start-2 col-span-full py-10 pl-4 flex items-center justify-center border-b border-[#3D425C]">
|
||||
<Image
|
||||
src={'/img/home-page/map.png'}
|
||||
src={'/img/pages/home/stats/map.jpg'}
|
||||
alt={''}
|
||||
fill
|
||||
className="!static object-cover"
|
||||
@@ -39,7 +39,7 @@ export function Statistics() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap col-span-3 py-4 pl-4 gap-4 border-b border-[#3D425C]">
|
||||
<div className="p-6 w-[376px] h-[250px] flex flex-col bg-[url(/img/home-page/highlight.svg)] bg-no-repeat">
|
||||
<div className="p-6 w-[376px] h-[250px] flex flex-col bg-[url(/img/pages/home/stats/highlight.svg)] bg-no-repeat">
|
||||
<p className="m-text">
|
||||
Конверсия из консультации в бронирование <br /> увеличивается на
|
||||
</p>
|
||||
@@ -57,7 +57,7 @@ export function Statistics() {
|
||||
48%
|
||||
</p>
|
||||
<Image
|
||||
src={'/img/home-page/increasing.svg'}
|
||||
src={'/img/pages/home/stats/increasing.svg'}
|
||||
width="176"
|
||||
height="122"
|
||||
alt={''}
|
||||
@@ -68,7 +68,7 @@ export function Statistics() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6 flex flex-col w-[376px] h-[250px] bg-[url(/img/home-page/highlight.svg)] bg-no-repeat">
|
||||
<div className="p-6 flex flex-col w-[376px] h-[250px] bg-[url(/img/pages/home/stats/highlight.svg)] bg-no-repeat">
|
||||
<p className="m-text">
|
||||
Конверсия из консультации в бронирование <br /> увеличивается на
|
||||
</p>
|
||||
@@ -86,7 +86,7 @@ export function Statistics() {
|
||||
42%
|
||||
</p>
|
||||
<Image
|
||||
src={'/img/home-page/increasing.svg'}
|
||||
src={'/img/pages/home/stats/increasing.svg'}
|
||||
width="176"
|
||||
height="122"
|
||||
alt={''}
|
||||
@@ -98,20 +98,20 @@ export function Statistics() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col p-6 w-[376px] h-[250px] bg-[url(/img/home-page/highlight.svg)] bg-no-repeat overflow-hidden">
|
||||
<div className="flex flex-col p-6 w-[376px] h-[250px] bg-[url(/img/pages/home/stats/highlight.svg)] bg-no-repeat overflow-hidden">
|
||||
<p className="m-text">
|
||||
Время реализации проекта <br /> сокращается до
|
||||
</p>
|
||||
<div className="relative flex h-full justify-end">
|
||||
<Image
|
||||
src={'/img/home-page/building.png'}
|
||||
src={'/img/pages/home/stats/building.png'}
|
||||
width={85}
|
||||
height={238}
|
||||
alt={''}
|
||||
className="absolute left-[23px] top-4"
|
||||
/>
|
||||
<Image
|
||||
src={'/img/home-page/building.png'}
|
||||
src={'/img/pages/home/stats/building.png'}
|
||||
width={85}
|
||||
height={238}
|
||||
className="absolute left-[79px] top-[77px]"
|
||||
@@ -122,12 +122,12 @@ export function Statistics() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-between p-6 w-[376px] h-[250px] relative bg-[url(/img/home-page/highlight.svg)] bg-no-repeat overflow-hidden">
|
||||
<div className="flex flex-col justify-between p-6 w-[376px] h-[250px] relative bg-[url(/img/pages/home/stats/highlight.svg)] bg-no-repeat overflow-hidden">
|
||||
<p className="m-text">
|
||||
Время на подготовку рекламных <br /> материалов сокращается до
|
||||
</p>
|
||||
<Image
|
||||
src={'/img/home-page/adv.png'}
|
||||
src={'/img/pages/home/stats/adv.png'}
|
||||
width={263}
|
||||
height={223}
|
||||
alt={''}
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { TagFilterItem } from '@/components/TagFilterItem';
|
||||
import { YearFilterDropdown } from '@/components/YearFilterDropdown';
|
||||
import { YearFilterItem } from '@/components/YearFilterItem';
|
||||
import { ProjectTags } from '@/consts/ProjectTags';
|
||||
import { ProjectYears } from '@/consts/ProjectYears';
|
||||
import { Vertical } from '@/ui/Vertical';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { TagFilterItem } from '../TagFilterItem';
|
||||
import { YearFilterDropdown } from '../YearFilterDropdown';
|
||||
import { YearFilterItem } from '../YearFilterItem';
|
||||
|
||||
export function ProjectsFilters() {
|
||||
const params = useSearchParams();
|
||||
@@ -3,30 +3,34 @@ import { IPost } from '@/types/IPost';
|
||||
export const Posts: IPost[] = [
|
||||
{
|
||||
id: '1',
|
||||
image: '/post1/cover.jpg',
|
||||
image: '/img/pages/blog/post1/cover.jpg',
|
||||
title:
|
||||
'Graff interactive забрал 2 места в «Битве стартапов-победителей Build UP 2023»',
|
||||
desc: 'Решения SIPUNI, GRAFF interactive и ГК «СТЕНА» стали победителями нашей «Битвы стартапов-победителей Build UP 2023»',
|
||||
tags: ['награды', 'недвижимость', 'новое'],
|
||||
mainImage: '/post1/main.jpg',
|
||||
mainImage: '/img/pages/blog/post1/main.jpg',
|
||||
createdAt: '12 ФЕВРАЛЯ 2024',
|
||||
extraDesc:
|
||||
'Среди девелоперов, представители которых приняли участие в выборе победителей эфира: Группа «Самолет», ГК «А101», Холдинг Setl Group, ГК ТОЧНО, ДОНСТРОЙ, Федеральный девелопер «Неометрия», «Ак Барс Дом», PIONEER, ГК «Первый Трест» и Capital Group.',
|
||||
video: '/post1/video.jpg',
|
||||
slides: ['/post1/slides/1.jpg', '/post1/slides/2.jpg', '/post1/video.jpg'],
|
||||
video: '/img/pages/blog/post1/video.jpg',
|
||||
slides: [
|
||||
'/img/pages/blog/post1/slides/1.jpg',
|
||||
'/img/pages/blog/post1/slides/2.jpg',
|
||||
'/img/pages/blog/post1/video.jpg',
|
||||
],
|
||||
review: {
|
||||
author: {
|
||||
name: 'Егор Бобров',
|
||||
position: 'Коммерческий директор авторского квартала «Машаров»',
|
||||
avatar: '/post1/avatar.jpg',
|
||||
avatar: '/img/pages/blog/post1/avatar.jpg',
|
||||
},
|
||||
text: 'Конверсия из показа в сделку выросла в 1,5 раза. Эффективность инструмента была подтверждена буквально в первый день после его внедрения. Например, один из клиентов, посетив офис и увидев свою будущую квартиру с помощью интерактивной панели, сразу решил купить недвижимость в этом проекте, отказавшись от других вариантов.',
|
||||
},
|
||||
extraVideo: '/post1/extra_video.jpg',
|
||||
extraVideo: '/img/pages/blog/post1/extra_video.jpg',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
image: '/post2.jpg',
|
||||
image: '/img/pages/blog/post2/cover.jpg',
|
||||
title:
|
||||
'Graff interactive на международном фестивале маркетинга и креатива в недвижимости WOW FEST 2023',
|
||||
desc: 'В начале сентября приняли участие в международном фестивале маркетинга и креатива в недвижимости WOW FEST 2023. В рамках программы фестиваля мы познакомили участников и гостей форума с нашим интерактивным инструментом продаж.',
|
||||
@@ -35,7 +39,7 @@ export const Posts: IPost[] = [
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
image: '/post3.jpg',
|
||||
image: '/img/pages/blog/post3/cover.jpg',
|
||||
title: 'Транспортное и специальное тренажеростроение — 2023',
|
||||
desc: '27 апреля 2023 года в Москве — состоялась XV Международная конференция «Транспортное и специальное тренажеростроение — 2023». Директор GRAFF interactive принял участие и выступил с докладом',
|
||||
tags: ['лекция', 'тренажеры'],
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import { ReactNode, useEffect, useRef } from 'react';
|
||||
|
||||
interface Props {
|
||||
element: ReactNode;
|
||||
className: string;
|
||||
}
|
||||
|
||||
export function ClassNameWrapper({ element, className }: Props) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!className.split(' ').length) return;
|
||||
|
||||
ref.current?.children
|
||||
.item(0)
|
||||
?.classList.add(...className.split(' ').filter(Boolean));
|
||||
}, [className]);
|
||||
|
||||
return <div ref={ref}>{element}</div>;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ArrowLeftIcon } from '@/components/icons/ArrowLeftIcon';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { useWindowWidth } from '@/hooks/useWindowWidth';
|
||||
import {
|
||||
ReactNode,
|
||||
@@ -160,7 +161,10 @@ export function InfinitySlider({
|
||||
/>
|
||||
</div>
|
||||
<button onClick={nextSlide} className="max-sm:hidden">
|
||||
<ArrowLeftIcon className="rotate-180" />
|
||||
<ClassNameWrapper
|
||||
className="rotate-180"
|
||||
element={<ArrowLeftIcon />}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ArrowLeftIcon } from '@/components/icons/ArrowLeftIcon';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
|
||||
export function SliderControls({
|
||||
slidesCount = 6,
|
||||
@@ -63,7 +64,7 @@ export function SliderControls({
|
||||
onClick={onRightClick}
|
||||
className="rounded-full p-5 border border-[#3D425C]"
|
||||
>
|
||||
<ArrowLeftIcon className="rotate-180" />
|
||||
<ClassNameWrapper className="rotate-180" element={<ArrowLeftIcon />} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useWindowWidth } from '@/hooks/useWindowWidth';
|
||||
import {
|
||||
Fragment,
|
||||
ReactElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -17,11 +18,13 @@ export function SliderWithScaling<T>({
|
||||
slides,
|
||||
slideElement,
|
||||
className = '',
|
||||
alignItems = 'start',
|
||||
title,
|
||||
}: {
|
||||
slides: T[];
|
||||
slideElement: (_: T & { current: boolean }) => ReactElement;
|
||||
className?: string;
|
||||
alignItems?: 'start' | 'center' | 'end';
|
||||
title: string;
|
||||
}) {
|
||||
const width = useWindowWidth();
|
||||
@@ -97,15 +100,17 @@ export function SliderWithScaling<T>({
|
||||
<div {...handlers}>
|
||||
<div
|
||||
ref={ref}
|
||||
className="flex items-start gap-x-4 -mr-6 relative select-none"
|
||||
className={`flex items-${alignItems} gap-x-4 -mr-6 relative select-none`}
|
||||
style={{
|
||||
transition: `${sliderOffset === 0 || sliderOffset === baseoffset * 2 ? 0 : 1}s`,
|
||||
transform: `translateX(${sliderOffset}px)`,
|
||||
}}
|
||||
>
|
||||
{order.map((slide, index) =>
|
||||
slideElement({ current: index === 1, ...slide }),
|
||||
)}
|
||||
{order.map((slide, index) => (
|
||||
<Fragment key={index}>
|
||||
{slideElement({ current: index === 1, ...slide })}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,23 +12,6 @@ const config: Config = {
|
||||
'gradient-conic':
|
||||
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
||||
},
|
||||
keyframes: {
|
||||
scaling: {
|
||||
'0%': {
|
||||
transition: 'all 1s ease',
|
||||
minHeight: '31.8vw',
|
||||
minWidth: '31.6vw',
|
||||
},
|
||||
'100%': {
|
||||
transition: 'all 1s ease',
|
||||
minHeight: '43.2vw',
|
||||
minWidth: '48vw',
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
scaling: 'scaling 1s ease-in-out both',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"@/*": ["./src/*"],
|
||||
"@/components/*": ["./src/components/*"],
|
||||
"@/hooks/*": ["./src/hooks/*"],
|
||||
"@/hocs/*": ["./src/hocs/*"],
|
||||
"@/stores/*": ["./src/stores/*"],
|
||||
"@/pages/*": ["./src/pages/*"],
|
||||
"@/utils/*": ["./src/utils/*"]
|
||||
|
||||