Update resume animation

This commit is contained in:
2025-05-23 00:32:49 -06:00
parent fc1a4e2560
commit e6b50d5ea5
5 changed files with 271 additions and 179 deletions

View File

@ -0,0 +1,95 @@
import { useSignal } from "@preact/signals";
import { useEffect } from "preact/hooks";
interface Skill {
id: string;
name: string;
level: number;
}
interface SkillsSectionProps {
title: string;
skills: Skill[];
}
export default function SkillsSection({ title, skills }: SkillsSectionProps) {
const animatedLevels = useSignal<{ [key: string]: number }>({});
const hasAnimated = useSignal(false);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !hasAnimated.value) {
hasAnimated.value = true;
// Start animation for all skills
skills.forEach((skill) => {
animateSkill(skill.id, skill.level);
});
}
});
},
{ threshold: 0.3 }
);
const skillsElement = document.getElementById('skills-section');
if (skillsElement) {
observer.observe(skillsElement);
}
return () => {
if (skillsElement) {
observer.unobserve(skillsElement);
}
};
}, [skills]);
const animateSkill = (skillId: string, targetLevel: number) => {
const duration = 1500; // 1.5 seconds
const steps = 60; // 60 frames for smooth animation
const increment = targetLevel / steps;
let currentStep = 0;
const animate = () => {
if (currentStep <= steps) {
const currentValue = Math.min(increment * currentStep, targetLevel);
animatedLevels.value = {
...animatedLevels.value,
[skillId]: currentValue
};
currentStep++;
requestAnimationFrame(animate);
}
};
requestAnimationFrame(animate);
};
return (
<div id="skills-section" class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{title || "Skills"}</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
{skills.map((skill) => {
const currentLevel = animatedLevels.value[skill.id] || 0;
const progressValue = currentLevel * 20; // Convert 1-5 scale to 0-100
return (
<div key={skill.id}>
<label class="label">
<span class="label-text">{skill.name}</span>
</label>
<progress
class="progress progress-primary w-full transition-all duration-100 ease-out"
value={progressValue}
max="100"
>
</progress>
</div>
);
})}
</div>
</div>
</div>
);
}