Enlarge Gallery
shadcn-extras/enlarge-galleryFreeComponent
A cinematic, full-screen image gallery with expanding thumbnails.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/NayanDevLab/shadcn-extras/dev/public/c/enlarge-gallery.jsonSource
1'use client';23import React, { useState, useCallback } from 'react';4import { ChevronLeft, ChevronRight } from 'lucide-react';5import { cn } from '@/lib/utils';6import './enlarge-gallery.css';78export interface EnlargeGalleryItem {9 id: string | number;10 src: string;11 alt?: string;12 title: string;13 description?: string;14}1516export interface EnlargeGalleryProps extends React.HTMLAttributes<HTMLDivElement> {17 items: EnlargeGalleryItem[];18}1920export const EnlargeGallery = React.forwardRef<21 HTMLDivElement,22 EnlargeGalleryProps23>(({ className, items, ...props }, ref) => {24 const [activeIndex, setActiveIndex] = useState(0);2526 // The thumbnail strip as a queue of item ids, left to right; the active27 // item is excluded. Every change removes the incoming item from the queue28 // and pushes the outgoing item onto the end.29 const [thumbOrder, setThumbOrder] = useState<(string | number)[]>(() =>30 items.slice(1).map((item) => item.id)31 );3233 const goToIndex = useCallback(34 (newIndex: number) => {35 setActiveIndex((oldIndex) => {36 if (oldIndex === newIndex) return oldIndex;3738 setThumbOrder((order) => [39 ...order.filter((id) => id !== items[newIndex].id),40 items[oldIndex].id,41 ]);4243 return newIndex;44 });45 },46 [items]47 );4849 if (!items || items.length === 0) return null;5051 const activeItem = items[activeIndex];52 const total = items.length;5354 const indexOfId = (id: string | number) =>55 items.findIndex((i) => i.id === id);5657 return (58 <div59 ref={ref}60 className={cn('enlarge-gallery-root font-sans', className)}61 {...props}62 >63 <div className='enlarge-gallery-gallery relative h-full w-full'>64 {/* Slides / Track */}65 <div className='enlarge-gallery-track absolute inset-0 h-full w-full'>66 {items.map((item, index) => {67 const active = index === activeIndex;68 const offset = active69 ? 070 : thumbOrder.indexOf(item.id) - (thumbOrder.length - 1) / 2;7172 return (73 <div74 key={item.id}75 className='enlarge-gallery-item'76 data-active={String(active)}77 >78 <div79 className='enlarge-gallery-slide'80 style={{ '--offset': offset } as React.CSSProperties}81 >82 {/* eslint-disable-next-line @next/next/no-img-element */}83 <img84// … truncated
What it pulls in
npm packages
Files it writes
More from shadcn-extras
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Image Gridanimated-image-grid | shadcn-extras | Components | Free | no deps · 3 files | |
| Blog Card Fourblog-card-four | shadcn-extras | Components | Free | 1 dep | |
| Blog Card Oneblog-card-one | shadcn-extras | Components | Free | no deps | |
| Blog Card Threeblog-card-three | shadcn-extras | Components | Free | 1 dep | |
| Blog Card Twoblog-card-two | shadcn-extras | Components | Free | 1 dep | |
| Bulb Iconbulb-icon | shadcn-extras | Components | Free | 2 deps | |
| Chevron Stepschevron-steps | shadcn-extras | Components | Free | no deps | |
| Circular Gallerycircular-gallery | shadcn-extras | Components | Free | no deps · 3 files |
