You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
4.9 KiB
TypeScript
148 lines
4.9 KiB
TypeScript
import { useRef } from 'react';
|
|
import styles from './citiesCard.module.scss';
|
|
import { Card } from '@/components/card';
|
|
import useLocale from '@/utils/useLocale';
|
|
import { LocalesMap } from '@/utils/useLocale';
|
|
import CityPolotskSmallEn from '@/assets/images/city-polotsk-small-en.svg';
|
|
import CityNovopolotskSmallEn from '@/assets/images/city-novopolotsk-small-en.svg';
|
|
import CityBigEn from '@/assets/images/city-big-en.svg';
|
|
import CityPolotskSmallRu from '@/assets/images/city-polotsk-small-ru.svg';
|
|
import CityNovopolotskSmallRu from '@/assets/images/city-novopolotsk-small-ru.svg';
|
|
import CityBigRu from '@/assets/images/city-big-ru.svg';
|
|
import maskUrl from '@/assets/images/cities-star-mask.svg?url';
|
|
import ridebusImage from '@/assets/images/cities-backdrop.jpg';
|
|
import Image from 'next/image';
|
|
import useFrame from '@/utils/useFrame';
|
|
import useScroll from '@/utils/useScroll';
|
|
import { useRouter } from 'next/router';
|
|
import useMediaQuery from '@/utils/useMediaQuery';
|
|
|
|
const locales: LocalesMap = {
|
|
ru: {
|
|
title: 'Поддержка нескольких городов',
|
|
description:
|
|
'Поддерживаются города Полоцк и Новополоцк, но мы планируем добавлять расписание общественного транспорта и для других городов Беларуси',
|
|
},
|
|
en: {
|
|
title: 'Multi-city support',
|
|
description:
|
|
'The cities of Polotsk and Novopolotsk are supported, but we plan to add public transportation schedules for other cities of Belarus as well',
|
|
},
|
|
};
|
|
|
|
function SmallCitiesLine() {
|
|
const router = useRouter();
|
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
const breakpoint800 = useMediaQuery('(max-width: 800px)');
|
|
|
|
const cityWidth = breakpoint800 ? 170 : 220;
|
|
const swapWidth = cityWidth * 2;
|
|
|
|
useScroll((scrollY, delta, time) => {
|
|
|
|
const offset = -(scrollY / 6) - (time / 30);
|
|
|
|
if (rootRef.current) {
|
|
rootRef.current.style.transform = `rotate(3deg) translate3D(${offset % swapWidth + cityWidth * 2}px, 0px, 0px)`;
|
|
}
|
|
}, {}, [cityWidth]);
|
|
|
|
const CityPolotsk = router.locale === 'ru' ? CityPolotskSmallRu : CityPolotskSmallEn;
|
|
const CityNovopolotsk = router.locale === 'ru' ? CityNovopolotskSmallRu : CityNovopolotskSmallEn;
|
|
|
|
return (
|
|
<div ref={rootRef} className={styles.smallCitiesLine}>
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function BigCitiesLine() {
|
|
const router = useRouter();
|
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
const breakpoint800 = useMediaQuery('(max-width: 800px)');
|
|
|
|
const cityWidth = (breakpoint800 ? 200 : 260) + 9;
|
|
const swapWidth = cityWidth * 1;
|
|
|
|
useScroll((scrollY, delta, time) => {
|
|
|
|
const offset = (scrollY / 6) + (time / 30);
|
|
|
|
if (rootRef.current) {
|
|
rootRef.current.style.transform = `rotate(356deg) translate3D(${offset % swapWidth * 2}px, 0px, 0px)`;
|
|
}
|
|
}, {}, [cityWidth]);
|
|
|
|
const CityPolotsk = router.locale === 'ru' ? CityPolotskSmallRu : CityPolotskSmallEn;
|
|
const CityNovopolotsk = router.locale === 'ru' ? CityNovopolotskSmallRu : CityNovopolotskSmallEn;
|
|
|
|
return (
|
|
<div ref={rootRef} className={styles.bigCitiesLine}>
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
<CityPolotsk />
|
|
<CityNovopolotsk />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function CitiesCard() {
|
|
const t = useLocale(locales);
|
|
const ridebusImageMaskRef = useRef<HTMLDivElement>(null);
|
|
const ridebusImageRef = useRef<HTMLDivElement>(null);
|
|
|
|
useFrame((delta, time) => {
|
|
if (ridebusImageMaskRef.current && ridebusImageRef.current) {
|
|
ridebusImageMaskRef.current.style.transform = `rotate(${-(time * 0.005) % 360}deg) translate3D(0px, 0px, 0px)`;
|
|
ridebusImageRef.current.style.transform = `rotate(${(time * 0.005) % 360}deg) translate3D(0px, 0px, 0px)`;
|
|
}
|
|
});
|
|
|
|
return (
|
|
<Card
|
|
className={styles.card}
|
|
title={t('title')}
|
|
subtitle={t('description')}
|
|
backdropOnText
|
|
classes={{ subtitle: styles.description, title: styles.title }}
|
|
>
|
|
<div className={styles.mockupPhoneContainer}>
|
|
<div
|
|
className={styles.ridebusImageMask}
|
|
ref={ridebusImageMaskRef}
|
|
style={{
|
|
maskImage: `url(${maskUrl.src})`,
|
|
}}>
|
|
<div ref={ridebusImageRef} className={styles.ridebusImageAnchor}>
|
|
<Image
|
|
className={styles.ridebusImage}
|
|
height={800}
|
|
width={800}
|
|
placeholder="blur"
|
|
alt=""
|
|
src={ridebusImage}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<SmallCitiesLine />
|
|
<BigCitiesLine />
|
|
</div>
|
|
</Card>
|
|
);
|
|
} |