import React, { useState, useEffect, useCallback, useRef } from 'react'; import styled from 'styled-components'; import { GlassIconButton } from '@/components/ui/glass-icon-button'; import { Check } from 'lucide-react'; interface ImageWaveProps { // 图片列表数据 images: string[]; // 容器宽度 containerWidth?: string; // 容器高度 containerHeight?: string; // 单个图片宽度 itemWidth?: string; // 单个图片高度 itemHeight?: string; // 图片间距 gap?: string; // 是否开启自动动画 autoAnimate?: boolean; // 自动动画间隔时间(ms) autoAnimateInterval?: number; // 是否开启点击事件 onClick?: (index: number) => void; } const Wrapper = styled.div<{ width?: string; height?: string }>` display: flex; align-items: center; justify-content: center; width: ${props => props.width || '100vw'}; height: ${props => props.height || '100vh'}; background-color: transparent; `; const Items = styled.div<{ gap?: string }>` display: flex; gap: ${props => props.gap || '0.4rem'}; perspective: calc(var(--index) * 35); &.has-expanded .item:not(.expanded) { filter: grayscale(1) brightness(0.3); } &.has-expanded .item:hover { filter: grayscale(1) brightness(0.3); } &.has-expanded .item.expanded:hover { filter: inherit; transform: translateZ(calc(var(--index) * 10)); } `; const Item = styled.div<{ width?: string; height?: string }>` width: ${props => props.width || 'calc(var(--index) * 3)'}; height: ${props => props.height || 'calc(var(--index) * 12)'}; background-color: #222; background-size: cover; background-position: center; cursor: pointer; filter: grayscale(1) brightness(0.5); transition: transform 1.25s var(--transition), filter 3s var(--transition), width 1.25s var(--transition), margin 1.25s var(--transition); will-change: transform, filter, rotateY, width; &::before { content: ''; position: absolute; width: 20px; height: 100%; right: calc(var(--index) * -1); } &::after { left: calc(var(--index) * -1); } &:hover { filter: inherit; transform: translateZ(calc(var(--index) * 7.8)); } &:hover + * { filter: inherit; transform: translateZ(calc(var(--index) * 6.8)) rotateY(35deg); z-index: -1; } &:hover + * + * { filter: inherit; transform: translateZ(calc(var(--index) * 5.6)) rotateY(40deg); z-index: -2; } &:hover + * + * + * { filter: inherit; transform: translateZ(calc(var(--index) * 3.6)) rotateY(30deg); z-index: -3; } &:hover + * + * + * + * { filter: inherit; transform: translateZ(calc(var(--index) * .6)) rotateY(15deg); z-index: -4; } &:has(+ :hover) { filter: inherit; transform: translateZ(calc(var(--index) * 6.8)) rotateY(-35deg); } &:has(+ * + :hover) { filter: inherit; transform: translateZ(calc(var(--index) * 5.6)) rotateY(-40deg); } &:has(+ * + * + :hover) { filter: inherit; transform: translateZ(calc(var(--index) * 3.6)) rotateY(-30deg); } &:has(+ * + * + * + :hover) { filter: inherit; transform: translateZ(calc(var(--index) * .6)) rotateY(-15deg); } &.expanded { width: 28vw; filter: inherit; z-index: 100; transform: translateZ(calc(var(--index) * 7.8)); margin: 0.45vw; } &.selected { filter: inherit; } `; export const ImageWave: React.FC = ({ images, containerWidth, containerHeight, itemWidth, itemHeight, gap, autoAnimate = false, autoAnimateInterval = 2000, onClick, }) => { const [currentExpandedItem, setCurrentExpandedItem] = useState(null); const [currentSelectedIndex, setCurrentSelectedIndex] = useState(null); const itemsRef = useRef(null); const autoAnimateRef = useRef(null); const currentIndexRef = useRef(0); const handleItemClick = (index: number) => { if (currentExpandedItem === index) { setCurrentExpandedItem(null); } else { setCurrentExpandedItem(index); } }; const handleOutsideClick = useCallback((e: MouseEvent) => { if (itemsRef.current && !itemsRef.current.contains(e.target as Node)) { setCurrentExpandedItem(null); } }, []); const handleKeyDown = useCallback((e: KeyboardEvent) => { if (e.key === 'Escape') { setCurrentExpandedItem(null); } }, []); useEffect(() => { document.addEventListener('click', handleOutsideClick); document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('click', handleOutsideClick); document.removeEventListener('keydown', handleKeyDown); }; }, [handleOutsideClick, handleKeyDown]); useEffect(() => { return () => { if (autoAnimateRef.current) { clearTimeout(autoAnimateRef.current); } }; }, [autoAnimate]); const handleSelectImage = (index: number) => { setCurrentSelectedIndex(index); onClick?.(index); }; return ( {images.map((image, index) => ( handleItemClick(index)} tabIndex={0} > {/* 添加一个玻璃按钮 勾选当前图片 移入/选中改变图标颜色 */} handleSelectImage(index)} className="absolute top-1 right-1 z-[999] cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity duration-300 group-hover:bg-blue-500/50" /> ))} ); };