Skip to content

Instantly share code, notes, and snippets.

@Livog
Created February 29, 2024 17:10
Show Gist options
  • Save Livog/1a25bfd4f036689372edb9585a46ac22 to your computer and use it in GitHub Desktop.
Save Livog/1a25bfd4f036689372edb9585a46ac22 to your computer and use it in GitHub Desktop.
Slider
'use client'
import 'swiper/css'
import 'swiper/css/navigation'
import { useRef, useState, useEffect, type ReactNode, type CSSProperties } from 'react'
import { Navigation } from 'swiper/modules'
import type { Swiper as SwiperType, SwiperOptions } from 'swiper/types'
import ChevronLeftIcon from '@public/icons/chevron-left.svg'
import ChevronRightIcon from '@public/icons/chevron-right.svg'
import clsx from 'clsx'
const formatSwiperSettings = (settings: SwiperOptions): SwiperOptions => {
const tempSettings = {
watchSlidesProgress: true,
modules: [Navigation],
slidesPerView: 1,
speed: 250,
spaceBetween: 10,
preloadImages: false,
grabCursor: true,
...settings
}
if (settings.pagination) {
tempSettings.pagination = {
el: '.swiper-pagination',
clickable: true
}
}
return tempSettings
}
export default function Slider({
children,
className = undefined,
swiperSettings
}: {
children: ReactNode
className?: string
swiperSettings: SwiperOptions
}) {
const [swiper, setSwiper] = useState<SwiperType | null>(null)
const sliderRef = useRef<HTMLDivElement>(null)
const [isBeginning, setIsBeginning] = useState(true)
const [isEnd, setIsEnd] = useState(false)
swiperSettings = formatSwiperSettings(swiperSettings)
const navigationDefaultClassName = `after:!content-[''] bg-white rounded-full !w-[40px] !h-[40px] [&_svg]:text-blue [&_svg]:!w-[20px] [&_svg]:relative opacity-0 shadow-md transition-opacity duration-300`
useEffect(() => {
if (!sliderRef.current) return
import('swiper/core').then((mod) => {
const Swiper = mod.default
// @ts-ignore
const tempSwiper = new Swiper(sliderRef.current, {
...swiperSettings,
on: {
init(swiper: SwiperType) {
setIsBeginning(swiper.isBeginning)
setIsEnd(swiper.isEnd)
},
slideChange(swiper: SwiperType) {
setIsBeginning(swiper.isBeginning)
setIsEnd(swiper.isEnd)
}
}
})
setSwiper(tempSwiper)
})
}, [sliderRef.current])
return (
<div ref={sliderRef} className={clsx('swiper', className)}>
<div className="swiper-wrapper">{children}</div>
<div className="swiper-pagination"></div>
{swiperSettings.navigation && (
<div
className={clsx('swiper-button-prev [&_svg]:left-[-1px]', { '!opacity-100': !isBeginning }, navigationDefaultClassName)}
onClick={() => {
swiper?.slidePrev()
}}
style={{ '--swiper-navigation-sides-offset': '-12px' } as CSSProperties}
>
<ChevronLeftIcon />
</div>
)}
{swiperSettings.navigation && (
<div
className={clsx('swiper-button-next [&_svg]:right-[-1px]', { '!opacity-100': !isEnd }, navigationDefaultClassName)}
onClick={() => {
swiper?.slideNext()
}}
style={{ '--swiper-navigation-sides-offset': '-12px' } as CSSProperties}
>
<ChevronRightIcon />
</div>
)}
<div className="swiper-scrollbar"></div>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment