From a344b6f4de7122a09f483adb8428ffeea319d7d3 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:50:35 +0300 Subject: [PATCH 01/10] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82?= =?UTF-8?q?=20scss=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B2=20index?= =?UTF-8?q?.scss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/styles/index.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/styles/index.scss b/src/app/styles/index.scss index a69cfda..0b8e49f 100644 --- a/src/app/styles/index.scss +++ b/src/app/styles/index.scss @@ -1,3 +1,3 @@ -@import './fonts'; -@import './variables'; -@import './reset'; \ No newline at end of file +@use 'fonts'; +@use 'variables'; +@use 'reset'; \ No newline at end of file From d7e66eec7150d49c898d5917c08e3e07fd9f0f3d Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:51:02 +0300 Subject: [PATCH 02/10] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20=D0=B3=D1=80=D0=B0=D0=B4=D0=B8?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/styles/variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/styles/variables.scss b/src/app/styles/variables.scss index 5ee1974..575989b 100644 --- a/src/app/styles/variables.scss +++ b/src/app/styles/variables.scss @@ -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; From e33cd1b139ba74f1f92b1a3ece444c1de4831784 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:51:49 +0300 Subject: [PATCH 03/10] =?UTF-8?q?refactor:=20=D0=BA=D0=BE=D0=BD=D1=84?= =?UTF-8?q?=D0=B8=D0=B3=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D1=81=D0=BC=D0=B5=D0=BD=D1=8B=20=D0=B3=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=20=D0=B2=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimeFrameSlider/ui/TimeFrameSlider/constants.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/constants.ts b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/constants.ts index 737ede5..4f61b6a 100644 --- a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/constants.ts +++ b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/constants.ts @@ -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 From 8fec89a699bbbbf74b0fc0901ea41bef2e3eed00 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:52:51 +0300 Subject: [PATCH 04/10] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D1=81=D0=BC=D0=B5=D0=BD=D1=8B=20=D0=B3?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/TimeFrameSlider/TimeFrameSlider.tsx | 60 ++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.tsx b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.tsx index 9ff0d38..2cc1e4e 100644 --- a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.tsx +++ b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.tsx @@ -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(null) const containerRef = useRef(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(() => {
{currentPeriod.yearFrom} + {'\u00A0'} {currentPeriod.yearTo}
@@ -137,7 +153,7 @@ export const TimeFrameSlider = memo(() => { onClick={handlePrev} aria-label='Предыдущий период' > - +
- +
+ +
) }) From 5a2a7642d332d94cfbd14c2a5d9b759a37cc0c6e Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:53:34 +0300 Subject: [PATCH 05/10] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=8D=D0=BB=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=D0=BE=D0=B2,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimeFrameSlider.module.scss | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss index b8c5bdb..aa8e25c 100644 --- a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss +++ b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss @@ -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,15 +30,22 @@ } .title { - position: relative; + position: absolute; z-index: 2; - margin-bottom: 40px; - padding-left: 60px; + left: 0; + top: 170px; + + padding-left: 75px; font-weight: 700; font-size: 56px; line-height: 120%; + max-width: 15ch; + + border-left: 5px solid transparent; + border-image: var(--gradient-primary) 1; + @media (width <=768px) { margin-bottom: 20px; @@ -50,7 +61,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,8 +80,9 @@ .controls { position: absolute; - left: 60px; - bottom: 50px; + transform-origin: left; + left: 100px; + bottom: 0; z-index: 10; display: flex; @@ -81,8 +100,7 @@ } .pagination { - margin-bottom: 10px; - + font-weight: 400; font-size: 14px; } @@ -159,4 +177,8 @@ @media (width <=768px) { display: none; } +} + +.eventCarousel { + padding: 55px 80px 105px; } \ No newline at end of file From 65630bae8ad37e4225887acebb025b1589657664 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:55:22 +0300 Subject: [PATCH 06/10] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BA=D0=B0=D1=80=D1=83=D1=81=D0=B5=D0=BB?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D0=B9,=20=D1=81?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B0=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B9=20=D1=82=D1=80=D0=B8=D0=B3=D0=B3=D0=B5=D1=80=D0=B8=D1=82?= =?UTF-8?q?=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B0=D1=86=D0=B8=D1=8E.=20=D0=98?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D1=80?= =?UTF-8?q?=D0=B0=D1=81=D0=BF=D0=BE=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BE=D0=BA=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=B3=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/EventsCarousel/EventsCarousel.module.scss | 4 ++-- .../TimeFrameSlider/ui/EventsCarousel/EventsCarousel.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.module.scss b/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.module.scss index f48d676..68c1485 100644 --- a/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.module.scss +++ b/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.module.scss @@ -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); diff --git a/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.tsx b/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.tsx index baf628c..f6e7d00 100644 --- a/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.tsx +++ b/src/widgets/TimeFrameSlider/ui/EventsCarousel/EventsCarousel.tsx @@ -89,7 +89,7 @@ export const EventsCarousel = memo( }, containerRef) return () => ctx.revert() - }, [visible]) + }, [visible, events]) /** * Обработчик инициализации Swiper From f1118e5aecdce4e7304df7b8efa5d75b35a5ac7c Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:55:54 +0300 Subject: [PATCH 07/10] =?UTF-8?q?fix:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B3=D0=BE=D1=80=D0=B8=D0=B7=D0=BE=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BE=D1=82=D1=81=D1=82=D1=83?= =?UTF-8?q?=D0=BF=20=D1=83=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/ui/Card/Card.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/ui/Card/Card.module.scss b/src/shared/ui/Card/Card.module.scss index f580337..afeb97b 100644 --- a/src/shared/ui/Card/Card.module.scss +++ b/src/shared/ui/Card/Card.module.scss @@ -1,5 +1,5 @@ .card { - padding: 20px; + padding: 20px 0; } .title { From 33763767d939c35f789e3abbb23e5362609deffa Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:56:13 +0300 Subject: [PATCH 08/10] =?UTF-8?q?fix:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80?= =?UTF-8?q?=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/TimeFrameSlider/ui/EventsCarousel/constants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widgets/TimeFrameSlider/ui/EventsCarousel/constants.ts b/src/widgets/TimeFrameSlider/ui/EventsCarousel/constants.ts index 3765c66..b6149e8 100644 --- a/src/widgets/TimeFrameSlider/ui/EventsCarousel/constants.ts +++ b/src/widgets/TimeFrameSlider/ui/EventsCarousel/constants.ts @@ -1,4 +1,3 @@ -import gsap from 'gsap' import { Navigation } from 'swiper/modules' import type { SwiperOptions } from 'swiper/types' From 93787eaf4d1d421c6c195e9f6cc573d6a55397c9 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:57:07 +0300 Subject: [PATCH 09/10] =?UTF-8?q?fix:=20=D0=9F=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BB=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/TimeFrameSlider/TimeFrameSlider.module.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss index aa8e25c..ead27c0 100644 --- a/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss +++ b/src/widgets/TimeFrameSlider/ui/TimeFrameSlider/TimeFrameSlider.module.scss @@ -31,17 +31,16 @@ .title { position: absolute; + top: 170px; + left: 0; z-index: 2; - left: 0; - top: 170px; - + max-width: 15ch; padding-left: 75px; font-weight: 700; font-size: 56px; line-height: 120%; - max-width: 15ch; border-left: 5px solid transparent; border-image: var(--gradient-primary) 1; @@ -80,7 +79,6 @@ .controls { position: absolute; - transform-origin: left; left: 100px; bottom: 0; z-index: 10; @@ -89,6 +87,8 @@ flex-direction: column; gap: 20px; + transform-origin: left; + @media (width <=768px) { position: static; From 4ec072055f810a0cbd251ea6695ee3c311cb9380 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 21 Nov 2025 12:59:48 +0300 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20=D0=92=20=D0=BF=D1=80=D0=B5=D0=BF?= =?UTF-8?q?=D1=83=D1=88=20=D1=85=D1=83=D0=BA=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D0=BA=20unit=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/pre-push | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.husky/pre-push b/.husky/pre-push index 15fcede..4decfec 100644 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -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 diff --git a/package.json b/package.json index 69fde29..40e5551 100644 --- a/package.json +++ b/package.json @@ -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" },