Начало
Я решил построить проект с правилом: никаких готовых UI-китов и шаблонов - всё практически с нуля.
Стек
Выбор технологий был простым - последнее время я увлекался документацией Next.js, что и побудило меня сделать свой сайт на нём.
| Слой | Технология |
|---|---|
| Фреймворк | Next.js 15 (App Router) |
| UI | React 19 |
| Язык | TypeScript 5 |
| Стили | Sass + CSS Modules (BEM) |
| i18n | next-intl - EN + RU |
| Контент | MDX + gray-matter |
| 3D | Three.js |
| Анимации | GSAP |
| Карусель | Swiper |
| Иконки | Lucide React |
Архитектура: Feature-Sliced Design (почти)
Изначально я думал, что FSD - это волшебная палочка, которая решит все мои проблемы с расположением компонентов. Но как впоследствии оказалось, в проекте не так много бизнес-сущностей, и это скорее отяготило меня, чем дало какой-либо прирост в DX. Оглядываясь назад, я думаю, что FSD - не та методология, которую стоит использовать для небольших блог-приложений.
Вот как всё устроено:
app/ → маршрутизация, провайдеры, глобальные SEO-метаданные
widgets/ → Header, Footer, PostsFeed - автономные UI-блоки
sections/ → секции страниц
features/ → интерактивная логика (фильтр постов с дебаунсом)
entities/ → модель и API Post (чтение MDX из файловой системы)
shared/ → UI-кит, утилиты, конфиг i18n
Что делает проект интересным
3D-глобус навыков (Three.js)
Секция навыков на странице «Обо мне» - полностью кастомная Three.js-сцена: сфера из иконок технологий на основе SVG-текстур, нанесённых на спрайты.
Взаимодействие: при наведении на узел подсвечиваются его соединения с ближайшими соседями через дуговую геометрию. Клик плавно поворачивает глобус к нужному узлу с помощью анимации.
Производительность управляется явно:
prefers-reduced-motionотключает анимацию по запросу accessibility- Battery API приостанавливает анимацию при заряде ниже 20%
- Низкий
hardwareConcurrencyилиdeviceMemoryтакже снижает нагрузку
Анимированная лента карьерного пути
Секция «Мой путь» на странице «Обо мне» использует scrub-анимацию GSAP ScrollTrigger для управления прогресс-баром и плавающим шариком между карьерными вехами по мере скролла. Ресайз пересчитывает позиции через общую утилиту дебаунса.
Переходы между страницами
PageTransitionProvider рендерит полноэкранный загрузчик через React-портал. Навигация вызывает startTransition(href) вместо прямой ссылки - загрузчик успевает появиться до рендера нового маршрута.
Посты с живым поиском и фильтрацией по тегам
На странице постов - поиск в реальном времени и фильтрация по тегам. Поисковый ввод дебаунсируется (300 мс) через хук useDebounce - фильтрация запускается только после паузы в наборе, без лишних ре-рендеров на каждое нажатие клавиши.
i18n
Каждая видимая строка живёт в src/shared/i18n/locales/en.json и ru.json. Ничего не захардкожено в компонентах - ни лейблы, ни aria-атрибуты, ни плейсхолдеры. next-intl занимается определением локали, маршрутизацией (/en/... и /ru/...) и загрузкой сообщений.
SEO
Каждая страница генерирует собственный объект Metadata через общую утилиту createPageMetadata: канонические URL, hreflang-альтернативы для обеих локалей, Open Graph-теги и полный набор фавиконок.
Запустить локально
pnpm install
pnpm dev
