diff --git a/src/app/about/page.js b/src/app/about/page.js
index 1dc172b..9aff1c3 100644
--- a/src/app/about/page.js
+++ b/src/app/about/page.js
@@ -1,298 +1,29 @@
-"use client"
-import {useRef, useState, useEffect} from "react";
import Link from "next/link";
-import FadeInSection from "@/app/components/FadeInSection";
-
+export const metadata = {title: "About"};
+const timeline = [
+ {year: "2018", title: "The first spark", text: "I discovered programming through Scratch, turning small ideas into simple, playable games.", skills: ["Scratch", "Game logic"]},
+ {year: "2022", title: "Into the web", text: "I began building websites and learned the foundations of HTML, CSS, and accessible interface design.", skills: ["HTML", "CSS", "JavaScript"]},
+ {year: "2022", title: "From screen to hardware", text: "A Raspberry Pi opened the door to Python scripting, Linux, and the fun of connecting software with real hardware.", skills: ["Python", "Linux", "Raspberry Pi"]},
+ {year: "2024", title: "Full stack & beyond", text: "I expanded into databases, backend systems, Java, and larger projects—while continuing to sharpen my eye for frontend craft.", skills: ["SQL", "Python", "Java", "JavaScript"]},
+];
export default function About() {
- const timelineData = [
- {
- date: "2018",
- title: "First Contact with Coding",
- content:
- "I discovered my passion for technology by experimenting with Scratch and creating some simple Games.",
- },
- {
- date: "2022",
- title: "Exploring Web & Scripting",
- content:
- "Started creating small websites and got into HTML, CSS",
- },
- {
- date: "2022",
- title: "Raspberry Pi & Python",
- content:
- "Created some simple Python scripts for my Raspberry Pi, experimenting with the Raspberry Pi OS",
- },
- {
- date: "2024",
- title: "Full Stack & Beyond",
- content:
- "Ventured into backend (SQL, Python, Javascript, Java) and continued refining my frontend abilities.",
- },
- ];
-
- function getSkillEmoji(name) {
- switch (name) {
- case "JavaScript": return "🟨";
- case "Python": return "🐍";
- case "Java": return "☕";
- case "SQL": return "💾";
- case "HTML & CSS": return "🎨";
- default: return "💡";
- }
- }
-
- const skills = [
- {
- name: "JavaScript",
- level: 80,
- waveSpeed: "2s",
- 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 aboutMeRef = useRef(null);
- const buttonSectionRef = useRef(null);
- const scrollContainerRef = useRef(null);
- const [currentSection, setCurrentSection] = useState(0);
- const [timelineFinished, setTimelineFinished] = useState(false);
- const [showScrollPrompt, setShowScrollPrompt] = useState(false);
- useEffect(() => {
- setCurrentSection(0);
- setTimelineFinished(false);
- setTimeout(() => {
- sectionRefs.current[0]?.scrollIntoView({behavior: "auto", inline: "start"});
- window.scrollTo({top: 0, behavior: "smooth"});
- }, 100);
- }, []);
-
- useEffect(() => {
- let scrollListener;
-
- if (timelineFinished) {
- setShowScrollPrompt(true);
-
- scrollListener = () => {
- setShowScrollPrompt(false);
- window.removeEventListener("scroll", scrollListener);
- };
-
- window.addEventListener("scroll", scrollListener);
- }
-
- return () => {
- if (scrollListener) {
- window.removeEventListener("scroll", scrollListener);
- }
- };
- }, [timelineFinished]);
- const [isNavigating, setIsNavigating] = useState(false);
- const handleButtonClick = (direction) => {
- if (isNavigating) return;
- setIsNavigating(true);
- setCurrentSection((prev) => {
- const newSection = Math.max(0, Math.min(prev + direction, timelineData.length - 1));
- sectionRefs.current[newSection]?.scrollIntoView({behavior: "smooth", inline: "start"});
- return newSection;
- });
- setTimeout(() => {
- setIsNavigating(false);
- }, 600);
- };
- useEffect(() => {
- const observer = new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- const index = sectionRefs.current.findIndex((el) => el === entry.target);
- if (entry.isIntersecting && index !== -1) {
- setCurrentSection(index);
- }
- if (entry.isIntersecting && index === timelineData.length - 1) {
- setTimelineFinished(true);
- }
-
- });
- },
- {threshold: 0.6}
- );
- sectionRefs.current.forEach((el) => {
- if (el) observer.observe(el);
- });
- return () => observer.disconnect();
- }, [timelineData.length]);
- useEffect(() => {
- setTimelineFinished(currentSection === timelineData.length - 1);
- }, [currentSection, timelineData.length]);
- return (
-
-
-
- About Me
-
- I’m a passionate developer always excited about new challenges.
- Scroll down to learn more about me!
-
-
-
- {/* Timeline Section */}
-
- {/* Navigation buttons and timeline content here */}
-
- {timelineData.map((item, index) => {
- const adjustedSkills = skills.map((s) => {
- const stepLevel = s.progression?.[index] ?? 0;
- return {
- ...s,
- level: Math.floor((s.level * stepLevel) / 100),
- };
- });
- return (
-
(sectionRefs.current[index] = el)}
- className="timeline-page"
- >
-
-
- {item.date}
-
{item.title}
-
-
{item.content}
-
- {adjustedSkills.filter((s) => s.level > 0).map((skill, sIndex) => (
-
- {getSkillEmoji(skill.name)} {skill.name}
- {getSkillLabel(skill.level)}
-
- ))}
-
-
-
- );
- })}
-
- {currentSection > 0 && (
-
- )}
- {currentSection < timelineData.length - 1 && (
-
- )}
-
- {timelineFinished && showScrollPrompt && (
-
- ⬇ Scroll down to continue ⬇
-
- )}
- {/* FINAL BUTTON SECTION - MOVED OUTSIDE */}
- {timelineFinished && (
- // Fügen Sie dem Button-Section einen z-Index hinzu
-
-
-
-
-
- )}
+ return (<>
+
+
+
+
{timeline.map(item => (
+
+ {item.year}
+ {item.title}
{item.text}
{item.skills.map(skill => {skill})}
+
+ ))}
- )
-}
\ No newline at end of file
+ >);
+}
diff --git a/src/app/components/CustomCursor.jsx b/src/app/components/CustomCursor.jsx
new file mode 100644
index 0000000..b4ebbf9
--- /dev/null
+++ b/src/app/components/CustomCursor.jsx
@@ -0,0 +1,67 @@
+"use client";
+
+import React, {useEffect, useRef, useState} from "react";
+
+export default function CustomCursor() {
+ const cursorRef = useRef(null);
+ const rafRef = useRef(0);
+ const targetPos = useRef({ x: 0, y: 0 });
+ const currentPos = useRef({ x: 0, y: 0 });
+ const [hidden, setHidden] = useState(true);
+ const [active, setActive] = useState(false);
+ const [clicking, setClicking] = useState(false);
+ const animate = () => {
+ const lerp = 0.18;
+ currentPos.current.x += (targetPos.current.x - currentPos.current.x) * lerp;
+ currentPos.current.y += (targetPos.current.y - currentPos.current.y) * lerp;
+
+ if (cursorRef.current) {
+ cursorRef.current.style.transform = `translate3d(${currentPos.current.x}px, ${currentPos.current.y}px, 0)`;
+ }
+ rafRef.current = requestAnimationFrame(animate);
+ };
+ useEffect(() => {
+ const move = (e) => {
+ targetPos.current.x = e.clientX;
+ targetPos.current.y = e.clientY;
+ setHidden(false);
+ };
+ const mouseEnter = () => setHidden(false);
+ const mouseLeave = () => setHidden(true);
+ const mouseDown = () => setClicking(true);
+ const mouseUp = () => setClicking(false);
+ const updateActive = (e) => {
+ const el = e.target;
+ const clickable = el.closest?.(
+ 'a, button, [role="button"], input[type="submit"], input[type="button"], .clickable'
+ );
+ setActive(Boolean(clickable));
+ };
+ window.addEventListener("mousemove", move, { passive: true });
+ window.addEventListener("mouseenter", mouseEnter, { passive: true });
+ window.addEventListener("mouseleave", mouseLeave, { passive: true });
+ window.addEventListener("mousedown", mouseDown, { passive: true });
+ window.addEventListener("mouseup", mouseUp, { passive: true });
+ window.addEventListener("mouseover", updateActive, { passive: true });
+ rafRef.current = requestAnimationFrame(animate);
+ return () => {
+ window.removeEventListener("mousemove", move);
+ window.removeEventListener("mouseenter", mouseEnter);
+ window.removeEventListener("mouseleave", mouseLeave);
+ window.removeEventListener("mousedown", mouseDown);
+ window.removeEventListener("mouseup", mouseUp);
+ window.removeEventListener("mouseover", updateActive);
+ cancelAnimationFrame(rafRef.current);
+ };
+ }, []);
+ let className = "custom-cursor";
+ if (hidden) className += " custom-cursor--hidden";
+ if (active) className += " custom-cursor--active";
+ if (clicking) className += " custom-cursor--click";
+ return (
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/components/Footer.js b/src/app/components/Footer.js
index 1cb8139..cca2b74 100644
--- a/src/app/components/Footer.js
+++ b/src/app/components/Footer.js
@@ -1,15 +1,10 @@
export default function Footer() {
return (
-