Refactor timeline and skill display with enhanced animations

This commit is contained in:
IM23a-spirgif
2025-05-15 09:31:11 +02:00
parent 1fb265b604
commit 96a9e0b733
2 changed files with 174 additions and 89 deletions
+138 -89
View File
@@ -11,33 +11,65 @@ export default function About() {
"I discovered my passion for technology by experimenting with Scratch and creating some simple Games.", "I discovered my passion for technology by experimenting with Scratch and creating some simple Games.",
}, },
{ {
date: "2020", date: "2022",
title: "Exploring Web & Scripting", title: "Exploring Web & Scripting",
content: content:
"Started creating small websites and got into JavaScript, CSS, and working with various scripting languages.", "Started creating small websites and got into HTML, CSS",
}, },
{ {
date: "2022", date: "2022",
title: "Diving into Game Development", title: "Raspberry Pi & Python",
content: content:
"Tried Unity and C#, building small 2D and 3D prototypes to expand my skill set.", "Created some simple Python scripts for my Raspberry Pi, experimenting with the Raspberry Pi OS",
}, },
{ {
date: "2024", date: "2024",
title: "Full Stack & Beyond", title: "Full Stack & Beyond",
content: content:
"Ventured into backend (SQL, Python) and continued refining my frontend abilities, always exploring new challenges.", "Ventured into backend (SQL, Python, Javascript, Java) and continued refining my frontend abilities.",
}, },
]; ];
const skills = [ const skills = [
{name: "JavaScript", level: 80, waveSpeed: "2s"}, {
{name: "Python", level: 75, waveSpeed: "2.5s"}, name: "JavaScript",
{name: "C#", level: 50, waveSpeed: "3s"}, level: 80,
{name: "SQL", level: 85, waveSpeed: "2.2s"}, waveSpeed: "2s",
{name: "HTML & CSS", level: 70, waveSpeed: "2.7s"}, progression: [0, 30, 60, 80],
},
{
name: "Python",
level: 75,
waveSpeed: "2.5s",
progression: [10, 25, 50, 75],
},
{
name: "Java",
level: 50,
waveSpeed: "3s",
progression: [0, 0, 0, 60],
},
{
name: "SQL",
level: 85,
waveSpeed: "2.2s",
progression: [0, 0, 0, 85],
},
{
name: "HTML & CSS",
level: 70,
waveSpeed: "2.7s",
progression: [0, 30, 50, 80],
},
]; ];
const getSkillLabel = (level) => {
if (level < 25) return "Beginner";
if (level < 50) return "Intermediate";
if (level < 75) return "Advanced";
return "Expert";
};
const sectionRefs = useRef([]); const sectionRefs = useRef([]);
const aboutMeRef = useRef(null); const aboutMeRef = useRef(null);
const scrollContainerRef = useRef(null); const scrollContainerRef = useRef(null);
@@ -62,12 +94,16 @@ export default function About() {
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
(entries) => { (entries) => {
entries.forEach((entry) => { entries.forEach((entry) => {
if (entry.isIntersecting) { const index = sectionRefs.current.findIndex((el) => el === entry.target);
const index = sectionRefs.current.findIndex((el) => el === entry.target); if (entry.isIntersecting && index !== -1) {
if (index !== -1) { setCurrentSection(index);
setCurrentSection(index); }
setTimelineFinished(index === timelineData.length - 1); if (
} entry.isIntersecting &&
index === timelineData.length - 1 &&
entry.intersectionRatio >= 0.8
) {
setTimelineFinished(true);
} }
}); });
}, },
@@ -150,98 +186,111 @@ export default function About() {
width: "100%", width: "100%",
height: "100%", height: "100%",
scrollBehavior: "smooth", scrollBehavior: "smooth",
scrollbarWidth: "none", // Firefox scrollbarWidth: "none",
msOverflowStyle: "none", // IE/Edge msOverflowStyle: "none",
}} }}
> >
{timelineData.map((item, index) => ( {timelineData.map((item, index) => {
<section const adjustedSkills = skills.map((s) => {
key={index} const stepLevel = s.progression?.[index] ?? 0;
ref={(el) => (sectionRefs.current[index] = el)} return {
style={{ ...s,
flex: "0 0 100%", level: Math.floor((s.level * stepLevel) / 100),
scrollSnapAlign: "center", };
display: "flex", });
flexDirection: "column", return (
alignItems: "center", <section
justifyContent: "center", key={index}
padding: "2rem", ref={(el) => (sectionRefs.current[index] = el)}
boxSizing: "border-box", style={{
}} flex: "0 0 100%",
> scrollSnapAlign: "center",
<h2 style={{marginBottom: "1rem"}}>{item.title}</h2> display: "flex",
<h3 style={{marginBottom: "1rem"}}>{item.date}</h3> flexDirection: "column",
<p style={{maxWidth: "600px", textAlign: "center"}}>{item.content}</p> alignItems: "center",
</section> justifyContent: "center",
))} padding: "2rem",
</div> boxSizing: "border-box",
</section> }}
{/* Skills Section*/} >
{timelineFinished && ( <h2 style={{marginBottom: "1rem"}}>{item.title}</h2>
<section <h3 style={{marginBottom: "1rem"}}>{item.date}</h3>
style={{ <p style={{maxWidth: "600px", textAlign: "center", marginBottom: "2rem"}}>
minHeight: "100vh", {item.content}
display: "flex", </p>
flexDirection: "column",
alignItems: "center", {/* SKILLS: show per stage */}
justifyContent: "center", <div style={{display: "flex", gap: "2rem"}}>
padding: "2rem", <div style={{
color: "#fff", display: "flex",
}} gap: "2rem",
> flexWrap: "wrap",
<h2 style={{fontSize: "2rem", marginBottom: "2rem"}}>My Skills</h2> justifyContent: "center"
<div style={{display: "flex", gap: "2rem"}}> }}>
{skills.map((skill, index) => ( {adjustedSkills.filter((s) => s.level > 0).map((skill, sIndex) => (
<div key={index} style={{textAlign: "center"}}> <div
<div key={`${skill.name}-${index}`}
style={{ className={currentSection === index ? "skill-card animate-skill" : "skill-card"}
width: "60px", style={{
height: "200px", textAlign: "center",
backgroundColor: "#333", width: "120px",
borderRadius: "10px", animationDelay: `${sIndex * 100}ms`,
overflow: "hidden", animationFillMode: "both",
position: "relative", }}
border: "2px solid #555", >
}} <p style={{
> fontSize: "1.1rem",
<div fontWeight: "bold",
className="liquid" marginBottom: "0.5rem"
style={{ }}>
width: "100%", {skill.name}
height: `${skill.level}%`, </p>
position: "absolute", <div
bottom: 0, style={{
background: "linear-gradient(45deg, #7400a9, #411357)", padding: "0.5rem 1rem",
borderTop: "4px solid rgba(255, 255, 255, 0.6)", backgroundColor: "#1a001a",
animation: `wave ${skill.waveSpeed} infinite ease-in-out`, border: "2px solid #3d003d",
}} borderRadius: "10px",
> fontSize: "1rem",
<p style={{marginTop: "10px", fontSize: "1rem"}}>{skill.level}%</p> color: "#fff",
}}
>
{getSkillLabel(skill.level)}
</div>
</div>
))}
</div> </div>
</div> </div>
<p style={{marginTop: "10px", fontSize: "1rem"}}>{skill.name}</p> </section>
</div> );
))} })}
</div> </div>
<div style={{marginTop: "3rem"}}> {/* End of scroll container */}
{timelineFinished && (
<div style={{marginTop: "3rem", textAlign: "center", width: "100%"}}>
<Link href="/projects"> <Link href="/projects">
<button <button
className="learnMoreButton" className="learnMoreButton"
style={{ style={{
padding: "1rem 2rem", padding: "1rem 2rem",
fontSize: "1.25rem", fontSize: "1.25rem",
backgroundColor: "#3d003d",
border: "none", border: "none",
borderRadius: "5px", borderRadius: "5px",
color: "#fff", color: "#fff",
cursor: "pointer", cursor: "pointer",
transition: "background-color 0.3s ease",
}} }}
onMouseOver={(e) => (e.currentTarget.style.backgroundColor = "#2e002e")}
onMouseOut={(e) => (e.currentTarget.style.backgroundColor = "#3d003d")}
> >
View Projects View Projects
</button> </button>
</Link> </Link>
</div> </div>
</section> )}
)} </section>
</div> </div>
) )
} }
+36
View File
@@ -276,3 +276,39 @@ body {
opacity: 0; opacity: 0;
} }
@keyframes fadeInSkill {
0% {
opacity: 0;
transform: translateY(10px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.skill-card {
opacity: 0;
transform: translateY(10px);
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
}
.animate-skill {
animation: fadeInSkill 0.6s ease-out forwards;
}
@keyframes fadeInButton {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.learnMoreButton {
animation: fadeInButton 0.5s ease-out;
}