Newer
Older
My-Portfolio / frontend / src / components / sections / projects / HoverableIcon.jsx
import React, { useState, useEffect, useRef } from "react";
import { motion } from "framer-motion";
import clsx from "clsx"; // Import clsx for handling dynamic classes

const HoverableIconList = ({
  title,
  items,
  color = "red",
  getKey,
  onHoverStart, // New prop
  onHoverEnd, // New prop
  sectionId, // New prop to identify section
}) => {
  const [hoveredItem, setHoveredItem] = useState(null); // Track hovered item index
  const [isMobile, setIsMobile] = useState(false); // Track if the device is mobile
  const iconRefs = useRef([]); // Refs for each icon

  // 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
    };
  }, []);

  // Handle click outside to clear hoveredItem
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (
        isMobile &&
        hoveredItem !== null &&
        !iconRefs.current[hoveredItem]?.contains(event.target)
      ) {
        setHoveredItem(null);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isMobile, hoveredItem]);

  // Dynamically constructing class names using clsx
  const borderClass = `${color}`; // e.g., "yellow-400"
  const shadowClass = `[0_0_30px_rgba(255,255,255,0.6)]`; // e.g., "yellow-500"

  return (
    <div className="relative mx-auto text-center">
      <h2
        className={clsx(
          "text-2xl md:text-2xl font-sans font-semibold mb-8 text-orange-400",
          `text-${color}-400`
        )}
      >
        {title}
      </h2>
      <div className="flex gap-7 flex-wrap justify-center">
        {(items ?? []).map((item, index) => (
          <div
            key={getKey(item, index)}
            className="relative flex flex-col items-center mb-2 group"
            onMouseEnter={() => {
              if (!isMobile) {
                onHoverStart?.(sectionId, index, item.name);
                setHoveredItem(index);
              }
            }}
            onMouseLeave={() => {
              if (!isMobile) {
                onHoverEnd?.();
                setHoveredItem(null);
              }
            }}
            onClick={() => {
              if (isMobile) {
                const newHovered = hoveredItem === index ? null : index;
                setHoveredItem(newHovered);
                if (newHovered !== null) {
                  onHoverStart?.(sectionId, index, item.name);
                } else {
                  onHoverEnd?.();
                }
              }
            }}
          >
            <motion.img
              alt={item.name}
              src={item.logo}
              className={clsx(
                "p-2 w-[60px] md:w-[70px] rounded-full transition-all duration-100 group-hover:scale-110",
                hoveredItem === index &&
                  `border-4 border-${borderClass} shadow-lg hover:shadow-${shadowClass}`
              )}
            />
            {/* Inline Tooltip for Mobile */}
            {isMobile && hoveredItem === 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.name}
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
};

export default HoverableIconList;