Skip to content

Commit d5aa5ea

Browse files
authored
Merge pull request #306 from tjklint/refactor(1page)
docs: commented hero.tsx for better code readabliity.
2 parents 829e316 + f19c613 commit d5aa5ea

File tree

1 file changed

+119
-100
lines changed

1 file changed

+119
-100
lines changed

src/components/hero/hero.tsx

Lines changed: 119 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,144 @@
11
import React, { useEffect, useState, useRef } from 'react';
22
import 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
56
const 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
1921
const 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
3841
const 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)
5256
const 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
6469
const 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
7480
const 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
8592
const 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)
99108
const 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
108118
const 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
116127
interface 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
125137
const 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

Comments
 (0)