Components / Diamond Gallery

Diamond Gallery

A unique image gallery with 4 images arranged in a diamond pattern. Features hover effects with scale, blur, and grayscale transitions.

Preview

Hover over each image to see the focus effect.Images can optionally be wrapped in links for navigation.

Imagen de galería 1
Imagen de galería 2
Imagen de galería 3
Imagen de galería 4

Usage

tsx
import DiamondGallery from "@/components/diamond-gallery/diamond-gallery"

export function Example() {
  return (
    <div className="w-96 h-96">
      <DiamondGallery
        images={[
          { image: '/images/photo1.jpg', isLink: true, href: '/', target: '_blank' },
          { image: '/images/photo2.jpg', isLink: false },
          { image: '/images/photo3.jpg', isLink: false },
          { image: '/images/photo4.jpg', isLink: true, href: '/about' },
        ]}
      />
    </div>
  )
}

Props

PropTypeDescription
imagesImageItem[]Array of 4 images to display

ImageItem Type

PropertyTypeRequiredDescription
imagestringYesImage source URL
isLinkbooleanNoWrap image in anchor tag
hrefstringNoLink destination URL
targetstringNoLink target (_blank, _self, etc.)
relstringNoLink rel attribute

Features

  • Diamond-shaped layout with 4 rotated images
  • Hover effect: focused image scales up to 100%
  • Other images blur and turn grayscale on hover
  • Smooth 500ms transitions
  • Optional link wrapping for each image
  • Responsive - uses parent container dimensions
  • CSS-only animations (no JS animation library)

Image Positions

Images are positioned in a diamond pattern:

  • images[0] - Top center
  • images[1] - Left center
  • images[2] - Right center
  • images[3] - Bottom center

Notes

  • Requires exactly 4 images for proper layout
  • Parent container should have defined width/height
  • Uses aspect-square for consistent proportions
  • Images are rotated 45° and counter-rotated inside

Source Code

tsx
'use client'
import { useState } from 'react'

interface ImageItem {
    image: string
    isLink?: boolean
    href?: string
    target?: string
    rel?: string
}

interface DiamondGalleryProps {
    images: ImageItem[]
}

const DiamondGallery = ({ images }: DiamondGalleryProps) => {
    const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)

    const positions = [
        'top-0 left-1/2 transform -translate-x-1/2 -translate-y-[5%]',
        'left-0 top-1/2 transform -translate-y-1/2 -translate-x-[5%]',
        'right-0 top-1/2 transform -translate-y-1/2 translate-x-[5%]',
        'bottom-0 left-1/2 transform -translate-x-1/2 translate-y-[5%]'
    ]

    return (
        <div className='relative aspect-square h-full'>
            {images.slice(0, 4).map((img: ImageItem, idx: number) => {
                const imageElement = (
                    <img
                        src={img.image}
                        alt={`Gallery image ${idx + 1}`}
                        className='size-full object-cover -rotate-45 scale-150'
                        onMouseEnter={() => setHoveredIndex(idx)}
                        onMouseLeave={() => setHoveredIndex(null)}
                    />
                )

                return (
                    <div
                        className={`absolute w-1/2 h-1/2 rotate-45 rounded-lg transition-all duration-500 overflow-hidden 
              ${positions[idx]}
              ${hoveredIndex === idx ? 'scale-100 z-1' : 'scale-75 z-0'}
              ${hoveredIndex !== null && hoveredIndex !== idx
                            ? 'filter blur-sm grayscale'
                            : ''
                        }`}
                        key={idx}
                    >
                        {img.isLink ? (
                            <a
                                href={img.href}
                                target={img.target}
                                rel={img.rel}
                                className='block size-full'
                            >
                                {imageElement}
                            </a>
                        ) : (
                            imageElement
                        )}
                    </div>
                )
            })}
        </div>
    )
}

export default DiamondGallery;