6 Commits

Author SHA1 Message Date
Ilia Mashkov
48c8f7b1cf chore: remove duplicated contend from readme 2026-02-11 13:41:11 +03:00
Ilia Mashkov
338e8b233b chore: add demonstration gif and English readme 2026-02-11 13:25:23 +03:00
Ilia Mashkov
999da5fef4 Merge pull request #7 from e7f3/feature/stylelint
Feature/stylelint
2025-11-24 14:44:02 +03:00
Ilia Mashkov
d3816b0952 fix: Правки линтера 2025-11-24 12:22:02 +03:00
Ilia Mashkov
d3343f1f7b feat: Уставновлен плагин для соблюдения стилизации кода в файлах стилей 2025-11-24 12:21:04 +03:00
Ilia Mashkov
7c94fa8ffe Merge pull request #6 from e7f3/feature/minor-adjustments
Feature/minor adjustments
2025-11-23 16:20:18 +03:00
12 changed files with 759 additions and 435 deletions

302
README.md
View File

@@ -1,6 +1,286 @@
# Only Task # GSAP Carousel
Тестовое задание для only.digital ---
[🌐 English](#english) | [🇷🇺 Русский](#russian)
---
![Demo](assets/gsap-carousel.gif)
---
<a id="english"></a>
---
[🌍 Scroll to top](#) | [🇷🇺 Русский](#russian)
---
# GSAP Carousel
React-based UI component developed to explore advanced animation patterns using GSAP. This project focuses on synchronizing complex circular transitions with a dynamic content carousel.
## Technical Highlights
- **GSAP Integration**: Implementation of smooth, high-performance animations for state transitions
- **Circular Data Visualization**: An interactive timeline with selectable time periods
- **Adaptive Layout**: Fully responsive architecture supporting mobile, tablet, and desktop viewports
- **Custom Navigation**: Bespoke UI controls for seamless event browsing
## 🚀 Technologies
- **React 19** - User interface library
- **TypeScript 5** - Typed JavaScript
- **GSAP** - Smooth animation library
- **Swiper** - Modern carousel library
- **Webpack 5** - Module bundler
- **SCSS** - CSS preprocessor with modules
- **Jest** - Testing framework
- **ESLint + Prettier** - Code linting and formatting
## 📋 Requirements
- **Node.js** >= 18.0.0
- **pnpm** >= 8.0.0
## 🛠️ Installation
1. Clone the repository:
```bash
git clone <repository-url>
cd gsap-carousel
```
2. Install dependencies:
```bash
pnpm install
```
## 🎯 Available Commands
### Development
```bash
# Start dev-server on port 3000
pnpm dev
```
The application will be available at: http://localhost:3000
### Build
```bash
# Production build
pnpm build:prod
# Development build
pnpm build:dev
```
The build result will be in the `dist/` folder
### Testing
```bash
# Run all unit tests
pnpm test:unit
# Check TypeScript types
pnpm type-check
```
### Linting
```bash
# Check JavaScript/TypeScript code
pnpm lint
# Auto-fix errors
pnpm lint --fix
# Check styles (SCSS)
pnpm lint:styles
# Auto-fix styles
pnpm lint:styles --fix
```
### Storybook
```bash
# Run Storybook for component development
pnpm storybook
# Build static version of Storybook
pnpm build-storybook
```
### Pre-push Checks
```bash
# Run all checks before push
pnpm pre-push
```
This command runs:
- ✅ TypeScript type checking
- ✅ Code linting
- ✅ Style linting
- ✅ Unit tests
- ✅ Production build
## 📁 Project Structure
```
gsap-carousel/
├── config/ # Build configuration
│ ├── build/ # Webpack configuration
│ ├── jest/ # Jest configuration
│ └── storybook/ # Storybook configuration
├── dist/ # Production build (generated)
├── src/ # Source code
│ ├── app/ # Root application component
│ ├── entities/ # Business entities (data types)
│ ├── shared/ # Reusable components and utilities
│ │ ├── assets/ # Static resources (SVG, images)
│ │ └── ui/ # UI components (Button, Card)
│ └── widgets/ # Complex components (TimeFrameSlider)
├── .husky/ # Git hooks
├── package.json # Dependencies and scripts
└── tsconfig.json # TypeScript configuration
```
## 🎨 Main Components
### TimeFrameSlider
The main application widget combining a circular timeline and an events carousel.
**Features:**
- Interactive circular chart with periods
- Smooth GSAP animations during transitions
- Responsive design for mobile, tablet, and desktop
- Custom navigation
### CircleTimeline
A circular timeline with period points.
**Features:**
- Auto-rotation to the active period
- Click on points to switch periods
- Period title animations
### EventsCarousel
Historical events carousel using Swiper.
**Features:**
- Adaptive number of slides
- Custom navigation
- Smooth appearance/disappearance animation
## ⚡ Performance Optimization
The project is optimized for production:
-**Code splitting** - chunk separation (vendors, runtime, main)
-**Tree shaking** - removal of unused code
-**Gzip compression** - file compression (~68% size reduction)
-**Minification** - JS and CSS minification
-**CSS Modules** - isolated component styles
-**Babel caching** - caching for fast rebuilds
**Bundle size:**
- Uncompressed: ~371 KiB
- Gzipped: ~117 KiB
## 🧪 Testing
The project is covered by unit tests:
- ✅ Component tests (Button, Card, CircleTimeline, TimeFrameSlider, EventsCarousel)
- ✅ Utility tests (calculateCoordinates)
- ✅ Mocks for GSAP and Swiper
- ✅ 39 tests, 100% successful
## 📱 Responsiveness
The application is adapted for all devices:
- **Desktop** (>1440px) - Full version with circular chart
- **Tablet** (768px - 1024px) - Optimized version
- **Mobile** (<768px) - Simplified version with bottom navigation
## 🔧 Configuration
### Webpack
- Babel for transpilation (faster than ts-loader)
- CSS Modules for style isolation
- SVGR for importing SVG as React components
- Hot Module Replacement for development
- Bundle Analyzer for size analysis
### TypeScript
- Strict mode enabled
- Path aliases (`@/*``src/*`)
- Type checking separate from build
### ESLint
- Rules for React, TypeScript, Jest
- Prettier integration
- Import sorting
## 🤝 Git Hooks
Pre-push hook automatically runs:
1. Type checking
2. ESLint
3. Stylelint
4. Unit tests
5. Production build
This ensures that only working code enters the repository.
## 📝 License
ISC
**Happy coding! 🚀**
---
<a id="russian"></a>
---
[🌍 Scroll to top](#) | [🌐 English](#english)
---
# GSAP Carousel
React-компонент UI для изучения продвинутых паттернов анимации с использованием GSAP. Проект фокусируется на синхронизации сложных круговых переходов с динамической каруселью контента.
## Технические особенности
- **Интеграция GSAP**: Реализация плавных высокопроизводительных анимаций для переходов между состояниями
- **Круговая визуализация данных**: Интерактивная временная шкала с выбираемыми периодами
- **Адаптивный макет**: Полностью адаптивная архитектура, поддерживающая мобильные устройства, планшеты и десктопы
- **Кастомная навигация**: Собственные элементы управления UI для удобного просмотра событий
## 🚀 Технологии ## 🚀 Технологии
@@ -21,12 +301,14 @@
## 🛠️ Установка ## 🛠️ Установка
1. Клонируйте репозиторий: 1. Клонируйте репозиторий:
```bash ```bash
git clone <repository-url> git clone <repository-url>
cd only-task cd gsap-carousel
``` ```
2. Установите зависимости: 2. Установите зависимости:
```bash ```bash
pnpm install pnpm install
``` ```
@@ -98,6 +380,7 @@ pnpm pre-push
``` ```
Эта команда выполняет: Эта команда выполняет:
- ✅ Проверку типов TypeScript - ✅ Проверку типов TypeScript
- ✅ Линтинг кода - ✅ Линтинг кода
- ✅ Линтинг стилей - ✅ Линтинг стилей
@@ -107,7 +390,7 @@ pnpm pre-push
## 📁 Структура проекта ## 📁 Структура проекта
``` ```
only-task/ gsap-carousel/
├── config/ # Конфигурация сборки ├── config/ # Конфигурация сборки
│ ├── build/ # Webpack конфигурация │ ├── build/ # Webpack конфигурация
│ ├── jest/ # Jest конфигурация │ ├── jest/ # Jest конфигурация
@@ -128,26 +411,32 @@ only-task/
## 🎨 Основные компоненты ## 🎨 Основные компоненты
### TimeFrameSlider ### TimeFrameSlider
Главный виджет приложения, объединяющий круговую временную шкалу и карусель событий. Главный виджет приложения, объединяющий круговую временную шкалу и карусель событий.
**Особенности:** **Особенности:**
- Интерактивная круговая диаграмма с периодами - Интерактивная круговая диаграмма с периодами
- Плавные GSAP анимации при переключении - Плавные GSAP анимации при переключении
- Адаптивный дизайн для мобильных, планшетов и десктопа - Адаптивный дизайн для мобильных, планшетов и десктопа
- Кастомная навигация - Кастомная навигация
### CircleTimeline ### CircleTimeline
Круговая временная шкала с точками периодов. Круговая временная шкала с точками периодов.
**Особенности:** **Особенности:**
- Автоматический поворот к активному периоду - Автоматический поворот к активному периоду
- Клик по точкам для переключения - Клик по точкам для переключения
- Анимация заголовков периодов - Анимация заголовков периодов
### EventsCarousel ### EventsCarousel
Карусель исторических событий с использованием Swiper. Карусель исторических событий с использованием Swiper.
**Особенности:** **Особенности:**
- Адаптивное количество слайдов - Адаптивное количество слайдов
- Кастомная навигация - Кастомная навигация
- Плавная анимация появления/исчезновения - Плавная анимация появления/исчезновения
@@ -164,6 +453,7 @@ only-task/
-**Babel caching** - кеширование для быстрой пересборки -**Babel caching** - кеширование для быстрой пересборки
**Размер бандла:** **Размер бандла:**
- Uncompressed: ~371 KiB - Uncompressed: ~371 KiB
- Gzipped: ~117 KiB - Gzipped: ~117 KiB
@@ -187,6 +477,7 @@ only-task/
## 🔧 Конфигурация ## 🔧 Конфигурация
### Webpack ### Webpack
- Babel для транспиляции (быстрее ts-loader) - Babel для транспиляции (быстрее ts-loader)
- CSS Modules для изоляции стилей - CSS Modules для изоляции стилей
- SVGR для импорта SVG как React компонентов - SVGR для импорта SVG как React компонентов
@@ -194,11 +485,13 @@ only-task/
- Bundle Analyzer для анализа размера - Bundle Analyzer для анализа размера
### TypeScript ### TypeScript
- Strict mode включен - Strict mode включен
- Path aliases (`@/*``src/*`) - Path aliases (`@/*``src/*`)
- Проверка типов отдельно от сборки - Проверка типов отдельно от сборки
### ESLint ### ESLint
- Правила для React, TypeScript, Jest - Правила для React, TypeScript, Jest
- Prettier интеграция - Prettier интеграция
- Import sorting - Import sorting
@@ -206,6 +499,7 @@ only-task/
## 🤝 Git Hooks ## 🤝 Git Hooks
Pre-push hook автоматически запускает: Pre-push hook автоматически запускает:
1. Type checking 1. Type checking
2. ESLint 2. ESLint
3. Stylelint 3. Stylelint

BIN
assets/gsap-carousel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -40,6 +40,7 @@
"@storybook/addon-webpack5-compiler-babel": "^4.0.0", "@storybook/addon-webpack5-compiler-babel": "^4.0.0",
"@storybook/react": "^8.6.14", "@storybook/react": "^8.6.14",
"@storybook/react-webpack5": "^8.6.14", "@storybook/react-webpack5": "^8.6.14",
"@stylistic/stylelint-plugin": "^4.0.0",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0", "@testing-library/react": "^16.3.0",

25
pnpm-lock.yaml generated
View File

@@ -63,6 +63,9 @@ importers:
'@storybook/react-webpack5': '@storybook/react-webpack5':
specifier: ^8.6.14 specifier: ^8.6.14
version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.2)))(esbuild@0.25.12)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@8.6.14(prettier@3.6.2))(typescript@5.9.3)(webpack-cli@5.1.4) version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.2)))(esbuild@0.25.12)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@8.6.14(prettier@3.6.2))(typescript@5.9.3)(webpack-cli@5.1.4)
'@stylistic/stylelint-plugin':
specifier: ^4.0.0
version: 4.0.0(stylelint@16.25.0(typescript@5.9.3))
'@svgr/webpack': '@svgr/webpack':
specifier: ^8.1.0 specifier: ^8.1.0
version: 8.1.0(typescript@5.9.3) version: 8.1.0(typescript@5.9.3)
@@ -1664,6 +1667,12 @@ packages:
peerDependencies: peerDependencies:
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
'@stylistic/stylelint-plugin@4.0.0':
resolution: {integrity: sha512-CFwt3K4Y/7bygNCLCQ8Sy4Hzgbhxq3BsNW0FIuYxl17HD3ywptm54ocyeiLVRrk5jtz1Zwks7Xr9eiZt8SWHAw==}
engines: {node: ^18.12 || >=20.9}
peerDependencies:
stylelint: ^16.22.0
'@svgr/babel-plugin-add-jsx-attribute@8.0.0': '@svgr/babel-plugin-add-jsx-attribute@8.0.0':
resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==}
engines: {node: '>=14'} engines: {node: '>=14'}
@@ -5224,6 +5233,9 @@ packages:
peerDependencies: peerDependencies:
webpack: ^5.27.0 webpack: ^5.27.0
style-search@0.1.0:
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
stylelint-config-recommended-scss@14.1.0: stylelint-config-recommended-scss@14.1.0:
resolution: {integrity: sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==} resolution: {integrity: sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==}
engines: {node: '>=18.12.0'} engines: {node: '>=18.12.0'}
@@ -7531,6 +7543,17 @@ snapshots:
dependencies: dependencies:
storybook: 8.6.14(prettier@3.6.2) storybook: 8.6.14(prettier@3.6.2)
'@stylistic/stylelint-plugin@4.0.0(stylelint@16.25.0(typescript@5.9.3))':
dependencies:
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
'@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
postcss: 8.5.6
postcss-selector-parser: 7.1.0
postcss-value-parser: 4.2.0
style-search: 0.1.0
stylelint: 16.25.0(typescript@5.9.3)
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)':
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
@@ -11617,6 +11640,8 @@ snapshots:
dependencies: dependencies:
webpack: 5.103.0(esbuild@0.25.12)(webpack-cli@5.1.4) webpack: 5.103.0(esbuild@0.25.12)(webpack-cli@5.1.4)
style-search@0.1.0: {}
stylelint-config-recommended-scss@14.1.0(postcss@8.5.6)(stylelint@16.25.0(typescript@5.9.3)): stylelint-config-recommended-scss@14.1.0(postcss@8.5.6)(stylelint@16.25.0(typescript@5.9.3)):
dependencies: dependencies:
postcss-scss: 4.0.9(postcss@8.5.6) postcss-scss: 4.0.9(postcss@8.5.6)

View File

@@ -46,8 +46,12 @@ const {
module.exports = { module.exports = {
extends: 'stylelint-config-standard-scss', extends: 'stylelint-config-standard-scss',
plugins: ['stylelint-order'], plugins: [
'stylelint-order',
'@stylistic/stylelint-plugin',
],
rules: { rules: {
'@stylistic/indentation': 2,
'selector-class-pattern': null, 'selector-class-pattern': null,
'order/order': selectorOrdering, 'order/order': selectorOrdering,
'order/properties-order': propertyOrdering, 'order/properties-order': propertyOrdering,