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..."
|
||||
pnpm lint:styles || exit 1
|
||||
|
||||
echo "Запуск Unit тестов..."
|
||||
pnpm test:unit || exit 1
|
||||
|
||||
echo "Production сборка..."
|
||||
pnpm build:prod || exit 1
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"test:unit": "jest --config ./config/jest/jest.config.ts",
|
||||
"type-check": "tsc --noEmit",
|
||||
"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",
|
||||
"build-storybook": "storybook build -c config/storybook"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
@import './fonts';
|
||||
@import './variables';
|
||||
@import './reset';
|
||||
@use 'fonts';
|
||||
@use 'variables';
|
||||
@use 'reset';
|
||||
@@ -9,7 +9,7 @@
|
||||
--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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.card {
|
||||
padding: 20px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
.prevButtonWrapper {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -25px;
|
||||
left: -60px;
|
||||
z-index: 10;
|
||||
|
||||
transform: translateY(-50%);
|
||||
@@ -18,7 +18,7 @@
|
||||
.nextButtonWrapper {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: -25px;
|
||||
right: -60px;
|
||||
z-index: 10;
|
||||
|
||||
transform: translateY(-50%) rotate(180deg);
|
||||
|
||||
@@ -89,7 +89,7 @@ export const EventsCarousel = memo(
|
||||
}, containerRef)
|
||||
|
||||
return () => ctx.revert()
|
||||
}, [visible])
|
||||
}, [visible, events])
|
||||
|
||||
/**
|
||||
* Обработчик инициализации Swiper
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import gsap from 'gsap'
|
||||
import { Navigation } from 'swiper/modules'
|
||||
|
||||
import type { SwiperOptions } from 'swiper/types'
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
max-width: 1440px;
|
||||
min-height: 100vh;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
padding-top: 180px;
|
||||
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-family-main);
|
||||
@@ -17,6 +16,11 @@
|
||||
border-right: 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;
|
||||
|
||||
@media (width <=768px) {
|
||||
@@ -26,16 +30,22 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
position: absolute;
|
||||
top: 170px;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
|
||||
margin-bottom: 40px;
|
||||
padding-left: 60px;
|
||||
max-width: 15ch;
|
||||
padding-left: 75px;
|
||||
|
||||
font-weight: 700;
|
||||
font-size: 56px;
|
||||
line-height: 120%;
|
||||
|
||||
border-left: 5px solid transparent;
|
||||
border-image: var(--gradient-primary) 1;
|
||||
|
||||
|
||||
@media (width <=768px) {
|
||||
margin-bottom: 20px;
|
||||
padding-left: 0;
|
||||
@@ -50,7 +60,14 @@
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
width: calc(100% + 40px);
|
||||
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) {
|
||||
display: flex;
|
||||
@@ -62,14 +79,16 @@
|
||||
|
||||
.controls {
|
||||
position: absolute;
|
||||
left: 60px;
|
||||
bottom: 50px;
|
||||
left: 100px;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
transform-origin: left;
|
||||
|
||||
@media (width <=768px) {
|
||||
position: static;
|
||||
|
||||
@@ -81,8 +100,7 @@
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-bottom: 10px;
|
||||
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -160,3 +178,7 @@
|
||||
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 { 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 { CircleTimeline } from '../CircleTimeline/CircleTimeline'
|
||||
import { EventsCarousel } from '../EventsCarousel/EventsCarousel'
|
||||
@@ -35,16 +35,20 @@ export const TimeFrameSlider = memo(() => {
|
||||
const endYearRef = useRef<HTMLSpanElement>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Мемоизированные константы
|
||||
const totalPeriods = useMemo(() => HISTORICAL_PERIODS.length, [])
|
||||
const anglePerPoint = useMemo(() => 360 / totalPeriods, [totalPeriods])
|
||||
|
||||
// Текущий период
|
||||
const currentPeriod = useMemo(
|
||||
() => HISTORICAL_PERIODS[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(() => {
|
||||
if (startYearRef.current) {
|
||||
gsap.to(startYearRef.current, {
|
||||
innerText: currentPeriod.yearFrom,
|
||||
snap: { innerText: 1 },
|
||||
duration: 1,
|
||||
ease: 'power2.inOut',
|
||||
})
|
||||
gsap.fromTo(
|
||||
startYearRef.current,
|
||||
{
|
||||
innerText: prevYearFromRef.current,
|
||||
},
|
||||
{
|
||||
innerText: currentPeriod.yearFrom,
|
||||
...GSAP_ANIMATION_CONFIG,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (endYearRef.current) {
|
||||
gsap.to(endYearRef.current, {
|
||||
innerText: currentPeriod.yearTo,
|
||||
snap: { innerText: 1 },
|
||||
duration: 1,
|
||||
ease: 'power2.inOut',
|
||||
})
|
||||
gsap.fromTo(
|
||||
endYearRef.current,
|
||||
{
|
||||
innerText: prevYearToRef.current,
|
||||
},
|
||||
{
|
||||
innerText: currentPeriod.yearTo,
|
||||
...GSAP_ANIMATION_CONFIG,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
prevYearFromRef.current = currentPeriod.yearFrom
|
||||
prevYearToRef.current = currentPeriod.yearTo
|
||||
}, containerRef)
|
||||
|
||||
return () => ctx.revert()
|
||||
@@ -112,6 +127,7 @@ export const TimeFrameSlider = memo(() => {
|
||||
<div className={styles.content}>
|
||||
<div className={styles.centerDate}>
|
||||
<span ref={startYearRef}>{currentPeriod.yearFrom}</span>
|
||||
{'\u00A0'}
|
||||
<span ref={endYearRef}>{currentPeriod.yearTo}</span>
|
||||
</div>
|
||||
|
||||
@@ -137,7 +153,7 @@ export const TimeFrameSlider = memo(() => {
|
||||
onClick={handlePrev}
|
||||
aria-label='Предыдущий период'
|
||||
>
|
||||
<ChevronSvg width={6.25} height={12.5} stroke='#42567A' />
|
||||
<ChevronSvg width={9} height={14} stroke='#42567A' />
|
||||
</Button>
|
||||
<Button
|
||||
variant='round'
|
||||
@@ -147,8 +163,8 @@ export const TimeFrameSlider = memo(() => {
|
||||
aria-label='Следующий период'
|
||||
>
|
||||
<ChevronSvg
|
||||
width={6.25}
|
||||
height={12.5}
|
||||
width={9}
|
||||
height={14}
|
||||
stroke='#42567A'
|
||||
className={styles.rotated}
|
||||
/>
|
||||
@@ -157,7 +173,9 @@ export const TimeFrameSlider = memo(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EventsCarousel events={currentPeriod.events} visible />
|
||||
<div className={styles.eventCarousel}>
|
||||
<EventsCarousel events={currentPeriod.events} visible />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Power2 } from 'gsap'
|
||||
|
||||
/**
|
||||
* Константы для компонента TimeFrameSlider
|
||||
*/
|
||||
@@ -6,3 +8,12 @@
|
||||
* Угол позиции активного элемента (верхний правый угол)
|
||||
*/
|
||||
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