feat(slider): add slider feature
This commit is contained in:
@@ -1,100 +0,0 @@
|
||||
<template>
|
||||
<div v-if="slides.length > 0" class="app-banner px-4">
|
||||
<Swiper
|
||||
class="select-none"
|
||||
:slides-per-view="1"
|
||||
:space-between="50"
|
||||
pagination
|
||||
:pagination="{ clickable: true }"
|
||||
@swiper="onSwiper"
|
||||
@slideChange="onSlideChange"
|
||||
>
|
||||
<SwiperSlide v-for="slide in slides" :key="slide.id">
|
||||
<RouterLink
|
||||
v-if="slide?.link?.type === 'category'"
|
||||
:to="{name: 'product.categories.show', params: {category_id: slide.link.value.category_id}}"
|
||||
@click="sliderClick(slide)"
|
||||
>
|
||||
<img :src="slide.image" :alt="slide.title">
|
||||
</RouterLink>
|
||||
|
||||
<RouterLink
|
||||
v-else-if="slide?.link?.type === 'product'"
|
||||
:to="{name: 'product.show', params: {id: slide.link.value.product_id}}"
|
||||
@click="sliderClick(slide)"
|
||||
>
|
||||
<img :src="slide.image" :alt="slide.title">
|
||||
</RouterLink>
|
||||
|
||||
<img
|
||||
v-else-if="slide?.link?.type === 'url'"
|
||||
:src="slide.image"
|
||||
:alt="slide.title"
|
||||
@click="openExternalLink(slide.link.value.url, slide)"
|
||||
>
|
||||
|
||||
<img v-else :src="slide.image" :alt="slide.title"/>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {Swiper, SwiperSlide} from 'swiper/vue';
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import {onMounted, ref} from "vue";
|
||||
import {fetchBanner} from "@/utils/ftch.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const slides = ref([]);
|
||||
|
||||
const onSwiper = (swiper) => {
|
||||
console.log(swiper);
|
||||
};
|
||||
const onSlideChange = () => {
|
||||
console.log('slide change');
|
||||
};
|
||||
|
||||
function sliderClick(slide) {
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.SLIDER_HOME_CLICK, {
|
||||
banner: slide.title,
|
||||
});
|
||||
}
|
||||
|
||||
function openExternalLink(link, slide) {
|
||||
if (! link) {
|
||||
return;
|
||||
}
|
||||
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.SLIDER_HOME_CLICK, {
|
||||
banner: slide.title,
|
||||
});
|
||||
|
||||
window.Telegram.WebApp.openLink(link, {try_instant_view: false});
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const response = await fetchBanner();
|
||||
slides.value = response.data;
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.app-banner .swiper-horizontal > .swiper-pagination-bullets {
|
||||
position: relative;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.app-banner .swiper-horizontal .swiper-slide {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.app-banner .swiper-horizontal .swiper-slide img {
|
||||
border-radius: var(--radius-box);
|
||||
}
|
||||
</style>
|
||||
180
frontend/spa/src/components/MainpageSlider.vue
Normal file
180
frontend/spa/src/components/MainpageSlider.vue
Normal file
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="sliders.mainpage_slider.is_enabled && sliders.mainpage_slider.slides.length > 0"
|
||||
class="app-banner"
|
||||
:class="classList"
|
||||
>
|
||||
<Swiper
|
||||
:effect="slideEffect"
|
||||
class="select-none"
|
||||
:slides-per-view="1"
|
||||
:space-between="sliders.mainpage_slider.space_between"
|
||||
:pagination="pagination"
|
||||
:lazy="true"
|
||||
:modules="modules"
|
||||
:scrollbar="scrollbar"
|
||||
:free-mode="sliders.mainpage_slider.free_mode"
|
||||
:loop="sliders.mainpage_slider.loop"
|
||||
:autoplay="autoplay"
|
||||
@swiper="onSwiper"
|
||||
@slideChange="onSlideChange"
|
||||
>
|
||||
<SwiperSlide v-for="slide in sliders.mainpage_slider.slides" :key="slide.id">
|
||||
<RouterLink
|
||||
v-if="slide?.link?.type === 'category'"
|
||||
:to="{name: 'product.categories.show', params: {category_id: slide.link.value.category_id}}"
|
||||
@click="sliderClick(slide)"
|
||||
>
|
||||
<img :src="slide.image" :alt="slide.title" loading="lazy">
|
||||
</RouterLink>
|
||||
|
||||
<RouterLink
|
||||
v-else-if="slide?.link?.type === 'product'"
|
||||
:to="{name: 'product.show', params: {id: slide.link.value.product_id}}"
|
||||
@click="sliderClick(slide)"
|
||||
>
|
||||
<img :src="slide.image" :alt="slide.title" loading="lazy">
|
||||
</RouterLink>
|
||||
|
||||
<img
|
||||
v-else-if="slide?.link?.type === 'url'"
|
||||
:src="slide.image"
|
||||
:alt="slide.title"
|
||||
loading="lazy"
|
||||
@click="openExternalLink(slide.link.value.url, slide)"
|
||||
>
|
||||
|
||||
<img v-else :src="slide.image" :alt="slide.title" loading="lazy"/>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {Swiper, SwiperSlide} from 'swiper/vue';
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {EffectCoverflow, EffectCards, EffectCube, EffectFlip, Scrollbar, Autoplay} from 'swiper/modules';
|
||||
import {computed, onMounted} from "vue";
|
||||
import {useSlidersStore} from "@/stores/SlidersStore.js";
|
||||
|
||||
const sliders = useSlidersStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const modules = [
|
||||
Autoplay,
|
||||
EffectCards,
|
||||
EffectFlip,
|
||||
EffectCube,
|
||||
Scrollbar,
|
||||
EffectCoverflow,
|
||||
];
|
||||
|
||||
const classList = computed(() => {
|
||||
if (sliders.mainpage_slider.effect === 'cards') {
|
||||
return ['px-8'];
|
||||
}
|
||||
|
||||
if (sliders.mainpage_slider.effect === 'flip') {
|
||||
return ['px-4', 'pb-4', 'pt-4'];
|
||||
}
|
||||
|
||||
if (sliders.mainpage_slider.effect === 'cube') {
|
||||
return ['px-4', 'pb-10'];
|
||||
}
|
||||
|
||||
return ['px-4'];
|
||||
});
|
||||
|
||||
const onSwiper = (swiper) => {
|
||||
console.log(swiper);
|
||||
};
|
||||
const onSlideChange = () => {
|
||||
console.log('slide change');
|
||||
};
|
||||
|
||||
const slideEffect = computed(() => {
|
||||
if (sliders.mainpage_slider.effect === 'slide') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sliders.mainpage_slider.effect;
|
||||
});
|
||||
|
||||
const pagination = computed(() => {
|
||||
if (sliders.mainpage_slider.pagination) {
|
||||
return {
|
||||
clickable: true, dynamicBullets: false,
|
||||
};
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const scrollbar = computed(() => {
|
||||
if (sliders.mainpage_slider.scrollbar) {
|
||||
return {
|
||||
hide: true,
|
||||
};
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const autoplay = computed(() => {
|
||||
if (sliders.mainpage_slider.autoplay) {
|
||||
return {
|
||||
delay: 3000,
|
||||
reverseDirection: false,
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
function sliderClick(slide) {
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.SLIDER_HOME_CLICK, {
|
||||
banner: slide.title,
|
||||
});
|
||||
}
|
||||
|
||||
function openExternalLink(link, slide) {
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.SLIDER_HOME_CLICK, {
|
||||
banner: slide.title,
|
||||
});
|
||||
|
||||
window.Telegram.WebApp.openLink(link, {try_instant_view: false});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.debug('[Mainpage Slider] Status: ', sliders.mainpage_slider);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.app-banner {
|
||||
aspect-ratio: 740 / 400;
|
||||
}
|
||||
|
||||
.app-banner .swiper {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.app-banner .swiper-horizontal > .swiper-pagination-bullets {
|
||||
position: relative;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.app-banner .swiper-horizontal .swiper-slide {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.app-banner .swiper-horizontal .swiper-slide img {
|
||||
border-radius: var(--radius-box);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user