начальная анимация на загрузку
This commit is contained in:
parent
841bf404ec
commit
cc145c8804
@ -1,133 +0,0 @@
|
||||
"use client"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useHistory } from "react-router-dom"
|
||||
|
||||
export default function Welcome() {
|
||||
const history = useHistory()
|
||||
const [animationPhase, setAnimationPhase] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const timer1 = setTimeout(() => setAnimationPhase(1), 500)
|
||||
const timer2 = setTimeout(() => setAnimationPhase(2), 1500)
|
||||
const timer3 = setTimeout(() => setAnimationPhase(3), 2500)
|
||||
// const timer4 = setTimeout(() => history.push("/login"), 4000) // Раскомментируйте при необходимости
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer1)
|
||||
clearTimeout(timer2)
|
||||
clearTimeout(timer3)
|
||||
// clearTimeout(timer4)
|
||||
}
|
||||
}, [history])
|
||||
|
||||
return (
|
||||
<div className="min-h-screen relative overflow-hidden">
|
||||
{/* Фон и частицы */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C]">
|
||||
{/* floating particles */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-20 left-10 w-32 h-32 bg-white/5 rounded-full animate-pulse blur-xl"></div>
|
||||
<div className="absolute bottom-32 right-16 w-24 h-24 bg-white/10 rounded-full animate-bounce blur-lg"></div>
|
||||
<div className="absolute top-1/2 left-1/4 w-16 h-16 bg-white/5 rounded-full animate-ping blur-md"></div>
|
||||
<div className="absolute top-1/3 right-1/3 w-20 h-20 bg-white/5 rounded-full animate-pulse blur-lg"></div>
|
||||
</div>
|
||||
|
||||
{/* Основной контент */}
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-center z-10 px-8">
|
||||
{/* Заголовки и загрузка */}
|
||||
{/* ... ваш существующий код ... */}
|
||||
{/* SVG с анимацией конечностей */}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 64 64"
|
||||
className="h-[30rem] lg:h-[50rem] w-auto z-50 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
||||
>
|
||||
{/* Группа с зеркальным отражением всего, кроме рук */}
|
||||
<g transform="translate(64, 0) scale(-1, 1)">
|
||||
{/* Голова */}
|
||||
<circle cx={32} cy={12} r={6} fill="#000" />
|
||||
|
||||
{/* Тело */}
|
||||
<rect x={24} y={20} width={16} height={24} fill="#000" rx={2} />
|
||||
|
||||
{/* Левая рука (смотрит вниз) */}
|
||||
<path
|
||||
d="M34,26 Q51,16 40,3"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
strokeWidth={6}
|
||||
strokeLinecap="round"
|
||||
className={`limb`}
|
||||
style={{ '--length': '70' }}
|
||||
/>
|
||||
|
||||
{/* Правая рука (волнообразная вверх) */}
|
||||
<path
|
||||
d="M26,23 Q16,34 18,32"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
strokeWidth={6}
|
||||
strokeLinecap="round"
|
||||
className={`limb`}
|
||||
style={{ '--length': '60' }}
|
||||
/>
|
||||
|
||||
{/* Левая нога - длиннее */}
|
||||
<rect
|
||||
x={24}
|
||||
y={40}
|
||||
width={6}
|
||||
height={20}
|
||||
rx={3}
|
||||
className={`limb`}
|
||||
style={{ '--length': '60' }}
|
||||
/>
|
||||
|
||||
{/* Правая нога - длиннее */}
|
||||
<rect
|
||||
x={34}
|
||||
y={40}
|
||||
width={6}
|
||||
height={13}
|
||||
rx={3}
|
||||
className={`limb`}
|
||||
style={{ '--length': '50' }}
|
||||
/>
|
||||
</g>
|
||||
{/* Внутри SVG добавим стили для анимации линий */}
|
||||
<style>
|
||||
{`
|
||||
.limb {
|
||||
stroke-dasharray: var(--length);
|
||||
stroke-dashoffset: var(--length);
|
||||
opacity: 0;
|
||||
animation: growLine 2s forwards;
|
||||
/* Все начинают одновременно */
|
||||
}
|
||||
/* Можно оставить задержки равными нулю или убрать их */
|
||||
`}
|
||||
</style>
|
||||
{/* Анимация для всех элементов одновременно */}
|
||||
<defs>
|
||||
<style>
|
||||
{`
|
||||
@keyframes growLine {
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.limb {
|
||||
animation-delay: 0s; /* все начинают сразу */
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,75 +1,219 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import { useHistory } from "react-router-dom"
|
||||
import manImage from "../assets/man.svg" // Reverted to original import
|
||||
|
||||
export default function Welcome() {
|
||||
const history = useHistory()
|
||||
const [animationPhase, setAnimationPhase] = useState(0)
|
||||
const [displayedTitle, setDisplayedTitle] = useState("")
|
||||
const [displayedSubtitle, setDisplayedSubtitle] = useState("")
|
||||
const [loaderWidth, setLoaderWidth] = useState(0) // Изначально 0 для анимации слева направо
|
||||
|
||||
const fullTitle = "Реабилитация"
|
||||
const fullSubtitle = "Восстановление через движение"
|
||||
|
||||
useEffect(() => {
|
||||
const timer1 = setTimeout(() => setAnimationPhase(1), 500)
|
||||
const timer2 = setTimeout(() => setAnimationPhase(2), 1500)
|
||||
const timer3 = setTimeout(() => setAnimationPhase(3), 2500)
|
||||
// const timer4 = setTimeout(() => history.push("/login"), 4000) // Uncomment if you want auto-redirect
|
||||
// Phase 1: App name appears, ball appears (after 0.2s)
|
||||
const timer1 = setTimeout(() => setAnimationPhase(1), 700)
|
||||
// Phase 2: Limbs start growing (after 0.7s)
|
||||
// Limb growth animation is 2s, so it finishes at 0.7s + 2s = 2.7s
|
||||
const timer2 = setTimeout(() => setAnimationPhase(2), 700)
|
||||
// Phase 3: SVG rotates, ball tosses (after 1.7s, when limbs are fully grown)
|
||||
const timer3 = setTimeout(() => setAnimationPhase(3), 1700)
|
||||
// Phase 4: Subtitle and Loader appear (after ball toss finishes)
|
||||
// Ball toss animation is 1.2s with 0.1s delay, so it finishes around 1.7s + 0.1s + 1.2s = 3.0s
|
||||
// Starting Phase 4 at 3.1s ensures ball is completely gone
|
||||
const timer4 = setTimeout(() => setAnimationPhase(4), 3100) // Запускаем фазу 4 после исчезновения мяча
|
||||
// Phase 5: Ball starts bouncing (after subtitle and loader appear, e.g., 3.1s + 1s for subtitle opacity = 4.1s, so start at 4.2s)
|
||||
const timer5 = setTimeout(() => setAnimationPhase(5), 3100)
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer1)
|
||||
clearTimeout(timer2)
|
||||
clearTimeout(timer3)
|
||||
// clearTimeout(timer4)
|
||||
clearTimeout(timer4)
|
||||
clearTimeout(timer5)
|
||||
}
|
||||
}, [history])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (animationPhase >= 1) {
|
||||
setDisplayedTitle(fullTitle) // Заголовок появляется мгновенно
|
||||
}
|
||||
if (animationPhase >= 4) { // Подзаголовок и лоадер появляются в фазе 4
|
||||
setDisplayedSubtitle(fullSubtitle) // Подзаголовок появляется целиком
|
||||
setLoaderWidth(100) // Лоадер анимируется до полной ширины
|
||||
}
|
||||
}, [animationPhase]) // Зависимость от animationPhase
|
||||
|
||||
return (
|
||||
<div className="min-h-screen relative overflow-hidden">
|
||||
<img
|
||||
className="h-[30rem] lg:h-[50rem] w-auto z-50 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 opacity-15"
|
||||
src={manImage || "/placeholder.svg"} // Reverted to original img tag and src
|
||||
alt="Man illustration"
|
||||
/>
|
||||
{/* Uncomment and update path for emblemImage if needed */}
|
||||
{/* <img
|
||||
className="h-[30rem] lg:h-[0rem] w-auto z-50 absolute right-0 bottom-0 transform opacity-10"
|
||||
src={emblemImage || "/placeholder.svg"} // Reverted to original img tag and src
|
||||
alt="Emblem"
|
||||
/> */}
|
||||
{/* Background and particles */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C]">
|
||||
{/* Floating particles */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-20 left-10 w-32 h-32 bg-white/5 rounded-full animate-pulse blur-xl"></div>
|
||||
<div className="absolute bottom-32 right-16 w-24 h-24 bg-white/10 rounded-full animate-bounce blur-lg"></div>
|
||||
<div className="absolute top-1/2 left-1/4 w-16 h-16 bg-white/5 rounded-full animate-ping blur-md"></div>
|
||||
<div className="absolute top-1/3 right-1/3 w-20 h-20 bg-white/5 rounded-full animate-pulse blur-lg"></div>
|
||||
</div>
|
||||
{/* SVG with animated figure */}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 -10 64 74" /* Adjusted viewBox to prevent clipping */
|
||||
className={`h-[30rem] lg:h-[50rem] w-auto absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-0 ${animationPhase >= 3 ? 'svg-rotate-active' : ''}`}
|
||||
>
|
||||
<defs>
|
||||
<style>{`
|
||||
/* SVG Rotation */
|
||||
@keyframes svgRotate {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(30deg); }
|
||||
}
|
||||
.svg-rotate-active {
|
||||
animation: svgRotate 0.8s ease-out forwards; /* Faster rotation */
|
||||
}
|
||||
/* Limb growth animation for ARMS (paths) */
|
||||
.arm-limb {
|
||||
stroke-dasharray: var('--length');
|
||||
stroke-dashoffset: var('--length'); /* Initially hidden */
|
||||
}
|
||||
.arm-limb.limb-grow-active {
|
||||
animation: drawLine 0.5s linear forwards; /* 2s linear для синхронизации */
|
||||
}
|
||||
@keyframes drawLine {
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
/* Limb growth animation for LEGS (rects) */
|
||||
.leg-limb {
|
||||
transform-origin: top; /* Рост от верхней части (туловища) */
|
||||
transform: scaleY(0); /* Initially hidden */
|
||||
}
|
||||
.leg-limb.limb-grow-active {
|
||||
animation: growRect 0.4s linear forwards; /* 2s linear для синхронизации */
|
||||
}
|
||||
@keyframes growRect {
|
||||
from {
|
||||
transform: scaleY(0);
|
||||
}
|
||||
to {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
/* Counter-rotation for the tossing arm's group */
|
||||
@keyframes counterRotateArm {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(-5deg); } /* Уменьшен угол наклона руки */
|
||||
}
|
||||
.tossing-arm-counter-rotate {
|
||||
animation: counterRotateArm 0.8s ease-out forwards; /* Faster counter-rotation */
|
||||
transform-origin: 34px 26px;
|
||||
}
|
||||
/* Ball animation */
|
||||
.ball-toss-active {
|
||||
animation: tossBall 1.2s ease-out forwards; /* Увеличена длительность для плавности */
|
||||
animation-delay: 0.1s; /* Небольшая задержка после поворота руки */
|
||||
}
|
||||
@keyframes tossBall {
|
||||
0% { transform: translate(-50%, -50%) scale(1,1); opacity: 0; } /* Начальное положение, центрирование */
|
||||
10% { transform: translate(-50%, -50%) scale(1); opacity: 1; } /* Начальное положение, центрирование */
|
||||
25% { transform: translate(calc(-50% + 30px), calc(-50% - 80px)) scale(1.1); opacity: 1; } /* Бросок вверх и вправо */
|
||||
50% { transform: translate(calc(-50% + 40px), calc(-50% + 150px)) scale(1); opacity: 1; } /* Отскок вниз к ногам (имитация пола) */
|
||||
70% { transform: translate(calc(-50% + 40px), calc(-50% + 150px)) scale(5); opacity: 1; } /* Начинает лететь на пользователя, увеличиваясь */
|
||||
100% { transform: translate(calc(-50% + 40px), calc(-50% + 150px)) scale(200); opacity: 0; } /* Полностью летит на пользователя, исчезает */
|
||||
}
|
||||
/* New: Ball bounce animation */
|
||||
@keyframes bounceBall {
|
||||
0%, 100% { transform: translate(-50%, -50%) translateY(0); }
|
||||
50% { transform: translate(-50%, -52%) translateY(-45px); } /* Adjust bounce height as needed */
|
||||
}
|
||||
.ball-bounce-active {
|
||||
animation: bounceBall 0.8s ease-in-out infinite alternate; /* Smooth bounce, infinite, alternating */
|
||||
}
|
||||
`}</style>
|
||||
</defs>
|
||||
{/* Group with mirror transform for the human figure */}
|
||||
<g transform="translate(64, 0) scale(-1, 1)">
|
||||
{/* Голова */}
|
||||
<circle cx={32} cy={12} r={6} fill="#1A3A4A" />
|
||||
{/* Тело */}
|
||||
<rect x={24} y={20} width={16} height={24} fill="#1A3A4A" rx={2} />
|
||||
{/* Левая рука (смотрит вниз) - THIS IS THE TOSSING ARM AFTER MIRRORING */}
|
||||
{/* Wrapped in a new group for counter-rotation */}
|
||||
<g className={`${animationPhase >= 3 ? 'tossing-arm-counter-rotate' : ''}`}>
|
||||
<path
|
||||
d="M34,26 Q51,16 40,3"
|
||||
fill="none"
|
||||
stroke="#1A3A4A"
|
||||
strokeWidth={6}
|
||||
strokeLinecap="round"
|
||||
className={`arm-limb ${animationPhase >= 2 ? 'limb-grow-active' : ''}`} /* Apply active class when phase 2 starts */
|
||||
style={{ '--length': '70' }}
|
||||
/>
|
||||
</g>
|
||||
{/* Правая рука (волнообразная вверх) - This arm will remain static after growth */}
|
||||
<path
|
||||
d="M26,23 Q16,34 18,32"
|
||||
fill="none"
|
||||
stroke="#1A3A4A"
|
||||
strokeWidth={6}
|
||||
strokeLinecap="round"
|
||||
className={`arm-limb ${animationPhase >= 2 ? 'limb-grow-active' : ''}`} /* Apply active class when phase 2 starts */
|
||||
style={{ '--length': '60' }}
|
||||
/>
|
||||
{/* Левая нога - длиннее */}
|
||||
<rect
|
||||
x={24}
|
||||
y={40} /* Начало от нижней части туловища */
|
||||
width={6}
|
||||
height={20}
|
||||
rx={3}
|
||||
fill="#1A3A4A"
|
||||
className={`leg-limb ${animationPhase >= 2 ? 'limb-grow-active' : ''}`} /* Apply active class when phase 2 starts */
|
||||
/>
|
||||
{/* Правая нога - длиннее */}
|
||||
<rect
|
||||
x={34}
|
||||
y={40} /* Начало от нижней части туловища */
|
||||
width={6}
|
||||
height={13}
|
||||
rx={3}
|
||||
fill="#1A3A4A"
|
||||
className={`leg-limb ${animationPhase >= 2 ? 'limb-grow-active' : ''}`} /* Apply active class when phase 2 starts */
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
{/* Ball - now a separate div for absolute positioning */}
|
||||
<div
|
||||
className={`absolute rounded-full bg-[#FFA500] w-[2.7rem] h-[2.7rem] z-20 transition-opacity duration-200
|
||||
${animationPhase >= 1 ? 'opacity-100' : 'opacity-0'}
|
||||
${animationPhase >= 3 ? 'ball-toss-active' : ''}
|
||||
${animationPhase >= 5 ? 'ball-bounce-active' : ''}
|
||||
`}
|
||||
style={{
|
||||
// Adjusted initial position using vh/vw for better responsiveness
|
||||
top: 'calc(50% - 20vh)', // Примерно 20% высоты вьюпорта выше центра
|
||||
left: '50%', // Примерно 3.8% ширины вьюпорта левее центра
|
||||
transform: 'translate(-50%, -50%)', // Центрирует сам div относительно его top/left
|
||||
}}
|
||||
/>
|
||||
{/* Main Content */}
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-center z-10 px-8">
|
||||
<div className="text-center px-8 z-10">
|
||||
{/* App Name */}
|
||||
<div
|
||||
className={`transition-all duration-1000 delay-300 ${
|
||||
animationPhase >= 1 ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
||||
}`}
|
||||
className={`transition-opacity duration-1000 delay-100 ${animationPhase >= 1 ? "opacity-100" : "opacity-0"}`}
|
||||
>
|
||||
<h1 className="text-5xl font-black text-white mb-4 tracking-tight filter drop-shadow-lg">Реабилитация</h1>
|
||||
<p className="text-white/90 text-xl font-medium tracking-wide">Восстановление через движение</p>
|
||||
</div>
|
||||
{/* Loading indicator */}
|
||||
<div
|
||||
className={`mt-16 transition-all duration-500 delay-700 ${
|
||||
animationPhase >= 1 ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
>
|
||||
<div className="w-64 h-3 bg-white/10 rounded-full mx-auto overflow-hidden backdrop-blur-sm border border-white/20">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-white via-white/80 to-white rounded-full shadow-lg"
|
||||
style={{
|
||||
width: `${Math.min((animationPhase + 1) * 25, 100)}%`,
|
||||
transition: "width 0.8s cubic-bezier(0.4, 0, 0.2, 1)",
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<p className="text-white/70 text-lg mt-6 font-medium">Загрузка...</p>
|
||||
<h1 className="text-5xl font-black text-white mb-4 tracking-tight filter drop-shadow-lg">{displayedTitle}</h1>
|
||||
{/* Line Loader - now appears with subtitle in phase 4, and grows from left to right */}
|
||||
<div
|
||||
className={`h-1 bg-white/70 rounded-full mx-auto my-2 transition-all duration-500 ease-out`}
|
||||
style={{ width: `${loaderWidth}%`, maxWidth: '200px', opacity: animationPhase >= 4 ? 1 : 0 }}
|
||||
></div>
|
||||
{/* Subtitle - appears with opacity transition in phase 4 */}
|
||||
<p className={`text-white/90 text-xl font-medium tracking-wide transition-opacity duration-1000 ${animationPhase >= 4 ? 'opacity-100' : 'opacity-0'}`}>
|
||||
{displayedSubtitle}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
79
src/pages/WelcomeOld.tsx
Normal file
79
src/pages/WelcomeOld.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
"use client"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useHistory } from "react-router-dom"
|
||||
import manImage from "../assets/man.svg" // Reverted to original import
|
||||
|
||||
export default function Welcome() {
|
||||
const history = useHistory()
|
||||
const [animationPhase, setAnimationPhase] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const timer1 = setTimeout(() => setAnimationPhase(1), 500)
|
||||
const timer2 = setTimeout(() => setAnimationPhase(2), 1500)
|
||||
const timer3 = setTimeout(() => setAnimationPhase(3), 2500)
|
||||
// const timer4 = setTimeout(() => history.push("/login"), 4000) // Uncomment if you want auto-redirect
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer1)
|
||||
clearTimeout(timer2)
|
||||
clearTimeout(timer3)
|
||||
// clearTimeout(timer4)
|
||||
}
|
||||
}, [history])
|
||||
|
||||
return (
|
||||
<div className="min-h-screen relative overflow-hidden">
|
||||
<img
|
||||
className="h-[30rem] lg:h-[50rem] w-auto z-50 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 opacity-15"
|
||||
src={manImage || "/placeholder.svg"} // Reverted to original img tag and src
|
||||
alt="Man illustration"
|
||||
/>
|
||||
{/* Uncomment and update path for emblemImage if needed */}
|
||||
{/* <img
|
||||
className="h-[30rem] lg:h-[0rem] w-auto z-50 absolute right-0 bottom-0 transform opacity-10"
|
||||
src={emblemImage || "/placeholder.svg"} // Reverted to original img tag and src
|
||||
alt="Emblem"
|
||||
/> */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C]">
|
||||
{/* Floating particles */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-20 left-10 w-32 h-32 bg-white/5 rounded-full animate-pulse blur-xl"></div>
|
||||
<div className="absolute bottom-32 right-16 w-24 h-24 bg-white/10 rounded-full animate-bounce blur-lg"></div>
|
||||
<div className="absolute top-1/2 left-1/4 w-16 h-16 bg-white/5 rounded-full animate-ping blur-md"></div>
|
||||
<div className="absolute top-1/3 right-1/3 w-20 h-20 bg-white/5 rounded-full animate-pulse blur-lg"></div>
|
||||
</div>
|
||||
{/* Main Content */}
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-center z-10 px-8">
|
||||
{/* App Name */}
|
||||
<div
|
||||
className={`transition-all duration-1000 delay-300 ${
|
||||
animationPhase >= 1 ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
||||
}`}
|
||||
>
|
||||
<h1 className="text-5xl font-black text-white mb-4 tracking-tight filter drop-shadow-lg">Реабилитация</h1>
|
||||
<p className="text-white/90 text-xl font-medium tracking-wide">Восстановление через движение</p>
|
||||
</div>
|
||||
{/* Loading indicator */}
|
||||
<div
|
||||
className={`mt-16 transition-all duration-500 delay-700 ${
|
||||
animationPhase >= 1 ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
>
|
||||
<div className="w-64 h-3 bg-white/10 rounded-full mx-auto overflow-hidden backdrop-blur-sm border border-white/20">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-white via-white/80 to-white rounded-full shadow-lg"
|
||||
style={{
|
||||
width: `${Math.min((animationPhase + 1) * 25, 100)}%`,
|
||||
transition: "width 0.8s cubic-bezier(0.4, 0, 0.2, 1)",
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<p className="text-white/70 text-lg mt-6 font-medium">Загрузка...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user