Merge pull request #4 from e7f3/feature/minor-changes
Feature/minor changes
This commit is contained in:
@@ -12,6 +12,9 @@ pnpm lint || exit 1
|
|||||||
echo "Проверка Stylelint..."
|
echo "Проверка Stylelint..."
|
||||||
pnpm lint:styles || exit 1
|
pnpm lint:styles || exit 1
|
||||||
|
|
||||||
|
echo "Запуск Unit тестов..."
|
||||||
|
pnpm test:unit || exit 1
|
||||||
|
|
||||||
echo "Production сборка..."
|
echo "Production сборка..."
|
||||||
pnpm build:prod || exit 1
|
pnpm build:prod || exit 1
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"test:unit": "jest --config ./config/jest/jest.config.ts",
|
"test:unit": "jest --config ./config/jest/jest.config.ts",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"pre-push": "pnpm type-check && pnpm lint && pnpm lint:styles && pnpm build:prod",
|
"pre-push": "pnpm type-check && pnpm lint && pnpm lint:styles && pnpm test:unit && pnpm build:prod",
|
||||||
"storybook": "storybook dev -p 6006 -c config/storybook",
|
"storybook": "storybook dev -p 6006 -c config/storybook",
|
||||||
"build-storybook": "storybook build -c config/storybook"
|
"build-storybook": "storybook build -c config/storybook"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
@import './fonts';
|
@use 'fonts';
|
||||||
@import './variables';
|
@use 'variables';
|
||||||
@import './reset';
|
@use 'reset';
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
--color-white: #FFF;
|
--color-white: #FFF;
|
||||||
|
|
||||||
// Градиенты
|
// Градиенты
|
||||||
--gradient-primary: linear-gradient(to right, #3877EE, #EF5DA8);
|
--gradient-primary: linear-gradient(to bottom, #3877EE, #EF5DA8);
|
||||||
|
|
||||||
// Типографика
|
// Типографика
|
||||||
--font-family-main: 'PT Sans', sans-serif;
|
--font-family-main: 'PT Sans', sans-serif;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.card {
|
.card {
|
||||||
padding: 20px;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
.prevButtonWrapper {
|
.prevButtonWrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: -25px;
|
left: -60px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
.nextButtonWrapper {
|
.nextButtonWrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: -25px;
|
right: -60px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
transform: translateY(-50%) rotate(180deg);
|
transform: translateY(-50%) rotate(180deg);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export const EventsCarousel = memo(
|
|||||||
}, containerRef)
|
}, containerRef)
|
||||||
|
|
||||||
return () => ctx.revert()
|
return () => ctx.revert()
|
||||||
}, [visible])
|
}, [visible, events])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Обработчик инициализации Swiper
|
* Обработчик инициализации Swiper
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import gsap from 'gsap'
|
|
||||||
import { Navigation } from 'swiper/modules'
|
import { Navigation } from 'swiper/modules'
|
||||||
|
|
||||||
import type { SwiperOptions } from 'swiper/types'
|
import type { SwiperOptions } from 'swiper/types'
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 1440px;
|
max-width: 1440px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 20px;
|
padding-top: 180px;
|
||||||
|
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-family: var(--font-family-main);
|
font-family: var(--font-family-main);
|
||||||
@@ -17,6 +16,11 @@
|
|||||||
border-right: 1px solid var(--color-border);
|
border-right: 1px solid var(--color-border);
|
||||||
border-left: 1px solid var(--color-border);
|
border-left: 1px solid var(--color-border);
|
||||||
|
|
||||||
|
background-image: linear-gradient(to right, rgba(#42567A, 0.1) 1px, transparent 1px);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center top;
|
||||||
|
background-size: 1px 100%;
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
@media (width <=768px) {
|
@media (width <=768px) {
|
||||||
@@ -26,16 +30,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
position: relative;
|
position: absolute;
|
||||||
|
top: 170px;
|
||||||
|
left: 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
margin-bottom: 40px;
|
max-width: 15ch;
|
||||||
padding-left: 60px;
|
padding-left: 75px;
|
||||||
|
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 56px;
|
font-size: 56px;
|
||||||
line-height: 120%;
|
line-height: 120%;
|
||||||
|
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-image: var(--gradient-primary) 1;
|
||||||
|
|
||||||
|
|
||||||
@media (width <=768px) {
|
@media (width <=768px) {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
@@ -50,7 +60,14 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
width: calc(100% + 40px);
|
||||||
height: 600px;
|
height: 600px;
|
||||||
|
margin: 0 -20px;
|
||||||
|
|
||||||
|
background-image: linear-gradient(to bottom, rgba(#42567A, 0.1) 1px, transparent 1px);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: 100% 1px;
|
||||||
|
|
||||||
@media (width <=768px) {
|
@media (width <=768px) {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -62,14 +79,16 @@
|
|||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 60px;
|
left: 100px;
|
||||||
bottom: 50px;
|
bottom: 0;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
|
||||||
|
transform-origin: left;
|
||||||
|
|
||||||
@media (width <=768px) {
|
@media (width <=768px) {
|
||||||
position: static;
|
position: static;
|
||||||
|
|
||||||
@@ -81,8 +100,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pagination {
|
.pagination {
|
||||||
margin-bottom: 10px;
|
font-weight: 400;
|
||||||
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,4 +177,8 @@
|
|||||||
@media (width <=768px) {
|
@media (width <=768px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventCarousel {
|
||||||
|
padding: 55px 80px 105px;
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import { HISTORICAL_PERIODS } from '@/entities/TimePeriod'
|
|||||||
import ChevronSvg from '@/shared/assets/chevron--left.svg'
|
import ChevronSvg from '@/shared/assets/chevron--left.svg'
|
||||||
import { Button } from '@/shared/ui/Button'
|
import { Button } from '@/shared/ui/Button'
|
||||||
|
|
||||||
import { ACTIVE_POSITION_ANGLE } from './constants'
|
import { ACTIVE_POSITION_ANGLE, GSAP_ANIMATION_CONFIG } from './constants'
|
||||||
import styles from './TimeFrameSlider.module.scss'
|
import styles from './TimeFrameSlider.module.scss'
|
||||||
import { CircleTimeline } from '../CircleTimeline/CircleTimeline'
|
import { CircleTimeline } from '../CircleTimeline/CircleTimeline'
|
||||||
import { EventsCarousel } from '../EventsCarousel/EventsCarousel'
|
import { EventsCarousel } from '../EventsCarousel/EventsCarousel'
|
||||||
@@ -35,16 +35,20 @@ export const TimeFrameSlider = memo(() => {
|
|||||||
const endYearRef = useRef<HTMLSpanElement>(null)
|
const endYearRef = useRef<HTMLSpanElement>(null)
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
// Мемоизированные константы
|
|
||||||
const totalPeriods = useMemo(() => HISTORICAL_PERIODS.length, [])
|
|
||||||
const anglePerPoint = useMemo(() => 360 / totalPeriods, [totalPeriods])
|
|
||||||
|
|
||||||
// Текущий период
|
// Текущий период
|
||||||
const currentPeriod = useMemo(
|
const currentPeriod = useMemo(
|
||||||
() => HISTORICAL_PERIODS[activePeriod],
|
() => HISTORICAL_PERIODS[activePeriod],
|
||||||
[activePeriod]
|
[activePeriod]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Мемоизированные константы
|
||||||
|
const totalPeriods = useMemo(() => HISTORICAL_PERIODS.length, [])
|
||||||
|
const anglePerPoint = useMemo(() => 360 / totalPeriods, [totalPeriods])
|
||||||
|
|
||||||
|
// Рефы для предыдущих значений периода
|
||||||
|
const prevYearFromRef = useRef(currentPeriod.yearFrom)
|
||||||
|
const prevYearToRef = useRef(currentPeriod.yearTo)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Расчет поворота при изменении активного периода
|
* Расчет поворота при изменении активного периода
|
||||||
* Использует кратчайший путь для анимации
|
* Использует кратчайший путь для анимации
|
||||||
@@ -68,22 +72,33 @@ export const TimeFrameSlider = memo(() => {
|
|||||||
|
|
||||||
const ctx = gsap.context(() => {
|
const ctx = gsap.context(() => {
|
||||||
if (startYearRef.current) {
|
if (startYearRef.current) {
|
||||||
gsap.to(startYearRef.current, {
|
gsap.fromTo(
|
||||||
innerText: currentPeriod.yearFrom,
|
startYearRef.current,
|
||||||
snap: { innerText: 1 },
|
{
|
||||||
duration: 1,
|
innerText: prevYearFromRef.current,
|
||||||
ease: 'power2.inOut',
|
},
|
||||||
})
|
{
|
||||||
|
innerText: currentPeriod.yearFrom,
|
||||||
|
...GSAP_ANIMATION_CONFIG,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endYearRef.current) {
|
if (endYearRef.current) {
|
||||||
gsap.to(endYearRef.current, {
|
gsap.fromTo(
|
||||||
innerText: currentPeriod.yearTo,
|
endYearRef.current,
|
||||||
snap: { innerText: 1 },
|
{
|
||||||
duration: 1,
|
innerText: prevYearToRef.current,
|
||||||
ease: 'power2.inOut',
|
},
|
||||||
})
|
{
|
||||||
|
innerText: currentPeriod.yearTo,
|
||||||
|
...GSAP_ANIMATION_CONFIG,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prevYearFromRef.current = currentPeriod.yearFrom
|
||||||
|
prevYearToRef.current = currentPeriod.yearTo
|
||||||
}, containerRef)
|
}, containerRef)
|
||||||
|
|
||||||
return () => ctx.revert()
|
return () => ctx.revert()
|
||||||
@@ -112,6 +127,7 @@ export const TimeFrameSlider = memo(() => {
|
|||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div className={styles.centerDate}>
|
<div className={styles.centerDate}>
|
||||||
<span ref={startYearRef}>{currentPeriod.yearFrom}</span>
|
<span ref={startYearRef}>{currentPeriod.yearFrom}</span>
|
||||||
|
{'\u00A0'}
|
||||||
<span ref={endYearRef}>{currentPeriod.yearTo}</span>
|
<span ref={endYearRef}>{currentPeriod.yearTo}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -137,7 +153,7 @@ export const TimeFrameSlider = memo(() => {
|
|||||||
onClick={handlePrev}
|
onClick={handlePrev}
|
||||||
aria-label='Предыдущий период'
|
aria-label='Предыдущий период'
|
||||||
>
|
>
|
||||||
<ChevronSvg width={6.25} height={12.5} stroke='#42567A' />
|
<ChevronSvg width={9} height={14} stroke='#42567A' />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant='round'
|
variant='round'
|
||||||
@@ -147,8 +163,8 @@ export const TimeFrameSlider = memo(() => {
|
|||||||
aria-label='Следующий период'
|
aria-label='Следующий период'
|
||||||
>
|
>
|
||||||
<ChevronSvg
|
<ChevronSvg
|
||||||
width={6.25}
|
width={9}
|
||||||
height={12.5}
|
height={14}
|
||||||
stroke='#42567A'
|
stroke='#42567A'
|
||||||
className={styles.rotated}
|
className={styles.rotated}
|
||||||
/>
|
/>
|
||||||
@@ -157,7 +173,9 @@ export const TimeFrameSlider = memo(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<EventsCarousel events={currentPeriod.events} visible />
|
<div className={styles.eventCarousel}>
|
||||||
|
<EventsCarousel events={currentPeriod.events} visible />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Power2 } from 'gsap'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Константы для компонента TimeFrameSlider
|
* Константы для компонента TimeFrameSlider
|
||||||
*/
|
*/
|
||||||
@@ -6,3 +8,12 @@
|
|||||||
* Угол позиции активного элемента (верхний правый угол)
|
* Угол позиции активного элемента (верхний правый угол)
|
||||||
*/
|
*/
|
||||||
export const ACTIVE_POSITION_ANGLE = -60
|
export const ACTIVE_POSITION_ANGLE = -60
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конфигурация анимации для изменения значения года
|
||||||
|
*/
|
||||||
|
export const GSAP_ANIMATION_CONFIG: gsap.TweenVars = {
|
||||||
|
snap: { innerText: 1 },
|
||||||
|
duration: 1,
|
||||||
|
ease: Power2.easeInOut,
|
||||||
|
} as const
|
||||||
|
|||||||
Reference in New Issue
Block a user