Updated
This commit is contained in:
@@ -2,135 +2,208 @@
|
|||||||
// import
|
// import
|
||||||
|
|
||||||
import useHomeData from "~/composables/api/home/useHomeData";
|
import useHomeData from "~/composables/api/home/useHomeData";
|
||||||
|
import { motion } from "motion-v";
|
||||||
|
|
||||||
// state
|
// state
|
||||||
|
|
||||||
const { data: homeData } = useHomeData();
|
const { data: homeData } = useHomeData();
|
||||||
|
|
||||||
const { $gsap: gsap, $ScrollTrigger: ScrollTrigger } = useNuxtApp();
|
const activeSlide = ref(0);
|
||||||
|
|
||||||
let gsapTimeline: gsap.core.Timeline;
|
const variants = {
|
||||||
let scrollTrigger: ScrollTrigger;
|
hide: { opacity: 0, y: -200 },
|
||||||
|
show: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
when: "beforeChildren",
|
||||||
|
staggerChildren: 0.15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exit: (slidesCount: number) => {
|
||||||
|
return {
|
||||||
|
opacity: 0,
|
||||||
|
y: 200,
|
||||||
|
transition: {
|
||||||
|
when: "afterChildren",
|
||||||
|
delay: slidesCount * 0.21,
|
||||||
|
staggerChildren: 0.1,
|
||||||
|
staggerDirection: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// lifecycle
|
const childContentVariants = {
|
||||||
|
hide: {
|
||||||
|
filter: "blur(20px)",
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
show: {
|
||||||
|
filter: "blur(0px)",
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
exit: {
|
||||||
|
filter: "blur(20px)",
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const childImageVariants = {
|
||||||
|
hide: {
|
||||||
|
filter: "blur(20px)",
|
||||||
|
y: 70,
|
||||||
|
scale: 0.65,
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
show: {
|
||||||
|
filter: "blur(0px)",
|
||||||
|
y: 0,
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
type: "spring",
|
||||||
|
damping: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exit: {
|
||||||
|
filter: "blur(20px)",
|
||||||
|
y: 70,
|
||||||
|
scale: 0.65,
|
||||||
|
opacity: 0,
|
||||||
|
transition: {
|
||||||
|
default: {
|
||||||
|
type: "spring",
|
||||||
|
damping: 20,
|
||||||
|
},
|
||||||
|
opacity: {
|
||||||
|
duration: 0.1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextSlide = () => {
|
||||||
|
const slidesCount = homeData.value!.show_case_slider.length;
|
||||||
|
if (activeSlide.value > slidesCount - 2) {
|
||||||
|
activeSlide.value = 0;
|
||||||
|
} else {
|
||||||
|
activeSlide.value = activeSlide.value + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
gsapTimeline = gsap.timeline();
|
nextSlide();
|
||||||
const showcaseElements = gsap.utils.toArray<HTMLElement>(".showcase-slide");
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setInterval(() => {
|
||||||
showcaseElements.forEach((element, index) => {
|
nextSlide();
|
||||||
gsapTimeline.fromTo(
|
}, 5000);
|
||||||
element,
|
|
||||||
index === 0
|
|
||||||
? {
|
|
||||||
opacity: 1,
|
|
||||||
scale: 1,
|
|
||||||
// rotateX: -25,
|
|
||||||
zIndex: 1,
|
|
||||||
top: 0,
|
|
||||||
ease: "none",
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
opacity: 0,
|
|
||||||
scale: 1,
|
|
||||||
// rotateX: -25,
|
|
||||||
zIndex: 1,
|
|
||||||
top: 20,
|
|
||||||
ease: "none",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
opacity: 1,
|
|
||||||
scale: 1,
|
|
||||||
// rotateX: 0,
|
|
||||||
zIndex: 5,
|
|
||||||
top: 0,
|
|
||||||
ease: "none",
|
|
||||||
},
|
|
||||||
index === 0 ? "-=0%" : undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
if (index < showcaseElements.length - 1) {
|
|
||||||
gsapTimeline.to(element, {
|
|
||||||
opacity: 0,
|
|
||||||
scale: 1.03,
|
|
||||||
// rotateX: 25,
|
|
||||||
top: -20,
|
|
||||||
ease: "none",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
scrollTrigger = ScrollTrigger.create({
|
|
||||||
trigger: "#products-showcase-container",
|
|
||||||
animation: gsapTimeline,
|
|
||||||
scrub: 1,
|
|
||||||
pin: true,
|
|
||||||
start: "top top",
|
|
||||||
anticipatePin: 1,
|
|
||||||
// markers: true,
|
|
||||||
end: "bottom top",
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
scrollTrigger.update();
|
|
||||||
scrollTrigger.refresh();
|
|
||||||
}, 1000);
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
gsapTimeline.progress(1).pause();
|
|
||||||
gsapTimeline.kill();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section
|
<section class="relative z-[999] h-[115svh] min-h-[1000px] pb-20 bg-black overflow-y-hidden flex-center">
|
||||||
id="products-showcase-container"
|
<AnimatePresence mode="popLayout">
|
||||||
class="perspective-midrange relative z-[999]"
|
<template
|
||||||
>
|
|
||||||
<div class="w-full min-h-[120svh] lg:min-h-[102svh] bg-black">
|
|
||||||
<div
|
|
||||||
v-for="(slide, index) in homeData!.show_case_slider"
|
v-for="(slide, index) in homeData!.show_case_slider"
|
||||||
:key="index"
|
:key="slide.id"
|
||||||
class="showcase-slide origin-bottom absolute size-full bg-black flex items-center justify-center max-lg:-mt-16 lg:mt-5"
|
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<motion.div
|
||||||
class="w-[280px] xs:w-[350px] lg:w-[500px] xl:w-[650px] z-20 mb-30 sm:mb-20 lg:mb-30"
|
v-if="activeSlide === index"
|
||||||
:src="slide.image"
|
:initial="{ opacity: 0 }"
|
||||||
:style="{
|
:animate="{ opacity: 1 }"
|
||||||
mask: 'linear-gradient(to bottom, black 0%, rgba(0,0,0,0) 100%)',
|
:exit="{ opacity: 0 }"
|
||||||
}"
|
:transition="{ duration: 1 }"
|
||||||
alt=""
|
class="absolute size-full inset-0 -z-10"
|
||||||
/>
|
>
|
||||||
<div class="flex flex-col items-center justify-center gap-6 text-center absolute z-20 mt-20">
|
<NuxtImg
|
||||||
<span class="text-white typo-h-6 sm:typo-h-5 lg:typo-h-4 xl:typo-h-3">
|
:src="slide.background_image"
|
||||||
{{ slide.title }}
|
class="absolute size-full object-cover"
|
||||||
</span>
|
/>
|
||||||
<p
|
</motion.div>
|
||||||
class="text-white max-w-[320px] xs:max-w-[360px] sm:max-w-[480px] lg:max-w-[550px] xl:max-w-[750px] typo-p-sm lg:typo-p-md xl:typo-p-lg"
|
</template>
|
||||||
>
|
</AnimatePresence>
|
||||||
{{ slide.description }}
|
|
||||||
</p>
|
<AnimatePresence mode="popLayout">
|
||||||
<NuxtLink
|
<template
|
||||||
:to="`/resellers/category/${slide.id}`"
|
v-for="(slide, index) in homeData!.show_case_slider"
|
||||||
class="relative"
|
:key="slide.id"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<motion.div
|
||||||
src="/img/heymlz/heymlz-falling.gif"
|
v-if="activeSlide === index"
|
||||||
class="absolute top-[101px] sm:top-[100px] lg:top-[117px] left-1/2 -translate-1/2 w-[200px] lg:w-[250px] drop-shadow-md"
|
:custom="homeData!.show_case_slider.length"
|
||||||
/>
|
:variants="variants"
|
||||||
<Button
|
initial="hide"
|
||||||
variant="primary"
|
animate="show"
|
||||||
end-icon="ci:arrow-left"
|
exit="exit"
|
||||||
class="mt-8 max-sm:py-2 max-lg:typo-label-xs px-10 rounded-full hover:bg-transparent"
|
class="size-full flex flex-col gap-20 items-center justify-center"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-6 perspective-midrange">
|
||||||
|
<motion.div
|
||||||
|
:variants="childImageVariants"
|
||||||
|
class="origin-bottom-left"
|
||||||
>
|
>
|
||||||
مشاهده دسته بندی
|
<NuxtImg
|
||||||
</Button>
|
class="w-[300px] z-20 mt-40"
|
||||||
</NuxtLink>
|
:src="slide.image3"
|
||||||
</div>
|
alt=""
|
||||||
</div>
|
/>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
:variants="childImageVariants"
|
||||||
|
class="origin-bottom"
|
||||||
|
>
|
||||||
|
<NuxtImg
|
||||||
|
class="w-[300px] z-20"
|
||||||
|
:src="slide.image2"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
:variants="childImageVariants"
|
||||||
|
class="origin-bottom-right"
|
||||||
|
>
|
||||||
|
<NuxtImg
|
||||||
|
class="w-[300px] z-20 mt-40"
|
||||||
|
:src="slide.image1"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
:variants="childContentVariants"
|
||||||
|
class="flex flex-col items-center justify-center gap-6 text-center"
|
||||||
|
>
|
||||||
|
<span class="text-white typo-h-6 sm:typo-h-5 lg:typo-h-4 xl:typo-h-3">
|
||||||
|
{{ slide.title }}
|
||||||
|
</span>
|
||||||
|
<p
|
||||||
|
class="text-white max-w-[320px] xs:max-w-[360px] sm:max-w-[480px] lg:max-w-[550px] xl:max-w-[750px] typo-p-sm lg:typo-p-md xl:typo-p-lg"
|
||||||
|
>
|
||||||
|
{{ slide.description }}
|
||||||
|
</p>
|
||||||
|
<NuxtLink
|
||||||
|
:to="`/resellers/category/${slide.id}`"
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<NuxtImg
|
||||||
|
src="/img/heymlz/heymlz-falling.gif"
|
||||||
|
class="absolute top-[101px] sm:top-[100px] lg:top-[117px] left-1/2 -translate-1/2 w-[200px] lg:w-[250px] drop-shadow-md"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
end-icon="ci:arrow-left"
|
||||||
|
class="mt-8 max-sm:py-2 max-lg:typo-label-xs px-10 rounded-full hover:bg-transparent"
|
||||||
|
>
|
||||||
|
مشاهده دسته بندی
|
||||||
|
</Button>
|
||||||
|
</NuxtLink>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
</template>
|
||||||
|
</AnimatePresence>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user