diff --git a/package-lock.json b/package-lock.json index 17b3bda..7c422b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.0.2", + "react-tooltip": "^5.28.0", "styled-components": "^6.1.13", "vite-plugin-svgr": "^4.3.0" }, @@ -796,6 +797,28 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1818,6 +1841,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -3837,6 +3865,19 @@ "react-dom": ">=18" } }, + "node_modules/react-tooltip": { + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", + "integrity": "sha512-R5cO3JPPXk6FRbBHMO0rI9nkUG/JKfalBSQfZedZYzmqaZQgq7GLzF8vcCWx6IhUCKg0yPqJhXIzmIO5ff15xg==", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz", diff --git a/package.json b/package.json index 5caff60..86c8ef5 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.0.2", + "react-tooltip": "^5.28.0", "styled-components": "^6.1.13", "vite-plugin-svgr": "^4.3.0" }, diff --git a/src/components/TallContent.jsx b/src/components/TallContent.jsx index 6395bbd..876d5b8 100644 --- a/src/components/TallContent.jsx +++ b/src/components/TallContent.jsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useRef } from "react"; import "../css/TallContent.css"; import { useTheme } from "../Context/ThemeContext"; import { useLang } from "../Context/LangContext"; @@ -7,14 +7,105 @@ const TallContent = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { const [animation, setAnimation] = useState(initialAnimation); const { colormode } = useTheme(); const { language } = useLang(); + const canvasRef = useRef(null); + + const speedFactor = 0.2; // Geschwindigkeit anpassen: kleiner = langsamer, größer = schneller + + useEffect(() => { + const canvas = canvasRef.current; + const ctx = canvas.getContext("2d"); + + canvas.width = canvas.parentElement.offsetWidth; + canvas.height = canvas.parentElement.offsetHeight; + + const particles = Array.from({ length: 50 }, () => ({ + x: Math.random() * canvas.width, + y: Math.random() * canvas.height, + radius: Math.random() * 4 + 1, + dx: (Math.random() * 0.5 - 0.25) * speedFactor, + dy: (Math.random() * 0.5 - 0.25) * speedFactor, + color: `hsl(${Math.random() * 360}, 70%, 70%)`, + })); + + const starFieldEffect = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + ctx.fillStyle = "rgba(0, 0, 0, 0.1)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + particles.forEach((particle) => { + particle.x += particle.dx; + particle.y += particle.dy; + + // Warp particles when they leave canvas + if (particle.x < 0) particle.x = canvas.width; + if (particle.x > canvas.width) particle.x = 0; + if (particle.y < 0) particle.y = canvas.height; + if (particle.y > canvas.height) particle.y = 0; + + ctx.beginPath(); + ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2); + ctx.fillStyle = particle.color; + ctx.fill(); + }); + + requestAnimationFrame(starFieldEffect); + }; + + starFieldEffect(); + + canvas.addEventListener("mousemove", (e) => { + const rect = canvas.getBoundingClientRect(); + const mouseX = e.clientX - rect.left; + const mouseY = e.clientY - rect.top; + + particles.forEach((particle) => { + const dx = particle.x - mouseX; + const dy = particle.y - mouseY; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < 150) { + const force = (150 - distance) / 150; + particle.dx += (dx / distance) * force * -0.05; + particle.dy += (dy / distance) * force * -0.05; + } + }); + }); + + canvas.addEventListener("click", (e) => { + const rect = canvas.getBoundingClientRect(); + const mouseX = e.clientX - rect.left; + const mouseY = e.clientY - rect.top; + + particles.forEach((particle) => { + const dx = particle.x - mouseX; + const dy = particle.y - mouseY; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < 200) { + const force = (200 - distance) / 200; + particle.dx += (dx / distance) * force * 1.5; + particle.dy += (dy / distance) * force * 1.5; + } + }); + }); + + const handleResize = () => { + canvas.width = canvas.parentElement.offsetWidth; + canvas.height = canvas.parentElement.offsetHeight; + }; + + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, [speedFactor]); return (