Reflect career progression from Technical Product Owner to AI Solution Architect & Technical Architect (since June 2024). Add AI & ML skill category (LangChain, RAG, Agentic Systems, MCP Server). Pin dependency versions, clean up config, move favicon, and add new PDF assets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
180 lines
6.6 KiB
TypeScript
180 lines
6.6 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef, useState } from 'react';
|
|
|
|
interface Skill {
|
|
name: string;
|
|
level: number; // 1-5
|
|
category: string;
|
|
}
|
|
|
|
const skillsData: Skill[] = [
|
|
// AI & ML
|
|
{ name: 'LangChain / LangGraph', level: 4, category: 'AI & ML' },
|
|
{ name: 'RAG & Vector Databases', level: 4, category: 'AI & ML' },
|
|
{ name: 'LLMs (Ollama, LM Studio, Claude)', level: 4, category: 'AI & ML' },
|
|
{ name: 'AI Agentic Systems', level: 4, category: 'AI & ML' },
|
|
{ name: 'MCP Server Integration', level: 3, category: 'AI & ML' },
|
|
{ name: 'Prompt Engineering', level: 4, category: 'AI & ML' },
|
|
|
|
// Programmiersprachen
|
|
{ name: 'Python', level: 4, category: 'Programmiersprachen' },
|
|
{ name: 'PHP & FW Laravel', level: 4, category: 'Programmiersprachen' },
|
|
{ name: 'JavaScript', level: 4, category: 'Programmiersprachen' },
|
|
{ name: 'Node.js', level: 3, category: 'Programmiersprachen' },
|
|
{ name: 'Vue.js / Next.js', level: 4, category: 'Programmiersprachen' },
|
|
{ name: 'HTML', level: 5, category: 'Programmiersprachen' },
|
|
{ name: 'CSS & Frameworks', level: 5, category: 'Programmiersprachen' },
|
|
{ name: 'Sass', level: 4, category: 'Programmiersprachen' },
|
|
|
|
// Datenbanken
|
|
{ name: 'SQL (MS/DB2/Oracle)', level: 4, category: 'Datenbanken' },
|
|
{ name: 'MySQL, MariaDB, Postgres', level: 4, category: 'Datenbanken' },
|
|
{ name: 'ChromaDB / Vector DBs', level: 3, category: 'Datenbanken' },
|
|
{ name: 'Redis', level: 4, category: 'Datenbanken' },
|
|
{ name: 'MongoDB', level: 3, category: 'Datenbanken' },
|
|
{ name: 'CouchDB', level: 3, category: 'Datenbanken' },
|
|
|
|
// DevOps & Cloud
|
|
{ name: 'Linux Bash Scripting', level: 4, category: 'DevOps & Cloud' },
|
|
{ name: 'Git / SVN', level: 4, category: 'DevOps & Cloud' },
|
|
{ name: 'Docker / Kubernetes', level: 4, category: 'DevOps & Cloud' },
|
|
{ name: 'Terraform / Ansible', level: 3, category: 'DevOps & Cloud' },
|
|
{ name: 'AWS / Azure', level: 3, category: 'DevOps & Cloud' },
|
|
{ name: 'CI/CD Pipelines', level: 4, category: 'DevOps & Cloud' },
|
|
|
|
// Grafik & Design
|
|
{ name: 'Adobe Suite (u.a. PS/XD)', level: 4, category: 'Grafik & Design' },
|
|
{ name: 'Affinity', level: 4, category: 'Grafik & Design' },
|
|
{ name: 'FinalCut', level: 4, category: 'Grafik & Design' },
|
|
];
|
|
|
|
const categories = [
|
|
'AI & ML',
|
|
'Programmiersprachen',
|
|
'Datenbanken',
|
|
'DevOps & Cloud',
|
|
'Grafik & Design',
|
|
];
|
|
|
|
export default function Skills() {
|
|
const [activeCategory, setActiveCategory] = useState<string>('AI & ML');
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
const ref = useRef<HTMLElement>(null);
|
|
|
|
useEffect(() => {
|
|
const currentRef = ref.current;
|
|
const observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) {
|
|
setIsVisible(true);
|
|
}
|
|
},
|
|
{ threshold: 0.1 }
|
|
);
|
|
|
|
if (currentRef) {
|
|
observer.observe(currentRef);
|
|
}
|
|
|
|
return () => {
|
|
if (currentRef) {
|
|
observer.unobserve(currentRef);
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
const filteredSkills = skillsData.filter((skill) => skill.category === activeCategory);
|
|
|
|
return (
|
|
<section
|
|
id="skills"
|
|
ref={ref}
|
|
className={`py-20 px-4 sm:px-6 lg:px-8 bg-gradient-to-br from-bg-light to-white transition-opacity duration-1000 ${
|
|
isVisible ? 'opacity-100' : 'opacity-0'
|
|
}`}
|
|
>
|
|
<div className="max-w-6xl mx-auto">
|
|
<h2 className="text-3xl sm:text-4xl font-bold text-text text-center mb-4 relative inline-block w-full">
|
|
Technische Fähigkeiten
|
|
</h2>
|
|
<p className="text-center text-text-light mb-12 max-w-2xl mx-auto">
|
|
Umfassende Expertise in modernen Technologien und Frameworks
|
|
</p>
|
|
|
|
{/* Category Tabs */}
|
|
<div className="flex flex-wrap justify-center gap-3 mb-12">
|
|
{categories.map((category, index) => (
|
|
<button
|
|
key={category}
|
|
onClick={() => setActiveCategory(category)}
|
|
className={`px-5 py-3 rounded-lg font-semibold text-sm transition-all duration-300 ${
|
|
activeCategory === category
|
|
? 'bg-primary text-white shadow-lg scale-105'
|
|
: 'bg-white text-text-light hover:bg-gray-100 hover:text-text shadow-md'
|
|
} ${isVisible ? 'animate-fade-in' : 'opacity-0'}`}
|
|
style={{ animationDelay: `${index * 50}ms` }}
|
|
>
|
|
{category}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Skills Grid */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{filteredSkills.map((skill, index) => (
|
|
<div
|
|
key={skill.name}
|
|
className={`bg-white rounded-lg p-6 shadow-md hover:shadow-xl transition-all duration-300 hover:-translate-y-1 ${
|
|
isVisible ? 'animate-fade-in' : 'opacity-0'
|
|
}`}
|
|
style={{ animationDelay: `${(index + categories.length) * 50}ms` }}
|
|
>
|
|
{/* Skill Name */}
|
|
<h3 className="font-bold text-text mb-3 text-base">{skill.name}</h3>
|
|
|
|
{/* Level Bar */}
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex-1 bg-gray-200 rounded-full h-2.5 overflow-hidden">
|
|
<div
|
|
className="bg-gradient-to-r from-primary to-primary-dark h-full rounded-full transition-all duration-1000 ease-out"
|
|
style={{
|
|
width: isVisible ? `${(skill.level / 5) * 100}%` : '0%',
|
|
transitionDelay: `${(index + categories.length) * 50 + 200}ms`,
|
|
}}
|
|
/>
|
|
</div>
|
|
<span className="text-sm font-bold text-primary min-w-[2rem] text-right">
|
|
{skill.level}/5
|
|
</span>
|
|
</div>
|
|
|
|
{/* Level Dots */}
|
|
<div className="flex gap-1 mt-3">
|
|
{[1, 2, 3, 4, 5].map((dot) => (
|
|
<div
|
|
key={dot}
|
|
className={`w-2 h-2 rounded-full transition-all duration-300 ${
|
|
dot <= skill.level ? 'bg-primary' : 'bg-gray-300'
|
|
}`}
|
|
style={{
|
|
transitionDelay: `${(index + categories.length) * 50 + dot * 50}ms`,
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Info Text */}
|
|
<div className="mt-12 text-center">
|
|
<p className="text-text-light text-sm">
|
|
<strong className="text-primary">Bewertungsskala:</strong> 1 = Grundkenntnisse | 5 = Expertenwissen
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|