fixes slider
This commit is contained in:
@@ -2,7 +2,7 @@ import { clients } from '../consts/clients';
|
||||
|
||||
export function Clients() {
|
||||
return (
|
||||
<div className="mt-[100px] space-y-8">
|
||||
<div className="mt-[100px] space-y-8 select-none">
|
||||
<div className="flex items-center overflow-hidden w-screen mt-10 min-h-[117px]">
|
||||
<MarqueeHalf items={clients.slice(0, clients.length / 3)} />
|
||||
<MarqueeHalf items={clients.slice(0, clients.length / 3)} />
|
||||
|
||||
@@ -12,7 +12,7 @@ export function Form() {
|
||||
<div className="relative max-lg:flex items-center gap-x-[35px]">
|
||||
<FeedbackForm />
|
||||
<div className="max-sm:hidden absolute lg:bottom-0 lg:-right-[min(136px,calc(136/1600*100vw))] sm:-right-[min(196px,calc(196/768*100vw))] animate-[spin_10s_linear_infinite]">
|
||||
<div className="relative lg:w-[calc(512/1600*100vw)] sm:w-[calc(512/768*100vw)] aspect-square flex justify-center transition-all duration-500 lg:hover:w-[calc(446/1600*100vw)] origin-center">
|
||||
<div className="relative lg:w-[calc(512/1600*100vw)] sm:w-[calc(512/768*100vw)] aspect-square flex justify-center transition-all duration-500 lg::w-[calc(446/1600*100vw)] origin-center">
|
||||
<div className="lg:w-[calc(116/1600*100vw)] sm:w-[calc(116/768*100vw)] flex flex-col justify-between h-full absolute">
|
||||
<img src="/src/assets/form/1_1.png" alt="" />
|
||||
<img src="/src/assets/form/1_2.png" alt="" />
|
||||
|
||||
@@ -25,15 +25,11 @@ export function Header() {
|
||||
|
||||
return (
|
||||
<header className="lg:px-6 px-4 flex max-lg:justify-between items-center lg:h-16 h-12 border-b border-[#3D425C] bg-[#14161F]">
|
||||
<Link to={'/'}>
|
||||
<ClassNameWrapper
|
||||
element={<Logo />}
|
||||
className="h-8 lg:h-10 max-sm:hidden"
|
||||
/>
|
||||
<ClassNameWrapper
|
||||
element={<LogoWithoutText />}
|
||||
className="h-8 sm:hidden"
|
||||
/>
|
||||
<Link to={'/'} className="max-sm:hidden">
|
||||
<ClassNameWrapper element={<Logo />} className="h-8 lg:h-10" />
|
||||
</Link>
|
||||
<Link to={'/'} className="sm:hidden">
|
||||
<ClassNameWrapper element={<LogoWithoutText />} className="h-8" />
|
||||
</Link>
|
||||
<nav className="flex self-stretch mx-auto max-lg:hidden">
|
||||
{[
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion, useInView } from 'framer-motion';
|
||||
import { Title } from './ui/Title';
|
||||
import { promotionFeatures } from '../consts/promotionFeatures';
|
||||
import { useRef, useState } from 'react';
|
||||
import { useHover } from 'usehooks-ts';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { hashes } from '../consts/motivationHashes';
|
||||
import { ChevronUpIcon } from './icons/ChevronUpIcon';
|
||||
@@ -59,7 +58,10 @@ function DesktopFeature({
|
||||
|
||||
const width = useWindowWidth();
|
||||
|
||||
const hovered = useHover(ref);
|
||||
// const hovered = useHover(ref);
|
||||
const inView = useInView(ref, {
|
||||
margin: '0% 0% -67%',
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -71,7 +73,7 @@ function DesktopFeature({
|
||||
className="flex justify-between gap-x-4 [clip-path:polygon(0%_0%,100%_0%,100%_calc(100%+28px),0%_calc(100%+28px))]"
|
||||
transition={{ duration: 0.7 }}
|
||||
animate={
|
||||
hovered || hash.slice(1) === hashes.get(number)
|
||||
inView || hash.slice(1) === hashes.get(number)
|
||||
? { height: 0.265 * width }
|
||||
: { height: 0.0875 * width }
|
||||
}
|
||||
@@ -82,11 +84,11 @@ function DesktopFeature({
|
||||
<p className="text-[32px] leading-none mt-12 font-medium transition-all duration-700">
|
||||
{title}
|
||||
</p>
|
||||
{(hovered || hash.slice(1) === hashes.get(number)) && (
|
||||
{(inView || hash.slice(1) === hashes.get(number)) && (
|
||||
<motion.p
|
||||
className="font-medium h4 opacity-60"
|
||||
animate={
|
||||
hovered || hash.slice(1) === hashes.get(number)
|
||||
inView || hash.slice(1) === hashes.get(number)
|
||||
? { opacity: 0.6 }
|
||||
: { opacity: 0 }
|
||||
}
|
||||
@@ -102,7 +104,7 @@ function DesktopFeature({
|
||||
transition={{ duration: 1 }}
|
||||
animate={{
|
||||
translateX:
|
||||
hovered || hash.slice(1) === hashes.get(number)
|
||||
inView || hash.slice(1) === hashes.get(number)
|
||||
? (images.length - 1) * width * 0.15 + (images.length - 2) * 8
|
||||
: 0,
|
||||
}}
|
||||
@@ -117,7 +119,7 @@ function DesktopFeature({
|
||||
className="h-full "
|
||||
animate={{
|
||||
maxHeight:
|
||||
(hovered || hash.slice(1) === hashes.get(number)) &&
|
||||
(inView || hash.slice(1) === hashes.get(number)) &&
|
||||
index === 0
|
||||
? 0.265 * width
|
||||
: 0.0875 * width,
|
||||
|
||||
@@ -21,7 +21,7 @@ export function Stands() {
|
||||
<SliderWithScaling
|
||||
slides={stands}
|
||||
SlideElement={Stand}
|
||||
className="pb-20 space-y-8"
|
||||
className="pb-0 space-y-8 max-sm:pb-20"
|
||||
slideSizes={
|
||||
width >= 1024
|
||||
? ['31.6vw', '31.8vw', '48vw', '48vw']
|
||||
|
||||
@@ -1,74 +1,154 @@
|
||||
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
||||
import { ArrowLeftIcon } from '../icons/ArrowLeftIcon';
|
||||
import { ArrowRightIcon } from '../icons/ArrowRightIcon';
|
||||
|
||||
export function SliderControls({
|
||||
slidesCount = 6,
|
||||
height,
|
||||
width,
|
||||
slide = 0,
|
||||
onLeftClick,
|
||||
onRightClick,
|
||||
className,
|
||||
}: {
|
||||
slidesCount?: number;
|
||||
width: number;
|
||||
height: number;
|
||||
slide: number;
|
||||
onLeftClick: () => void;
|
||||
onRightClick: () => void;
|
||||
className?: string;
|
||||
}) {
|
||||
const length = 2 * Math.PI * (height / 2) + (width - height) * 2;
|
||||
export const SliderControls = forwardRef<
|
||||
{ left: () => void; right: () => void },
|
||||
{
|
||||
slidesCount: number;
|
||||
width: number;
|
||||
height: number;
|
||||
slide: number;
|
||||
onLeftClick: () => void;
|
||||
onRightClick: () => void;
|
||||
className?: string;
|
||||
}
|
||||
>(
|
||||
(
|
||||
{
|
||||
slidesCount,
|
||||
height,
|
||||
width,
|
||||
slide = 0,
|
||||
onLeftClick,
|
||||
onRightClick,
|
||||
className,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const length = 2 * Math.PI * (height / 2) + (width - height) * 2;
|
||||
|
||||
return (
|
||||
<div className={'flex items-center gap-2 ' + className}>
|
||||
<div className="relative flex justify-center max-sm:order-2">
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={`0 0 ${width} ${height}`}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="bg-[#14161F] rounded-full"
|
||||
const prevBtnRef = useRef<HTMLButtonElement>(null);
|
||||
const nextBtnRef = useRef<HTMLButtonElement>(null);
|
||||
const strokeRef = useRef<SVGRectElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
nextBtnRef.current?.click();
|
||||
}, 5000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [onRightClick]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
left: () => prevBtnRef.current?.click(),
|
||||
right: () => nextBtnRef.current?.click(),
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={'flex items-center gap-2 ' + className}>
|
||||
<div className="relative flex justify-center max-sm:order-2">
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={`0 0 ${width} ${height}`}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="bg-[#14161F] rounded-full"
|
||||
>
|
||||
<rect
|
||||
x="1"
|
||||
y="1"
|
||||
width={width - 2}
|
||||
height={height - 2}
|
||||
rx={(height - 2) / 2}
|
||||
stroke="#3D425C"
|
||||
strokeLinecap="butt"
|
||||
/>
|
||||
<rect
|
||||
className="transition-all duration-300"
|
||||
ref={strokeRef}
|
||||
x="1"
|
||||
y="1"
|
||||
width={width - 2}
|
||||
height={height - 2}
|
||||
rx={(height - 2) / 2}
|
||||
stroke="white"
|
||||
strokeLinecap="butt"
|
||||
strokeDasharray={`calc(${length}/${slidesCount}*${slide + 1}) ${length - (length / slidesCount) * (slide + 1)}`}
|
||||
strokeDashoffset={0}
|
||||
/>
|
||||
</svg>
|
||||
<p className="absolute self-center font-medium h4">
|
||||
{Math.round(slide) + 1} из {slidesCount}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
ref={prevBtnRef}
|
||||
onClick={() => {
|
||||
// if (slide === 0) {
|
||||
// let timeout: number | undefined;
|
||||
// strokeRef.current!.classList.remove(
|
||||
// 'transition-all',
|
||||
// 'duration-300',
|
||||
// );
|
||||
// strokeRef.current!.setAttribute(
|
||||
// 'stroke-dasharray',
|
||||
// `${length} 0`,
|
||||
// );
|
||||
// new Promise<void>(
|
||||
// res =>
|
||||
// (timeout = setTimeout(() => {
|
||||
// strokeRef.current!.classList.add(
|
||||
// 'transition-all',
|
||||
// 'duration-300',
|
||||
// );
|
||||
// res();
|
||||
// }, 1)),
|
||||
// ).then(() => {
|
||||
// onLeftClick();
|
||||
// clearTimeout(timeout);
|
||||
// });
|
||||
// } else {}
|
||||
onLeftClick();
|
||||
}}
|
||||
className="rounded-full sm:p-5 p-4 border border-[#3D425C] bg-[#14161F]"
|
||||
>
|
||||
<rect
|
||||
x="1"
|
||||
y="1"
|
||||
width={width - 2}
|
||||
height={height - 2}
|
||||
rx={(height - 2) / 2}
|
||||
stroke="#3D425C"
|
||||
strokeLinecap="butt"
|
||||
/>
|
||||
<rect
|
||||
className="transition-all duration-300"
|
||||
x="1"
|
||||
y="1"
|
||||
width={width - 2}
|
||||
height={height - 2}
|
||||
rx={(height - 2) / 2}
|
||||
stroke="white"
|
||||
strokeLinecap="butt"
|
||||
strokeDasharray={`calc(${length}/${slidesCount}*${slide + 1}) ${length - (length / slidesCount) * (slide + 1)}`}
|
||||
strokeDashoffset={`-${height / 2}`}
|
||||
/>
|
||||
</svg>
|
||||
<p className="h4 font-medium absolute self-center">
|
||||
{Math.round(slide) + 1} из {slidesCount}
|
||||
</p>
|
||||
<ArrowLeftIcon />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
// if (slide + 1 === slidesCount) {
|
||||
// let timeout: number | undefined;
|
||||
// strokeRef.current!.classList.remove(
|
||||
// 'transition-all',
|
||||
// 'duration-300',
|
||||
// );
|
||||
// strokeRef.current!.setAttribute(
|
||||
// 'stroke-dasharray',
|
||||
// `0 ${length}`,
|
||||
// );
|
||||
// new Promise<void>(res => {
|
||||
// timeout = setTimeout(() => {
|
||||
// strokeRef.current!.classList.add(
|
||||
// 'transition-all',
|
||||
// 'duration-300',
|
||||
// );
|
||||
// res();
|
||||
// }, 1);
|
||||
// }).then(() => {
|
||||
// onRightClick();
|
||||
// clearTimeout(timeout);
|
||||
// });
|
||||
// } else
|
||||
onRightClick();
|
||||
}}
|
||||
ref={nextBtnRef}
|
||||
className="rounded-full sm:p-5 p-4 border border-[#3D425C] bg-[#14161F] max-sm:order-2"
|
||||
>
|
||||
<ArrowRightIcon />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={onLeftClick}
|
||||
className="rounded-full sm:p-5 p-4 border border-[#3D425C] bg-[#14161F]"
|
||||
>
|
||||
<ArrowLeftIcon />
|
||||
</button>
|
||||
<button
|
||||
onClick={onRightClick}
|
||||
className="rounded-full sm:p-5 p-4 border border-[#3D425C] bg-[#14161F] max-sm:order-2"
|
||||
>
|
||||
<ArrowRightIcon />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -36,6 +36,10 @@ export function SliderWithScaling<T extends { img: string }>({
|
||||
|
||||
const sliderRef = useRef<HTMLDivElement>(null);
|
||||
const itemRef = useRef<HTMLDivElement>(null);
|
||||
const controlsRef = useRef<{ left: () => void; right: () => void }>({
|
||||
left: () => {},
|
||||
right: () => {},
|
||||
});
|
||||
|
||||
const [order, dispatch] = useReducer(
|
||||
(state: typeof slides, action: 'prev' | 'next') => {
|
||||
@@ -70,20 +74,20 @@ export function SliderWithScaling<T extends { img: string }>({
|
||||
setCurrentSliding(null);
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
}, [slide]);
|
||||
|
||||
function nextSlide() {
|
||||
// if (!transiting) {
|
||||
// }
|
||||
setCurrentSliding('next');
|
||||
dispatch('next');
|
||||
if (!transiting) {
|
||||
setCurrentSliding('next');
|
||||
dispatch('next');
|
||||
}
|
||||
}
|
||||
|
||||
function prevSlide() {
|
||||
// if (!transiting) {
|
||||
// }
|
||||
setCurrentSliding('prev');
|
||||
dispatch('prev');
|
||||
if (!transiting) {
|
||||
setCurrentSliding('prev');
|
||||
dispatch('prev');
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -91,8 +95,8 @@ export function SliderWithScaling<T extends { img: string }>({
|
||||
}, [baseoffset, order, slide]);
|
||||
|
||||
const handlers = useSwipeable({
|
||||
onSwipedLeft: nextSlide,
|
||||
onSwipedRight: prevSlide,
|
||||
onSwipedLeft: () => controlsRef.current.right(),
|
||||
onSwipedRight: () => controlsRef.current.left(),
|
||||
trackMouse: true,
|
||||
preventScrollOnSwipe: true,
|
||||
touchEventOptions: { passive: false },
|
||||
@@ -100,7 +104,7 @@ export function SliderWithScaling<T extends { img: string }>({
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col relative ' + className}>
|
||||
<div className="overflow-hidden sm:-mx-6 -mx-4 h-full">
|
||||
<div className="h-full -mx-4 overflow-hidden sm:-mx-6">
|
||||
<div {...handlers} className="h-full">
|
||||
<div
|
||||
className={`flex items-${alignItems} gap-x-4 -mr-6 select-none`}
|
||||
@@ -149,6 +153,7 @@ export function SliderWithScaling<T extends { img: string }>({
|
||||
</div>
|
||||
</div>
|
||||
<SliderControls
|
||||
ref={controlsRef}
|
||||
slide={slide}
|
||||
onLeftClick={prevSlide}
|
||||
onRightClick={nextSlide}
|
||||
@@ -158,8 +163,8 @@ export function SliderWithScaling<T extends { img: string }>({
|
||||
className={
|
||||
'absolute ' +
|
||||
(controlsPosition === 'top'
|
||||
? 'top-[75px]'
|
||||
: 'bottom-0 sm:self-end self-center')
|
||||
? 'top-[75px] sm:self-end'
|
||||
: 'lg:bottom-32 bottom-0 sm:self-end self-center')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user