techstack tooltip / tall Content main => particle playground
This commit is contained in:
@@ -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 (
|
||||
<div
|
||||
className={`container tallContent animate__animated ${animation} ${colormode}`}
|
||||
onMouseEnter={() => onMouseEnter(setAnimation)}
|
||||
onAnimationEnd={() => onAnimationEnd(setAnimation)}
|
||||
/* onMouseEnter={() => onMouseEnter(setAnimation)}
|
||||
*/ onAnimationEnd={() => onAnimationEnd(setAnimation)}
|
||||
>
|
||||
TallContent
|
||||
<canvas ref={canvasRef} className="particleCanvas"></canvas>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,16 +17,14 @@ import Linux from "../assets/icons/skill-icons/icons/Linux-Dark.svg?react";
|
||||
|
||||
import "../css/TechStack.css";
|
||||
import { Link } from "react-router-dom";
|
||||
import "animate.css";
|
||||
import { useTheme } from "../Context/ThemeContext";
|
||||
import { useLang } from "../Context/LangContext";
|
||||
|
||||
const TechStack = ({
|
||||
initialAnimation,
|
||||
/* onMouseEnter, */
|
||||
onAnimationEnd,
|
||||
isExpanded,
|
||||
onExpandToggle, // Receive the handler as a prop
|
||||
onExpandToggle,
|
||||
}) => {
|
||||
const techStack = [
|
||||
{ name: "React", component: ReactIcon, className: "reactIcon", id: 1 },
|
||||
@@ -99,6 +97,7 @@ const TechStack = ({
|
||||
const [animation, setAnimation] = useState(initialAnimation);
|
||||
const { colormode } = useTheme();
|
||||
const { language } = useLang();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
@@ -107,20 +106,20 @@ const TechStack = ({
|
||||
colormode === "light" ? "light" : "dark",
|
||||
"animate__animated",
|
||||
animation,
|
||||
{ expanded: isExpanded } // Conditional class
|
||||
{ expanded: isExpanded }
|
||||
)}
|
||||
/* onMouseEnter={() => onMouseEnter(setAnimation)} */
|
||||
onAnimationEnd={() => onAnimationEnd(setAnimation)}
|
||||
>
|
||||
<h2>Tech Stack</h2>
|
||||
<div className="techStack">
|
||||
{techStack
|
||||
.filter((tech) => isExpanded || !tech.needExpand) // Filter based on isExpanded
|
||||
.filter((tech) => isExpanded || !tech.needExpand)
|
||||
.map((tech) => {
|
||||
const IconComponent = tech.component;
|
||||
return (
|
||||
<div key={tech.id} className="techStackItem">
|
||||
<div key={tech.id} className="techStackItem tooltip">
|
||||
<IconComponent className={`techIcon ${tech.className}`} />
|
||||
<span className="tooltipText">{tech.name}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user