2022-07-12 10:55:28 +02:00
|
|
|
<template>
|
2022-08-12 16:46:44 +02:00
|
|
|
<div class="relative pt-10 px-2">
|
2022-08-16 13:59:37 +02:00
|
|
|
<div class="mb-2">
|
|
|
|
<div class="w-full flex flex-wrap gap-3 items-center">
|
|
|
|
<h2
|
|
|
|
class="text-xl font-bold tracking-tight text-gray-900 dark:text-gray-100"
|
|
|
|
>
|
|
|
|
<slot name="title" />
|
|
|
|
</h2>
|
|
|
|
|
|
|
|
<button
|
|
|
|
v-if="suggestGeoloc && isIPLocation"
|
|
|
|
class="inline-flex bg-primary rounded text-white flex-initial px-4 py-2 justify-center w-full md:w-min whitespace-nowrap"
|
|
|
|
@click="emit('doGeoLoc')"
|
|
|
|
>
|
|
|
|
{{ t("Geolocate me") }}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<slot name="subtitle" />
|
2022-07-12 10:55:28 +02:00
|
|
|
</div>
|
|
|
|
<div class="hidden sm:block" v-show="showScrollLeftButton">
|
|
|
|
<button
|
|
|
|
@click="scrollLeft"
|
|
|
|
class="absolute inset-y-0 my-auto z-10 rounded-full bg-white w-10 h-10 border border-shadowColor -left-5"
|
|
|
|
>
|
|
|
|
<div class=""><</div>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div class="overflow-hidden">
|
|
|
|
<div
|
2022-08-16 13:59:37 +02:00
|
|
|
class="relative w-full snap-x snap-always snap-mandatory overflow-x-auto flex pb-6 gap-x-5 gap-y-8"
|
2022-07-12 10:55:28 +02:00
|
|
|
ref="scrollContainer"
|
|
|
|
@scroll="scrollHandler"
|
|
|
|
>
|
|
|
|
<slot name="content" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="hidden sm:block" v-show="showScrollRightButton">
|
|
|
|
<button
|
|
|
|
@click="scrollRight"
|
|
|
|
class="absolute inset-y-0 my-auto z-10 rounded-full bg-white w-10 h-10 border border-shadowColor -right-5"
|
|
|
|
>
|
|
|
|
<div class="">></div>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
import { computed, inject, onMounted, onUnmounted, ref } from "vue";
|
|
|
|
import { useI18n } from "vue-i18n";
|
|
|
|
import { LocationType } from "../../types/user-location.model";
|
|
|
|
|
|
|
|
withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
suggestGeoloc?: boolean;
|
|
|
|
}>(),
|
|
|
|
{ suggestGeoloc: true }
|
|
|
|
);
|
|
|
|
|
|
|
|
const emit = defineEmits(["doGeoLoc"]);
|
|
|
|
|
|
|
|
const { t } = useI18n({ useScope: "global" });
|
|
|
|
|
|
|
|
const userLocationInjection = inject<{
|
|
|
|
userLocation: LocationType;
|
|
|
|
}>("userLocation");
|
|
|
|
|
|
|
|
const isIPLocation = computed(
|
|
|
|
() => userLocationInjection?.userLocation.isIPLocation
|
|
|
|
);
|
|
|
|
|
|
|
|
const showScrollRightButton = ref(true);
|
|
|
|
const showScrollLeftButton = ref(false);
|
|
|
|
|
|
|
|
const scrollContainer = ref<any>();
|
|
|
|
|
|
|
|
const scrollHandler = () => {
|
|
|
|
if (scrollContainer.value) {
|
|
|
|
showScrollRightButton.value =
|
|
|
|
scrollContainer.value.scrollLeft <
|
|
|
|
scrollContainer.value.scrollWidth - scrollContainer.value.clientWidth;
|
|
|
|
showScrollLeftButton.value = scrollContainer.value.scrollLeft > 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const doScroll = (e: Event, left: number) => {
|
|
|
|
e.preventDefault();
|
|
|
|
if (scrollContainer.value) {
|
|
|
|
scrollContainer.value.scrollBy({
|
|
|
|
left,
|
|
|
|
behavior: "smooth",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const scrollLeft = (e: Event) => {
|
|
|
|
doScroll(e, -300);
|
|
|
|
};
|
|
|
|
|
|
|
|
const scrollRight = (e: Event) => {
|
|
|
|
doScroll(e, 300);
|
|
|
|
};
|
|
|
|
|
|
|
|
const scrollHorizontalToVertical = (evt: WheelEvent) => {
|
2022-08-16 13:59:37 +02:00
|
|
|
evt.deltaY > 0 ? doScroll(evt, 300) : doScroll(evt, -300);
|
2022-07-12 10:55:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
scrollContainer.value.addEventListener("wheel", scrollHorizontalToVertical);
|
|
|
|
});
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
if (scrollContainer.value) {
|
|
|
|
scrollContainer.value.removeEventListener(
|
|
|
|
"wheel",
|
|
|
|
scrollHorizontalToVertical
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|