This commit is contained in:
2025-01-10 16:05:35 +05:00
parent 8075d0e6d1
commit 9bf6784713
31 changed files with 202 additions and 163 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 57 KiB

+2 -2
View File
@@ -63,13 +63,13 @@ export function ArticleActions({
<>
<button
onClick={handleEditArticle}
className="relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
className="relative p-2 transition-opacity bg-black rounded-full bg-opacity-60 hover:bg-opacity-70"
>
<EditIcon />
</button>
<button
onClick={handleDeleteArticle}
className="relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
className="relative p-2 transition-opacity bg-black rounded-full bg-opacity-60 hover:bg-opacity-70"
>
<DeleteIcon />
</button>
+3 -3
View File
@@ -17,18 +17,18 @@ export function DeleteItemModal({
const remove = useDeleteMutation(entity, id);
return (
<div className="bg-white shadow-lg text-black p-8 rounded-xl flex flex-col gap-4">
<div className="flex flex-col gap-4 p-8 text-black bg-white shadow-lg rounded-xl">
<div className="flex justify-between items-center border-b border-[#ccc] pb-4 gap-4">
<p className="text-xl">{title}</p>
<button
onClick={() => setModal(null, '')}
className="p-2 hover:bg-white hover:bg-opacity-10 transition-colors rounded-full"
className="p-2 transition-colors rounded-full hover:bg-white hover:bg-opacity-10"
>
<CloseIcon />
</button>
</div>
<Button onClick={remove} className="text-white self-end outline-none">
<Button onClick={remove} className="self-end text-white outline-none">
Удалить {entity === 'projects' ? 'проект' : 'компанию'}
</Button>
</div>
+3 -1
View File
@@ -39,7 +39,9 @@ export function FilterItem({
return (
<button
className={`flex gap-x-1 btn-text font-semibold rounded-3xl px-3 sm:py-3 py-2 border group ${chosen || (!chosen && count) ? 'text-white' : 'text-[#737AA1]'} ${
className={`flex gap-x-1 btn-text font-semibold rounded-3xl px-3 sm:py-3 py-2 border group ${
chosen || (!chosen && count) ? 'text-white' : 'text-[#737AA1]'
} ${
chosen
? 'bg-[#798FFF] border-[#798FFF]'
: 'border-[#3D425C] card-gradient-2'
+15 -10
View File
@@ -21,14 +21,19 @@ export function ItemActions({ item }: { item: IProject | ICompany }) {
const { setModal } = useModalStore();
function handleEdit() {
setModal(
isProject(item) ? (
<ProjectFormModal action="edit" defaultValues={item} />
) : (
<CompanyFormModal action="edit" defaultValues={item} />
),
`edit${isProject(item) ? 'Project' : 'Company'}`
);
if (isProject(item)) {
const { company, ...project } = item;
setModal(
<ProjectFormModal action="edit" defaultValues={project} />,
'editProject'
);
} else {
const { projects, ...company } = item;
setModal(
<CompanyFormModal action="edit" defaultValues={company} />,
'editCompany'
);
}
}
function handleDelete() {
@@ -48,13 +53,13 @@ export function ItemActions({ item }: { item: IProject | ICompany }) {
<div className="absolute top-0 right-0 p-4 hidden gap-2 z-[5] group-hover:flex">
<button
onClick={handleEdit}
className="relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
className="relative p-2 transition-opacity bg-black rounded-full bg-opacity-60 hover:bg-opacity-70"
>
<EditIcon />
</button>
<button
onClick={handleDelete}
className="relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
className="relative p-2 transition-opacity bg-black rounded-full bg-opacity-60 hover:bg-opacity-70"
>
<DeleteIcon />
</button>
+10 -10
View File
@@ -43,31 +43,31 @@ export function Header() {
className="max-lg:hidden"
/>
</Link>
<div className="m-auto relative flex-1 flex justify-center">
<div className="relative flex justify-center flex-1 m-auto">
<nav
className={`fixed lg:top-5 top-4 p-1 rounded-[20px] bg-[#37393B99] backdrop-blur-[20px] sm:flex grid${
className={`fixed lg:top-5 top-4 p-1 rounded-[20px] bg-[#37393B99] backdrop-blur-[20px] md:flex grid${
burgerOpened ? ' grid-rows-5' : ''
} gap-1 z-[12]`}
>
<Link
href={'/'}
className="aspect-square p-4 max-sm:hidden lg:hidden hover:bg-[#232425] rounded-xl"
className="aspect-square p-4 max-md:hidden lg:hidden hover:bg-[#232425] rounded-xl"
>
<ClassNameWrapper element={<LogoIcon />} className={'w-4 h-4'} />
</Link>
<HeaderLink
className="max-sm:hidden"
className="max-md:hidden"
href={'/products'}
text={'Продукты'}
/>
<HeaderLink
className="max-sm:hidden"
className="max-md:hidden"
href={'/about'}
text={'О нас'}
/>
<HeaderLink className="max-sm:hidden" href={'/blog'} text={'Блог'} />
<HeaderLink className="max-md:hidden" href={'/blog'} text={'Блог'} />
<HeaderLink
className="max-sm:hidden"
className="max-md:hidden"
href={'/projects'}
text={'Проекты'}
/>
@@ -79,12 +79,12 @@ export function Header() {
Оставить заявку
</Button>
<button
className="!border-none p-[18px] sm:hidden row-start-1 hover:bg-[#232425] rounded-2xl active:opacity-50"
className="!border-none p-[18px] md:hidden row-start-1 hover:bg-[#232425] rounded-2xl active:opacity-50"
onClick={() => setBurgerOpened((prev) => !prev)}
>
<ClassNameWrapper
element={burgerOpened ? <CloseIcon /> : <BurgerIcon />}
className="text-white w-4 h-4"
className="w-4 h-4 text-white"
/>
</button>
{data && data.auth && (
@@ -96,7 +96,7 @@ export function Header() {
</button>
)}
{burgerOpened && (
<div className="absolute space-y-1 w-full h-full row-start-2 grid p-1">
<div className="absolute grid w-full h-full row-start-2 p-1 space-y-1">
<HeaderLink
className="lg:hidden"
href={'/products'}
+8 -8
View File
@@ -70,14 +70,14 @@ export function ProjectFormModal<TAction extends 'create' | 'edit'>({
});
return (
<div className="text-black bg-white p-4 rounded-lg relative top-10 space-y-4">
<div className="relative p-4 space-y-4 text-black bg-white rounded-lg top-10">
<div className="flex justify-between items-center border-b border-[#ccc] pb-4 gap-4">
<p className="text-xl">
{action === 'create' ? 'Создание проекта' : 'Изменение проекта'}
</p>
<button
onClick={() => setModal(null, '')}
className="p-2 hover:bg-white hover:bg-opacity-10 transition-colors rounded-full"
className="p-2 transition-colors rounded-full hover:bg-white hover:bg-opacity-10"
>
<CloseIcon />
</button>
@@ -93,7 +93,7 @@ export function ProjectFormModal<TAction extends 'create' | 'edit'>({
required
autoFocus
type="text"
className="border border-neutral-500 outline-none px-3 py-2 rounded-lg"
className="px-3 py-2 border rounded-lg outline-none border-neutral-500"
placeholder="Название"
{...register('title', { required: true })}
id="name"
@@ -103,7 +103,7 @@ export function ProjectFormModal<TAction extends 'create' | 'edit'>({
<label htmlFor="city">Город</label>
<input
type="text"
className="border border-neutral-500 outline-none px-3 py-2 rounded-lg"
className="px-3 py-2 border rounded-lg outline-none border-neutral-500"
{...register('city', { required: true })}
id="city"
placeholder="Город"
@@ -119,13 +119,13 @@ export function ProjectFormModal<TAction extends 'create' | 'edit'>({
})}
defaultValue={defaultValues?.releaseDate.split('T')[0]}
id="releaseDate"
className="border border-neutral-500 outline-none px-3 py-2 rounded-lg"
className="px-3 py-2 border rounded-lg outline-none border-neutral-500"
/>
</div>
<div className="flex flex-col">
<label htmlFor="description">Описание</label>
<textarea
className="border border-neutral-500 outline-none px-3 py-2 rounded-lg"
className="px-3 py-2 border rounded-lg outline-none border-neutral-500"
placeholder="Описание"
{...register('description', { required: false })}
id="description"
@@ -136,7 +136,7 @@ export function ProjectFormModal<TAction extends 'create' | 'edit'>({
<select
{...register('stage', { valueAsNumber: true })}
id="stage"
className="border border-neutral-500 outline-none px-3 py-2 rounded-lg"
className="px-3 py-2 border rounded-lg outline-none border-neutral-500"
>
{Array.from({ length: 6 }, (_, i) => i + 1).map((stage) => (
<option key={stage} value={stage} label={stage.toString()} />
@@ -148,7 +148,7 @@ export function ProjectFormModal<TAction extends 'create' | 'edit'>({
<select
id="company"
{...register('companyId')}
className="border border-neutral-500 outline-none px-3 py-2 rounded-lg col-start-3 h-fit"
className="col-start-3 px-3 py-2 border rounded-lg outline-none border-neutral-500 h-fit"
>
<option value={undefined}>-</option>
{companies?.map((company) => (
+3 -3
View File
@@ -4,10 +4,10 @@ import Image from 'next/image';
export function InProcess() {
return (
<div className="grid xl:grid-cols-3 grid-rows-3 max-xl:grid-rows-4 border-b border-[#3D425C] xl:-mt-40 xl:bg-[url(/img/pages/about/desktop_ellipse.svg)] bg-no-repeat bg-cover h-[calc(100dvh-64px)]">
<h1 className="xl:text-8xl h1 items-center xl:col-span-2 xl:row-start-2 xl:row-span-2 content-end pb-10">
<div className="flex items-end flex-wrap">
<h1 className="items-center content-end pb-10 xl:text-8xl h1 xl:col-span-2 xl:row-start-2 xl:row-span-2">
<div className="flex flex-wrap items-end">
<span>Мы</span>
<div className="flex relative ml-4 -mr-6">
<div className="relative flex ml-4 -mr-6">
<Image
src={'/img/pages/about/Vanya.png'}
width={64}
+1 -1
View File
@@ -18,7 +18,7 @@ export function Awards() {
>
<Title className="absolute">Награды</Title>
<div
className="flex gap-x-3 gap-y-2 max-lg:flex-col transition-all duration-500 h-full w-full"
className="flex w-full h-full transition-all duration-500 gap-x-3 gap-y-2 max-lg:flex-col"
style={{
minHeight:
scroll > 400
@@ -151,7 +151,7 @@ export function Calculator() {
/>
</div>
<div className="space-y-10 lg:max-w-[1040px] w-full max-lg:order-1">
<div className="flex items-end h-80 w-full">
<div className="flex items-end w-full h-80">
<StatsColumn
color={'#D375FF'}
percents={100}
@@ -171,7 +171,7 @@ export function Calculator() {
title="Продано"
/>
</div>
<div className="max-lg:block hidden space-y-4 mt-4 w-full max-lg:order-2">
<div className="hidden w-full mt-4 space-y-4 max-lg:block max-lg:order-2">
<hr className="border-[#232425]" />
<div className="flex justify-between">
<div className="space-y-1">
@@ -198,7 +198,7 @@ export function Calculator() {
</div>
</div>
</div>
<div className="lg:flex hidden gap-x-3">
<div className="hidden lg:flex gap-x-3">
<div className="rounded-2xl bg-[linear-gradient(to_top,#7A7A7A40,#7A7A7A30)] p-7 w-1/2 relative overflow-hidden">
<div className="space-y-11">
<p className="font-medium text1">Срок реализации объекта</p>
@@ -25,7 +25,7 @@ export function ConsultationRange({
}
return (
<div className="lg:space-y-3 space-y-2 self-stretch">
<div className="self-stretch space-y-2 lg:space-y-3">
<p className="font-medium text-[#7A7A7A] btnl">Консультаций в месяц</p>
<div
className="px-7 py-9 bg-[#37393B99] rounded-2xl relative lg:w-[360px] flex"
@@ -35,7 +35,7 @@ export function ConsultationRange({
className="absolute left-0 top-0 rounded-2xl h-full bg-[#37393B99] backdrop-blur-2xl flex justify-between gap-x-3 items-center z-[2]"
ref={panRef}
>
<p className="font-medium select-none pl-4 btnl">{consultations}</p>
<p className="pl-4 font-medium select-none btnl">{consultations}</p>
<div
className="self-center select-none absolute [user-drag:none] cursor-grab active:cursor-move [:.grabbing_*_&]:!cursor-grabbing focus:cursor-move"
onMouseDown={() => false}
@@ -28,7 +28,7 @@ export function RegionSelector({
useOnClickOutside([dropdownRef, root], () => setOpened(false));
return (
<div className="lg:space-y-3 relative select-none max-lg:order-2">
<div className="relative select-none lg:space-y-3 max-lg:order-2">
<p className="font-medium text-[#7A7A7A] btnl max-lg:hidden">Регион</p>
<div
ref={root}
@@ -46,7 +46,7 @@ export function RegionSelector({
{(regionsData as Region[]).map((region, index) => (
<p
key={index}
className="font-medium px-8 py-6 hover:backdrop-blur-2xl rounded-xl flex justify-between items-center w-full"
className="flex items-center justify-between w-full px-8 py-6 font-medium hover:backdrop-blur-2xl rounded-xl"
onClick={() => {
onChosen(region);
setOpened(false);
@@ -10,8 +10,8 @@ export function StatsColumn({
color: string;
}) {
return (
<div className="space-y-1 w-1/3">
<div className="flex gap-1 items-center justify-center select-none">
<div className="w-1/3 space-y-1">
<div className="flex items-center justify-center gap-1 select-none">
<p className="font-medium accent">{value}</p>
<p className="rounded-2xl px-2 p-[7px] bg-[#37393B99] btns font-medium">
{percents}%
@@ -31,7 +31,7 @@ export function InteractivePresentation() {
text="Режим «Инфраструктура» знакомит пользователя с перспективной застройкой целого района. В зависимости от срока сдачи либо функциональной нагрузки того или иного блока можно ввести выделение цветом."
className="aspect-[460/560] w-[calc(460/1440*100vw)] max-w-[460px]"
>
<div className="grid grid-cols-2 grid-rows gap-1">
<div className="grid grid-cols-2 gap-1 grid-rows">
<NatureIcon />
<KidsIcon />
<MetroIcon />
@@ -119,25 +119,25 @@ export function InteractivePresentation() {
export function DoubleCard() {
return (
<div className="space-y-3 w-1/4">
<div className="w-1/4 space-y-3">
<CardContainer
title="Выбор квартиры на генплане"
className="aspect-[459/274] w-[calc(459/1440*100vw)] max-w-[459px]"
>
<div className="space-y-4">
<div className="flex gap-x-6 items-center">
<div className="flex items-center gap-x-6">
<EmotionalIcon />
<p className="font-medium">
Эмоциональне вовлечение пользователя в выбор квартиры
</p>
</div>
<div className="flex gap-x-6 items-center">
<div className="flex items-center gap-x-6">
<LocationIcon />
<p className="font-medium">
Удобство выбора расположения и видовых характеристик
</p>
</div>
<div className="flex gap-x-6 items-center"></div>
<div className="flex items-center gap-x-6"></div>
</div>
</CardContainer>
<CardContainer
@@ -181,11 +181,11 @@ export function CardContainer({
text ? '' : ' justify-between'
}`}
>
<p className="heading2 font-medium">{title}</p>
<p className="font-medium heading2">{title}</p>
<div className={!!text ? 'flex-1 content-center m-auto' : ''}>
{children}
</div>
{text && <p className="text1 font-medium">{text}</p>}
{text && <p className="font-medium text1">{text}</p>}
</div>
);
}
@@ -51,8 +51,8 @@ export function CityPoint({
top: y + '%',
}}
>
<p className="font-medium text2 w-full leading-4">{title}</p>
<div className="flex py-px relative">
<p className="w-full font-medium leading-4 text2">{title}</p>
<div className="relative flex py-px">
{companiesWithMapIcon
.slice(0, 3)
.map(({ mapIcon, title, id }, index) => (
@@ -50,11 +50,11 @@ export function ProjectsSlider({
}) => (
<div
key={id}
className="space-y-6 p-6 w-full h-full"
className="w-full h-full p-6 space-y-6"
style={{ width: ref.current?.clientWidth }}
>
<div className="space-y-1">
<p className="font-medium text-2xl">{name}</p>
<p className="text-2xl font-medium">{name}</p>
<div className="flex flex-wrap gap-x-1">
{company && (
<div className="rounded-[17px] border border-[#37393B] flex items-center gap-x-1 px-2 py-1.5">
+57 -49
View File
@@ -1,6 +1,7 @@
'use client';
import { useScroll } from '@/hooks/useScroll';
import { useWindowWidth } from '@/hooks/useWindowWidth';
import { Title } from '@/ui/Title';
import Image from 'next/image';
import { useEffect, useRef, useState } from 'react';
@@ -16,9 +17,11 @@ export function Motivation() {
setInitTopOffset(ref.current?.getBoundingClientRect().top ?? 0);
}, [ref]);
const width = useWindowWidth();
return (
<div className="lg:space-y-16 space-y-10">
<Title headerLevel={1} className="text-center">
<div className="space-y-10 lg:space-y-16">
<Title headerLevel={1} className="text-center md:max-lg:text-5xl">
Помогаем девелоперам продавать недвижимость проще и&nbsp;
<span className="relative">
<span className="text-[#37393B]">быстрее</span>
@@ -27,11 +30,11 @@ export function Motivation() {
дороже
</Title>
<div
className="grid lg:gap-3 gap-2 relative transition-all max-lg:grid-cols-2"
className="relative grid gap-2 transition-all md:gap-3 md:max-lg:grid-cols-2"
style={{
width: `calc((100vw - 40px) * ${
1 +
(initTopOffset - scroll > 200 && scroll !== 0
(width >= 1024 && initTopOffset - scroll > 400 && scroll !== 0
? scroll >= 150
? Math.min(
(0.33 * (initTopOffset - scroll - 200)) /
@@ -41,43 +44,49 @@ export function Motivation() {
: 0.33
: 0)
})`,
gridTemplate: `calc(226 / (412 + 979) * 100vw * ${
initTopOffset - scroll > 200 && scroll !== 0
? scroll >= 150
? Math.min(
1 +
((initTopOffset - scroll - 200) / (initTopOffset - 350)) *
(734 / 512 - 1),
734 / 512
)
: 734 / 512
: 1
}) calc(274 / (412 + 979) * 100vw * ${
initTopOffset - scroll > 200 && scroll !== 0
? scroll >= 150
? Math.min(
1 +
((initTopOffset - scroll - 200) / (initTopOffset - 350)) *
(734 / 512 - 1),
734 / 512
)
: 734 / 512
: 1
}) / calc(${
initTopOffset - scroll > 200 && scroll !== 0
? scroll >= 150
? Math.min(
979 +
((initTopOffset - scroll - 200) / (initTopOffset - 350)) *
(1400 - 979),
1400
)
: 1400
: 979
} / 1440 * 100vw) calc(412 / 1440 * 100vw)`,
gridTemplate:
width >= 1024
? `calc(226 / (412 + 979) * 100vw * ${
initTopOffset - scroll > 200 && scroll !== 0
? scroll >= 150
? Math.min(
1 +
((initTopOffset - scroll - 200) /
(initTopOffset - 350)) *
(734 / 512 - 1),
734 / 512
)
: 734 / 512
: 1
}) calc(274 / (412 + 979) * 100vw * ${
initTopOffset - scroll > 200 && scroll !== 0
? scroll >= 150
? Math.min(
1 +
((initTopOffset - scroll - 200) /
(initTopOffset - 350)) *
(734 / 512 - 1),
734 / 512
)
: 734 / 512
: 1
}) / calc(${
initTopOffset - scroll > 200 && scroll !== 0
? scroll >= 150
? Math.min(
979 +
((initTopOffset - scroll - 200) /
(initTopOffset - 350)) *
(1400 - 979),
1400
)
: 1400
: 979
} / 1440 * 100vw) calc(412 / 1440 * 100vw)`
: '1fr 1fr',
}}
>
<div className="lg:row-span-2 max-lg:col-span-2 relative max-lg:row-start-2 col-span-1">
<div className="relative col-span-1 lg:row-span-2 max-lg:col-span-2">
<video
ref={ref}
src="/videos/pages/home/showreel.mp4"
@@ -85,33 +94,32 @@ export function Motivation() {
loop
muted
playsInline
className="rounded-xl object-cover h-full w-full transition-all max-lg:aspect-[340/512]"
// ${scroll < 150 ? 'lg:aspect-[1400/734]' : 'lg:aspect-[979/512]'}`}
className="rounded-xl object-cover h-full w-full transition-all lg:aspect-[979/512] md:aspect-[736/441] aspect-[340/512] max-h-screen"
/>
</div>
<div className="lg:p-6 p-4 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] rounded-2xl relative col-span-1 row-span-1 transition-all max-lg:space-y-4">
<p className="font-medium heading2 lg:max-w-[50%] xl:max-w-[60%]">
<div className="md:p-6 p-4 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] rounded-2xl relative col-span-1 row-span-1 max-lg:space-y-4 md:max-lg:aspect-[362/226]">
<p className="font-medium heading2 md:max-w-[50%]">
Интеграция в&nbsp;офисы продаж
</p>
<div className="lg:absolute relative lg:w-[calc(168/412*100%)] lg:h-[calc(168/226*100%)] lg:bottom-6 lg:right-6">
<div className="md:absolute relative lg:w-[calc(168/412*100%)] md:h-[calc(168/226*100%)] md:w-[calc(168/362*100%)] md:bottom-6 md:right-6">
<Image
src="/img/pages/home/motivation/integration.png"
alt="integration"
fill
className="!relative object-cover rounded-full"
sizes=""
fill
/>
</div>
</div>
<div className="lg:p-6 p-4 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] rounded-2xl col-span-1 relative row-span-1 flex flex-col items-center justify-between overflow-hidden gap-y-7 transition-all">
<p className="font-medium heading2 self-stretch">
<div className="md:p-6 p-4 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] rounded-2xl col-span-1 relative row-span-1 flex flex-col items-center justify-between md:max-lg:aspect-[362/226] overflow-hidden">
<p className="self-stretch font-medium heading2">
Удаленная демонстрация
</p>
<div className="lg:relative absolute w-full h-full left-4 -bottom-1 flex items-end">
<div className="lg:relative absolute lg:w-[calc(282/412*100%)] lg:h-[calc(169/274*100%)] md:w-[calc(314/362*100%)] md:h-[calc(188/226*100%)] md:max-lg:-bottom-9 w-[calc(264/166*100%)] h-[calc(158/220*100%)] max-md:-bottom-0.5 max-md:left-4">
<Image
src="/img/pages/home/motivation/remote_demo.png"
alt="remote demo"
className="!relative object-cover max-w-[calc(282/412*100vw)] max-h-[calc(169/412*100vw)] object-left"
className="!relative object-cover object-left-top rounded-[4px]"
sizes=""
fill
/>
+1 -1
View File
@@ -18,7 +18,7 @@ export function Projects() {
return (
<div className="lg:space-y-16 space-y-10 lg:mt-40 mt-[100px]">
<div className="lg:flex space-y-10">
<div className="space-y-10 lg:flex">
<Title>
За 15 лет работы мы реализовали{' '}
<span className="text-gradient">
@@ -16,9 +16,9 @@ export function ReviewContent({
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1 }}
className="h-full flex justify-center items-center group relative"
className="relative flex items-center justify-center h-full"
>
<div className="lg:space-y-6 space-y-4 lg:max-w-[40%] absolute lg:left-6 lg:top-6 top-4 left-4 transition-opacity delay-500 opacity-0 group-hover:opacity-100 z-[5]">
<div className="lg:space-y-6 space-y-4 lg:max-w-[60%] absolute lg:left-6 lg:top-6 top-4 left-4 transition-opacity z-[5]">
<p className="max-w-[507px] text2 leading-[16.2px] opacity-80">
{author}
</p>
@@ -31,7 +31,7 @@ export function ReviewContent({
muted
autoPlay
playsInline
className="h-full w-full object-cover object-center absolute rounded-2xl"
className="absolute object-cover object-center w-full h-full rounded-2xl"
/>
<div className="transition-all delay-500 bg-gradient-to-r from-[rgba(20,22,31,0.6)] to-[rgba(20,22,31,0)] absolute h-full w-full rounded-2xl" />
</motion.div>
@@ -1,4 +1,5 @@
import { PlayIcon } from '@/components/icons/PlayIcon';
import { motion } from 'framer-motion';
import Image from 'next/image';
import { Dispatch, SetStateAction, useEffect, useRef } from 'react';
import { useHover } from 'usehooks-ts';
@@ -18,6 +19,7 @@ export function ReviewTab({
setCurrentHovered: Dispatch<SetStateAction<number | undefined>>;
index: number;
}) {
const titleRef = useRef<HTMLDivElement>(null);
const ref = useRef<HTMLButtonElement>(null);
const hovered = useHover(ref);
@@ -27,12 +29,12 @@ export function ReviewTab({
}, [hovered, index, setCurrentHovered]);
return (
<button
<motion.button
onClick={onClick}
className={
'items-stretch rounded-xl p-1 backdrop-blur-[34.2px] bg-[#37393B99] transition-opacity delay-500 group-hover:opacity-100 max-lg:opacity-100 opacity-0 flex' +
(active ? ' min-w-[280px]' : '')
}
className="flex items-stretch rounded-xl p-1 backdrop-blur-[34.2px] bg-[#37393B99] max-h-[104px] outline-none"
animate={{
width: active ? 283 : 104,
}}
ref={ref}
>
<Image
@@ -43,13 +45,19 @@ export function ReviewTab({
className="rounded-xl min-w-24 min-h-24"
/>
{active && (
<div className="flex flex-col justify-between p-2 flex-1">
<p className="text1 leading-[18.9px] text-left">{title}</p>
<motion.div
key={index}
ref={titleRef}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="flex flex-col justify-between flex-1 p-2"
>
<p className="self-stretch text-left text1">{title}</p>
<div className="self-end w-fit">
<PlayIcon />
</div>
</div>
</motion.div>
)}
</button>
</motion.button>
);
}
@@ -15,11 +15,15 @@ export function Reviews() {
const [currentHovered, setCurrentHovered] = useState<number>();
// useEffect(() => {
// console.log(currentHovered);
// }, [currentHovered]);
return (
<div className="max-lg:space-y-2">
<div
ref={ref}
className={`relative m-auto aspect-[340/557] lg:space-y-20 lg:aspect-[1040/540] lg:mt-[140px] mt-[100px] max-lg:flex max-lg:flex-col transition-all group duration-500`}
className={`relative m-auto aspect-[340/557] lg:space-y-20 lg:aspect-[1040/540] lg:mt-[140px] mt-[100px] max-lg:flex max-lg:flex-col transition-all group aduration-500`}
style={{
width:
scroll < 400
+8 -8
View File
@@ -20,8 +20,8 @@ export function Statistics() {
<span className="text-gradient"> эффективный продукт,</span> которым
пользуются уже {count !== undefined && getCompaniesCount(count)}
</Title>
<div className="grid lg:grid-cols-4 lg:grid-rows-2 gap-3 lg:aspect-[1400/462]">
<div className="p-6 flex flex-col justify-between lg:row-span-2 max-lg:aspect-[340/224] lg:col-span-2 max-lg:row-start-1 bg-[url(/img/pages/home/stats/building2.png),linear-gradient(to_bottom_right,#7A7A7A50,transparent)] bg-no-repeat bg-right-bottom bg-[length:65%,100%] rounded-lg">
<div className="grid xl:grid-cols-4 xl:grid-rows-2 md:grid-cols-2 md:grid-rows-4 gap-3 xl:aspect-[1400/462]">
<div className="p-6 flex flex-col justify-between md:row-span-2 max-xl:aspect-[340/224] md:col-span-2 bg-[url(/img/pages/home/stats/building2.png),linear-gradient(to_bottom_right,#7A7A7A50,transparent)] bg-no-repeat bg-right-bottom bg-[length:65%,100%] rounded-lg">
<p className="text1 font-medium lg:max-w-[35%] max-w-[70%]">
Время реализации проекта сокращается до
</p>
@@ -33,21 +33,21 @@ export function Statistics() {
<Figure
percent={12}
text="Конверсия из бронирования в продажу увеличивается на"
className="max-lg:aspect-[340/224]"
className="max-xl:aspect-[340/224] md:max-xl:col-start-1"
/>
<Figure
percent={18}
text="Конверсия из консультации в бронирование увеличивается на"
className="lg:col-start-3 max-lg:aspect-[340/224]"
className="xl:col-start-3 md:col-start-1 max-xl:aspect-[340/224]"
/>
<div className="lg:col-start-4 lg:row-start-1 max-lg:aspect-[340/224] bg-[linear-gradient(to_top_left,#7a7a7a50,transparent)] p-6 rounded-lg flex flex-col justify-between relative">
<p className="font-medium text1 lg:w-3/4">
<div className="xl:col-start-4 xl:row-start-1 md:col-start-2 md:row-start-3 max-xl:aspect-[340/224] bg-[linear-gradient(to_top_left,#7a7a7a50,transparent)] md:p-6 rounded-lg flex flex-col justify-between relative">
<p className="text1">
Время на подготовку рекламных материалов сокращается до
</p>
<p className="font-medium heading2">
<span className="line1">4</span> раз
</p>
<div className="absolute min-w-[calc(103/338*100%)] bottom-12 right-16">
<div className="absolute w-[calc(103/338*100%)] md:max-xl:w-[calc(103/380*100%)] md:bottom-12 md:right-16">
<Image
src="/img/pages/home/stats/Forum_Zoolog_09-03.png"
fill
@@ -56,7 +56,7 @@ export function Statistics() {
sizes=""
/>
</div>
<div className="absolute min-w-[calc(103/338*100%)] bottom-6 right-6">
<div className="absolute w-[calc(103/338*100%)] md:max-xl:w-[calc(103/380*100%)] md:bottom-6 md:right-6">
<Image
src="/img/pages/home/stats/Forum_Zoolog_09-03(2).png"
fill
+6 -6
View File
@@ -20,23 +20,23 @@ export function Streaming() {
});
return (
<div className="pt-16 lg:space-y-16 space-y-10">
<div className="pt-16 space-y-10 lg:space-y-16">
<Title>
Уникальная технология{' '}
<span className="text-gradient">удаленной демонстрации</span> дает
возможность презентовать объект покупателю из&nbsp;любой точки мира
</Title>
<div className="grid lg:grid-cols-4 gap-3">
<div className="grid gap-3 lg:grid-cols-4">
{data?.map((project) => (
<StreamingProject key={project.id} href="/" {...project} />
))}
<div className="border border-[#3D425C] rounded-2xl flex justify-center items-center p-6">
<div className="space-y-6 flex flex-col items-center">
<p className="text-center font-medium heading2">
<div className="flex flex-col items-center space-y-6">
<p className="font-medium text-center heading2">
Расскажем и покажем как это работает на&nbsp;созвоне
</p>
<Button
className="rounded-lg btnl px-6 py-4"
className="px-6 py-4 rounded-lg btnl"
onClick={() => setModal(<ModalWithFeedbackForm />, 'form')}
>
Оставить заявку
@@ -97,7 +97,7 @@ function StreamingProject({
href={href}
className="hidden group-hover:block absolute w-full h-full left-0 bottom-0 rounded-2xl font-medium bg-[radial-gradient(#000000CC,transparent)] backdrop-blur-[3px] content-center text-center"
>
<p className="flex gap-2 justify-center btnl">
<p className="flex justify-center gap-2 btnl">
Начать демонстрацию <ArrowMoreIcon />
</p>
</Link>
@@ -20,18 +20,18 @@ export function ProjectCard(project: IProject) {
whileInView={{ opacity: 1 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }}
className="group relative aspect-square p-4 flex items-end overflow-hidden rounded-2xl"
className="relative flex items-end p-4 overflow-hidden group aspect-square rounded-2xl"
>
<ItemActions item={project} />
<div
className="group-hover:scale-110 transition-transform duration-500 absolute top-0 left-0 w-full h-full bg-cover bg-center bg-no-repeat"
className="absolute top-0 left-0 w-full h-full transition-transform duration-500 bg-center bg-no-repeat bg-cover group-hover:scale-110"
style={{
backgroundImage: `url(${process.env.NEXT_PUBLIC_S3_BUCKET}${image})`,
}}
/>
<div className="absolute top-0 left-0 w-full h-full bg-gradient-card" />
<div className="relative flex flex-col gap-4">
<p className="heading1 font-medium">{title}</p>
<p className="font-medium heading1">{title}</p>
<div className="flex flex-wrap gap-2">
{company && (
<div className="px-2 py-1.5 font-medium rounded-2xl bg-[#37393B99] [backdrop-filter:blur(4px)] flex items-center gap-1 btns">
@@ -56,7 +56,7 @@ export function ProjectCard(project: IProject) {
))}
{stage! < 6 && (
<div className="bg-[#37393B99] px-3 py-2 rounded-full w-fit flex items-center gap-1 [backdrop-filter:blur(4px)]">
<p className="btns font-semibold">{stagePercentage}%</p>
<p className="font-semibold btns">{stagePercentage}%</p>
<ProgressPie value={stagePercentage} />
</div>
)}
@@ -46,7 +46,7 @@ export function ProjectsList({
{projects ? (
<ProjectsSection projects={projects} />
) : (
<p className="h3 text-center mt-7 font-medium">Проекты не найдены</p>
<p className="font-medium text-center h3 mt-7">Проекты не найдены</p>
)}
</div>
</div>
@@ -14,7 +14,7 @@ export function ProjectsPageHeader() {
});
return (
<div className="lg:space-y-10 space-y-5 relative">
<div className="relative space-y-5 lg:space-y-10">
<Title className="text-center" headerLevel={2}>
За 15 лет работы мы реализовали
<br />
+3 -3
View File
@@ -45,9 +45,9 @@ export function Figure({
className
}
>
<p className="text1 font-medium lg:w-2/3">{text}</p>
<p className="font-medium heading2">
<span className="line1 font-medium" ref={figureRef}>
<p className="text1">{text}</p>
<p className="font-medium accent">
<span className="font-medium line1" ref={figureRef}>
{percent}
</span>
%
+17 -11
View File
@@ -49,12 +49,12 @@ export function InfinitySlider({
setIsAnimating(true);
switch (action) {
case 'prev':
setSlide(slide => (slide === 0 ? slides.length - 1 : slide - 1));
setSliderOffset(prev => prev - baseOffset);
setSlide((slide) => (slide === 0 ? slides.length - 1 : slide - 1));
setSliderOffset((prev) => prev - baseOffset);
return [state[state.length - 5], ...state.slice(0, -1)];
case 'next':
setSlide(slide => (slide + 1) % slides.length);
setSliderOffset(prev => prev + baseOffset);
setSlide((slide) => (slide + 1) % slides.length);
setSliderOffset((prev) => prev + baseOffset);
return [...state.slice(1), state[4]];
default:
return state;
@@ -66,17 +66,17 @@ export function InfinitySlider({
...slides,
slides[0],
slides[1],
],
]
);
const nextSlide = useCallback(
() => !isAnimating && dispatch('next'),
[isAnimating],
[isAnimating]
);
const prevSlide = useCallback(
() => !isAnimating && dispatch('prev'),
[isAnimating],
[isAnimating]
);
const handlers = useSwipeable({
@@ -95,7 +95,7 @@ export function InfinitySlider({
return () =>
refValue?.removeEventListener('transitionend', () =>
setIsAnimating(false),
setIsAnimating(false)
);
}, [sliderOffset, order, slide]);
@@ -115,7 +115,11 @@ export function InfinitySlider({
className="flex items-stretch relative select-none"
style={{
columnGap: slidesGap,
transition: `${sliderOffset === -baseOffset || sliderOffset === -baseOffset * 3 ? 0 : 0.5}s`,
transition: `${
sliderOffset === -baseOffset || sliderOffset === -baseOffset * 3
? 0
: 0.5
}s`,
transform: `translateX(${sliderOffset}px)`,
}}
>
@@ -123,10 +127,12 @@ export function InfinitySlider({
<div
key={index}
style={{
minWidth: slideWidth,
width: slideWidth,
transform:
width >= 1024
? `translateX(${offset}${typeof offset === 'number' ? 'px' : ''})`
? `translateX(${offset}${
typeof offset === 'number' ? 'px' : ''
})`
: '',
}}
className={
+14 -8
View File
@@ -45,14 +45,14 @@ export function SliderWithScaling<T extends { title: string; id: number }>({
setTransiting(true);
switch (action) {
case 'prev':
setSlide(slide => (slide === 0 ? slides.length - 1 : slide - 1));
setSlide((slide) => (slide === 0 ? slides.length - 1 : slide - 1));
setSliderOffset(3 * baseoffset);
return [
{ ...state[state.length - 5], id: Math.random() },
...state.slice(0, -1),
];
case 'next':
setSlide(slide => (slide + 1) % slides.length);
setSlide((slide) => (slide + 1) % slides.length);
setSliderOffset(baseoffset);
return [...state.slice(1), { ...state[4], id: Math.random() }];
default:
@@ -65,7 +65,7 @@ export function SliderWithScaling<T extends { title: string; id: number }>({
...slides,
{ ...slides[0], id: Math.random() },
{ ...slides[1], id: Math.random() },
],
]
);
function nextSlide() {
@@ -102,7 +102,13 @@ export function SliderWithScaling<T extends { title: string; id: number }>({
style={{
minHeight: minHeightScaled,
transform: `translateX(${sliderOffset}px)`,
transitionDuration: `${sliderOffset !== baseoffset && sliderOffset !== 3 * baseoffset && sliderOffset !== 0 ? 1 : 0}s`,
transitionDuration: `${
sliderOffset !== baseoffset &&
sliderOffset !== 3 * baseoffset &&
sliderOffset !== 0
? 1
: 0
}s`,
}}
ref={sliderRef}
>
@@ -111,18 +117,18 @@ export function SliderWithScaling<T extends { title: string; id: number }>({
key={currentSlide.id}
initial={
index === 1
? { minWidth: minWidthScaled, minHeight: minHeightScaled }
: { minWidth, minHeight }
? { width: minWidthScaled, minHeight: minHeightScaled }
: { width: minWidth, minHeight }
}
transition={{ duration: 1, type: 'just' }}
animate={
index === 2
? {
minWidth: minWidthScaled,
width: minWidthScaled,
minHeight: minHeightScaled,
}
: {
minWidth,
width: minWidth,
minHeight,
}
}