fixed carousel

This commit is contained in:
2026-05-30 07:20:39 +01:00
parent 74a908f07f
commit 87f8d2b04e

View File

@@ -16,6 +16,7 @@ interface ContentCardCarouselProps {
cards: ContentCardItem[] cards: ContentCardItem[]
} }
// correctly works
function getVisibleCardCount() { function getVisibleCardCount() {
if (typeof window === 'undefined') return 1 if (typeof window === 'undefined') return 1
if (window.matchMedia('(min-width: 1024px)').matches) return 3 if (window.matchMedia('(min-width: 1024px)').matches) return 3
@@ -52,21 +53,26 @@ export default function ContentCardCarousel({ cards }: ContentCardCarouselProps)
const maxIndex = useMemo(() => Math.max(cards.length - visibleCards, 0), [cards.length, visibleCards]) const maxIndex = useMemo(() => Math.max(cards.length - visibleCards, 0), [cards.length, visibleCards])
// custom mod function because JS does not have working modulus
function mod(n: number, m: number) {
return ((n % m) + m) % m;
}
useEffect(() => { useEffect(() => {
setCurrentIndex((previous) => Math.min(previous, maxIndex)) setCurrentIndex((previous) => Math.min(previous, maxIndex))
}, [maxIndex]) }, [maxIndex])
// % of track width — matches flex slide sizes (100% / 50% / 33.333% per breakpoint) // % of track width — matches flex slide sizes (100% / 50% / 33.333% per breakpoint)
const trackOffsetPercent = cards.length > 0 ? (currentIndex * 100) / cards.length : 0 const trackOffsetPercent = cards.length > 0 ? ((currentIndex) * -100) / visibleCards : 0
const next = () => { const next = () => {
if (maxIndex === 0) return if (maxIndex === 0) return
setCurrentIndex((previous) => (previous >= maxIndex ? 0 : previous + 1)) setCurrentIndex(mod(Math.abs((currentIndex + 1)), (cards.length)))
} }
const previous = () => { const previous = () => {
if (maxIndex === 0) return if (maxIndex === 0) return
setCurrentIndex((index) => (index <= 0 ? maxIndex : index - 1)) setCurrentIndex(mod((currentIndex - 1), (cards.length)))
} }
return ( return (
@@ -76,7 +82,7 @@ export default function ContentCardCarousel({ cards }: ContentCardCarouselProps)
<div className="carousel-viewport relative overflow-hidden"> <div className="carousel-viewport relative overflow-hidden">
<div <div
className="carousel-track flex items-stretch transition-transform duration-500 ease-in-out" className="carousel-track flex items-stretch transition-transform duration-500 ease-in-out"
style={{ transform: `translate3d(-${trackOffsetPercent}%, 0, 0)` }} style={{ transform: `translate3d(${trackOffsetPercent}%, 0, 0)` }}
> >
{cards.map((card, index) => { {cards.map((card, index) => {
const isEdgeCard = const isEdgeCard =
@@ -97,15 +103,14 @@ export default function ContentCardCarousel({ cards }: ContentCardCarouselProps)
})} })}
</div> </div>
<div className="pointer-events-none absolute inset-y-0 left-0 w-12 bg-gradient-to-r from-white to-transparent dark:from-black" /> <div className="absolute inset-y-0 left-0 w-12 bg-linear-to-r from-white to-transparent dark:from-black" />
<div className="pointer-events-none absolute inset-y-0 right-0 w-12 bg-gradient-to-l from-white to-transparent dark:from-black" /> <div className="absolute inset-y-0 right-0 w-12 bg-linear-to-l from-white to-transparent dark:from-black" />
</div> </div>
<div className="carousel-controls relative z-20 mt-6 flex justify-center gap-4"> <div className="carousel-controls relative z-20 mt-6 flex justify-center gap-4">
<button <button
type="button" type="button"
onClick={previous} onClick={previous}
disabled={maxIndex === 0}
className="carousel-control-btn" className="carousel-control-btn"
aria-label="Show previous content cards" aria-label="Show previous content cards"
> >