90 lines
2.0 KiB
TypeScript
90 lines
2.0 KiB
TypeScript
import React from "react";
|
|
import Image, { ImageProps } from "next/image";
|
|
import styled, { keyframes, Keyframes } from "styled-components";
|
|
|
|
interface CrossFadeImagesProps {
|
|
width: ImageProps["width"];
|
|
height: ImageProps["height"];
|
|
images: string[];
|
|
presentationTime: number;
|
|
fadeTime: number;
|
|
}
|
|
|
|
const AnimatedImage = styled(Image)<{ layout: string; $delay: number }>`
|
|
animation-delay: ${(p) => p.$delay}s;
|
|
`;
|
|
|
|
const Container = styled.div<{ $animation: Keyframes; $duration: number; }>`
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
|
|
.not-first {
|
|
margin-left: -100%;
|
|
}
|
|
|
|
& > div {
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
flex: none;
|
|
|
|
img {
|
|
animation-name: ${(p) => p.$animation};
|
|
animation-timing-function: ease-in-out;
|
|
animation-iteration-count: infinite;
|
|
animation-duration: ${(p) => p.$duration}s;
|
|
}
|
|
}
|
|
`;
|
|
|
|
const CrossFadeImages: React.FC<CrossFadeImagesProps> = ({
|
|
width, height, images, presentationTime, fadeTime,
|
|
}) => {
|
|
const len = images.length;
|
|
const SINGLE_IMAGE_TIME = presentationTime + fadeTime;
|
|
const TOTAL_TIME = SINGLE_IMAGE_TIME * len;
|
|
|
|
const animation = keyframes`
|
|
0% {
|
|
opacity: 1;
|
|
}
|
|
${(presentationTime / TOTAL_TIME) * 100}% {
|
|
opacity: 1;
|
|
}
|
|
${(1 / len) * 100}% {
|
|
opacity: 0;
|
|
}
|
|
${100 - ((fadeTime / TOTAL_TIME) * 100)}% {
|
|
opacity: 0;
|
|
}
|
|
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
`;
|
|
|
|
const delays = images.map((_, idx) => idx * SINGLE_IMAGE_TIME).reverse();
|
|
|
|
return (
|
|
<Container
|
|
$animation={animation}
|
|
$duration={len * SINGLE_IMAGE_TIME}
|
|
>
|
|
{ images.map((image, idx) => (
|
|
<div key={idx} className={idx > 0 ? "not-first" : undefined}>
|
|
<AnimatedImage
|
|
key={image}
|
|
src={image}
|
|
objectFit="cover"
|
|
width={width}
|
|
height={height}
|
|
layout="responsive"
|
|
$delay={delays[idx]}
|
|
/>
|
|
</div>
|
|
))}
|
|
</Container>
|
|
);
|
|
};
|
|
|
|
export default CrossFadeImages;
|