Files
cfw-autumn/apps/website/components/problem-animation.tsx
2026-04-27 16:13:15 +01:00

83 lines
2.3 KiB
TypeScript
Executable File

"use client";
const IMAGE_SOURCES = [
"/images/issues/Slack.svg",
"/images/issues/Frame%202147243001.svg",
"/images/issues/Frame%202147242729.svg",
"/images/issues/Slack-1.svg",
"/images/issues/Frame%202147243134.svg",
"/images/issues/Slack-2.svg",
"/images/issues/Frame%202147243146.svg",
"/images/issues/Stripe.svg",
];
const ITEM_COUNT = IMAGE_SOURCES.length;
const PAUSE_SECONDS = 2;
const SCROLL_SECONDS = 0.5;
const TOTAL_SECONDS = ITEM_COUNT * (PAUSE_SECONDS + SCROLL_SECONDS);
function buildKeyframes() {
const stepPct = 100 / ITEM_COUNT;
const pauseRatio = PAUSE_SECONDS / (PAUSE_SECONDS + SCROLL_SECONDS);
const perItemTranslate = 50 / ITEM_COUNT;
const frames = ["0% { transform: translateY(0); }"];
for (let i = 0; i < ITEM_COUNT; i++) {
const holdY = i * perItemTranslate;
const nextY = (i + 1) * perItemTranslate;
const pauseEndPct = (i * stepPct + stepPct * pauseRatio).toFixed(4);
const stepEndPct = ((i + 1) * stepPct).toFixed(4);
const holdTransform =
holdY === 0 ? "translateY(0)" : `translateY(-${holdY.toFixed(4)}%)`;
frames.push(`${pauseEndPct}% { transform: ${holdTransform}; }`);
frames.push(
`${stepEndPct}% { transform: translateY(-${nextY.toFixed(4)}%); }`,
);
}
return frames.join("\n ");
}
const keyframesCSS = buildKeyframes();
export default function ProblemAnimation() {
return (
<div className="relative w-full h-140 md:h-175 lg:h-175 xl:h-full bg-[#080808] overflow-hidden">
<style>{`
@keyframes carouselUp {
${keyframesCSS}
}
`}</style>
<div className="pointer-events-none absolute inset-x-0 top-0 h-20 z-10 bg-gradient-to-b from-[#080808] to-transparent" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-20 z-10 bg-gradient-to-t from-[#080808] to-transparent" />
<div
className="flex flex-col items-center will-change-transform"
style={{
animation: `carouselUp ${TOTAL_SECONDS}s ease-in-out infinite`,
}}
>
{[...IMAGE_SOURCES, ...IMAGE_SOURCES].map((src, i) => (
<div
key={i}
className="flex items-center justify-center shrink-0 w-full h-[80px] md:h-[140px]"
>
<img
src={src}
alt=""
className="block max-h-full max-w-[90%] object-contain"
loading="lazy"
decoding="async"
draggable={false}
/>
</div>
))}
</div>
</div>
);
}