feat: added slider animation to boxes in layout
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, type KeyboardEvent } from "react";
|
import { useEffect, useState, type KeyboardEvent } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
|
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
|
||||||
@@ -30,6 +30,8 @@ export type LayoutContentPromo = {
|
|||||||
|
|
||||||
type PromoRailSide = "left" | "right";
|
type PromoRailSide = "left" | "right";
|
||||||
|
|
||||||
|
const PROMO_ROTATION_INTERVAL_MS = 8_000;
|
||||||
|
|
||||||
function RailButton({
|
function RailButton({
|
||||||
href,
|
href,
|
||||||
label,
|
label,
|
||||||
@@ -213,6 +215,7 @@ function PromoRail({
|
|||||||
const t = useTranslations("LayoutPromos");
|
const t = useTranslations("LayoutPromos");
|
||||||
const reduceMotion = useReducedMotion();
|
const reduceMotion = useReducedMotion();
|
||||||
const [activeSlide, setActiveSlide] = useState(0);
|
const [activeSlide, setActiveSlide] = useState(0);
|
||||||
|
const [isPaused, setIsPaused] = useState(false);
|
||||||
const direction = side === "left" ? -1 : 1;
|
const direction = side === "left" ? -1 : 1;
|
||||||
const activeCards = slides[activeSlide] ?? slides[0];
|
const activeCards = slides[activeSlide] ?? slides[0];
|
||||||
const railId = `${side}-promo-rail`;
|
const railId = `${side}-promo-rail`;
|
||||||
@@ -221,6 +224,16 @@ function PromoRail({
|
|||||||
setActiveSlide((current) => (current + step + slides.length) % slides.length);
|
setActiveSlide((current) => (current + step + slides.length) % slides.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (reduceMotion || isPaused || slides.length < 2) return;
|
||||||
|
|
||||||
|
const timer = window.setTimeout(() => {
|
||||||
|
setActiveSlide((current) => (current + 1) % slides.length);
|
||||||
|
}, PROMO_ROTATION_INTERVAL_MS);
|
||||||
|
|
||||||
|
return () => window.clearTimeout(timer);
|
||||||
|
}, [activeSlide, isPaused, reduceMotion, slides.length]);
|
||||||
|
|
||||||
const handleNavigationKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
const handleNavigationKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
||||||
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
||||||
|
|
||||||
@@ -231,6 +244,10 @@ function PromoRail({
|
|||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
aria-label={t(side === "left" ? "leftRailLabel" : "rightRailLabel")}
|
aria-label={t(side === "left" ? "leftRailLabel" : "rightRailLabel")}
|
||||||
|
onMouseEnter={() => setIsPaused(true)}
|
||||||
|
onMouseLeave={() => setIsPaused(false)}
|
||||||
|
onFocusCapture={() => setIsPaused(true)}
|
||||||
|
onBlurCapture={() => setIsPaused(false)}
|
||||||
className="relative z-50 hidden min-[1420px]:block"
|
className="relative z-50 hidden min-[1420px]:block"
|
||||||
>
|
>
|
||||||
<div className="sticky top-4 py-4">
|
<div className="sticky top-4 py-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user