разбила на части иконку человека/экран welcome

This commit is contained in:
Tatyana 2025-08-12 12:40:45 +03:00
parent d1827da97a
commit f6439c5647
3 changed files with 316 additions and 209 deletions

View File

@ -1,4 +0,0 @@
<svg width="178" height="180" viewBox="0 0 178 180" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M118.667 9.91528C121.38 9.91542 123.643 12.1872 123.643 14.927V27.1047L124.175 27.1536C134.077 28.0763 141.367 31.5011 146.366 36.842C151.369 42.1874 154.135 49.513 154.869 58.3401L154.871 58.3528C155.054 60.0693 153.575 61.6604 151.745 61.6604H26.2546C24.5046 61.6603 23.0064 60.1434 23.1306 58.3303C23.8658 49.5074 26.6319 42.1855 31.6335 36.842C36.6329 31.5011 43.9227 28.0763 53.825 27.1536L54.3562 27.1047V14.927C54.3563 12.1872 56.6193 9.91551 59.3328 9.91528C62.0464 9.91528 64.3093 12.1871 64.3093 14.927V26.7083H113.69V14.927C113.69 12.1871 115.953 9.91528 118.667 9.91528Z" fill="white" stroke="white" stroke-width="1.17201"/>
<path d="M29.6675 74.0277H148.333C152.086 74.0277 155.165 77.1208 155.165 80.9056V126.881C155.165 137.988 152.405 147.154 146.512 153.54C140.627 159.918 131.533 163.614 118.667 163.614H59.3335C46.4675 163.614 37.3735 159.918 31.4888 153.54C25.5961 147.154 22.8364 137.988 22.8364 126.881V80.9056C22.8364 77.1208 25.9154 74.0277 29.6675 74.0277ZM66.0874 123.206C64.1626 122.399 61.9224 122.399 59.9976 123.206C59.0441 123.606 58.1723 124.166 57.3833 124.88L57.3657 124.896L57.3501 124.912C55.9194 126.432 55.0396 128.514 55.0396 130.614C55.0396 132.713 55.9194 134.795 57.3501 136.315L57.3657 136.331L57.3833 136.347C58.1723 137.062 59.0442 137.621 59.9976 138.021C60.9476 138.419 61.989 138.663 63.0425 138.663C64.096 138.663 65.1373 138.419 66.0874 138.021C67.0408 137.621 67.9127 137.062 68.7017 136.347L68.7183 136.331L68.7349 136.315C70.1656 134.795 71.0444 132.713 71.0444 130.614C71.0444 128.514 70.1656 126.432 68.7349 124.912L68.7183 124.896L68.7017 124.88L68.4019 124.62C67.6934 124.028 66.9217 123.556 66.0874 123.206ZM66.0874 97.0834C64.1626 96.2763 61.9224 96.2764 59.9976 97.0834C59.0442 97.4831 58.1723 98.0427 57.3833 98.7572L57.3599 98.7777L57.3394 98.8011C56.6295 99.595 56.0741 100.472 55.6772 101.43C55.2817 102.385 55.0396 103.432 55.0396 104.491C55.0396 105.549 55.2817 106.596 55.6772 107.551C56.0741 108.51 56.6295 109.386 57.3394 110.18L57.3599 110.203L57.3833 110.224C58.1723 110.939 59.0442 111.498 59.9976 111.898C60.9476 112.296 61.989 112.54 63.0425 112.54C64.096 112.54 65.1373 112.296 66.0874 111.898C67.0408 111.498 67.9127 110.939 68.7017 110.224L68.7241 110.203L68.7446 110.18C69.4545 109.386 70.0099 108.51 70.4067 107.551C70.8023 106.596 71.0444 105.549 71.0444 104.491C71.0444 103.432 70.8023 102.385 70.4067 101.43C70.0098 100.472 69.4546 99.595 68.7446 98.8011L68.7241 98.7777L68.7017 98.7572L68.4019 98.4965C67.6934 97.9052 66.9217 97.4332 66.0874 97.0834ZM92.0444 97.0834C90.2342 96.255 88.1465 96.2052 86.3032 96.9349L85.9556 97.0834C85.0021 97.4832 84.1303 98.0426 83.3413 98.7572L83.3237 98.7728L83.3081 98.7894C81.8774 100.309 80.9976 102.391 80.9976 104.491C80.9976 106.59 81.8774 108.672 83.3081 110.192L83.3237 110.208L83.3413 110.224C84.1303 110.939 85.0021 111.498 85.9556 111.898C86.9057 112.296 87.9469 112.54 89.0005 112.54C90.0541 112.54 91.0953 112.296 92.0454 111.898C92.9989 111.498 93.8707 110.939 94.6597 110.224L94.6772 110.208L94.6929 110.192C96.1236 108.672 97.0034 106.59 97.0034 104.491C97.0034 102.391 96.1236 100.309 94.6929 98.7894L94.6772 98.7728L94.6597 98.7572L94.3599 98.4965C93.6514 97.9053 92.8797 97.4332 92.0454 97.0834H92.0444Z" fill="white" stroke="white" stroke-width="1.17201"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,235 +1,111 @@
"use client" "use client"
import type React from "react"
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
// import { useIonRouter } from '@ionic/react';
export default function Welcome() { const CourseComplete: React.FC = () => {
const [animationPhase, setAnimationPhase] = useState(0) const [animationPhase, setAnimationPhase] = useState(0)
const [displayedTitle, setDisplayedTitle] = useState("")
const [displayedSubtitle, setDisplayedSubtitle] = useState("")
const [loaderWidth, setLoaderWidth] = useState(0) // Изначально 0 для анимации слева направо
const fullTitle = "Реабилитация"
const fullSubtitle = "Восстановление через движение"
useEffect(() => { useEffect(() => {
// Phase 1: App name appears, ball appears (after 0.2s) const timer1 = setTimeout(() => setAnimationPhase(1), 500)
const timer1 = setTimeout(() => setAnimationPhase(1), 700) const timer2 = setTimeout(() => setAnimationPhase(2), 1000)
// Phase 2: Limbs start growing (after 0.7s) const timer3 = setTimeout(() => setAnimationPhase(3), 1500)
// Limb growth animation is 2s, so it finishes at 0.7s + 2s = 2.7s const timer4 = setTimeout(() => setAnimationPhase(3), 2000)
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 () => { return () => {
clearTimeout(timer1) clearTimeout(timer1)
clearTimeout(timer2) clearTimeout(timer2)
clearTimeout(timer3) clearTimeout(timer3)
clearTimeout(timer4) clearTimeout(timer4)
clearTimeout(timer5)
} }
}, []) }, [])
useEffect(() => {
if (animationPhase >= 1) {
setDisplayedTitle(fullTitle) // Заголовок появляется мгновенно
}
if (animationPhase >= 4) { // Подзаголовок и лоадер появляются в фазе 4
setDisplayedSubtitle(fullSubtitle) // Подзаголовок появляется целиком
setLoaderWidth(100) // Лоадер анимируется до полной ширины
}
}, [animationPhase]) // Зависимость от animationPhase
// const router = useIonRouter()
// useEffect(() => {
// const timer = setTimeout(() => {
// router.push("/home", "forward")
// }, 5000) // Задержка 3 секунды
// return () => clearTimeout(timer)
// }, [router])
return ( return (
<div className="min-h-screen relative overflow-hidden">
{/* Background and particles */}
<div className="absolute inset-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C]">
{/* 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 */
/> <div className="min-h-screen bg-gradient-to-br from-[#3ABBC7] to-[#0D212C] flex items-center justify-center">
</g> {/* Men Animation */}
{/* Правая рука (волнообразная вверх) - 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 */
/> <div className="min-h-screen p-4 relative overflow-hidden max-w-4xl mx-auto">
{/* Левая нога - длиннее */} <div className="absolute inset-0 flex items-start justify-center pt-30">
<rect {/* тело */}
x={24} <div className="absolute top-20 left-1/2 transform -translate-x-1/2">
y={40} /* Начало от нижней части туловища */ <svg xmlns="http://www.w3.org/2000/svg" width="109" height="166" viewBox="0 0 109 166" fill="none">
width={6} <rect width="109" height="166" rx="39" fill="#F3945B" />
height={20} </svg>
rx={3} </div>
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 top-80 left-[20%] transform -translate-y-1/2">
<div <svg xmlns="http://www.w3.org/2000/svg" width="292" height="221" viewBox="0 0 292 221" fill="none">
className={`absolute rounded-full bg-[#FFA500] w-[2.7rem] h-[2.7rem] z-20 transition-opacity duration-200 <path d="M26 78.0571C43.5001 101.057 67.9999 122.5 111 129C154 135.5 164 119.557 202.5 138.557C241 157.557 248.5 188.057 252 203.057C255.5 218.057 270 221.057 277.5 220.057C285 219.057 289.5 212.557 291 206.057C292.5 199.557 287.5 159.557 246.5 121.557C205.5 83.5571 174 95.0575 114.5 89.5571C55.0001 84.0568 39.5 24.0576 34 9.55715C28.5001 -4.94333 -1.70972e-05 -2.94326 0 15.5571C1.70972e-05 34.0576 8.49988 55.0571 26 78.0571Z" fill="black" />
${animationPhase >= 1 ? 'opacity-100' : 'opacity-0'} </svg>
${animationPhase >= 3 ? 'ball-toss-active' : ''} </div>
${animationPhase >= 5 ? 'ball-bounce-active' : ''}
`} {/* нога 1 */}
style={{ <div className="absolute bottom-[ -20px ] left-[ calc(50% -60px) ] w-[37px] h-[129px]">
// Adjusted initial position using vh/vw for better responsiveness <svg xmlns="http://www.w3.org/2000/svg" width="37" height="129" viewBox="0 0 37 129" fill="none">
top: 'calc(50% - 20vh)', // Примерно 20% высоты вьюпорта выше центра <rect width="37" height="129" rx="18.5" fill="#F3945B" />
left: '50%', // Примерно 3.8% ширины вьюпорта левее центра </svg>
transform: 'translate(-50%, -50%)', // Центрирует сам div относительно его top/left </div>
}}
/> {/* нога 2 */}
{/* Main Content */} <div className="absolute bottom-[ -20px ] right-[ calc(50% -60px) ] w-[37px] h-[178px]">
<div className="flex items-center justify-center min-h-screen"> <svg xmlns="http://www.w3.org/2000/svg" width="37" height="178" viewBox="0 0 37 178" fill="none">
<div className="text-center px-8 z-10"> <rect width="37" height="178" rx="18.5" fill="#F3945B" />
{/* App Name */} </svg>
<div </div>
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">{displayedTitle}</h1> <div className="absolute top-2.5 left-1/2 transform -translate-x-1/2">
{/* Line Loader - now appears with subtitle in phase 4, and grows from left to right */} <svg xmlns="http://www.w3.org/2000/svg" width="75" height="75" viewBox="0 0 75 75" fill="none">
<circle cx={37.5} cy={37.5} r={37.5} fill="#F3945B" />
</svg>
</div>
{/* мяч */}
<div className='absolute top-[-10px] left-1/2 transform -translate-x-1/2'>
<svg xmlns='http://www.w3.org/2000/svg' width='54' height='54' viewBox='0 0 54 54' fill='none'>
<circle cx='27' cy='27' r='27' fill='#F3945B' />
</svg>
</div>
</div>
<div className="text-center z-10 max-w-md">
{/* Main Content */}
<div className="flex items-center justify-center min-h-screen">
<div className="text-center px-8 z-10">
{/* App Name */}
<div <div
className={`h-1 bg-white/70 rounded-full mx-auto my-2 transition-all duration-500 ease-out`} className={`transition-opacity duration-1000 delay-100 ${animationPhase >= 1 ? "opacity-100" : "opacity-0"}`}
style={{ width: `${loaderWidth}%`, maxWidth: '340px', opacity: animationPhase >= 4 ? 1 : 0 }} >
></div> <h1 className="text-5xl font-black text-white mb-4 tracking-tight filter drop-shadow-lg">Реабилитация</h1>
{/* Subtitle - appears with opacity transition in phase 4 */} {/* Line Loader - now appears with subtitle in phase 4, and grows from left to right */}
<p className={`text-white/90 text-xl font-medium tracking-wide transition-opacity duration-1000 ${animationPhase >= 4 ? 'opacity-100' : 'opacity-0'}`}> <div
{displayedSubtitle} className="h-1 bg-white/70 rounded-full mx-auto my-2 transition-all duration-500 ease-out"
</p> style={{
width: animationPhase >= 3 ? '320px' : '0px', // или начальное значение
maxWidth: '320px',
opacity: animationPhase >= 3 ? 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 >= 1 ? 'opacity-100' : 'opacity-0'}`}>
Восстановление через движение
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div >
) )
} }
export default CourseComplete

235
src/pages/WelcomeOld.tsx Normal file
View File

@ -0,0 +1,235 @@
"use client"
import { useEffect, useState } from "react"
// import { useIonRouter } from '@ionic/react';
export default function Welcome() {
const [animationPhase, setAnimationPhase] = useState(0)
const [displayedTitle, setDisplayedTitle] = useState("")
const [displayedSubtitle, setDisplayedSubtitle] = useState("")
const [loaderWidth, setLoaderWidth] = useState(0) // Изначально 0 для анимации слева направо
const fullTitle = "Реабилитация"
const fullSubtitle = "Восстановление через движение"
useEffect(() => {
// 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(timer5)
}
}, [])
useEffect(() => {
if (animationPhase >= 1) {
setDisplayedTitle(fullTitle) // Заголовок появляется мгновенно
}
if (animationPhase >= 4) { // Подзаголовок и лоадер появляются в фазе 4
setDisplayedSubtitle(fullSubtitle) // Подзаголовок появляется целиком
setLoaderWidth(100) // Лоадер анимируется до полной ширины
}
}, [animationPhase]) // Зависимость от animationPhase
// const router = useIonRouter()
// useEffect(() => {
// const timer = setTimeout(() => {
// router.push("/home", "forward")
// }, 5000) // Задержка 3 секунды
// return () => clearTimeout(timer)
// }, [router])
return (
<div className="min-h-screen relative overflow-hidden">
{/* Background and particles */}
<div className="absolute inset-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C]">
{/* 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 */
/>
</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 */
/>
{/* Левая нога - длиннее */}
<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 px-8 z-10">
{/* App Name */}
<div
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">{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: '340px', 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>
</div>
</div>
)
}