import { Controller } from "@hotwired/stimulus"
|
|
|
|
export default class extends Controller {
|
|
static targets = ["carousel", "marker"]
|
|
|
|
connect() {
|
|
this.boundUpdate = this.update.bind(this)
|
|
this.boundEqualizeHeights = this.equalizeHeights.bind(this)
|
|
this.carouselTarget.addEventListener("scroll", this.boundUpdate, { passive: true })
|
|
window.addEventListener("resize", this.boundEqualizeHeights)
|
|
this.equalizeHeights()
|
|
this.update()
|
|
}
|
|
|
|
disconnect() {
|
|
this.carouselTarget.removeEventListener("scroll", this.boundUpdate)
|
|
window.removeEventListener("resize", this.boundEqualizeHeights)
|
|
}
|
|
|
|
equalizeHeights() {
|
|
const articles = this.carouselTarget.querySelectorAll(":scope > li > article")
|
|
articles.forEach((article) => (article.style.height = "auto"))
|
|
const tallest = Array.from(articles).reduce((max, article) => Math.max(max, article.offsetHeight), 0)
|
|
articles.forEach((article) => (article.style.height = `${tallest}px`))
|
|
}
|
|
|
|
update() {
|
|
const slides = Array.from(this.carouselTarget.children)
|
|
const center = this.carouselTarget.scrollLeft + this.carouselTarget.clientWidth / 2
|
|
|
|
let activeIndex = 0
|
|
let closest = Infinity
|
|
|
|
slides.forEach((slide, i) => {
|
|
const slideCenter = slide.offsetLeft + slide.offsetWidth / 2
|
|
const distance = Math.abs(slideCenter - center)
|
|
if (distance < closest) {
|
|
closest = distance
|
|
activeIndex = i
|
|
}
|
|
})
|
|
|
|
this.markerTargets.forEach((marker, i) => {
|
|
marker.classList.toggle("current", i === activeIndex)
|
|
})
|
|
}
|
|
|
|
goto(event) {
|
|
const index = parseInt(event.currentTarget.dataset.index, 10)
|
|
const slide = this.carouselTarget.children[index]
|
|
if (slide) {
|
|
this.carouselTarget.scrollTo({ left: slide.offsetLeft, behavior: "smooth" })
|
|
}
|
|
}
|
|
}
|