lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
46 lines (45 loc) • 3.61 kB
JavaScript
// @ts-nocheck
"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useRef, useId } from "react";
import { cn } from "../../lib/utils";
export const MagicCard = ({ imageUrl, title, icon, className, ...props }) => {
const cardRef = useRef(null);
const id = useId();
// Sanitize ID for use in URL
const filterId = `magic-card-blur-${id.replace(/:/g, '')}`;
const handleMouseMove = (e) => {
const card = cardRef.current;
if (!card)
return;
const rect = card.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const relativeX = e.clientX - centerX;
const relativeY = e.clientY - centerY;
// Normalize to -1 to 1 range
const x = (relativeX / (rect.width / 2)).toFixed(3);
const y = (relativeY / (rect.height / 2)).toFixed(3);
card.style.setProperty('--pointer-x', x);
card.style.setProperty('--pointer-y', y);
};
const handleMouseLeave = () => {
const card = cardRef.current;
if (!card)
return;
// Reset to default "off-screen" position, matching the default fallback
card.style.setProperty('--pointer-x', '-10');
card.style.setProperty('--pointer-y', '-10');
};
return (_jsxs("article", { ref: cardRef, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: cn("group relative aspect-[4/3] w-[300px] cursor-pointer rounded-xl outline outline-2 outline-neutral-200 dark:outline-neutral-800 bg-neutral-50 dark:bg-neutral-900 transition-all duration-300 active:scale-[0.99] active:translate-y-px [container-type:size]", className), ...props, children: [_jsxs("div", { className: "absolute inset-0 grid place-items-center gap-2 overflow-hidden rounded-xl [clip-path:inset(0_round_12px)]", children: [_jsx("div", { className: "img-container absolute inset-0 grid place-items-center opacity-25 group-hover:opacity-100 transition-opacity duration-300", style: {
transform: 'translateZ(0)',
filter: `url(#${filterId}) saturate(5) brightness(1.3) contrast(1.4)`,
translate: 'calc(var(--pointer-x, -10) * 50cqi) calc(var(--pointer-y, -10) * 50cqh)',
scale: '3.4',
willChange: 'transform, filter'
}, children: _jsx("img", { src: imageUrl, alt: "", className: "w-[100px] select-none" }) }), _jsx("img", { src: imageUrl, alt: "", className: "relative z-[2] w-[100px] select-none" }), _jsx("h2", { className: "relative z-[4] m-0 text-base font-medium select-none text-neutral-900 dark:text-neutral-100", children: title })] }), _jsx("div", { className: "pointer-events-none absolute inset-0 z-[2] rounded-xl border-[3px] border-transparent [transform:translateZ(0)] [clip-path:inset(0_round_12px)] backdrop-blur-sm backdrop-saturate-[4.2] backdrop-brightness-[2.5] backdrop-contrast-[2.5]", style: {
mask: 'linear-gradient(#fff 0 100%) border-box, linear-gradient(#fff 0 100%) padding-box',
maskComposite: 'exclude',
WebkitMaskComposite: 'xor', // Webkit fallback for exclude behavior
} }), _jsx("svg", { className: "absolute h-0 w-0 overflow-visible opacity-0 pointer-events-none", children: _jsx("defs", { children: _jsx("filter", { id: filterId, width: "500%", height: "500%", children: _jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "28" }) }) }) })] }));
};