summaryrefslogtreecommitdiff
path: root/frontend/src/components/LoadingScreen.tsx
blob: 5f33d000597e721f63eb6223ca64a234ac39354e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import React, { useEffect, useState, useRef } from 'react'

type Props = {
  onComplete: () => void
}

export const LoadingScreen: React.FC<Props> = ({ onComplete }) => {
  const [fadeOut, setFadeOut] = useState(false)
  const [mounted, setMounted] = useState(true)
  const [subtitle, setSubtitle] = useState('')
  const [animatedText, setAnimatedText] = useState('')
  const subtitleLoaded = useRef(false)

  useEffect(() => {
    console.log('Loading screen mounted - starting timer...')
    
    // Set fixed subtitle and animate it
    if (!subtitleLoaded.current) {
      subtitleLoaded.current = true
      
      const fixedSubtitle = 'Whisper of the Heart'
      setSubtitle(fixedSubtitle)
      
      // Animate text character by character
      let currentIndex = 0
      const animateText = () => {
        if (currentIndex <= fixedSubtitle.length) {
          setAnimatedText(fixedSubtitle.slice(0, currentIndex))
          currentIndex++
          setTimeout(animateText, 50) // 50ms delay between characters
        }
      }
      
      // Start animation after heart appears (1000ms = 0.2s heart delay + 0.8s heart animation)
      setTimeout(animateText, 1000)
    }
    
    // Start fade after 4 seconds (longer to show ray spinning)
    const fadeTimer = setTimeout(() => {
      console.log('4 seconds passed - Starting fade out...')
      setFadeOut(true)
    }, 4000)

    // Complete after fade finishes (4s show + 1s fade = 5s total)
    const completeTimer = setTimeout(() => {
      console.log('5 seconds passed - Loading screen completing...')
      setMounted(false)
      onComplete()
    }, 5000)

    return () => {
      console.log('Cleaning up timers...')
      clearTimeout(fadeTimer)
      clearTimeout(completeTimer)
    }
  }, []) // Empty dependency array - run once on mount

  const handleClick = () => {
    console.log('Loading screen clicked, completing early...')
    setFadeOut(true)
    setTimeout(() => {
      setMounted(false)
      onComplete()
    }, 1000)
  }

  console.log('LoadingScreen render - fadeOut:', fadeOut, 'mounted:', mounted)

  if (!mounted) return null

  return (
    <div className={`loading-screen ${fadeOut ? 'fade-out' : ''}`} onClick={handleClick}>
      <div className="loading-logo">
        <div className="heart-container">
          <div className="sun-rays loading-animate-rays">
            <svg viewBox="0 0 100 100" className="rays-svg">
              {/* Rising Sun flag style rays - triangular rays extending to edges */}
              <g transform="translate(50, 50)">
                {[...Array(16)].map((_, i) => {
                  const angle = (i * 22.5);
                  const nextAngle = ((i + 1) * 22.5);
                  const rayWidth = 11.25; // Half the angle between rays for triangular shape

                  // Create triangular ray path
                  const startAngle = angle - rayWidth;
                  const endAngle = angle + rayWidth;

                  const innerRadius = 0; // Start from center (heart center)
                  const outerRadius = 70; // Extend to screen edge

                  const x1 = Math.cos(startAngle * Math.PI / 180) * innerRadius;
                  const y1 = Math.sin(startAngle * Math.PI / 180) * innerRadius;
                  const x2 = Math.cos(endAngle * Math.PI / 180) * innerRadius;
                  const y2 = Math.sin(endAngle * Math.PI / 180) * innerRadius;
                  const x3 = Math.cos(startAngle * Math.PI / 180) * outerRadius;
                  const y3 = Math.sin(startAngle * Math.PI / 180) * outerRadius;
                  const x4 = Math.cos(endAngle * Math.PI / 180) * outerRadius;
                  const y4 = Math.sin(endAngle * Math.PI / 180) * outerRadius;

                  return (
                    <polygon
                      key={i}
                      points={`${x1},${y1} ${x2},${y2} ${x4},${y4} ${x3},${y3}`}
                      fill={i % 2 === 0 ? "#8B0000" : "#000000"}
                      opacity="0.9"
                    />
                  );
                })}
              </g>
            </svg>
          </div>
          <div className="heart-outline loading-animate-heart">
            <svg viewBox="0 0 100 100" className="heart-svg">
              <path d="M50,85 C50,85 10,60 10,35 C10,18 20,8 35,8 C42,8 50,13 50,25 C50,13 58,8 65,8 C80,8 90,18 90,35 C90,60 50,85 50,85 Z"
                    fill="#8B0000"
                    stroke="#8B0000"
                    strokeWidth="2"/>
            </svg>
          </div>
          <div className="logo-text loading-animate-text">soryu</div>
          <div className="loading-subtitle loading-animate-subtitle">{animatedText}</div>
          <div className="loading-dots loading-animate-text">
            <span>.</span><span>.</span><span>.</span>
          </div>
        </div>
      </div>
    </div>
  )
}