main page + clients page fixes
This commit is contained in:
@@ -13,7 +13,7 @@ const ClientsPageCarousel = () => {
|
||||
const defaultOffset = isOddCount ? 300 : 0;
|
||||
|
||||
const { setModal } = useStore();
|
||||
const [letters, setLetters] = useState<Image[]>(thanksgivingLetters);
|
||||
const [letters] = useState<Image[]>(thanksgivingLetters);
|
||||
const [currentImage, setCurrentImage] = useState(middleLetter);
|
||||
const [offset, setOffset] = useState(IMAGE_WIDTH);
|
||||
|
||||
@@ -53,7 +53,7 @@ const ClientsPageCarousel = () => {
|
||||
<div className="py-24">
|
||||
<div className="flex h-[450px] w-[calc(100vw-20px)] overflow-hidden relative">
|
||||
<div
|
||||
className="flex transition-all duration-500 justify-center w-full "
|
||||
className="flex transition-all duration-500 justify-center w-full"
|
||||
style={{
|
||||
transform: `translateX(${offset - defaultOffset}px)`,
|
||||
}}
|
||||
@@ -77,7 +77,7 @@ const ClientsPageCarousel = () => {
|
||||
className="absolute left-1/4 top-1/3 bg-[#e8e8e8] w-10 h-10 rounded-full"
|
||||
onClick={handleOnLeftButtonClick}
|
||||
>
|
||||
<ArrowCarouselIcon isLeft className="w-3 h-4 m-auto" />{" "}
|
||||
<ArrowCarouselIcon isLeft className="w-[10px] h-4 m-auto" />{" "}
|
||||
</button>
|
||||
<button
|
||||
className="absolute right-1/4 top-1/3 bg-[#e8e8e8] w-10 h-10 rounded-full"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Image } from "../../types";
|
||||
import CrossIcon from "../../icons/CrossIcon";
|
||||
import useStore from "../../store/store";
|
||||
import ArrowCarouselIcon from "../../icons/ArrowCarouselIcon";
|
||||
import { useState } from "react";
|
||||
|
||||
type ZoomInLetterModalProps = {
|
||||
images: Image[];
|
||||
@@ -9,15 +13,29 @@ const ZoomInLetterModal = ({
|
||||
images,
|
||||
currentImage,
|
||||
}: ZoomInLetterModalProps) => {
|
||||
const { setModal } = useStore();
|
||||
const [selectedImage, setSelectedImage] = useState(currentImage);
|
||||
|
||||
const handleOnRightClick = () => {
|
||||
setSelectedImage((prev) => prev + 1);
|
||||
};
|
||||
|
||||
const handleOnLeftClick = () => {
|
||||
setSelectedImage((prev) => prev - 1);
|
||||
};
|
||||
|
||||
const handleOnCloseModal = () => {
|
||||
setModal(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed w-screen h-screen bg-[#fff] z-30 flex justify-center items-center"
|
||||
// onClick={handleOnCloseClick}
|
||||
>
|
||||
<div className="fixed w-screen h-screen bg-[#fff] z-30 flex justify-center items-center">
|
||||
<div
|
||||
className="flex"
|
||||
className="flex w-fit duration-300 transition-all"
|
||||
style={{
|
||||
transform: `translateX(calc(${-1 * currentImage}*000vw))`,
|
||||
transform: `translateX(calc(${
|
||||
Math.round(images.length / 2) - selectedImage
|
||||
}*100vw))`,
|
||||
}}
|
||||
>
|
||||
{images.map((image) => {
|
||||
@@ -33,6 +51,24 @@ const ZoomInLetterModal = ({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className="absolute top-2 right-2 z-30 cursor-pointer p-[10px]"
|
||||
onClick={handleOnCloseModal}
|
||||
>
|
||||
<CrossIcon color="#000" />
|
||||
</div>
|
||||
<div
|
||||
className="z-30 absolute top-1/2 right-2 p-[10px] cursor-pointer"
|
||||
onClick={handleOnRightClick}
|
||||
>
|
||||
<ArrowCarouselIcon className="stroke-black" />
|
||||
</div>
|
||||
<div
|
||||
className="z-30 absolute top-1/2 left-2 p-[10px] cursor-pointer"
|
||||
onClick={handleOnLeftClick}
|
||||
>
|
||||
<ArrowCarouselIcon isLeft />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import LogoIcon from "../../icons/LogoIcon";
|
||||
import SocialLinks from "./SocialLinks";
|
||||
import LanguageSwitcher from "./LanguageSwitcher";
|
||||
import Tabs from "../Tabs";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const Header = (): JSX.Element => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -14,8 +14,8 @@ const Question = ({ title, description }: QuestionProps) => {
|
||||
};
|
||||
return (
|
||||
<li
|
||||
className={`group cursor-pointer flex justify-between items-center text-2xl border-b flex-col select-none transition-[height] duration-500 overflow-hidden pb-7 ${
|
||||
isOpen ? "h-40" : "h-24"
|
||||
className={`group cursor-pointer flex justify-between items-center text-2xl border-b flex-col select-none transition-all duration-500 overflow-hidden ease-in-out pb-7 ${
|
||||
isOpen ? "max-h-96" : "max-h-24"
|
||||
}`}
|
||||
onClick={handleOnQuestionClick}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { createContext } from "react";
|
||||
|
||||
export const SliderContext = createContext(1);
|
||||
+32
-8
@@ -1,7 +1,9 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import FirstSlide from "./slides/FirstSlide";
|
||||
import SecondSlide from "./slides/SecondSlide";
|
||||
import ThirdSlide from "./slides/ThirdSlide";
|
||||
import { SliderContext } from "./Context";
|
||||
import SwiperPaginationBullets from "../../SwiperPaginationBullets";
|
||||
|
||||
const slides = [
|
||||
{ element: <FirstSlide />, id: 1 },
|
||||
@@ -10,7 +12,13 @@ const slides = [
|
||||
];
|
||||
|
||||
const MainPageSlider = () => {
|
||||
const [offset, setOffset] = useState(-0);
|
||||
const [offset, setOffset] = useState(0);
|
||||
const [currentSlide, setCurrentSlide] = useState(1);
|
||||
|
||||
useEffect(() => {
|
||||
const updatedSlide = -1 * offset + 1;
|
||||
setCurrentSlide(updatedSlide);
|
||||
}, [offset]);
|
||||
|
||||
const handleRightArrowClick = () => {
|
||||
setOffset((currentOffset) => {
|
||||
@@ -31,17 +39,27 @@ const MainPageSlider = () => {
|
||||
return currentOffset + 1;
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnSlideChange = (slide: number) => {
|
||||
const updatedOffset = (slide - 1) * -1;
|
||||
|
||||
setCurrentSlide(slide);
|
||||
setOffset(updatedOffset);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col select-none relative">
|
||||
<div className="flex h-[calc(100vh-150px)] justify-between w-[calc(100vw-20px)] px-2 pt-20">
|
||||
<div className="w-[calc(100vw-80px)] overflow-hidden">
|
||||
<div className="w-screen overflow-hidden bg-gradient-radial from-[#773272] via-[#1e1530] to-[#1e1530]">
|
||||
<div
|
||||
className="flex transition-[1.25s]"
|
||||
className="flex transition-[1.25s] "
|
||||
style={{ transform: `translateX(calc(${offset}*100vw))` }}
|
||||
>
|
||||
{slides.map((slide) => (
|
||||
<div key={slide.id}>{slide.element}</div>
|
||||
))}
|
||||
<SliderContext.Provider value={currentSlide}>
|
||||
{slides.map((slide) => (
|
||||
<div key={slide.id}>{slide.element}</div>
|
||||
))}
|
||||
</SliderContext.Provider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -56,6 +74,12 @@ const MainPageSlider = () => {
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
<SwiperPaginationBullets
|
||||
className="absolute bottom-2 left-[50%]"
|
||||
currentBullet={currentSlide}
|
||||
bulletCount={slides.length}
|
||||
handleOnBulletSwitch={handleOnSlideChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import { useEffect, useRef, useContext } from "react";
|
||||
import gsap from "gsap";
|
||||
import { SliderContext } from "../Context";
|
||||
|
||||
const FirstSlide = () => {
|
||||
const firstImageRef = useRef(null);
|
||||
const secondImageRef = useRef(null);
|
||||
const currentContext = useContext(SliderContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (!firstImageRef.current || !secondImageRef.current) return;
|
||||
|
||||
if (currentContext === 1) {
|
||||
gsap.fromTo(
|
||||
firstImageRef.current,
|
||||
{ transform: "scale(2.0)" },
|
||||
{
|
||||
transform: "scale(1.6)",
|
||||
duration: 1.5,
|
||||
scrollTrigger: {
|
||||
trigger: firstImageRef.current,
|
||||
start: "10% bottom",
|
||||
},
|
||||
}
|
||||
);
|
||||
gsap.fromTo(
|
||||
secondImageRef.current,
|
||||
{ transform: "scale(2.0)", left: "5%", top: "25%" },
|
||||
{
|
||||
transform: "scale(1.5)",
|
||||
left: "-0%",
|
||||
top: "30%",
|
||||
duration: 2.2,
|
||||
scrollTrigger: {
|
||||
trigger: firstImageRef.current,
|
||||
start: "10% bottom",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}, [currentContext]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center align-middle min-w-[100vw] max-w-[100vw]">
|
||||
<p className="font-bold text-8xl text-wrap text-white mx-auto leading-[110px]">
|
||||
Технологии расширенной
|
||||
<br /> реальности для вашего бизнеса
|
||||
</p>
|
||||
<img
|
||||
ref={firstImageRef}
|
||||
className="absolute top-[30%] scale-150 left-[6%]"
|
||||
src="/images/slides/first-slide-2.png"
|
||||
alt="image"
|
||||
/>
|
||||
<img
|
||||
ref={secondImageRef}
|
||||
className="absolute top-[30%] scale-150 left-[20%]"
|
||||
src="/images/slides/first-slide-1.png"
|
||||
alt="image"
|
||||
/>
|
||||
<p className="absolute text-white text-4xl top-[85%] left-[62%]">
|
||||
Мы приглашаем вас в мир
|
||||
<br /> удивительного будущего с<br /> технологиями виртуальной <br /> и
|
||||
смешанной реальности
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FirstSlide;
|
||||
+19
-8
@@ -1,16 +1,27 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect, useRef, useContext } from "react";
|
||||
import { gsap } from "gsap";
|
||||
import { SliderContext } from "../Context";
|
||||
|
||||
const SecondSlide = () => {
|
||||
const firstImageRef = useRef(null);
|
||||
const currentSlider = useContext(SliderContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (firstImageRef.current)
|
||||
gsap.to(firstImageRef.current, {
|
||||
left: "151%",
|
||||
top: "18%",
|
||||
duration: 1.5,
|
||||
});
|
||||
}, []);
|
||||
if (!firstImageRef.current) return;
|
||||
if (currentSlider === 2)
|
||||
gsap.fromTo(
|
||||
firstImageRef.current,
|
||||
{
|
||||
left: "167%",
|
||||
top: "2%",
|
||||
},
|
||||
{
|
||||
left: "151%",
|
||||
top: "18%",
|
||||
duration: 2.0,
|
||||
}
|
||||
);
|
||||
}, [currentSlider]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center align-middle min-w-[100vw] max-w-[100vw]">
|
||||
+16
-11
@@ -1,19 +1,24 @@
|
||||
import { useRef, useEffect } from "react";
|
||||
import { useRef, useEffect, useContext } from "react";
|
||||
import { gsap } from "gsap";
|
||||
import { SliderContext } from "../Context";
|
||||
|
||||
const ThirdSlide = () => {
|
||||
const currentSlider = useContext(SliderContext);
|
||||
|
||||
const firstImageRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (firstImageRef.current)
|
||||
gsap.fromTo(
|
||||
firstImageRef.current,
|
||||
{
|
||||
transform: "scale(1.15)",
|
||||
},
|
||||
{ transform: "scale(1)", duration: 1.5 }
|
||||
);
|
||||
}, []);
|
||||
if (!firstImageRef.current) return;
|
||||
|
||||
gsap.fromTo(
|
||||
firstImageRef.current,
|
||||
{
|
||||
transform: "scale(1.15)",
|
||||
},
|
||||
{ transform: "scale(1)", duration: 2 }
|
||||
);
|
||||
}, [currentSlider]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center align-middle min-w-[100vw] max-w-[100vw] relative">
|
||||
<p className="font-bold text-8xl text-wrap text-white w-[1500px] mx-auto leading-[87px]">
|
||||
@@ -27,7 +32,7 @@ const ThirdSlide = () => {
|
||||
/>
|
||||
<img
|
||||
ref={firstImageRef}
|
||||
className="absolute top-[-100%] left-[-18%]"
|
||||
className="absolute top-[-100%] left-[-14%]"
|
||||
src="/images/slides/third-slide-2.svg"
|
||||
alt="image"
|
||||
/>
|
||||
@@ -1,73 +0,0 @@
|
||||
import { useRef } from "react";
|
||||
|
||||
const FirstSlide = () => {
|
||||
const firstImageRef = useRef(null);
|
||||
const secondImageRef = useRef(null);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (firstImageRef.current) {
|
||||
// console.log("imageRef.current", firstImageRef.current);
|
||||
// gsap.fromTo(
|
||||
// firstImageRef.current,
|
||||
// { transform: "scale(2.0)" },
|
||||
// {
|
||||
// transform: "scale(1.6)",
|
||||
// duration: 1.5,
|
||||
// scrollTrigger: {
|
||||
// trigger: firstImageRef.current,
|
||||
// start: "10% bottom",
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
// gsap.fromTo(
|
||||
// secondImageRef.current,
|
||||
// { transform: "scale(2.0)", left: "5%" },
|
||||
// {
|
||||
// transform: "scale(1.6)",
|
||||
// left: "-5%",
|
||||
// duration: 2.2,
|
||||
// scrollTrigger: {
|
||||
// trigger: firstImageRef.current,
|
||||
// start: "10% bottom",
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
// }, []);
|
||||
return (
|
||||
<div className="flex flex-col justify-center align-middle min-w-[100vw] max-w-[100vw]">
|
||||
<p className="font-bold text-8xl text-wrap text-white mx-auto leading-[87px]">
|
||||
Технологии расширенной
|
||||
<br /> реальности для вашего бизнеса
|
||||
</p>
|
||||
|
||||
{/* <motion.div
|
||||
initial={{ scale: 1.2 }}
|
||||
whileInView={{ scale: 1 }}
|
||||
viewport={{ amount: "all" }}
|
||||
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98] }}
|
||||
className="flex flex-col gap-1"
|
||||
> */}
|
||||
<img
|
||||
ref={firstImageRef}
|
||||
className="absolute top-[40%]"
|
||||
src="/images/slides/first-slide-2.png"
|
||||
alt="image"
|
||||
/>
|
||||
{/* </motion.div> */}
|
||||
<img
|
||||
ref={secondImageRef}
|
||||
className="absolute top-[40%] scale-150 left-[10%]"
|
||||
src="/images/slides/first-slide-1.png"
|
||||
alt="image"
|
||||
/>
|
||||
<p className="absolute text-white text-4xl top-[85%] left-[57%]">
|
||||
Мы приглашаем вас в мир
|
||||
<br /> удивительного будущего с<br /> технологиями виртуальной <br /> и
|
||||
смешанной реальности
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FirstSlide;
|
||||
@@ -0,0 +1,37 @@
|
||||
type SwiperPaginationBulletsProps = {
|
||||
className?: string;
|
||||
currentBullet: number;
|
||||
bulletCount: number;
|
||||
handleOnBulletSwitch: (updatedBullet: number) => void;
|
||||
};
|
||||
|
||||
const SwiperPaginationBullets = ({
|
||||
className,
|
||||
currentBullet,
|
||||
bulletCount,
|
||||
handleOnBulletSwitch,
|
||||
}: SwiperPaginationBulletsProps) => {
|
||||
const bullets = Array.from({ length: bulletCount }, (_, index) => {
|
||||
return { id: index + 1 };
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={`${className ? className : ""} flex cursor-pointer`}>
|
||||
{bullets.map((bullet) => (
|
||||
<div
|
||||
className="p-1"
|
||||
key={bullet.id}
|
||||
onClick={() => handleOnBulletSwitch(bullet.id)}
|
||||
>
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
currentBullet === bullet.id ? "bg-white" : "opacity-20 bg-black"
|
||||
}`}
|
||||
></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SwiperPaginationBullets;
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useEffect } from "react";
|
||||
import Header from "./Header/Header";
|
||||
import Footer from "./Footer/Footer";
|
||||
import { Outlet } from "react-router-dom";
|
||||
@@ -6,6 +7,19 @@ import useStore from "../store/store";
|
||||
|
||||
const Wrapper = () => {
|
||||
const { modal } = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
const body = document.body;
|
||||
if (!body) return;
|
||||
|
||||
if (!modal) {
|
||||
body.style.overflow = "visible";
|
||||
return;
|
||||
}
|
||||
|
||||
body.style.overflow = "hidden";
|
||||
}, [modal]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{modal}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
type ArrowCarouselIconProps = {
|
||||
isLeft?: boolean;
|
||||
className?: string;
|
||||
color?: string;
|
||||
};
|
||||
|
||||
const ArrowCarouselIcon = ({ isLeft, className }: ArrowCarouselIconProps) => {
|
||||
const ArrowCarouselIcon = ({
|
||||
isLeft,
|
||||
className,
|
||||
color = "#000",
|
||||
}: ArrowCarouselIconProps) => {
|
||||
return (
|
||||
<svg
|
||||
className={`w-6 h-6 ${className ? className : ""} ${
|
||||
className={`w-6 h-6 stroke-black ${className ? className : ""} ${
|
||||
isLeft ? "rotate-180" : ""
|
||||
}`}
|
||||
role="presentation"
|
||||
@@ -16,7 +21,7 @@ const ArrowCarouselIcon = ({ isLeft, className }: ArrowCarouselIconProps) => {
|
||||
>
|
||||
<polyline
|
||||
fill="none"
|
||||
stroke="#000000"
|
||||
stroke={color}
|
||||
strokeLinecap="butt"
|
||||
strokeWidth="1"
|
||||
points="0.5,0.5 8.5,8.5 0.5,16.5"
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
const CrossIcon = () => {
|
||||
type CrossIconProps = {
|
||||
color?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const CrossIcon = ({ color, className }: CrossIconProps) => {
|
||||
return (
|
||||
<svg
|
||||
className={`${className ? className : ""}`}
|
||||
role="presentation"
|
||||
width="23px"
|
||||
height="23px"
|
||||
@@ -8,7 +14,12 @@ const CrossIcon = () => {
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g stroke="none" stroke-width="1" fill="#fff" fill-rule="evenodd">
|
||||
<g
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
fill={color ? color : "#fff"}
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<rect
|
||||
transform="translate(11.313708, 11.313708) rotate(-45.000000) translate(-11.313708, -11.313708) "
|
||||
x="10.3137085"
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
display: inline-block;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-weight: bold;
|
||||
height: 70px;
|
||||
width: 50px;
|
||||
padding: 10px 15px 10px 10px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
@@ -52,7 +54,7 @@
|
||||
-o-transform: rotate(-135deg);
|
||||
-webkit-transform: rotate(-135deg);
|
||||
transform: rotate(-135deg);
|
||||
right: 10px;
|
||||
right: 30px;
|
||||
top: 50%;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MainPageSlider from "../../components/MainPage/Slider";
|
||||
import MainPageSlider from "../../components/MainPage/Slider/Slider";
|
||||
import Services from "../../components/MainPage/Services";
|
||||
import LastProjects from "../../components/MainPage/LastProjects";
|
||||
import AboutUs from "../../components/MainPage/AboutUs";
|
||||
@@ -6,7 +6,7 @@ import Feedback from "../../components/MainPage/OftenQuestion";
|
||||
|
||||
const MainPage = () => {
|
||||
return (
|
||||
<div className="min-h-[calc(100vh-152px)]">
|
||||
<div className="min-h-[calc(100vh-152px)] overflow-hidden">
|
||||
<MainPageSlider />
|
||||
<Services />
|
||||
<LastProjects />
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
export default {
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
// extend: {animation: {
|
||||
// 'spin-slow': 'spin 3s linear infinite',
|
||||
// }},
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user