first commit
This commit is contained in:
132
modules/home/citiesCard/citiesCard.module.scss
Normal file
132
modules/home/citiesCard/citiesCard.module.scss
Normal file
@@ -0,0 +1,132 @@
|
||||
.card {
|
||||
--on-background: #122F60;
|
||||
--on-background-secondary: #2C4678;
|
||||
--background: #D8E2FF;
|
||||
width: 100%;
|
||||
height: 580px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mockupPhoneContainer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.backdropImage {
|
||||
z-index: 1;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
height: 650px;
|
||||
}
|
||||
|
||||
.ridebusImageMask {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 640px;
|
||||
height: 640px;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
mask-position: 50%;
|
||||
bottom: -140px;
|
||||
right: -140px;
|
||||
}
|
||||
|
||||
.ridebusImageAnchor {
|
||||
bottom: 320px;
|
||||
left: 320px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.ridebusImage {
|
||||
z-index: 1;
|
||||
bottom: -400px;
|
||||
left: -400px;
|
||||
position: absolute;
|
||||
width: 800px;
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
z-index: 1;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
height: 650px;
|
||||
}
|
||||
|
||||
.smallCitiesLine {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
right: -50px;
|
||||
bottom: 260px;
|
||||
transform-origin: right center;
|
||||
transform: rotate(4deg);
|
||||
|
||||
svg {
|
||||
width: 220px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.bigCitiesLine {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
right: -280px;
|
||||
bottom: 100px;
|
||||
transform-origin: right center;
|
||||
transform: rotate(356deg);
|
||||
gap: 9px;
|
||||
|
||||
svg {
|
||||
width: 260px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.card {
|
||||
height: 490px;
|
||||
}
|
||||
.ridebusImageMask {
|
||||
width: 440px;
|
||||
height: 440px;
|
||||
bottom: -70px;
|
||||
right: -110px;
|
||||
}
|
||||
.ridebusImageAnchor {
|
||||
bottom: 220px;
|
||||
left: 220px;
|
||||
}
|
||||
.smallCitiesLine {
|
||||
bottom: 200px;
|
||||
}
|
||||
.bigCitiesLine {
|
||||
bottom: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.card {
|
||||
height: 390px;
|
||||
}
|
||||
.smallCitiesLine {
|
||||
bottom: 160px;
|
||||
|
||||
svg {
|
||||
width: 170px;
|
||||
}
|
||||
}
|
||||
.bigCitiesLine svg {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
144
modules/home/citiesCard/citiesCard.tsx
Normal file
144
modules/home/citiesCard/citiesCard.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
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 * 1;
|
||||
|
||||
useScroll((scrollY, delta, time) => {
|
||||
|
||||
const offset = -(scrollY / 6) - (time / 30);
|
||||
|
||||
if (rootRef.current) {
|
||||
rootRef.current.style.transform = `rotate(3deg) translate3D(${offset % swapWidth + cityWidth}px, 0px, 0px)`;
|
||||
}
|
||||
}, {}, [cityWidth]);
|
||||
|
||||
const CityPolotsk = router.locale === 'ru' ? CityPolotskSmallRu : CityPolotskSmallEn;
|
||||
|
||||
return (
|
||||
<div ref={rootRef} className={styles.smallCitiesLine}>
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
<CityPolotsk />
|
||||
</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}px, 0px, 0px)`;
|
||||
}
|
||||
}, {}, [cityWidth]);
|
||||
|
||||
const CityNovopolotsk = router.locale === 'ru' ? CityNovopolotskSmallRu : CityNovopolotskSmallEn;
|
||||
|
||||
return (
|
||||
<div ref={rootRef} className={styles.bigCitiesLine}>
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<CityNovopolotsk />
|
||||
<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>
|
||||
);
|
||||
}
|
||||
1
modules/home/citiesCard/index.tsx
Normal file
1
modules/home/citiesCard/index.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export * from './citiesCard';
|
||||
Reference in New Issue
Block a user