lightswind
Version:
A professionally designed animate react component library & templates market that brings together functionality, accessibility, and beautiful aesthetics for modern applications.
85 lines (84 loc) • 6.1 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useRef } from 'react';
import { cn } from '../lib/utils';
import { Github, Code, Dices, Terminal, Settings, Heart, Star, Zap, Trophy, Shield } from 'lucide-react';
const DEFAULT_CARDS = [
{ id: '1', icon: Github, title: 'GitHub', description: 'Code repository' },
{ id: '2', icon: Code, title: 'Code', description: 'Development tools' },
{ id: '3', icon: Dices, title: 'Games', description: 'Interactive projects' },
];
const DEFAULT_ICONS = [Github, Code, Dices, Terminal, Settings, Heart, Star, Zap, Trophy, Shield];
const CodeHoverCards = ({ cards = DEFAULT_CARDS, className, cardClassName, maskRadius = 300, characterCount = 2000, characterSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', animationDuration = 0.5, borderRadius = 26, cardGap = '1rem', iconSize = 48, iconColor = '#ffffff', backgroundColor = '#000000', borderColor = '#ffffff1e', enableTouch = true, columns = 3, minHeight = 399, onCardClick, onCardHover, disabled = false, showBorder = true, }) => {
const [mousePositions, setMousePositions] = useState({});
const [randomTexts, setRandomTexts] = useState({});
const cardRefs = useRef({});
const generateRandomString = (length) => {
return Array.from({ length }, () => characterSet[Math.floor(Math.random() * characterSet.length)]).join('');
};
const handleMouseMove = (e, cardId) => {
if (disabled)
return;
const card = cardRefs.current[cardId];
if (!card)
return;
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setMousePositions(prev => ({ ...prev, [cardId]: { x, y } }));
setRandomTexts(prev => ({ ...prev, [cardId]: generateRandomString(characterCount) }));
};
const handleTouchMove = (e, cardId) => {
if (disabled || !enableTouch)
return;
const card = cardRefs.current[cardId];
if (!card)
return;
const rect = card.getBoundingClientRect();
const touch = e.touches[0];
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
setMousePositions(prev => ({ ...prev, [cardId]: { x, y } }));
setRandomTexts(prev => ({ ...prev, [cardId]: generateRandomString(characterCount) }));
};
const handleCardClick = (card) => {
if (disabled)
return;
if (card.href) {
window.open(card.href, '_blank');
}
onCardClick?.(card);
};
const handleCardHover = (card) => {
if (disabled)
return;
onCardHover?.(card);
};
const getColumnClass = () => {
const columnMap = {
1: 'grid-cols-1',
2: 'grid-cols-1 md:grid-cols-2',
3: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
4: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
};
return columnMap[columns];
};
return (_jsx("div", { className: cn('min-h-screen w-full flex items-center justify-center px-0 py-4', className), style: { backgroundColor }, children: _jsx("div", { className: "container mx-auto", children: _jsx("div", { className: cn('grid gap-4', getColumnClass()), style: { gap: cardGap }, children: cards.map((card) => {
const IconComponent = card.icon;
const position = mousePositions[card.id] || { x: 0, y: 0 };
const randomText = randomTexts[card.id] || '';
return (_jsxs("div", { className: cn('group relative w-full', disabled && 'pointer-events-none opacity-50', cardClassName), children: [_jsxs("div", { ref: (el) => { cardRefs.current[card.id] = el; }, className: cn('relative w-full h-full flex items-center justify-center overflow-hidden cursor-pointer transition-all duration-200', 'hover:scale-105 active:scale-95', showBorder && 'border-[0.5px]'), style: {
borderColor: showBorder ? borderColor : 'transparent',
borderRadius: `${borderRadius}px`,
minHeight: `${minHeight}px`,
aspectRatio: '1',
}, onMouseMove: (e) => handleMouseMove(e, card.id), onTouchMove: enableTouch ? (e) => handleTouchMove(e, card.id) : undefined, onClick: () => handleCardClick(card), onMouseEnter: () => handleCardHover(card), children: [_jsx("div", { className: "relative z-10", children: _jsx(IconComponent, { size: iconSize, style: { color: iconColor }, className: "transition-transform duration-200 group-hover:scale-110" }) }), _jsx("div", { className: "absolute inset-0 pointer-events-none z-[5]", style: {
mixBlendMode: 'darken',
} }), _jsx("div", { className: "absolute inset-0 font-mono text-sm leading-tight text-white opacity-0 group-hover:opacity-100 transition-opacity duration-500 overflow-hidden break-all", style: {
WebkitMaskImage: `radial-gradient(${maskRadius}px circle at ${position.x}px ${position.y}px, #000 20%, rgba(0, 0, 0, 0.25), transparent)`,
maskImage: `radial-gradient(${maskRadius}px circle at ${position.x}px ${position.y}px, #000 20%, rgba(0, 0, 0, 0.25), transparent)`,
transform: 'scale(1.025)',
transitionDuration: `${animationDuration}s`,
}, children: randomText })] }), (card.title || card.description) && (_jsxs("div", { className: "mt-4 text-center", children: [card.title && (_jsx("h3", { className: "text-lg font-semibold text-white mb-1", children: card.title })), card.description && (_jsx("p", { className: "text-sm text-gray-400", children: card.description }))] }))] }, card.id));
}) }) }) }));
};
export default CodeHoverCards;