11import React , { useEffect , useState , useRef } from 'react' ;
22import styled , { keyframes , css } from 'styled-components' ;
3- import spaceship from '../../assets/spaceship/webp/spaceship.webp' ;
3+ import spaceship from '../../assets/spaceship/webp/spaceship.webp' ; // Importing spaceship image
44
5+ // Main container for the hero section
56const HeroContainer = styled . section `
67 display: flex;
7- flex-direction: column;
8- min-height: 100vh;
9- background-color: #1e1e1e;
10- color: #fff;
11- overflow: hidden;
8+ flex-direction: column; /* Stack items vertically by default */
9+ min-height: 100vh; /* Full viewport height */
10+ background-color: #1e1e1e; /* Dark background */
11+ color: #fff; /* White text */
12+ overflow: hidden; /* Prevent overflow */
1213 font-family: 'RobotoMono', sans-serif; /* Use RobotoMono font */
1314
1415 @media (min-width: 768px) {
15- flex-direction: row;
16+ flex-direction: row; /* On larger screens, layout side by side */
1617 }
1718` ;
1819
20+ // Left container for text and main title
1921const LeftContainer = styled . div `
20- flex: 1;
22+ flex: 1; /* Take up equal space */
2123 display: flex;
2224 flex-direction: column;
23- justify-content: center;
24- padding: 40px 40px 40px 40px ; /* Add padding to the left side */
25- text-align: left; /* Align text to the left */
26- margin-top: -10%; /* Adjust to move text above the vertical center */
25+ justify-content: center; /* Center text vertically */
26+ padding: 40px; /* Padding around the text */
27+ text-align: left; /* Left-align the text */
28+ margin-top: -10%; /* Adjust to move text slightly up */
2729
2830 @media (max-width: 768px) {
29- padding-top: 0; /* Remove upper padding for mobile */
30- margin-top: 0; /* Remove top margin for mobile */
31+ padding-top: 0; /* Remove padding for smaller screens */
32+ margin-top: 0; /* Remove negative margin for mobile */
3133 }
3234
3335 @media (min-width: 768px) {
34- flex: 0 0 35%;
36+ flex: 0 0 35%; /* Take up 35% of the space on larger screens */
3537 }
3638` ;
3739
40+ // Right container for the spaceship and animations
3841const RightContainer = styled . div `
39- flex: 1;
40- position: relative;
42+ flex: 1; /* Take up equal space */
43+ position: relative; /* Needed for absolute positioning of circles */
4144 display: flex;
42- justify-content: center;
43- align-items: center;
44- overflow: hidden; /* Ensure nothing overflows */
45- min-height: 50vh; /* Ensure it takes a minimum height on mobile */
45+ justify-content: center; /* Center the spaceship horizontally */
46+ align-items: center; /* Center the spaceship vertically */
47+ overflow: hidden; /* Prevent overflow of elements */
48+ min-height: 50vh; /* Minimum height for smaller screens */
4649
4750 @media (min-width: 768px) {
48- flex: 0 0 65%;
51+ flex: 0 0 65%; /* Take up 65% of the space on larger screens */
4952 }
5053` ;
5154
55+ // Floating animation for the spaceship (smooth up and down motion)
5256const floatAnimation = keyframes `
5357 0% {
54- transform: translateY(0);
58+ transform: translateY(0); /* Start at original position */
5559 }
5660 50% {
57- transform: translateY(-10px);
61+ transform: translateY(-10px); /* Move 10px up */
5862 }
5963 100% {
60- transform: translateY(0);
64+ transform: translateY(0); /* Return to original position */
6165 }
6266` ;
6367
68+ // Styling for the spaceship image with floating animation
6469const Spaceship = styled . img `
65- width: 80%; /* Adjusted to take up more space */
66- z-index: 1;
67- animation: ${ floatAnimation } 3s infinite;
70+ width: 80%; /* Set spaceship width to 80% of the container */
71+ z-index: 1; /* Ensure it stays above any background elements */
72+ animation: ${ floatAnimation } 3s infinite; /* Apply floating animation */
6873
6974 @media (min-width: 768px) {
70- width: 50%;
75+ width: 50%; /* Make it smaller on larger screens */
7176 }
7277` ;
7378
79+ // Animation for shrinking and moving circles
7480const shrinkAndMove = ( left : number , top : number , containerWidth : number , containerHeight : number ) => keyframes `
7581 0% {
76- transform: translate(0, 0) scale(1);
77- opacity: 1;
82+ transform: translate(0, 0) scale(1); /* Start at full size and original position */
83+ opacity: 1; /* Fully visible */
7884 }
7985 100% {
80- transform: translate(${ containerWidth / 2 - left } px, ${ containerHeight / 2 - top } px) scale(0);
81- opacity: 0;
86+ transform: translate(${ containerWidth / 2 - left } px, ${ containerHeight / 2 - top } px) scale(0); /* Move and shrink */
87+ opacity: 0; /* Fade out */
8288 }
8389` ;
8490
91+ // Circle styling with animation based on position and size
8592const Circle = styled . div < { left : number ; top : number ; size : number ; containerWidth : number ; containerHeight : number } > `
86- position: absolute;
87- background-color: #fff;
88- border-radius: 50%;
89- opacity: 0.8;
93+ position: absolute; /* Absolute positioning for floating circles */
94+ background-color: #fff; /* White background for the circles */
95+ border-radius: 50%; /* Make the div a circle */
96+ opacity: 0.8; /* Slight transparency */
97+
9098 ${ ( { left, top, size, containerWidth, containerHeight } ) => css `
91- width: ${ size } px;
92- height: ${ size } px;
93- left: ${ left } px;
94- top: ${ top } px;
95- animation: ${ shrinkAndMove ( left , top , containerWidth , containerHeight ) } 2s linear forwards;
99+ width: ${ size } px; /* Set width based on random size */
100+ height: ${ size } px; /* Set height to match width */
101+ left: ${ left } px; /* Set horizontal position */
102+ top: ${ top } px; /* Set vertical position */
103+ animation: ${ shrinkAndMove ( left , top , containerWidth , containerHeight ) } 2s linear forwards; /* Animate shrinking */
96104 ` }
97105` ;
98106
107+ // Styling for the gradient text (title)
99108const GradientText = styled . h2 `
100- background: linear-gradient(90deg, #8a2be2, #d4a1ff);
101- -webkit-background-clip: text;
102- -webkit-text-fill-color: transparent;
103- font-size: 4em; /* Make the text much bigger */
104- font-weight: bold; /* Make the text bolder */
105- margin: 0.5em 0;
109+ background: linear-gradient(90deg, #8a2be2, #d4a1ff); /* Purple gradient */
110+ -webkit-background-clip: text; /* Clip background to text */
111+ -webkit-text-fill-color: transparent; /* Make text transparent to show gradient */
112+ font-size: 4em; /* Large font size */
113+ font-weight: bold; /* Bold text */
114+ margin: 0.5em 0; /* Space around the text */
106115` ;
107116
117+ // Styling for the typewriter effect text
108118const TypewriterText = styled . div `
109119 color: #d4a1ff; /* Light purple color */
110- font-size: 1.5em; /* Adjust the size */
111- margin-top: 0.5em;
112- white-space: nowrap;
113- overflow: hidden;
120+ font-size: 1.5em; /* Medium font size */
121+ margin-top: 0.5em; /* Space above the text */
122+ white-space: nowrap; /* Prevent text from wrapping */
123+ overflow: hidden; /* Hide overflowing text */
114124` ;
115125
126+ // Interface for circle properties
116127interface CircleProps {
117- id : number ;
118- left : number ;
119- top : number ;
120- size : number ;
121- containerWidth : number ;
122- containerHeight : number ;
128+ id : number ; /* Unique ID for each circle */
129+ left : number ; /* Horizontal position */
130+ top : number ; /* Vertical position */
131+ size : number ; /* Circle size */
132+ containerWidth : number ; /* Width of the container */
133+ containerHeight : number ; /* Height of the container */
123134}
124135
136+ // Main Hero component
125137const Hero : React . FC = ( ) => {
126- const [ circles , setCircles ] = useState < CircleProps [ ] > ( [ ] ) ;
127- const [ topLine , setTopLine ] = useState ( '' ) ;
128- const [ currentText , setCurrentText ] = useState ( '' ) ;
129- const rightContainerRef = useRef < HTMLDivElement > ( null ) ;
138+ const [ circles , setCircles ] = useState < CircleProps [ ] > ( [ ] ) ; // State to manage circles
139+ const [ topLine , setTopLine ] = useState ( '' ) ; // State for random headline
140+ const [ currentText , setCurrentText ] = useState ( '' ) ; // State for typewriter text
141+ const rightContainerRef = useRef < HTMLDivElement > ( null ) ; // Ref to get the right container's dimensions
130142
131143 const topLines = [
132144 "You’re finally awake. Let’s explore my work." ,
@@ -139,7 +151,7 @@ const Hero: React.FC = () => {
139151 "Say hello to my little projects!" ,
140152 "Welcome to the dark side of my portfolio." ,
141153 "One portfolio to rule them all." ,
142- ] ;
154+ ] ; // Array of possible headline texts
143155
144156 const typewriterTexts = [
145157 "Software Developer" ,
@@ -149,104 +161,111 @@ const Hero: React.FC = () => {
149161 "AI Enthusiast" ,
150162 "Coffee Drinker" ,
151163 "Hackathon Fanatic"
152- ] ;
164+ ] ; // Array of texts for the typewriter effect
153165
154166 useEffect ( ( ) => {
155- // Set a random top line once
167+ // Pick a random top line for the header when the component mounts
156168 setTopLine ( topLines [ Math . floor ( Math . random ( ) * topLines . length ) ] ) ;
157169 } , [ ] ) ;
158170
159171 useEffect ( ( ) => {
172+ // Typewriter effect
160173 const typeWriter = ( ) => {
161174 let i = 0 ;
162175 let textPos = 0 ;
163176 let currentString = typewriterTexts [ i ] ;
164- const speed = 100 ;
165- const deleteSpeed = 50 ;
166- const waitTime = 2000 ;
177+ const speed = 100 ; // Typing speed
178+ const deleteSpeed = 50 ; // Deleting speed
179+ const waitTime = 2000 ; // Time before deleting starts
167180
181+ // Function to handle typing the text
168182 function type ( ) {
169- setCurrentText ( currentString . substring ( 0 , textPos ) + '_' ) ;
183+ setCurrentText ( currentString . substring ( 0 , textPos ) + '_' ) ; // Add typing cursor
170184
171185 if ( textPos ++ === currentString . length ) {
172- setTimeout ( ( ) => deleteText ( ) , waitTime ) ;
186+ setTimeout ( ( ) => deleteText ( ) , waitTime ) ; // Wait and start deleting
173187 } else {
174- setTimeout ( type , speed ) ;
188+ setTimeout ( type , speed ) ; // Continue typing
175189 }
176190 }
177191
192+ // Function to handle deleting the text
178193 function deleteText ( ) {
179- setCurrentText ( currentString . substring ( 0 , textPos ) + '_' ) ;
194+ setCurrentText ( currentString . substring ( 0 , textPos ) + '_' ) ; // Add typing cursor while deleting
180195
181196 if ( textPos -- === 0 ) {
182- i = ( i + 1 ) % typewriterTexts . length ;
183- currentString = typewriterTexts [ i ] ;
184- setTimeout ( type , speed ) ;
197+ i = ( i + 1 ) % typewriterTexts . length ; // Cycle through text array
198+ currentString = typewriterTexts [ i ] ; // Get next string
199+ setTimeout ( type , speed ) ; // Start typing again
185200 } else {
186- setTimeout ( deleteText , deleteSpeed ) ;
201+ setTimeout ( deleteText , deleteSpeed ) ; // Continue deleting
187202 }
188203 }
189204
190- type ( ) ;
205+ type ( ) ; // Start the typewriter effect
191206 } ;
192207
193- typeWriter ( ) ;
208+ typeWriter ( ) ; // Invoke the typewriter function on component mount
194209 } , [ ] ) ;
195210
196211 useEffect ( ( ) => {
212+ // Create new circles every 333 milliseconds for the spaceship animation
197213 const interval = setInterval ( ( ) => {
198214 if ( rightContainerRef . current ) {
199- const containerWidth = rightContainerRef . current . clientWidth ;
200- const containerHeight = rightContainerRef . current . clientHeight ;
215+ const containerWidth = rightContainerRef . current . clientWidth ; // Get container width
216+ const containerHeight = rightContainerRef . current . clientHeight ; // Get container height
201217
202218 const newCircles : CircleProps [ ] = Array . from ( { length : 7 } ) . map ( ( ) => {
203- const isVerticalEdge = Math . random ( ) > 0.5 ;
219+ const isVerticalEdge = Math . random ( ) > 0.5 ; // Randomly decide if circle spawns at vertical edge
204220 const left = isVerticalEdge
205- ? ( Math . random ( ) > 0.5 ? 0 : containerWidth - 10 ) // Left or right edge
206- : Math . random ( ) * containerWidth ;
221+ ? ( Math . random ( ) > 0.5 ? 0 : containerWidth - 10 ) // Either the left or right edge
222+ : Math . random ( ) * containerWidth ; // Random horizontal position
223+
207224 const top = ! isVerticalEdge
208- ? ( Math . random ( ) > 0.5 ? 0 : containerHeight - 10 ) // Top or bottom edge
209- : Math . random ( ) * containerHeight ;
225+ ? ( Math . random ( ) > 0.5 ? 0 : containerHeight - 10 ) // Either the top or bottom edge
226+ : Math . random ( ) * containerHeight ; // Random vertical position
210227
211228 return {
212- id : Date . now ( ) + Math . random ( ) ,
229+ id : Date . now ( ) + Math . random ( ) , // Generate unique ID
213230 left,
214231 top,
215- size : Math . random ( ) * 20 + 10 ,
232+ size : Math . random ( ) * 20 + 10 , // Random size for the circle
216233 containerWidth,
217234 containerHeight,
218235 } ;
219236 } ) ;
220237
221- setCircles ( prevCircles => [ ...prevCircles , ...newCircles ] ) ;
238+ setCircles ( prevCircles => [ ...prevCircles , ...newCircles ] ) ; // Add new circles to state
239+
240+ // Remove the new circles after 2 seconds
222241 setTimeout ( ( ) => {
223242 setCircles ( prevCircles =>
224243 prevCircles . filter ( circle => ! newCircles . some ( newCircle => newCircle . id === circle . id ) )
225244 ) ;
226245 } , 2000 ) ;
227246 }
228- } , 333 ) ;
247+ } , 333 ) ; // Create circles every 333ms
229248
230- return ( ) => clearInterval ( interval ) ;
249+ return ( ) => clearInterval ( interval ) ; // Clean up interval on component unmount
231250 } , [ ] ) ;
232251
233252 return (
234253 < HeroContainer >
235254 < LeftContainer >
236- < h1 > { topLine } </ h1 >
237- < GradientText > I'm TJ Klint.</ GradientText >
238- < TypewriterText > { currentText } </ TypewriterText >
255+ < h1 > { topLine } </ h1 > { /* Display random headline */ }
256+ < GradientText > I'm TJ Klint.</ GradientText > { /* Display name with gradient effect */ }
257+ < TypewriterText > { currentText } </ TypewriterText > { /* Display typewriter effect text */ }
239258 </ LeftContainer >
240259 < RightContainer ref = { rightContainerRef } >
241- < Spaceship src = { spaceship } alt = "Spaceship" />
260+ < Spaceship src = { spaceship } alt = "Spaceship" /> { /* Display the floating spaceship */ }
242261 { circles . map ( circle => (
243262 < Circle
244- key = { circle . id }
245- left = { circle . left }
246- top = { circle . top }
247- size = { circle . size }
248- containerWidth = { circle . containerWidth }
249- containerHeight = { circle . containerHeight }
263+ key = { circle . id } /* Key for each circle */
264+ left = { circle . left } /* Horizontal position */
265+ top = { circle . top } /* Vertical position */
266+ size = { circle . size } /* Circle size */
267+ containerWidth = { circle . containerWidth } /* Width of the container */
268+ containerHeight = { circle . containerHeight } /* Height of the container */
250269 />
251270 ) ) }
252271 </ RightContainer >
0 commit comments