Newer
Older
My-Portfolio / frontend / src / components / sections / projects / HoverableSkill.jsx
import React, { useEffect, useRef, useState } from "react";
import { motion, useAnimation } from "framer-motion";
import clsx from "clsx";
import MouseTracker from "../../MouseTracker"; // Import the MouseTracker component

const HoverableSkillList = ({
  title,
  items = [], // Default to an empty array to avoid undefined errors
  color = "red",
  hoveredItem,
  setHoveredItem,
  section,
  getKey,
  isVisible,
}) => {
  const borderClass = `text-${color}-400`;
  const controls = useAnimation();
  const skillLevelRefs = useRef([]);
  const [isMobile, setIsMobile] = useState(false);

  // Detect if the device is mobile
  useEffect(() => {
    const checkIsMobile = () => {
      setIsMobile(window.innerWidth <= 768); // Adjust breakpoint as needed
    };

    checkIsMobile(); // Check on initial render
    window.addEventListener("resize", checkIsMobile); // Check on window resize

    return () => {
      window.removeEventListener("resize", checkIsMobile); // Cleanup
    };
  }, []);

  useEffect(() => {
    if (isVisible) {
      controls.start((item) => {
        const circumference = 2 * Math.PI * 40; // Adjusted radius
        const skillLevel = parseInt(
          item.skill.split(": ")[1].split("/")[0],
          10
        );
        return {
          strokeDashoffset: circumference - (skillLevel / 5) * circumference,
          transition: { duration: 1, ease: "easeInOut" },
        };
      });
    } else {
      controls.set({ strokeDashoffset: 2 * Math.PI * 40 });
    }
  }, [isVisible, controls]);

  // Check if the current item is hovered
  const isHovered =
    hoveredItem.section === section && hoveredItem.index !== null;

  return (
    <div className="relative mx-auto text-center">
      <h2
        className={clsx("text-2xl font-sans font-semibold mb-8", borderClass)}
      >
        {title}
      </h2>
      <div className="flex gap-3 flex-wrap justify-center">
        {items.map((item, index) => {
          const circumference = 2 * Math.PI * 40;

          return (
            <div
              key={getKey(item, index)}
              className="relative flex flex-col items-center mb-2 group"
              onMouseEnter={() =>
                !isMobile && setHoveredItem({ section, index })
              }
              onMouseLeave={() =>
                !isMobile && setHoveredItem({ section: null, index: null })
              }
              onClick={() => isMobile && setHoveredItem({ section, index })}
            >
              <div className="relative w-[70px] h-[70px] sm:w-[70px] sm:h-[70px] md:w-[80px] md:h-[80px] lg:w-[90px] lg:h-[90px]">
                {" "}
                {/* Adjusted size for mobile */}
                <svg
                  className="absolute top-0 left-0 w-full h-full transform -rotate-90"
                  viewBox="0 0 100 100"
                >
                  {/* Background Circle */}
                  <circle
                    cx="50"
                    cy="50"
                    r="40"
                    fill="transparent"
                    stroke="gray"
                    strokeWidth="6"
                    strokeDasharray={circumference}
                  />
                  {/* Animated Progress Circle */}
                  <motion.circle
                    cx="50"
                    cy="50"
                    r="40"
                    fill="transparent"
                    stroke="currentColor"
                    strokeWidth="7"
                    strokeDasharray={circumference}
                    initial={{ strokeDashoffset: circumference }}
                    animate={controls}
                    custom={item}
                    className={clsx(borderClass, "transition-all duration-300")}
                  />
                </svg>
                {/* Icon */}
                <motion.img
                  alt={item.name}
                  src={item.logo}
                  className={clsx(
                    "p-2 w-[60px] h-[60px] sm:w-[70px] sm:h-[70px] rounded-full transition-all duration-100 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2",
                    isHovered &&
                      hoveredItem.index === index &&
                      "shadow-[0_0_50px_rgba(255,255,255,0.9)]"
                  )}
                />
              </div>
              <p className="mt-2 text-base text-white">{item.name}</p>

              {/* Inline Tooltip for Mobile */}
              {isMobile && isHovered && hoveredItem.index === index && (
                <div className="absolute bottom-full mb-2 bg-black text-white text-sm font-bold rounded-md px-8 py-3 shadow-lg">
                  {item.skill}
                </div>
              )}
            </div>
          );
        })}
      </div>

      {/* MouseTracker for Desktop Tooltip */}
      {!isMobile && isHovered && (
        <MouseTracker text={items[hoveredItem.index].skill} />
      )}
    </div>
  );
};

export default HoverableSkillList;