vbv/client/src/pages/learningPath/learningPathPage/LearningPathPathView.vue

82 lines
2.6 KiB
Vue

<script setup lang="ts">
import LearningPathScrollButton from "@/pages/learningPath/learningPathPage/LearningPathScrollButton.vue";
import { useScroll } from "@vueuse/core";
import { computed, nextTick, ref, watch } from "vue";
import type { LearningContentWithCompletion, LearningPathType } from "@/types";
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
import LearningPathPathTopic from "./LearningPathPathTopic.vue";
const props = defineProps<{
learningPath: LearningPathType | undefined;
nextLearningContent: LearningContentWithCompletion | undefined;
useMobileLayout: boolean;
hideButtons?: boolean;
overrideCircleUrlBase?: string;
filter?: string;
}>();
const scrollIncrement = 600;
const learnPathDiagram = ref<HTMLElement | null>(null);
const { x, arrivedState } = useScroll(learnPathDiagram, { behavior: "smooth" });
const scrollRight = () => scrollLearnPathDiagram(scrollIncrement);
const scrollLeft = () => scrollLearnPathDiagram(-scrollIncrement);
const scrollLearnPathDiagram = (offset: number) => {
x.value += offset;
};
const topics = computed(() => props.learningPath?.topics ?? []);
watch(
() => props.filter,
() => {
// we need to update the scroll state of the element, otherwise the arrows won't match the scroll state
// https://github.com/vueuse/vueuse/issues/2875
nextTick(() => {
if (learnPathDiagram.value) {
const scrollEvent = new Event("scroll");
learnPathDiagram.value.dispatchEvent(scrollEvent);
}
});
}
);
</script>
<template>
<div v-if="!props.learningPath" class="m-8 flex justify-center">
<LoadingSpinner />
</div>
<div v-else class="relative flex flex-row items-center">
<LearningPathScrollButton
v-show="!arrivedState.left"
direction="left"
:hidden="props.useMobileLayout"
@click="scrollLeft"
></LearningPathScrollButton>
<div
ref="learnPathDiagram"
class="no-scrollbar flex h-96 snap-x flex-row overflow-auto py-5 sm:py-10"
>
<LearningPathPathTopic
v-for="(topic, topicIndex) in props.learningPath?.topics ?? []"
:key="topic.title"
:topic-index="topicIndex"
:topic="topic"
:next-learning-content="nextLearningContent"
:override-circle-url-base="overrideCircleUrlBase"
:filter="filter"
:is-last-topic="topicIndex === topics.length - 1"
/>
</div>
<LearningPathScrollButton
v-show="!arrivedState.right"
direction="right"
:hidden="props.useMobileLayout"
@click="scrollRight"
></LearningPathScrollButton>
</div>
</template>