feat: добавлены анимации загрузки и переходов между разделами
- Добавлен полноэкранный индикатор загрузки с размытием фона (LoadingOverlay) - Реализован глобальный контекст загрузки для отслеживания переходов между страницами - Добавлены плавные fade-анимации при переходах между страницами - Реализованы поочередные (stagger) анимации для карточек: * Карточки дней на странице расписания * Карточки уроков внутри каждого дня * Карточки групп на главной странице - Анимации работают на всех устройствах, включая мобильные - Улучшен компонент Spinner с поддержкой разных размеров - Исправлена ошибка гидратации с вложенными <li> элементами в навигации - Оптимизированы задержки анимаций для более быстрого отображения контента
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import React from 'react'
|
||||
import type { Day as DayType } from '@/shared/model/day'
|
||||
import { getDayOfWeek } from '@/shared/utils'
|
||||
import { Lesson } from '@/widgets/schedule/lesson'
|
||||
@@ -48,9 +49,10 @@ export function Day({ day }: {
|
||||
<div className='snap-start hidden md:block' style={{ flex: '0 0 3rem' }} />
|
||||
{day.lessons.map((lesson, i) => (
|
||||
<Lesson
|
||||
key={i}
|
||||
width={longNames ? 450 : 350}
|
||||
lesson={lesson}
|
||||
key={i}
|
||||
lesson={lesson}
|
||||
animationDelay={i * 0.08}
|
||||
/>
|
||||
))}
|
||||
<div className='snap-start hidden md:block' style={{ flex: `0 0 calc(100vw - 4rem - ${longNames ? 450 : 350}px - 1rem)` }} />
|
||||
|
||||
@@ -50,7 +50,15 @@ export function Schedule({ days }: {
|
||||
return (
|
||||
<div className="flex flex-col p-4 md:p-8 lg:p-16 gap-6 md:gap-12 lg:gap-14">
|
||||
{days.map((day, i) => (
|
||||
<Day day={day} key={`${group}_day${i}`} />
|
||||
<div
|
||||
key={`${group}_day${i}`}
|
||||
className="stagger-card"
|
||||
style={{
|
||||
animationDelay: `${i * 0.1}s`,
|
||||
} as React.CSSProperties}
|
||||
>
|
||||
<Day day={day} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -22,9 +22,10 @@ import { BsFillGeoAltFill } from 'react-icons/bs'
|
||||
import { RiGroup2Fill } from 'react-icons/ri'
|
||||
import { ResourcesDialog } from '@/widgets/schedule/resources-dialog'
|
||||
|
||||
export function Lesson({ lesson, width = 350 }: {
|
||||
export function Lesson({ lesson, width = 350, animationDelay }: {
|
||||
lesson: LessonType
|
||||
width: number
|
||||
animationDelay?: number
|
||||
}) {
|
||||
const [resourcesDialogOpened, setResourcesDialogOpened] = React.useState(false)
|
||||
|
||||
@@ -63,7 +64,12 @@ export function Lesson({ lesson, width = 350 }: {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className={`w-full ${width === 450 ? 'md:w-[450px] md:min-w-[450px] md:max-w-[450px]' : 'md:w-[350px] md:min-w-[350px] md:max-w-[350px]'} flex flex-col relative overflow-hidden snap-start scroll-ml-16 shrink-0`}>
|
||||
<Card
|
||||
className={`w-full ${width === 450 ? 'md:w-[450px] md:min-w-[450px] md:max-w-[450px]' : 'md:w-[350px] md:min-w-[350px] md:max-w-[350px]'} flex flex-col relative overflow-hidden snap-start scroll-ml-16 shrink-0 stagger-card`}
|
||||
style={animationDelay !== undefined ? {
|
||||
animationDelay: `${animationDelay}s`,
|
||||
} as React.CSSProperties : undefined}
|
||||
>
|
||||
{lesson.isChange && <div className='absolute top-0 left-0 w-full h-full bg-gradient-to-br from-[#ffc60026] to-[#95620026] pointer-events-none'></div>}
|
||||
<CardHeader>
|
||||
<div className='flex gap-2 md:gap-4'>
|
||||
|
||||
Reference in New Issue
Block a user