92 lines
2.4 KiB
Plaintext
92 lines
2.4 KiB
Plaintext
---
|
|
import type { HomepageBannerImage } from '../lib/fallback-data';
|
|
|
|
type Props = {
|
|
images: HomepageBannerImage[];
|
|
randomizeAfterFirst?: boolean;
|
|
};
|
|
|
|
const { images, randomizeAfterFirst = false } = Astro.props;
|
|
const slides = images.length > 0 ? images : [{ src: '/images/banner.png', alt: 'Swansea Airport banner' }];
|
|
---
|
|
|
|
<div class="banner-rotator" data-banner-rotator data-randomize-after-first={randomizeAfterFirst ? 'true' : undefined}>
|
|
{slides.map((image, index) => (
|
|
<img
|
|
class:list={['banner-slide', { active: index === 0 }]}
|
|
src={image.src}
|
|
alt={image.alt}
|
|
loading={index === 0 ? 'eager' : 'lazy'}
|
|
decoding="async"
|
|
data-banner-slide
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{slides.length > 1 && (
|
|
<script>
|
|
(() => {
|
|
const root = document.querySelector('[data-banner-rotator]');
|
|
if (!root || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
|
|
|
const slides = Array.from(root.querySelectorAll('[data-banner-slide]'));
|
|
if (slides.length < 2) return;
|
|
|
|
if (root.getAttribute('data-randomize-after-first') === 'true') {
|
|
const firstSlide = slides[0];
|
|
const restSlides = slides.slice(1);
|
|
|
|
for (let index = restSlides.length - 1; index > 0; index -= 1) {
|
|
const swapIndex = Math.floor(Math.random() * (index + 1));
|
|
[restSlides[index], restSlides[swapIndex]] = [restSlides[swapIndex], restSlides[index]];
|
|
}
|
|
|
|
slides.splice(0, slides.length, firstSlide, ...restSlides);
|
|
}
|
|
|
|
let currentIndex = 0;
|
|
window.setInterval(() => {
|
|
slides[currentIndex].classList.remove('active');
|
|
currentIndex = (currentIndex + 1) % slides.length;
|
|
slides[currentIndex].classList.add('active');
|
|
}, 3500);
|
|
})();
|
|
</script>
|
|
)}
|
|
|
|
<style>
|
|
.banner-rotator {
|
|
position: relative;
|
|
width: 100%;
|
|
min-height: clamp(9rem, 21vw, 16rem);
|
|
overflow: hidden;
|
|
isolation: isolate;
|
|
background: #dcecff;
|
|
}
|
|
|
|
.banner-slide {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: block;
|
|
object-fit: cover;
|
|
opacity: 0;
|
|
transform: scale(1.035);
|
|
transition:
|
|
opacity 1.1s ease,
|
|
transform 7s ease;
|
|
}
|
|
|
|
.banner-slide.active {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.banner-slide {
|
|
transition: none;
|
|
}
|
|
}
|
|
</style>
|