fixes, almost done slider, refactoring

This commit is contained in:
2024-08-07 20:02:24 +05:00
parent afecc27fd1
commit 242006434c
90 changed files with 292 additions and 233 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

+3 -1
View File
@@ -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 },
);
+4 -1
View File
@@ -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,
},
+2 -2
View File
@@ -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() {
+16 -11
View File
@@ -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-систему застройщика и получает актуальную информацию по ценам и статусам квартир.',
},
]}
+2 -2
View File
@@ -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() {
+21 -5
View File
@@ -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>
+21 -5
View File
@@ -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>
+2 -1
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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
+2 -7
View File
@@ -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 -4
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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">
-4
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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 -2
View File
@@ -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();
+12 -8
View File
@@ -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: ['лекция', 'тренажеры'],
+22
View File
@@ -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>;
}
+5 -1
View File
@@ -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>
)}
+2 -1
View File
@@ -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>
);
+9 -4
View File
@@ -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>
-17
View File
@@ -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: [],
+1
View File
@@ -21,6 +21,7 @@
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/hooks/*": ["./src/hooks/*"],
"@/hocs/*": ["./src/hocs/*"],
"@/stores/*": ["./src/stores/*"],
"@/pages/*": ["./src/pages/*"],
"@/utils/*": ["./src/utils/*"]