feat: Добавлены названия периодов с анимацией появления
This commit is contained in:
@@ -46,15 +46,30 @@
|
|||||||
background-clip: padding-box;
|
background-clip: padding-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .label,
|
&:hover .number,
|
||||||
&.active .label {
|
&.active .number {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.number {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
|
color: var(--color-text);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -67,6 +67,9 @@ export const CircleTimeline = memo(function CircleTimeline({
|
|||||||
// Реф для массива точек периодов
|
// Реф для массива точек периодов
|
||||||
const pointsRef = useRef<(HTMLDivElement | null)[]>([])
|
const pointsRef = useRef<(HTMLDivElement | null)[]>([])
|
||||||
|
|
||||||
|
// Реф для заголовков периодов
|
||||||
|
const titlesRef = useRef<(HTMLSpanElement | null)[]>([])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Эффект для анимации поворота круга и контр-поворота точек
|
* Эффект для анимации поворота круга и контр-поворота точек
|
||||||
* Запускается при изменении rotation
|
* Запускается при изменении rotation
|
||||||
@@ -82,16 +85,38 @@ export const CircleTimeline = memo(function CircleTimeline({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Контр-поворот точек, чтобы текст оставался читаемым
|
// Контр-поворот точек, чтобы текст оставался читаемым
|
||||||
pointsRef.current.forEach((point) => {
|
pointsRef.current.forEach((point, index) => {
|
||||||
if (point) {
|
if (point) {
|
||||||
gsap.to(point, {
|
gsap.to(point, {
|
||||||
rotation: -rotation,
|
rotation: -rotation,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
ease: ANIMATION_EASE,
|
ease: ANIMATION_EASE,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Анимация заголовка
|
||||||
|
const title = titlesRef.current[index]
|
||||||
|
if (title) {
|
||||||
|
// Сбрасываем предыдущие анимации для этого элемента
|
||||||
|
gsap.killTweensOf(title)
|
||||||
|
|
||||||
|
if (index === activeIndex) {
|
||||||
|
gsap.to(title, {
|
||||||
|
opacity: 1,
|
||||||
|
visibility: 'visible',
|
||||||
|
duration: 0.5,
|
||||||
|
delay: ANIMATION_DURATION, // Ждем окончания вращения
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
gsap.to(title, {
|
||||||
|
opacity: 0,
|
||||||
|
visibility: 'hidden',
|
||||||
|
duration: 0.2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [rotation])
|
}, [rotation, activeIndex])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Мемоизированный расчет позиций точек на круге
|
* Мемоизированный расчет позиций точек на круге
|
||||||
@@ -138,7 +163,15 @@ export const CircleTimeline = memo(function CircleTimeline({
|
|||||||
aria-label={`Period ${index + 1}: ${period.label}`}
|
aria-label={`Period ${index + 1}: ${period.label}`}
|
||||||
aria-current={index === activeIndex ? 'true' : 'false'}
|
aria-current={index === activeIndex ? 'true' : 'false'}
|
||||||
>
|
>
|
||||||
<span className={styles.label}>{index + 1}</span>
|
<span className={styles.number}>{index + 1}</span>
|
||||||
|
<span
|
||||||
|
className={styles.title}
|
||||||
|
ref={(el) => {
|
||||||
|
titlesRef.current[index] = el
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{period.label}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user