upd
This commit is contained in:
+9
-31
@@ -56,38 +56,16 @@ export default function RootLayout({
|
||||
</LenisProvider>
|
||||
</QueryProvider>
|
||||
<Script id="metrika-counter" strategy="afterInteractive">
|
||||
{`(function (m, e, t, r, i, k, a) {
|
||||
m[i] =
|
||||
m[i] ||
|
||||
function () {
|
||||
(m[i].a = m[i].a || []).push(arguments);
|
||||
};
|
||||
m[i].l = 1 * new Date();
|
||||
for (var j = 0; j < document.scripts.length; j++) {
|
||||
if (document.scripts[j].src === r) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
(k = e.createElement(t)),
|
||||
(a = e.getElementsByTagName(t)[0]),
|
||||
(k.async = 1),
|
||||
(k.src = r),
|
||||
a.parentNode.insertBefore(k, a);
|
||||
})(
|
||||
window,
|
||||
document,
|
||||
'script',
|
||||
'https://mc.yandex.ru/metrika/tag.js',
|
||||
'ym',
|
||||
);
|
||||
|
||||
ym(98587267, 'init', {
|
||||
clickmap: true,
|
||||
trackLinks: true,
|
||||
accurateTrackBounce: true,
|
||||
webvisor: true,
|
||||
});`}
|
||||
{` (function(m,e,t,r,i,k,a){
|
||||
m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||
m[i].l=1*new Date();
|
||||
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
||||
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)
|
||||
})(window, document,'script','https://mc.yandex.ru/metrika/tag.js?id=105144448', 'ym');
|
||||
|
||||
ym(105144448, 'init', {ssr:true, webvisor:true, clickmap:true, ecommerce:"dataLayer", accurateTrackBounce:true, trackLinks:true});`}
|
||||
</Script>
|
||||
<noscript><div><img src="https://mc.yandex.ru/watch/105144448" style={{position:"absolute", left: "-9999px"}} alt="" /></div></noscript>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { GradientButton } from "@/ui/GradientButton";
|
||||
import { Title } from "@/ui/Title";
|
||||
import { getCompaniesCount } from "@/utils/getCompaniesCount";
|
||||
import { shuffle } from "@/utils/shuffle";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { GridContextProvider, GridDropZone, swap } from "react-grid-dnd";
|
||||
import AddIcon from "@/components/icons/AddIcon";
|
||||
import RestartIcon from "@/components/icons/RestartIcon";
|
||||
@@ -26,32 +26,36 @@ export function Clients() {
|
||||
|
||||
const [shuffled, setShuffled] = useState<ICompany[]>([]);
|
||||
|
||||
const excludeCompanies = [
|
||||
"Рисан",
|
||||
"Efes",
|
||||
"ЭНКО",
|
||||
"КамаСтройИнвест",
|
||||
"Брусника",
|
||||
"Маяк",
|
||||
"Мавис",
|
||||
"НКС",
|
||||
"Паритет",
|
||||
"Лето",
|
||||
"СБК",
|
||||
"Делом",
|
||||
"УГМК",
|
||||
"ГК Альфа",
|
||||
"Синара",
|
||||
"Кортрос",
|
||||
"Атмосфера",
|
||||
"Голос",
|
||||
"Сибинтел",
|
||||
"Основа",
|
||||
"Центр-Инвест",
|
||||
"DNS",
|
||||
"ПСК Дом девелопмент",
|
||||
"ПИК",
|
||||
];
|
||||
const excludeCompanies = useMemo(
|
||||
() => [
|
||||
"Рисан",
|
||||
"Efes",
|
||||
"ЭНКО",
|
||||
"КамаСтройИнвест",
|
||||
"Брусника",
|
||||
"Маяк",
|
||||
"Мавис",
|
||||
"НКС",
|
||||
"Паритет",
|
||||
"Лето",
|
||||
"СБК",
|
||||
"Делом",
|
||||
"УГМК",
|
||||
"ГК Альфа",
|
||||
"Синара",
|
||||
"Кортрос",
|
||||
"Атмосфера",
|
||||
"Голос",
|
||||
"Сибинтел",
|
||||
"Основа",
|
||||
"Центр-Инвест",
|
||||
"DNS",
|
||||
"ПСК Дом девелопмент",
|
||||
"ПИК",
|
||||
"ГК «Сумма элементов»",
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!companies) return;
|
||||
@@ -63,7 +67,7 @@ export function Clients() {
|
||||
setEnCompanies(
|
||||
shuffled.filter((company) => !excludeCompanies.includes(company.title))
|
||||
);
|
||||
}, [shuffled]);
|
||||
}, [excludeCompanies, shuffled]);
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -108,7 +112,7 @@ export function Clients() {
|
||||
}`}
|
||||
ref={ref}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex justify-between items-center">
|
||||
<Title className="mx-auto">
|
||||
<span className="text-gradient">
|
||||
{count !== undefined && getCompaniesCount(count, locale)}
|
||||
@@ -117,7 +121,7 @@ export function Clients() {
|
||||
</Title>
|
||||
<OpenFormModalWrapper
|
||||
modal={<CompanyFormModal action="create" />}
|
||||
className="aspect-square flex flex-col items-center justify-center gap-3"
|
||||
className="aspect-square flex flex-col gap-3 justify-center items-center"
|
||||
>
|
||||
<GradientButton>
|
||||
<div className="text-white lg:size-[2.778vw] size-7">
|
||||
@@ -157,7 +161,7 @@ export function Clients() {
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className={`absolute flex z-[1] flex-col items-center justify-center gap-3 lg:w-[calc((100vw-120px)/11)] md:max-lg:w-[calc((100vw-64px)/5)] w-[calc((100vw-36px)/3)] aspect-square`}
|
||||
className={`z-[1] lg:w-[calc((100vw-120px)/11)] md:max-lg:w-[calc((100vw-64px)/5)] w-[calc((100vw-36px)/3)] aspect-square flex absolute flex-col gap-3 justify-center items-center`}
|
||||
style={{
|
||||
left:
|
||||
(enCompanies.length % (isLg ? 11 : isMd ? 5 : 3)) *
|
||||
|
||||
@@ -41,7 +41,7 @@ function NewStreaming() {
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="max-lg:h-[400px]">
|
||||
<div className="max-lg:h-[400px] flex-1">
|
||||
<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] ">
|
||||
Graff.estate stream is available on any device — all you need for
|
||||
|
||||
@@ -11,8 +11,8 @@ import { queryOptions, useQuery } from "@tanstack/react-query";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
|
||||
export function Projects() {
|
||||
// const { data: projects } = useGetProjectsQuery();
|
||||
const { data: projects } = useQuery(queryProjectsOptions);
|
||||
const { data: projects } = useGetProjectsQuery();
|
||||
// const { data: projects } = useQuery(queryProjectsOptions);
|
||||
const t = useTranslations("projects");
|
||||
const locale = useLocale();
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
'use client';
|
||||
"use client";
|
||||
|
||||
import { useGetProjectsQuery } from '@/queries/getProjects';
|
||||
import { Title } from '@/ui/Title';
|
||||
import { VideoPlayer } from '@/ui/VideoPlayer';
|
||||
import { motion } from 'framer-motion';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
import { useSwipeable } from 'react-swipeable';
|
||||
import { StreamingProject } from './StreamingProject';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useGetProjectsQuery } from "@/queries/getProjects";
|
||||
import { Title } from "@/ui/Title";
|
||||
import { VideoPlayer } from "@/ui/VideoPlayer";
|
||||
import { motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { useSwipeable } from "react-swipeable";
|
||||
import { StreamingProject } from "./StreamingProject";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function Streaming() {
|
||||
const { data: streamingProjects } = useGetProjectsQuery(
|
||||
'Удаленная демонстрация'
|
||||
"Удаленная демонстрация"
|
||||
);
|
||||
|
||||
const [isViewportEntered, setIsViewportEntered] = useState(false);
|
||||
@@ -41,28 +41,27 @@ export function Streaming() {
|
||||
touchEventOptions: { passive: false },
|
||||
});
|
||||
|
||||
const t = useTranslations('streaming');
|
||||
const t = useTranslations("streaming");
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
onViewportEnter={handleOnViewportFeatureEnter}
|
||||
viewport={{ margin: '-10% 0% 0% 0%', once: true }}
|
||||
viewport={{ margin: "-10% 0% 0% 0%", once: true }}
|
||||
className="lg:mt-[140px] mt-[100px] lg:space-y-[4.444vw] md:max-lg:space-y-[6.25vw] space-y-[11.111vw]"
|
||||
>
|
||||
<Title className="max-md:hidden select-none">
|
||||
{t('title1')}
|
||||
<span className="text-gradient"> {t('title2')}</span>{' '}
|
||||
{t('title3')}
|
||||
{t("title1")}
|
||||
<span className="text-gradient"> {t("title2")}</span> {t("title3")}
|
||||
</Title>
|
||||
<Title headerLevel={2} className="md:hidden text-center select-none">
|
||||
<span className="text-gradient">{t('title4')}</span>
|
||||
{t('title5')}
|
||||
<span className="text-gradient">{t("title4")}</span>
|
||||
{t("title5")}
|
||||
</Title>
|
||||
<div
|
||||
className="lg:grid md:max-lg:flex grid-cols-4 gap-3 px-5 md:-mx-5 md:max-lg:overflow-auto [scrollbar-width:none] relative max-md:aspect-[340/344] transform-3d items-stretch"
|
||||
className="lg:grid md:max-lg:flex grid-cols-3 gap-3 px-5 md:-mx-5 md:max-lg:overflow-auto [scrollbar-width:none] relative max-md:aspect-[340/344] transform-3d items-stretch"
|
||||
{...handlers}
|
||||
>
|
||||
{streamingProjects?.slice(0, 3).map((project, index, { length }) => (
|
||||
{/* {streamingProjects?.slice(0, 3).map((project, index, { length }) => (
|
||||
<StreamingProject
|
||||
key={project.id}
|
||||
{...project}
|
||||
@@ -71,39 +70,37 @@ export function Streaming() {
|
||||
count={length + 1}
|
||||
href="/"
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
))} */}
|
||||
{/* <div
|
||||
className={`bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF00] [background:linear-gradient(to_right,#FFFFFF14,#FFFFFF00)] p-0.5 lg:rounded-[1.111vw] rounded-2xl flex flex-1 justify-center duration-500 items-center md:max-lg:min-w-[300px] group max-md:absolute self-stretch max-md:h-full transition-transform select-none max-md:w-[calc(100%-40px)] max-md:bg-[#0F101199] max-md:[backdrop-filter:blur(40px)] ${
|
||||
streamingProjects &&
|
||||
(Math.min(streamingProjects!.length + 1, 4) - 1 === current
|
||||
? 'max-md:translate-z-10'
|
||||
: 'max-md:scale-85')
|
||||
? "max-md:translate-z-10"
|
||||
: "max-md:scale-85")
|
||||
} ${
|
||||
streamingProjects &&
|
||||
(Math.min(streamingProjects!.length + 1, 4) - 1 ===
|
||||
(current + 1) % Math.min(streamingProjects!.length + 1, 4)
|
||||
? 'max-md:translate-x-[calc(7.5%+20px)]'
|
||||
? "max-md:translate-x-[calc(7.5%+20px)]"
|
||||
: Math.min(streamingProjects!.length + 1, 4) - 1 ===
|
||||
(current - 1 + Math.min(streamingProjects!.length + 1, 4)) %
|
||||
Math.min(streamingProjects!.length + 1, 4)
|
||||
? 'max-md:translate-x-[calc(-7.5%-20px)]'
|
||||
: '')
|
||||
? "max-md:translate-x-[calc(-7.5%-20px)]"
|
||||
: "")
|
||||
}`}
|
||||
>
|
||||
<div className="md:bg-[#0F1011] h-full w-full lg:rounded-[1.111vw] rounded-2xl flex items-center p-6">
|
||||
<div className="flex flex-col items-center space-y-6">
|
||||
<p className="heading2 font-medium text-center">
|
||||
{t('info')}
|
||||
</p>
|
||||
<p className="heading2 font-medium text-center">{t("info")}</p>
|
||||
<Link
|
||||
href={'/form'}
|
||||
href={"/form"}
|
||||
className="btnm font-medium group-hover:scale-105 duration-500 lg:px-[1.667vw] lg:py-[1.181vw] px-6 py-[17px] transition-transform lg:rounded-[0.833vw] rounded-xl bg-gradient"
|
||||
>
|
||||
{t('leave_request')}
|
||||
{t("leave_request")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<VideoPlayer
|
||||
src="/videos/pages/home/streaming.mp4"
|
||||
@@ -111,10 +108,10 @@ export function Streaming() {
|
||||
loop
|
||||
autoPlay
|
||||
muted
|
||||
className="lg:apect-[1400/640] max-h-dvh md:max-lg:aspect-[736/480] aspect-[340/600]"
|
||||
className="lg:apect-[1400/640]a max-h-dvh md:max-lg:aspect-[736/480] aspect-[340/600] flex-1"
|
||||
>
|
||||
<p className="absolute font-medium md:bottom-6 md:left-6 bottom-4 left-4 lg:max-w-[40%] md:max-lg:max-w-[80%] accent">
|
||||
{t('demo_available')}
|
||||
{t("demo_available")}
|
||||
</p>
|
||||
</VideoPlayer>
|
||||
</motion.div>
|
||||
|
||||
@@ -125,7 +125,7 @@ export const enMapProjects: EnMapProject[] = [
|
||||
video: "/videos/pages/home/Риваят.mp4",
|
||||
},
|
||||
{
|
||||
logo: "/img/pages/home/Brusnika.png",
|
||||
logo: "/img/pages/home/brusnika.png",
|
||||
video: "/videos/pages/home/Izdanie.mp4",
|
||||
},
|
||||
];
|
||||
|
||||
+24
-23
@@ -1,34 +1,35 @@
|
||||
import { api } from '@/api';
|
||||
import { streaming } from '@/consts/streaming';
|
||||
import { IProject } from '@/types/IProject';
|
||||
import { queryOptions, useQuery } from '@tanstack/react-query';
|
||||
import { api } from "@/api";
|
||||
import { streaming } from "@/consts/streaming";
|
||||
import { IProject } from "@/types/IProject";
|
||||
import { queryOptions, useQuery } from "@tanstack/react-query";
|
||||
|
||||
export const queryProjectsOptions = queryOptions({
|
||||
queryKey: ['projects'],
|
||||
queryFn: () => api.get('projects').json<IProject[]>(),
|
||||
queryKey: ["projects"],
|
||||
queryFn: () => api.get("projects").json<IProject[]>(),
|
||||
select: (data) => data.filter((p) => "BARAHA TOWN" !== p.englishTitle),
|
||||
});
|
||||
|
||||
export function useGetProjectsQuery(tags?: string | string[]) {
|
||||
|
||||
return useQuery(
|
||||
tags && tags.length > 0
|
||||
? queryOptions({
|
||||
queryKey: ['projects', ...(Array.isArray(tags) ? tags : [tags])],
|
||||
queryFn: () =>
|
||||
api
|
||||
.get(
|
||||
`projects?${Array.isArray(tags)
|
||||
? tags.map((tag) => `tags=${tag}`).join('&')
|
||||
: 'tags=' + tags
|
||||
}`
|
||||
)
|
||||
.json<IProject[]>(),
|
||||
select:
|
||||
tags === 'Удаленная демонстрация'
|
||||
? (data) =>
|
||||
data.filter((p) => streaming.some((s) => s.title === p.title))
|
||||
: undefined,
|
||||
})
|
||||
queryKey: ["projects", ...(Array.isArray(tags) ? tags : [tags])],
|
||||
queryFn: () =>
|
||||
api
|
||||
.get(
|
||||
`projects?${
|
||||
Array.isArray(tags)
|
||||
? tags.map((tag) => `tags=${tag}`).join("&")
|
||||
: "tags=" + tags
|
||||
}`
|
||||
)
|
||||
.json<IProject[]>(),
|
||||
select:
|
||||
tags === "Удаленная демонстрация"
|
||||
? (data) =>
|
||||
data.filter((p) => streaming.some((s) => s.title === p.title))
|
||||
: (data) => data.filter((p) => "BARAHA TOWN" !== p.englishTitle),
|
||||
})
|
||||
: queryProjectsOptions
|
||||
);
|
||||
}
|
||||
|
||||
+14
-14
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
"use client";
|
||||
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import {
|
||||
ComponentProps,
|
||||
forwardRef,
|
||||
@@ -8,9 +8,9 @@ import {
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { VideoMutingBtn } from './VideoMutingBtn';
|
||||
import { VideoProgressBar } from './VideoProgressBar';
|
||||
} from "react";
|
||||
import { VideoMutingBtn } from "./VideoMutingBtn";
|
||||
import { VideoProgressBar } from "./VideoProgressBar";
|
||||
|
||||
export const VideoPlayer = forwardRef<
|
||||
HTMLVideoElement,
|
||||
@@ -18,7 +18,7 @@ export const VideoPlayer = forwardRef<
|
||||
src: string;
|
||||
showMutingBtn: boolean;
|
||||
children?: React.ReactNode;
|
||||
} & ComponentProps<'video'>
|
||||
} & ComponentProps<"video">
|
||||
>(
|
||||
(
|
||||
{ src, showMutingBtn, children, loop = true, autoPlay = true, className },
|
||||
@@ -48,7 +48,7 @@ export const VideoPlayer = forwardRef<
|
||||
function handlePlaybackClick() {
|
||||
if (!videoRef.current) return;
|
||||
setPlaying(videoRef.current.paused);
|
||||
videoRef.current[videoRef.current.paused ? 'play' : 'pause']();
|
||||
videoRef.current[videoRef.current.paused ? "play" : "pause"]();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -57,8 +57,8 @@ export const VideoPlayer = forwardRef<
|
||||
const timeUpdateHandler = () =>
|
||||
setProgress(((video.currentTime ?? 0) / (video.duration ?? 1)) * 100);
|
||||
|
||||
videoRef.current.addEventListener('timeupdate', timeUpdateHandler);
|
||||
return () => video.removeEventListener('timeupdate', timeUpdateHandler);
|
||||
videoRef.current.addEventListener("timeupdate", timeUpdateHandler);
|
||||
return () => video.removeEventListener("timeupdate", timeUpdateHandler);
|
||||
}, []);
|
||||
|
||||
const [isViewportEntered, setIsViewportEntered] = useState(false);
|
||||
@@ -71,19 +71,19 @@ export const VideoPlayer = forwardRef<
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
viewport={{ margin: '-10% 0% 0% 0%', once: true }}
|
||||
viewport={{ margin: "-10% 0% 0% 0%", once: true }}
|
||||
onViewportEnter={handleOnViewportFeatureEnter}
|
||||
className="relative h-full"
|
||||
className="relative w-full h-full"
|
||||
>
|
||||
<video
|
||||
ref={videoRef}
|
||||
src={isViewportEntered ? src : ''}
|
||||
src={isViewportEntered ? src : ""}
|
||||
autoPlay={autoPlay}
|
||||
muted={muted}
|
||||
loop={loop}
|
||||
playsInline
|
||||
className={`lg:rounded-[1.111vw] rounded-2xl w-full h-full object-cover${
|
||||
className ? ' ' + className : ''
|
||||
className ? " " + className : ""
|
||||
}`}
|
||||
/>
|
||||
{showMutingBtn && (
|
||||
@@ -117,4 +117,4 @@ export const VideoPlayer = forwardRef<
|
||||
}
|
||||
);
|
||||
|
||||
VideoPlayer.displayName = 'VideoPlayer';
|
||||
VideoPlayer.displayName = "VideoPlayer";
|
||||
|
||||
Reference in New Issue
Block a user