"use client";
import * as React from "react";
import { cn, scaleValue } from "@/lib/utils";
import { useRef } from "react";
interface SocialIconProps {
className?: string;
src: string;
href: string;
name: string;
handleIconHover?: (e: React.MouseEvent<HTMLLIElement>) => void;
iconSize: number;
}
export const SocialIcon = React.forwardRef<HTMLLIElement, SocialIconProps>(
({ className, src, href, name, handleIconHover, iconSize }, ref) => {
return (
<>
<style jsx>
{`
.icon:hover + .icon {
width: calc(
var(--icon-size) * 1.33 + var(--dock-offset-right, 0px)
);
height: calc(
var(--icon-size) * 1.33 + var(--dock-offset-right, 0px)
);
margin-top: calc(
var(--icon-size) * -0.33 + var(--dock-offset-right, 0) * -1
);
}
.icon:hover + .icon + .icon {
width: calc(
var(--icon-size) * 1.17 + var(--dock-offset-right, 0px)
);
height: calc(
var(--icon-size) * 1.17 + var(--dock-offset-right, 0px)
);
margin-top: calc(
var(--icon-size) * -0.17 + var(--dock-offset-right, 0) * -1
);
}
.icon:has(+ .icon:hover) {
width: calc(
var(--icon-size) * 1.33 + var(--dock-offset-left, 0px)
);
height: calc(
var(--icon-size) * 1.33 + var(--dock-offset-left, 0px)
);
margin-top: calc(
var(--icon-size) * -0.33 + var(--dock-offset-left, 0) * -1
);
}
.icon:has(+ .icon + .icon:hover) {
width: calc(
var(--icon-size) * 1.17 + var(--dock-offset-left, 0px)
);
height: calc(
var(--icon-size) * 1.17 + var(--dock-offset-left, 0px)
);
margin-top: calc(
var(--icon-size) * -0.17 + var(--dock-offset-left, 0) * -1
);
}
`}
</style>
<li
ref={ref}
style={{
transition:
"width, height, margin-top, cubic-bezier(0.25, 1, 0.5, 1) 150ms",
"--icon-size": `${iconSize}px`,
}}
onMouseMove={handleIconHover}
className={cn(
`icon h-[var(--icon-size)] w-[var(--icon-size)] rounded-md px-[calc(var(--icon-size)*0.133)] group/li cursor-pointer hover:w-[calc(var(--icon-size)*1.5)] hover:h-[calc(var(--icon-size)*1.5)] hover:-mt-[calc(var(--icon-size)/2)]`,
className
)}
>
<a href={href} className="relative">
<span
className={`text-xs absolute top-[-30px] border border-zinc-200 dark:border-zinc-800 text-black dark:text-white rounded-md bg-gradient-to-t from-zinc-100/50 dark:from-zinc-900 p-1 px-2 left-1/2 -translate-x-1/2 opacity-0 transition-opacity duration-200 group-hover/li:opacity-100 `}
>
{name}
</span>
<img
src={src}
alt={name}
className="rounded-[inherit] h-full w-full"
/>
</a>
</li>
</>
);
}
);
SocialIcon.displayName = "SocialIcon";
interface SocialDockProps {
className?: string;
children: React.ReactNode;
maxAdditionalSize?: number;
iconSize?: number;
}
export const SocialDock = React.forwardRef<HTMLDivElement, SocialDockProps>(
({ className, children, maxAdditionalSize = 5, iconSize = 40 }, ref) => {
const dockRef = useRef<HTMLDivElement | null>(null);
const handleIconHover = (e: React.MouseEvent<HTMLLIElement>) => {
if (!dockRef.current) return;
const mousePos = e.clientX;
const iconPosLeft = e.currentTarget.getBoundingClientRect().left;
const iconWidth = e.currentTarget.getBoundingClientRect().width;
const cursorDistance = (mousePos - iconPosLeft) / iconWidth;
const offsetPixels = scaleValue(
cursorDistance,
[0, 1],
[maxAdditionalSize * -1, maxAdditionalSize]
);
dockRef.current.style.setProperty(
"--dock-offset-left",
`${offsetPixels * -1}px`
);
dockRef.current.style.setProperty(
"--dock-offset-right",
`${offsetPixels}px`
);
};
return (
<nav ref={dockRef} className="">
<ul
className={cn(
"flex items-center bg-gradient-to-t from-zinc-100/50 dark:from-zinc-900 shadow-sm dark:shadow-none p-2 rounded-2xl border border-zinc-200 dark:border-zinc-800",
className
)}
>
{React.Children.map(children, (child) =>
React.isValidElement(child)
? React.cloneElement(child, { handleIconHover, iconSize })
: child
)}
</ul>
</nav>
);
}
);
SocialDock.displayName = "SocialDock";