refactor: enhance localization strings and standardize component formatting across multiple files

This commit is contained in:
2025-07-11 16:12:53 +05:00
parent 3b7dd8cd01
commit c54272780f
8 changed files with 146 additions and 140 deletions
+4 -4
View File
@@ -13,9 +13,9 @@
"develope": "We help developers sell", "develope": "We help developers sell",
"easier": "real estate easier and ", "easier": "real estate easier and ",
"faster": "faster", "faster": "faster",
"cheaper": "cheaper", "expensive": "more expensive ",
"integration": "Integration in sales offices", "integration": "Integration in sales offices",
"remote_demo": "Remote demo" "remote_demo": "Remote demonstrations"
}, },
"integrations": { "integrations": {
"title": "Integration in sales offices", "title": "Integration in sales offices",
@@ -33,7 +33,7 @@
}, },
"interactive_presentation": { "interactive_presentation": {
"title": "Interactive presentation", "title": "Interactive presentation",
"experience": "enhances property selection", "experience": "enhances property selection experience",
"increase": "and boosts apartment sales in a residential complex" "increase": "and boosts apartment sales in a residential complex"
}, },
"search_and_select": { "search_and_select": {
@@ -50,7 +50,7 @@
"three_d_tour": { "three_d_tour": {
"title": "Virtual tour of a residential complex", "title": "Virtual tour of a residential complex",
"court": "Courtyard", "court": "Courtyard",
"mop": "CUA", "mop": "Common areas",
"flats": "Apartments", "flats": "Apartments",
"parking": "Parking", "parking": "Parking",
"office": "Commercial" "office": "Commercial"
+2 -2
View File
@@ -223,7 +223,7 @@ export function Header() {
)} )}
</AnimatePresence> </AnimatePresence>
</div> </div>
{pathname.startsWith("/projects") && ( {/* {pathname.startsWith("/projects") && (
<Link <Link
href={"https://dprofile.ru/graff.estate"} href={"https://dprofile.ru/graff.estate"}
className="max-xl:hidden rounded-[20px] bg-[#37393B99] backdrop-blur-[20px] hover:bg-[#232425] py-5 pl-[63px] pr-[33px] right-5 fixed z-[2] top-5 overflow-clip bg-[url(/img/components/header/dp.png)] bg-no-repeat bg-right-bottom" className="max-xl:hidden rounded-[20px] bg-[#37393B99] backdrop-blur-[20px] hover:bg-[#232425] py-5 pl-[63px] pr-[33px] right-5 fixed z-[2] top-5 overflow-clip bg-[url(/img/components/header/dp.png)] bg-no-repeat bg-right-bottom"
@@ -237,7 +237,7 @@ export function Header() {
/> />
<p className="btnm font-medium">{t("case")}</p> <p className="btnm font-medium">{t("case")}</p>
</Link> </Link>
)} )} */}
</header> </header>
); );
} }
+25 -25
View File
@@ -1,19 +1,19 @@
'use client'; "use client";
import { Icon } from '@/ui/Icon'; import { Icon } from "@/ui/Icon";
import { Title } from '@/ui/Title'; import { Title } from "@/ui/Title";
import { useTranslations } from 'next-intl'; import { useTranslations } from "next-intl";
import { Slider } from './Slider'; import { Slider } from "./Slider";
import { CityPoint } from './CityPoint'; import { CityPoint } from "./CityPoint";
import { enCities, enCitiesMobile } from '@/consts/cities'; import { enCities, enCitiesMobile } from "@/consts/cities";
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from "react";
import { useMediaQueries } from '@/hooks/useMediaQueries'; import { useMediaQueries } from "@/hooks/useMediaQueries";
import { useCityPointStore } from '@/stores/useCityPointStore'; import { useCityPointStore } from "@/stores/useCityPointStore";
import { useGetMapPointByCity } from '@/queries/getMapPointByCity'; import { useGetMapPointByCity } from "@/queries/getMapPointByCity";
import { enMapProject } from '@/consts/mockEnMapProject'; import { enMapProject } from "@/consts/mockEnMapProject";
function NewMap() { function NewMap() {
const t = useTranslations('map'); const t = useTranslations("map");
const [currentHovered, setCurrentHovered] = useState<number | undefined>(); const [currentHovered, setCurrentHovered] = useState<number | undefined>();
@@ -24,14 +24,14 @@ function NewMap() {
const { isLg } = useMediaQueries(); const { isLg } = useMediaQueries();
return ( return (
<div className='relative mt-[140px] flex flex-col lg:gap-16 max-lg:gap-2'> <div className="relative mt-[140px] flex flex-col lg:gap-16 max-lg:gap-2">
<Title> <Title>
Over 15 years of work, we have completed{' '} Over 15 years of work, we have completed{" "}
<span className='text-gradient'>49 projects for developers</span> in the <span className="text-gradient">49 projects for developers</span> in the
field of interactive technologies. field of interactive technologies
</Title> </Title>
<div className='max-lg:overflow-x-auto overflow-y-visible h-full scrollbar-hide md:max-lg:-mx-4 max-md:-mx-2.5 mt-16 relative'> <div className="max-lg:overflow-x-auto overflow-y-visible h-full scrollbar-hide md:max-lg:-mx-4 max-md:-mx-2.5 mt-16 relative">
<div className='bg-[url(/img/pages/home/stats/en_map1.png)] max-lg:w-[90vw] max-lg:h-[100vw] bg-no-repeat bg-contain w-[62.967vw] h-[50vw] relative lg:left-[23.194vw]'> <div className="bg-[url(/img/pages/home/stats/en_map1.png)] max-lg:w-[90vw] max-lg:h-[100vw] bg-no-repeat bg-contain w-[62.967vw] h-[50vw] relative lg:left-[23.194vw]">
{(isLg ? enCities : enCitiesMobile).map((point, index) => ( {(isLg ? enCities : enCitiesMobile).map((point, index) => (
<CityPoint <CityPoint
key={point.title} key={point.title}
@@ -56,15 +56,15 @@ function NewMap() {
} }
/> />
<div className='lg:hidden absolute left-[50vw] bottom-[4.444vw] translate-y-1/2 -translate-x-1/2 w-[68.611vw] aspect-[247/56] rounded-[4.444vw] bg-[#37393B99] px-[4.167vw] py-[4.444vw] flex gap-[2.222vw] justify-between items-center'> <div className="lg:hidden absolute left-[50vw] bottom-[4.444vw] translate-y-1/2 -translate-x-1/2 w-[68.611vw] aspect-[247/56] rounded-[4.444vw] bg-[#37393B99] px-[4.167vw] py-[4.444vw] flex gap-[2.222vw] justify-between items-center">
<div className='w-[6.667vw] h-[6.667vw]'> <div className="w-[6.667vw] h-[6.667vw]">
<Icon <Icon
name='finger_print' name="finger_print"
svgProp={{ className: 'w-[6.667vw] h-[6.667vw]' }} svgProp={{ className: "w-[6.667vw] h-[6.667vw]" }}
/> />
</div> </div>
<p className='caption leading-[120%] font-medium select-none'> <p className="caption leading-[120%] font-medium select-none">
{t('instruction')} {t("instruction")}
</p> </p>
</div> </div>
</div> </div>
+48 -47
View File
@@ -1,13 +1,13 @@
/* eslint-disable @next/next/no-img-element */ /* eslint-disable @next/next/no-img-element */
'use client'; "use client";
import { StoriesModal } from '@/components/modals/StoriesModal'; import { StoriesModal } from "@/components/modals/StoriesModal";
import { useModalStore } from '@/stores/useModalStore'; import { useModalStore } from "@/stores/useModalStore";
import { Title } from '@/ui/Title'; import { Title } from "@/ui/Title";
import { useInView } from 'framer-motion'; import { useInView } from "framer-motion";
import { useTranslations } from 'next-intl'; import { useTranslations } from "next-intl";
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from "react";
import { CircularProgressbar } from 'react-circular-progressbar'; import { CircularProgressbar } from "react-circular-progressbar";
export function Motivation() { export function Motivation() {
const ref = useRef<HTMLVideoElement>(null); const ref = useRef<HTMLVideoElement>(null);
@@ -21,66 +21,67 @@ export function Motivation() {
const timeUpdateHandler = () => const timeUpdateHandler = () =>
setProgress((video.currentTime / video.duration) * 100); setProgress((video.currentTime / video.duration) * 100);
videoRef.current.addEventListener('timeupdate', timeUpdateHandler); videoRef.current.addEventListener("timeupdate", timeUpdateHandler);
return () => video.removeEventListener('timeupdate', timeUpdateHandler); return () => video.removeEventListener("timeupdate", timeUpdateHandler);
}, []); }, []);
const isInView = useInView(ref, { const isInView = useInView(ref, {
margin: '100% 0px -85% 0px', margin: "100% 0px -95% 0px",
}); });
const { setModal } = useModalStore(); const { setModal } = useModalStore();
const t = useTranslations('motivation'); const t = useTranslations("motivation");
return ( return (
<div className='lg:space-y-[4.444vw] md:max-lg:space-y-[6.25vw] max-md:space-y-[11.111vw]'> <div className="lg:space-y-[4.444vw] md:max-lg:space-y-[6.25vw] max-md:space-y-[11.111vw]">
<Title <Title
headerLevel={1} headerLevel={1}
className='text-center min-[2560px]:max-w-2/3 min-[2560px]:mx-auto' className="text-center min-[2560px]:max-w-2/3 min-[2560px]:mx-auto"
> >
{t('develope')} {t("develope")}
<span className='max-lg:hidden'>&nbsp;</span> <span className="max-lg:hidden">&nbsp;</span>
<span className='lg:hidden'> </span> <span className="lg:hidden"> </span>
{t('easier')} {t("easier")}
<span className='relative'> <span className="relative">
<span className='text-[#37393B]'>{t('faster')}</span> <span className="text-[#37393B]">{t("faster")}</span>
<span className='absolute top-[55%] -left-[2.5%] 2xl:h-1.5 h-1 w-[105%] bg-white' /> <span className="absolute top-[55%] -left-[2.5%] 2xl:h-1.5 h-1 w-[105%] bg-white" />
</span>{' '} </span>
{t('cheaper')} <br />
{t("expensive")}
</Title> </Title>
<div className='grid lg:gap-[0.833vw] md:max-lg:gap-[1.563vw] gap-[2.222vw]'> <div className="grid lg:gap-[0.833vw] md:max-lg:gap-[1.563vw] gap-[2.222vw]">
<div <div
className={`col-start-1 lg:row-span-2 max-lg:col-span-2 duration-300 transition-all ${ className={`col-start-1 lg:row-span-2 max-lg:col-span-2 duration-300 transition-all ${
isInView isInView
? 'lg:w-[97.222vw] lg:h-[50.972vw]' ? "lg:w-[97.222vw] lg:h-[50.972vw]"
: 'lg:w-[67.986vw] lg:h-[35.556vw]' : "lg:w-[67.986vw] lg:h-[35.556vw]"
}`} }`}
> >
<video <video
ref={ref} ref={ref}
src='/videos/pages/home/showreel.mp4' src="/videos/pages/home/showreel.mp4"
poster='/img/pages/home/motivation/showreel_poster.jpg' poster="/img/pages/home/motivation/showreel_poster.jpg"
autoPlay autoPlay
loop loop
muted muted
playsInline playsInline
className='lg:rounded-[1.111vw] rounded-2xl h-full w-full object-cover' className="lg:rounded-[1.111vw] rounded-2xl h-full w-full object-cover"
/> />
</div> </div>
<button <button
// onClick={() => setModal(<StoriesModal />)} // onClick={() => setModal(<StoriesModal />)}
className='flex flex-col justify-between lg:w-[28.611vw] md:max-lg:w-[47.135vw] lg:h-[15.694vw] md:max-lg:h-[29.427vw] w-[46.111vw] h-[61.111vw] lg:p-[1.667vw] p-4 lg:col-start-2 lg:row-start-1 row-start-2 bg-[radial-gradient(ellipse_at_bottom_right,#7A7A7A50,transparent)] lg:rounded-[1.111vw] rounded-2xl relative outline-none' className="flex flex-col justify-between lg:w-[28.611vw] md:max-lg:w-[47.135vw] lg:h-[15.694vw] md:max-lg:h-[29.427vw] w-[46.111vw] h-[61.111vw] lg:p-[1.667vw] p-4 lg:col-start-2 lg:row-start-1 row-start-2 bg-[radial-gradient(ellipse_at_bottom_right,#7A7A7A50,transparent)] lg:rounded-[1.111vw] rounded-2xl relative outline-none"
> >
<p className='font-medium heading2 lg:max-w-[51%] md:max-lg:max-w-[19.271vw] self-start text-left'> <p className="font-medium heading2 lg:max-w-[51%] md:max-lg:max-w-[19.271vw] self-start text-left">
{t('integration')} {t("integration")}
</p> </p>
<div className='lg:w-[11.667vw] md:max-lg:w-[21.875vw] w-[37.222vw] aspect-square md:absolute relative lg:right-[1.667vw] lg:bottom-[0.903vw] md:max-lg:right-[3.125vw] md:max-lg:bottom-[1.693vw]'> <div className="lg:w-[11.667vw] md:max-lg:w-[21.875vw] w-[37.222vw] aspect-square md:absolute relative lg:right-[1.667vw] lg:bottom-[0.903vw] md:max-lg:right-[3.125vw] md:max-lg:bottom-[1.693vw]">
<video <video
ref={videoRef} ref={videoRef}
src='/videos/pages/home/story.mp4' src="/videos/pages/home/story.mp4"
poster='/img/pages/home/motivation/stories_poster.jpg' poster="/img/pages/home/motivation/stories_poster.jpg"
className='aspect-square object-cover w-full h-full rounded-full' className="aspect-square object-cover w-full h-full rounded-full"
loop loop
playsInline playsInline
autoPlay autoPlay
@@ -94,24 +95,24 @@ export function Motivation() {
? {} ? {}
: { : {
path: { path: {
stroke: 'white', stroke: "white",
strokeLinecap: 'round', strokeLinecap: "round",
transition: 'linear', transition: "linear",
transitionDuration: '0.3s', transitionDuration: "0.3s",
}, },
} }
} }
className='absolute top-0 text-white rounded-full' className="absolute top-0 text-white rounded-full"
/> />
</div> </div>
</button> </button>
<div className='relative lg:w-[28.611vw] lg:h-[19.028vw] md:max-lg:w-[47.135vw] md:max-lg:h-[29.427vw] overflow-hidden w-[46.111vw] h-[61.111vw] bg-[radial-gradient(ellipse_at_bottom_right,#7A7A7A50,transparent)] col-start-2 row-start-2 lg:p-[1.667vw] p-4 lg:rounded-[1.111vw] rounded-2xl flex flex-col lg:gap-[1.944vw] md:max-lg:gap-[3.125vw] gap-[3.333vw]'> <div className="relative lg:w-[28.611vw] lg:h-[19.028vw] md:max-lg:w-[47.135vw] md:max-lg:h-[29.427vw] overflow-hidden w-[46.111vw] h-[61.111vw] bg-[radial-gradient(ellipse_at_bottom_right,#7A7A7A50,transparent)] col-start-2 row-start-2 lg:p-[1.667vw] p-4 lg:rounded-[1.111vw] rounded-2xl flex flex-col lg:gap-[1.944vw] md:max-lg:gap-[3.125vw] gap-[3.333vw]">
<p className='heading2 font-medium'>{t('remote_demo')}</p> <p className="heading2 font-medium">{t("remote_demo")}</p>
<div className='relative lg:w-[19.583vw] md:max-lg:w-[40.885vw] lg:rounded-[0.556vw] rounded-lg w-[73.333vw] md:self-center max-md:-bottom-0.5'> <div className="relative lg:w-[19.583vw] md:max-lg:w-[40.885vw] lg:rounded-[0.556vw] rounded-lg w-[73.333vw] md:self-center max-md:-bottom-0.5">
<img <img
src='/img/pages/home/motivation/remote_demo.png' src="/img/pages/home/motivation/remote_demo.png"
alt='remote demo' alt="remote demo"
className='!relative lg:rounded-[0.556vw] rounded-lg object-[-1px_-1px] object-contain lg:w-[19.583vw] md:max-lg:w-[40.885vw] w-[73.333vw]' className="!relative lg:rounded-[0.556vw] rounded-lg object-[-1px_-1px] object-contain lg:w-[19.583vw] md:max-lg:w-[40.885vw] w-[73.333vw]"
/> />
</div> </div>
</div> </div>
+24 -24
View File
@@ -1,47 +1,47 @@
import { Title } from '@/ui/Title'; import { Title } from "@/ui/Title";
import Link from 'next/link'; import Link from "next/link";
import ArrowMoreIcon from '../../../../public/icons/arrow_more.svg'; import ArrowMoreIcon from "../../../../public/icons/arrow_more.svg";
import { VideoPlayer } from '@/ui/VideoPlayer'; import { VideoPlayer } from "@/ui/VideoPlayer";
function NewStreaming() { function NewStreaming() {
return ( return (
<div className='lg:mt-[140px] max-lg:mt-[100px] flex flex-col gap-16'> <div className="lg:mt-[140px] max-lg:mt-[100px] flex flex-col gap-16">
<Title> <Title>
Our unique <span className='text-gradient'>remote demonstration</span>{' '} Our unique <span className="text-gradient">remote demonstration</span>{" "}
technology allows presenting an object to a customer from anywhere in technology allows presenting an object to a customer from anywhere in
the world. the world
</Title> </Title>
<div className='flex gap-3 max-lg:flex-col'> <div className="flex gap-3 max-lg:flex-col">
<div className='px-4 pt-4 pb-4 w-[31.875vw] bg-[#232425] rounded-2xl flex flex-col gap-3 max-lg:w-full max-lg:max-h-[500px] max-lg:justify-between'> <div className="px-4 pt-4 pb-4 w-[31.875vw] bg-[#232425] rounded-2xl flex flex-col gap-3 max-lg:w-full max-lg:max-h-[500px] max-lg:justify-between">
<div className='flex flex-col gap-2'> <div className="flex flex-col gap-2">
<p className='heading1 font-medium'>«Upside Towers»</p> <p className="heading1 font-medium">«Upside Towers»</p>
<div className='flex gap-2'> <div className="flex gap-2">
<div className='px-2 py-1.5 flex lg:gap-[0.278vw] gap-1 items-center lg:rounded-[1.181vw] rounded-2xl [backdrop-filter:blur(12px)] bg-[#37393B99] btns'> <div className="px-2 py-1.5 flex lg:gap-[0.278vw] gap-1 items-center lg:rounded-[1.181vw] rounded-2xl [backdrop-filter:blur(12px)] bg-[#37393B99] btns">
<div className='lg:w-[0.556vw] lg:h-[0.556vw] w-2 h-2 rounded-full m-1 bg-[#90C141]' /> <div className="lg:w-[0.556vw] lg:h-[0.556vw] w-2 h-2 rounded-full m-1 bg-[#90C141]" />
<div>Upside Development</div> <div>Upside Development</div>
</div> </div>
<div className='px-3 py-1.5 flex lg:gap-[0.278vw] gap-1 items-center lg:rounded-[1.181vw] rounded-2xl [backdrop-filter:blur(12px)] bg-[#37393B99] btns'> <div className="px-3 py-1.5 flex lg:gap-[0.278vw] gap-1 items-center lg:rounded-[1.181vw] rounded-2xl [backdrop-filter:blur(12px)] bg-[#37393B99] btns">
Moscow Moscow
</div> </div>
</div> </div>
</div> </div>
<div className='bg-[url(/img/components/products/streaming-notebook.png)] bg-contain bg-center bg-no-repeat w-[28.542vw] h-[24.514vw] rounded-2xl max-lg:w-full max-lg:h-[300px]'></div> <div className="bg-[url(/img/components/products/streaming-notebook.png)] bg-contain bg-center bg-no-repeat w-[28.542vw] h-[24.514vw] rounded-2xl max-lg:w-full max-lg:h-[300px]"></div>
<Link <Link
href={ href={
'https://stream.graff.tech/?build=upsideTowersDev&location=a1&lang=en' "https://stream.graff.tech/?build=upsideTowersDev&location=a1&lang=en"
} }
target='_blank' target="_blank"
className='transition-opacity duration-500 w-[20.833vw] h-[4.167vw] bg-gradient self-center md:max-lg:rounded-2xl rounded-xl font-medium [backdrop-filter:blur(3px)] content-center text-center z-1 max-lg:w-[300px] max-lg:h-[60px]' className="transition-opacity duration-500 w-[20.833vw] h-[4.167vw] bg-gradient self-center md:max-lg:rounded-2xl rounded-xl font-medium [backdrop-filter:blur(3px)] content-center text-center z-1 max-lg:w-[300px] max-lg:h-[60px]"
> >
<p className='btnl flex justify-center gap-2'> <p className="btnl flex justify-center gap-2">
Start demonstration Start demonstration
<ArrowMoreIcon className='text-white w-[1.389vw] h-[1.389vw] max-lg:w-[20px] max-lg:h-[20px]' /> <ArrowMoreIcon className="text-white w-[1.389vw] h-[1.389vw] max-lg:w-[20px] max-lg:h-[20px]" />
</p> </p>
</Link> </Link>
</div> </div>
<div className='max-lg:h-[400px]'> <div className="max-lg:h-[400px]">
<VideoPlayer src={'/videos/pages/home/streaming.mp4'} showMutingBtn> <VideoPlayer src={"/videos/pages/home/streaming.mp4"} showMutingBtn>
<p className='accent font-medium absolute top-6 left-6 w-[39.861vw] max-lg:w-[90vw] max-lg:text-[20px] '> <p className="accent font-medium absolute top-6 left-6 w-[39.861vw] max-lg:w-[90vw] max-lg:text-[20px] ">
Graff.estate stream is available on any device all you need for Graff.estate stream is available on any device all you need for
a demo is an internet connection. a demo is an internet connection.
</p> </p>
+18 -16
View File
@@ -1,38 +1,40 @@
'use client'; "use client";
import { import {
queryProjectsOptions, queryProjectsOptions,
useGetProjectsQuery, useGetProjectsQuery,
} from '@/queries/getProjects'; } from "@/queries/getProjects";
import { Title } from '@/ui/Title'; import { Title } from "@/ui/Title";
import { getProjectsCount } from '@/utils/getProjectsCount'; import { getProjectsCount } from "@/utils/getProjectsCount";
import { ProjectsSection } from '../ProjectsPage/ProjectsSection'; import { ProjectsSection } from "../ProjectsPage/ProjectsSection";
import { queryOptions, useQuery } from '@tanstack/react-query'; import { queryOptions, useQuery } from "@tanstack/react-query";
import { useLocale, useTranslations } from 'next-intl'; import { useLocale, useTranslations } from "next-intl";
export function Projects() { export function Projects() {
// const { data: projects } = useGetProjectsQuery(); // const { data: projects } = useGetProjectsQuery();
const { data: projects } = useQuery(queryProjectsOptions); const { data: projects } = useQuery(queryProjectsOptions);
const t = useTranslations("projects"); const t = useTranslations("projects");
const locale = useLocale() const locale = useLocale();
return ( return (
<div className="lg:space-y-16 sm:space-y-12 space-y-10 lg:mt-40 mt-[100px]"> <div className="lg:space-y-16 sm:space-y-12 space-y-10 lg:mt-40 mt-[100px]">
<div className="lg:flex sm:space-y-12 space-y-10"> <div className="lg:flex sm:space-y-12 space-y-10">
<Title> <Title>
{t('title1')}{' '} {t("title1")}{" "}
<span className="text-gradient"> <span className="text-gradient">
{projects && getProjectsCount(projects?.length, locale)}{' '} {projects && getProjectsCount(projects?.length, locale)}{" "}
{t('title2')} {t("title2")}
</span>{' '} </span>{" "}
{t('title3')} {t("title3")}
</Title> </Title>
</div> </div>
{projects && ( {projects && (
<ProjectsSection <ProjectsSection
projects={projects projects={projects.filter(
.filter((project) => project.stage !== 6) (project) =>
.slice(0, 6)} project.englishCity === "Dubai" ||
project.englishCity === "Abu Dhabi"
)}
/> />
)} )}
</div> </div>
@@ -1,47 +1,50 @@
'use client'; "use client";
import { IProject } from '@/types/IProject'; import { IProject } from "@/types/IProject";
import { motion } from 'framer-motion'; import { motion } from "framer-motion";
import Link from 'next/link'; import Link from "next/link";
import { usePathname } from 'next/navigation'; import { usePathname } from "next/navigation";
import ArrowRightIcon from '../../../../public/icons/arrow_right.svg'; import ArrowRightIcon from "../../../../public/icons/arrow_right.svg";
import { AwardsCard } from './AwardsCard'; import { AwardsCard } from "./AwardsCard";
import { ProjectCard } from './ProjectCard'; import { ProjectCard } from "./ProjectCard";
import { useTranslations } from 'next-intl'; import { useTranslations } from "next-intl";
import { useEffect } from "react";
export function ProjectsSection({ projects }: { projects: IProject[] }) { export function ProjectsSection({ projects }: { projects: IProject[] }) {
const pathname = usePathname(); const pathname = usePathname();
const t = useTranslations("projects"); const t = useTranslations("projects");
useEffect(() => {
console.log(projects);
}, [projects]);
return ( return (
<div <div
className={`grid ${ className={`grid ${
pathname.startsWith('/projects') ? 'lg:grid-cols-3' : 'lg:grid-cols-4' pathname.startsWith("/projects") ? "lg:grid-cols-3" : "lg:grid-cols-4"
} md:max-lg:grid-cols-2 gap-3`} } md:max-lg:grid-cols-2 gap-3`}
> >
{projects.map((project) => ( {projects.map((project) => (
<ProjectCard key={project.id} {...project} /> <ProjectCard key={project.id} {...project} />
))} ))}
{pathname.startsWith('/projects') && ( {pathname.startsWith("/projects") && (
<AwardsCard className="sm:col-start-2 sm:row-start-2 row-start-3" /> <AwardsCard className="sm:col-start-2 sm:row-start-2 row-start-3" />
)} )}
<motion.div <motion.div
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }} whileInView={{ opacity: 1 }}
viewport={{ once: true, margin: '-100px' }} viewport={{ once: true, margin: "-100px" }}
transition={{ transition={{
duration: 1, duration: 1,
ease: [0.58, 0.12, 0.27, 0.98], ease: [0.58, 0.12, 0.27, 0.98],
delay: 0.2, delay: 0.2,
}} }}
> >
{pathname === '/' && ( {pathname === "/" && (
<Link <Link
href={'/projects'} href={"/projects"}
scroll={false} scroll={false}
className="lg:rounded-[1.111vw] rounded-2xl bg-[#232425] hover:bg-[#23242599] transition-colors aspect-square self-center p-5 flex items-center justify-center btnl font-medium gap-2" className="lg:rounded-[1.111vw] rounded-2xl bg-[#232425] hover:bg-[#23242599] transition-colors aspect-square self-center p-5 flex items-center justify-center btnl font-medium gap-2"
> >
{t('watch')} {t("watch")}
<ArrowRightIcon className="lg:w-[1.389vw] lg:h-[1.389vw] md:max-lg:w-[2.604vw] md:max-lg:h-[2.604vw] w-5 h-5 text-white" /> <ArrowRightIcon className="lg:w-[1.389vw] lg:h-[1.389vw] md:max-lg:w-[2.604vw] md:max-lg:h-[2.604vw] w-5 h-5 text-white" />
</Link> </Link>
)} )}
+6 -6
View File
@@ -1,15 +1,15 @@
export function getCompaniesCount(count: number, locale: string) { export function getCompaniesCount(count: number, locale: string) {
if (locale === 'en') { if (locale === "en") {
return `${count}\xa0developer${count === 1 ? '' : 's'}`; return `${count}\xa0real estate developer${count === 1 ? "" : "s"}`;
} }
return `${count}\xa0застройщик${ return `${count}\xa0застройщик${
count > 10 && count < 15 count > 10 && count < 15
? 'ов' ? "ов"
: count % 10 === 1 : count % 10 === 1
? '' ? ""
: count % 10 === 2 || count % 10 === 3 || count % 10 === 4 : count % 10 === 2 || count % 10 === 3 || count % 10 === 4
? 'а' ? "а"
: 'ов' : "ов"
}`; }`;
} }