Skip to content

Commit

Permalink
[FEATURE] Add a zoom feature for images in the carousel
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoineBorda committed Oct 26, 2024
1 parent f2657aa commit 1409769
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 24 deletions.
68 changes: 45 additions & 23 deletions assets/components/ui/carousel.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use client'

import * as React from 'react'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import { ChevronLeft, ChevronRight, X } from 'lucide-react'
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogClose } from "@/components/ui/dialog"
import { ReactNode, useEffect, useState } from 'react'

interface CarouselItem {
Expand All @@ -11,75 +12,96 @@ interface CarouselItem {
}

interface CarouselProps {
items: CarouselItem[]
autoSlideInterval?: number // Optionnel : intervalle pour le diaporama automatique
items?: CarouselItem[]
autoSlideInterval?: number
}

const Carousel: React.FC<CarouselProps> = ({ items, autoSlideInterval = 3000 }) => {
export default function Carousel({ items = [], autoSlideInterval = 3000 }: CarouselProps) {
const [currentIndex, setCurrentIndex] = useState(0)
const [isEnlarged, setIsEnlarged] = useState(false)
const [enlargedIndex, setEnlargedIndex] = useState(0)

const nextSlide = () => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % items.length)
if (items.length > 0) {
setCurrentIndex((prevIndex) => (prevIndex + 1) % items.length)
}
}

const prevSlide = () => {
setCurrentIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length)
if (items.length > 0) {
setCurrentIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length)
}
}

const handleImageClick = (index: number) => {
setEnlargedIndex(index)
setIsEnlarged(true)
}

useEffect(() => {
if (autoSlideInterval > 0) {
if (autoSlideInterval > 0 && !isEnlarged && items.length > 0) {
const timer = setInterval(() => {
nextSlide()
}, autoSlideInterval)

return () => clearInterval(timer)
}
}, [currentIndex, autoSlideInterval])
}, [currentIndex, autoSlideInterval, isEnlarged, items.length])

if (!items || items.length === 0) {
return <div className="p-4 text-center">No items to display</div>
}

return (
<div className="relative max-w-md mx-auto w-60">
<div className="overflow-hidden bg-white border-2 rounded-base border-border dark:border-darkBorder shadow-light dark:shadow-dark dark:bg-secondaryBlack">
<div className="overflow-hidden bg-white border-2 rounded-lg shadow-md border-border dark:border-darkBorder dark:shadow-dark dark:bg-gray-800">
<div
className="flex transition-transform duration-300 ease-in-out"
style={{ transform: `translateX(-${currentIndex * 100}%)` }}
>
{items.map((item) => (
{items.map((item, index) => (
<div key={item.id} className="flex-shrink-0 w-full">
<div className="">
{/* Conteneur carré */}
<div className="w-full aspect-square">
{React.isValidElement(item.content) && React.cloneElement(item.content as React.ReactElement, {
className: "w-full h-full object-cover rounded",
})}
{/* Si content n'est pas une image, ajustez selon vos besoins */}
</div>
<div className="w-full cursor-pointer aspect-square" onClick={() => handleImageClick(index)}>
{React.isValidElement(item.content) && React.cloneElement(item.content as React.ReactElement, {
className: "w-full h-full object-cover rounded-lg",
})}
</div>
</div>
))}
</div>
</div>
{/* Bouton Précédent */}
<Button
variant="neutralStatic"
size="icon"
className="absolute top-0 bottom-0 my-auto left-2"
onClick={prevSlide}
aria-label="Précédent"
aria-label="Previous"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{/* Bouton Suivant */}
<Button
variant="neutralStatic"
size="icon"
className="absolute top-0 bottom-0 my-auto right-2"
onClick={nextSlide}
aria-label="Suivant"
aria-label="Next"
>
<ChevronRight className="w-4 h-4" />
</Button>

<Dialog open={isEnlarged} onOpenChange={setIsEnlarged}>
<DialogContent className="max-w-[90vw] max-h-[90vh] p-0 overflow-hidden">
<div className="relative w-full h-full">
{items[enlargedIndex] && React.isValidElement(items[enlargedIndex].content) &&
React.cloneElement(items[enlargedIndex].content as React.ReactElement, {
className: "w-full h-full object-contain",
})
}
</div>
</DialogContent>
</Dialog>
</div>
)
}

export { Carousel }
export { Carousel }
126 changes: 126 additions & 0 deletions assets/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
'use client'

import * as DialogPrimitive from '@radix-ui/react-dialog'
import { X } from 'lucide-react'

import * as React from 'react'

import { cn } from '@/lib/utils'
import { Button } from './button'

const Dialog = DialogPrimitive.Root

const DialogTrigger = DialogPrimitive.Trigger

const DialogPortal = DialogPrimitive.Portal

const DialogClose = DialogPrimitive.Close

const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
'fixed inset-0 z-50 bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className,
)}
{...props}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-base border-2 border-border dark:border-darkBorder bg-white dark:bg-darkBg p-6 shadow-light dark:shadow-dark duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4">
<Button variant="neutralStatic" size="icon" aria-label="Close">
<X className="w-4 h-4" />
</Button>
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName

const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col space-y-1.5 text-center sm:text-left',
className,
)}
{...props}
/>
)
DialogHeader.displayName = 'DialogHeader'

const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
className,
)}
{...props}
/>
)
DialogFooter.displayName = 'DialogFooter'

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
'text-lg font-heading leading-none tracking-tight',
className,
)}
{...props}
/>
))
DialogTitle.displayName = DialogPrimitive.Title.displayName

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn('text-sm font-base text-text dark:text-darkText', className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName

export {
Dialog,
DialogPortal,
DialogOverlay,
DialogClose,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
}
1 change: 0 additions & 1 deletion assets/react/controllers/SatisfactoryBp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip'
import { Separator } from "@/components/ui/separator"
import { CalendarClock, Download, Hammer, Heart, RefreshCcw, User } from "lucide-react";

interface Block {
Expand Down

0 comments on commit 1409769

Please sign in to comment.