62 lines
1.8 KiB
Plaintext
62 lines
1.8 KiB
Plaintext
---
|
||
interface Slide {
|
||
image: string;
|
||
title: string;
|
||
body: string;
|
||
}
|
||
|
||
const { slides }: { slides: Slide[] } = Astro.props;
|
||
---
|
||
|
||
<div class="login-carousel" data-carousel>
|
||
<button class="nav prev" type="button" aria-label="이전 슬라이드">‹</button>
|
||
|
||
<div class="track" data-track>
|
||
{slides.map((slide, idx) => (
|
||
<article class={`slide ${idx === 0 ? "is-active" : ""}`} data-index={idx}>
|
||
<img src={slide.image} alt={slide.title} loading="lazy" />
|
||
<div class="caption">
|
||
<h4>{slide.title}</h4>
|
||
<p>{slide.body}</p>
|
||
</div>
|
||
</article>
|
||
))}
|
||
</div>
|
||
|
||
<button class="nav next" type="button" aria-label="다음 슬라이드">›</button>
|
||
|
||
<div class="dots" aria-hidden="true">
|
||
{slides.map((_, idx) => (
|
||
<button
|
||
class={`dot ${idx === 0 ? "is-active" : ""}`}
|
||
type="button"
|
||
data-dot={idx}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
if (typeof window !== "undefined") {
|
||
const carousels = document.querySelectorAll("[data-carousel]");
|
||
|
||
carousels.forEach((root) => {
|
||
const slides = [...root.querySelectorAll(".slide")];
|
||
const dots = [...root.querySelectorAll(".dot")];
|
||
const prev = root.querySelector(".prev");
|
||
const next = root.querySelector(".next");
|
||
let current = 0;
|
||
|
||
const activate = (idx) => {
|
||
current = (idx + slides.length) % slides.length;
|
||
slides.forEach((el, i) => el.classList.toggle("is-active", i === current));
|
||
dots.forEach((el, i) => el.classList.toggle("is-active", i === current));
|
||
};
|
||
|
||
prev?.addEventListener("click", () => activate(current - 1));
|
||
next?.addEventListener("click", () => activate(current + 1));
|
||
dots.forEach((dot, i) => dot.addEventListener("click", () => activate(i)));
|
||
});
|
||
}
|
||
</script>
|